skip to content

helm install --verify fails on a chart that installs fine without it. How do you diagnose it?

level: seniorimportance: should knowfreq 33%

answer

  1. Only two checks can fail
  2. Take the cluster out of the picture first
  3. Missing sidecar, unknown key, or wrong bytes
  4. The .prov is readable — compare the digest yourself
  5. Re-packaging breaks provenance without changing files

basics

~20 s

Split it into three causes: no .prov served beside the .tgz, a keyring that lacks the signer's public key or is in a format Helm cannot read, or a digest mismatch because the tarball was re-packaged after signing. Reproduce locally with helm pull then helm verify.

solid answer

~50 s

`--verify` adds exactly two checks, so the failure is always one of three things. **No provenance**: the repository serves `maildigest-2.14.3.tgz` but not the matching `.tgz.prov`, so there is nothing to check. **Key problem**: the keyring the runner used does not contain the signer's public key — a wrong `--keyring` path, an empty home directory on a fresh CI runner, or a modern GnuPG keybox rather than the legacy keyring format Helm reads. **Digest mismatch**: the tarball's bytes differ from what was signed, which in practice means something re-packaged the chart between signing and publication. Diagnose by taking the cluster out of the picture: `helm pull` the chart and its provenance to disk, run `helm verify` on the pair, read the `.prov` (it is clear text, so the digest and chart version are visible), and compare a locally computed SHA-256 against the `files:` entry.

code

bash · 10 lines
bash
# 1. pull chart + provenance, drop the cluster from the picture
helm pull internal/maildigest --version 2.14.3 --prov
ls maildigest-2.14.3.tgz*          # is the .prov even there?

# 2. does the keyring hold the signer?
helm verify maildigest-2.14.3.tgz --keyring /etc/helm/trusted-signers.gpg

# 3. do the bytes match what was signed? (.prov is clear text)
sed -n '/^files:/,+2p' maildigest-2.14.3.tgz.prov
sha256sum maildigest-2.14.3.tgz

go deeper

for a junior

Know the two things --verify needs before you can debug it: a .prov file next to the chart, and the signer's public key in the keyring you pass. Most failures at this level are one of those two being absent.

for a middle

Practise reproducing the failure off-cluster with helm pull followed by helm verify, and be able to say which half of the check failed. Knowing that the .prov is readable text you can compare against a computed sha256 is the fastest tool you have.

for a senior

Show a method rather than a guess: three causes, one command each, fixed at the layer that produced them. Name re-packaging by a mirror as the classic digest-mismatch source, and be explicit that removing the flag to unblock a pipeline is not a fix.

for a principal

Argue about where this failure should surface at all. Verification at artifact ingress fails once, in a job you own, instead of intermittently across every cluster, and it lets you decide the response policy for a digest mismatch before an outage forces the decision.

`--verify` is a small surface, which is what makes this triage tractable: it can only fail for a handful of reasons, and each has a distinct signal. The scenario worth holding in mind is the ordinary one — an internal `maildigest` chart (the email-digest builder, version 2.14.3, a 240-line values file and a `values.schema.json` contract) that installs cleanly in a developer shell and fails in the pipeline the moment `--verify` is added. ### Step 0: separate the flag from everything else `helm install` without `--verify` proves nothing about provenance — it means the chart resolved and rendered. So do not start by comparing the two commands; start by removing the cluster entirely: ```bash helm pull internal/maildigest --version 2.14.3 --prov ls maildigest-2.14.3.tgz* helm verify maildigest-2.14.3.tgz --keyring /etc/helm/trusted-signers.gpg ``` If `helm verify` fails on the local pair, this has nothing to do with the cluster, the namespace, RBAC, or values. If the `.prov` never landed, you already have your answer. ### Cause 1: there is no provenance file For a chart resolved from a repository, `--verify` needs the server to host `<chart>-<version>.tgz.prov` beside the tarball. Publishers who ran `helm package` without `--sign` produce no such file; mirroring jobs frequently copy `*.tgz` and silently drop the sidecar; a repository that regenerates its index from tarballs it found on disk will happily list a chart whose provenance was never copied. The tell is that the file simply 404s. Fix it at the publisher: sign at package time and publish both artifacts as a unit, never one without the other. ### Cause 2: the key is not where Helm is looking `--keyring` defaults to `~/.gnupg/pubring.gpg`. A CI runner usually has no GnuPG home at all, so the default resolves to a nonexistent file and every signer is unknown. Even when a keyring exists, modern GnuPG keeps public keys in a keybox database rather than the legacy binary keyring Helm reads, so pointing at the wrong file gives you an empty trust set that looks identical to "signed by a stranger". The distinguishing evidence is that the failure is about the *signer or signature*, and it reproduces with a keyring you know is empty. The fix is to stop depending on ambient GnuPG state: build a keyring file containing exactly the public keys your organisation trusts, ship it to runners as a managed artifact, and pass `--keyring` explicitly everywhere. That also makes the trust set reviewable, which the developer's personal keyring never is. ### Cause 3: the digest does not match This is the interesting one, and the most common in an estate that mirrors charts. The `.prov` pins the SHA-256 of the exact tarball produced at signing. Anything that re-creates the archive — a mirror that unpacks and re-packs, a second `helm package` run publishing new bytes alongside the old `.prov`, a sync tool that "normalises" artifacts, a partially transferred file — changes those bytes and breaks the comparison while the signature over the document remains perfectly valid. You can confirm this by hand in seconds, because the `.prov` is clear-signed text: ```bash sed -n '/^files:/,+2p' maildigest-2.14.3.tgz.prov sha256sum maildigest-2.14.3.tgz ``` Two digests, one comparison. If they differ, no key or keyring change will ever help; the artifact you have is not the artifact that was signed. Fix the pipeline so the signed bytes are the published bytes — and if you need repeatable rebuilds, Helm 4's `helm package` honours `SOURCE_DATE_EPOCH` to keep tarballs reproducible. ### Cause 4, occasionally: mismatched pair A `.prov` from a neighbouring version can end up beside the wrong tarball after a hand-copy. The metadata block in the signed body names the chart and version, so reading the file tells you immediately that you are holding provenance for `2.14.2` next to a `2.14.3` tarball. ### What good triage looks like State the three buckets before touching anything, then collapse them with one command each: does the `.prov` exist, does the keyring contain the signer, does the digest match. Fix the cause at the layer that produced it — publisher, runner configuration, or mirror — rather than the layer that reported it. And say the thing an interviewer is listening for: dropping `--verify` to unblock the pipeline converts a genuine trust check into a comment in a runbook, so the flag is not the thing to remove while you investigate.

  • How do you tell a keyring problem from a digest problem without guessing?
    Run helm verify on the local pair and read which half failed: an unknown-signer failure is about keys, a hash failure is about bytes. Then confirm the byte side by hand — the .prov is clear-signed text, so you can print its files: block and compare it to a locally computed sha256 of the tarball. Two independent digests either agree or they do not; there is nothing to infer.
  • The CI runner has no GnuPG setup at all. What is the minimum it needs to verify a chart?
    A keyring file containing the public keys of the signers you trust, and --keyring pointing at it explicitly. No private key, no GnuPG agent, no personal keyring. Ship that file as a managed artifact rather than relying on ambient state on the runner, and remember Helm reads the legacy binary keyring format, so export from a modern GnuPG keybox before shipping it.
  • The pipeline is blocked and the fix is upstream. Do you drop --verify to ship?
    Not silently. Dropping the flag turns a trust check into an assumption, and flags removed under pressure are rarely restored. Prefer installing a known-good verified version, or a documented, time-boxed exception with the artifact digest recorded and a ticket on the publisher. If the failure is a digest mismatch you should be more cautious, not less — that is the one cause consistent with tampering rather than misconfiguration.

saying these in an interview costs you the question

  • Dropping --verify to unblock the build and moving on
  • Assuming any failure means the chart was tampered with
  • Blaming the cluster or RBAC for a provenance failure
  • Not knowing the .prov must be served beside the .tgz
  • Importing keys into a keyring Helm never reads
  • Re-signing a mirrored chart to make the error go away

context