After moving CI to Helm 4, why does helm plugin install now fail for a plugin that installed fine under Helm 3?
answer
- It fails on rebuild, not on upgrade
- A security default, not a format error
- Compare with chart signing's default posture
- The opt-out flag is spelled with false
- helm plugin install --verify defaults true
basics
~20 sHelm 4 verifies plugin provenance on install by default: helm plugin install --verify is true unless you say otherwise. An unsigned plugin that Helm 3 installed silently now fails, and the opt-out is --verify=false — there is no --allow-insecure-plugins flag.
solid answer
~50 sThis is the classic "the CLI upgrade broke the image, not the charts" symptom. Helm 4 rebuilt plugins, and one of the changes is a security default: `helm plugin install` verifies the plugin's signature by default, so an unsigned or unverifiable plugin that installed without comment under Helm 3 now fails. Two details matter operationally. First, the opt-out is `--verify=false`; candidates often invent a permissive-sounding flag that does not exist. Second, this bites on **rebuild**, not on upgrade: a plugin directory already sitting under the plugin path is loaded by Helm 4 — a `plugin.yaml` predating the new format is still read as a legacy CLI plugin — so a developer laptop keeps working while the freshly built CI image fails. Note the asymmetry with charts: `helm package --sign` is still opt-in and chart verification is not on by default.
code
bash · 9 lines# Helm 4 verifies plugin provenance by default
helm plugin install ./analytics-plugin-1.4.2.tgz
# deliberate, greppable exception for an unsigned third-party plugin
helm plugin install ./analytics-plugin-1.4.2.tgz --verify=false
# the better fix if the plugin is yours
helm plugin package --sign ./analytics-plugin
helm plugin verify ./analytics-plugin-1.4.2.tgzgo deeper
Know that Helm 4 checks a plugin's signature when installing it and that an unsigned plugin needs an explicit opt-out on the install command, rather than assuming the plugin itself is broken.
Be able to explain why the failure surfaces on a fresh image build and not on a machine that already has the plugin, and to name the opt-out precisely instead of inventing a permissive flag.
Demonstrate the operator's move: sign the plugin rather than disabling the check, keep any exception in one reviewable place, and use the migration as the moment to audit which plugins the pipeline really needs.
Own the trust argument — client-side plugin execution versus cluster-mediated chart rendering — and decide what your organisation's standing policy is for unsigned executables entering build images.
## The symptom A team moves its CI image from Helm 3 to Helm 4. Chart rendering is fine, the release history reads fine, the invoice-rendering worker deploys fine — and the image build fails at the step that installs the team's helper plugin. Nothing about the plugin changed. Meanwhile, every engineer's laptop still works, because their plugin directory was populated months ago and is simply carried forward. That split — installs fail, already-installed plugins keep working — is the signature of this class of migration issue, and it is worth recognising it in an interview because it explains why the failure appears late, in the pipeline, rather than during a local trial. ## What changed Helm 4 rebuilt the plugin system. The part relevant to a migration is the **verification default**: `helm plugin install --verify` defaults to **true**. Helm 4 also gained `helm plugin package --sign` and `helm plugin verify`, so plugins have a first-class signing story. If the plugin you are installing has no valid provenance to check, the install fails rather than proceeding. The opt-out is `--verify=false`. That precision matters more than it sounds: there is no `--allow-insecure-plugins` flag, no `HELM_ALLOW_UNSIGNED` environment variable, and no config file toggle to reach for. A candidate who confidently names one of those has pattern-matched from other tools rather than from Helm. ## What did not change An installed plugin is a directory under Helm's plugin path (`HELM_PLUGINS` still points at it, and `helm env` still prints it). Helm 4 reads a `plugin.yaml` that predates the new metadata format and treats it as a legacy CLI plugin, which is why plugins installed under Helm 3 keep appearing in `helm plugin list` and keep running after the client is replaced. That backward compatibility is the reason the problem is invisible on developer machines and visible only where the install step actually runs. ## The asymmetry worth carrying Helm's two signing stories have opposite defaults, and conflating them is a real error: - **Charts.** Provenance is OpenPGP-based: `helm package --sign` writes a clear-signed `.prov` file beside the `.tgz`, and it is **opt-in**. Nothing forces a chart consumer to verify, and most repositories serve unsigned charts. - **Plugins.** Verification on install is **on by default**, and you must opt out. The reasoning is about blast radius rather than about signing being newly fashionable. A chart renders into manifests that the API server then evaluates, and whatever it creates is still subject to RBAC, admission and the namespace's constraints. A CLI plugin is an executable that runs on the operator's workstation or CI runner with that operator's credentials, kubeconfig and environment. The trust decision is simply larger, so Helm made the safe posture the default there and only there. ## Handling it in a migration The options, roughly in order of preference: 1. **Get a signed plugin.** If the plugin is yours, `helm plugin package --sign` is now part of its release process, and `helm plugin verify` is how you check the artefact before it ever reaches an image build. This is the option that makes the pipeline both green and better than it was. 2. **Opt out explicitly, in one place.** If the plugin is a third-party one with no signature, `--verify=false` in the image build is a deliberate, greppable exception rather than a silent one. Write it once, with a comment naming what it trusts and why. 3. **Remove the dependency.** Migration is a good moment to notice that a plugin installed for one command three years ago is a standing execution-trust decision in every pipeline that uses the image. ## Where this sits in the wider move It is a small, sharp instance of the general shape of the Helm 3 to Helm 4 move: **charts and releases are adopted in place, and what breaks is automation**. Releases keep their `sh.helm.release.v1.<name>.v<rev>` records, `apiVersion: v2` charts install untouched, and the command set is identical — so the work is a sweep of everything around Helm, of which plugin installation is one line in a Dockerfile. It also happens to be the only place in Helm where a signature check is on by default, which makes it a good differentiator question: knowing it signals someone who read the release notes rather than someone who upgraded and hoped. ## What a good answer sounds like "Plugin installs verify by default in Helm 4, so an unsigned plugin fails; the flag is `--verify=false`, and I would rather sign the plugin than pass it. It only shows up when the image is rebuilt, because an existing plugin directory — even one whose `plugin.yaml` predates the new format — still loads. And it is not a general Helm rule: chart signing with `helm package --sign` is still opt-in."
- Why does chart signing stay opt-in while plugin verification is on by default?Blast radius. A chart renders into manifests the API server still evaluates under RBAC and admission control, so a bad chart is constrained by the cluster's own guardrails. A CLI plugin is an executable that runs on the operator's machine or CI runner with that operator's kubeconfig, tokens and environment — it is code execution on the client. Helm made the strict default where the trust decision is largest, and left `helm package --sign` and its `.prov` file as an explicit choice.
- Why did nobody notice this until the CI image was rebuilt?Because verification happens at install time, not at load time. Plugin directories already present under the plugin path are loaded by Helm 4 — including ones whose `plugin.yaml` predates the new metadata format, which are read as legacy CLI plugins. Developer machines and any long-lived runner therefore keep working after the client is swapped, and only a from-scratch image build re-runs `helm plugin install` and hits the new default.
- A teammate proposes adding a flag to allow insecure plugins globally. What do you tell them?That no such flag exists — the only opt-out is `--verify=false` on the install command itself, which is per-invocation and therefore visible in the Dockerfile or pipeline where it is used. That is a feature: the exception lives next to the plugin it applies to and can be grepped, reviewed and removed. The right direction is to sign the plugin so the exception disappears rather than to look for a way to turn the check off everywhere.
The plugin path is a coat pocket: whatever was already in it comes with you, but the new door has a metal detector and only checks what you carry in today.
saying these in an interview costs you the question
- Names a nonexistent flag such as --allow-insecure-plugins
- Thinks the failure is a plugin.yaml format rejection
- Claims Helm 4 also verifies chart signatures by default
- Says existing installed plugins stop working after the upgrade
- Suggests disabling verification globally instead of signing
- Assumes helm package --sign became mandatory in Helm 4