skip to content

How would you choose between the subprocess and extism/v1 runtimes for an internal Helm plugin?

level: seniorimportance: should knowfreq 33%

answer

  1. Two axes: portability and reach
  2. One artefact or one per platform
  3. What can it touch once it runs
  4. Sandbox versus the caller's credentials
  5. Signing applies either way

basics

~20 s

Choose subprocess when the plugin needs host access - kubeconfig, cloud credentials, other CLIs - and accept a build per OS and architecture. Choose extism/v1 for one portable WebAssembly artefact and a sandbox bounding what it reaches.

solid answer

~50 s

The `runtime` field in `plugin.yaml` is a distribution and blast-radius decision. `subprocess` means Helm executes a native binary or script: it has whatever access the invoking user has — filesystem, network, kubeconfig, cloud credentials in the environment — and can shell out to other tooling, but you must build, ship and keep current one artefact per OS and architecture, or depend on an interpreter being present. `extism/v1` means the plugin is a WebAssembly module Helm runs in an embedded runtime: one artefact runs everywhere Helm runs, and the module only reaches the host through what the runtime grants it, so a compromised or buggy plugin cannot quietly read your cloud credentials. The cost is a narrower toolchain, no shelling out, and more work when the plugin genuinely needs host resources. Signing and `--verify` apply to both, so the runtime choice is about capability and portability, not about trust in the artefact.

code

yaml · 5 lines
yaml
apiVersion: v1
name: values-lint
version: 1.2.7
type: cli/v1
runtime: extism/v1

go deeper

for a junior

Know that a Helm 4 plugin declares a runtime and that the two options are a native subprocess and a WebAssembly module. You are not expected to choose between them yet.

for a middle

Explain the mechanics of each: Helm executing a child process with the user's full environment, versus running a module inside an embedded runtime with only granted host access, and the artefact-per-platform consequence of the first.

for a senior

Reason from requirements to a choice — what the plugin must reach, how many machines it lands on, and what a compromise would cost — and show that signing and verification apply either way rather than being replaced by a sandbox.

for a principal

Own the tooling strategy: which internal plugins exist at all, who signs and publishes them, how they reach every laptop and runner at a pinned version, and how much of the burden of a per-platform build matrix the organisation should carry.

### The decision in one sentence `subprocess` buys you unrestricted access to the host at the cost of shipping a build per platform; `extism/v1` buys you one portable artefact and a sandbox at the cost of what the sandbox will not let you do. Everything else follows from those two trades. ### A concrete case Suppose a platform team maintains an internal plugin, `values-lint`, used by 43 engineers and 17 CI runners. It reads the 240-line values file for the team's stateless API chart — the one whose Deployment carries a ConfigMap checksum annotation so config changes roll pods — plus the values file for a document-indexing job, and enforces house rules that a JSON Schema cannot express: that every image reference is pinned by digest, that the indexing job's concurrency never exceeds the size of the queue pool, and that no environment file redefines a key the shared defaults already set. It runs as a pre-commit check and as a merge gate, and engineers work on a mix of macOS on both architectures and Linux. Read the requirements against the two runtimes. **Portability.** With `subprocess`, that plugin needs a build for darwin/arm64, darwin/amd64 and linux/amd64 at minimum, each signed, each published, each updated on every release. Miss one and a fraction of the 43 engineers cannot install it. Alternatively you write it as a script and accept a runtime dependency — an interpreter of a particular version present on every laptop and in all 17 runner images — which is the same problem wearing a different hat. With `extism/v1`, one `.wasm` module runs wherever Helm runs. For a widely-installed internal tool, this is usually the dominant consideration. **Capability.** The lint above reads files and computes. It does not need the cluster, cloud credentials, or other binaries. That is precisely the profile WebAssembly suits. Change the requirement — say the plugin must call the cluster to compare the live release's values, or shell out to an existing CLI, or read a credential file to reach an internal service — and the sandbox becomes friction, working through whatever host access the runtime exposes rather than simply doing it. At that point `subprocess` is the honest choice. **Blast radius.** A subprocess plugin runs with everything the caller has. On a CI runner that means a deploy identity for every environment; on a laptop it means the engineer's kubeconfig and any cloud session in the shell. A WebAssembly module reaches the host only through capabilities the runtime grants, so a supply-chain compromise of the plugin, or simply a careless dependency inside it, has far less to work with. This is the same instinct that made Helm 4 verify plugin signatures by default: the plugin runs where the credentials are. **Debuggability and skills.** A subprocess plugin is an ordinary program. You can run it directly outside Helm, attach a debugger, print to stderr, and reason about it with tools everyone already has. A WebAssembly plugin is less familiar, its build pipeline is another thing to keep working, and diagnosing a failure inside the host runtime is a smaller-community skill. Do not discount this on a platform team whose on-call rotation must support the tool. ### What the choice does not change Three things are constant across both runtimes, and mixing them up is the usual way this question goes wrong. 1. **Trust in the artefact is handled separately.** `helm plugin package --sign`, `helm plugin verify`, and `--verify` defaulting to true on `helm plugin install` all apply whichever runtime the plugin declares. WebAssembly is not a substitute for signing, and signing is not a substitute for a sandbox — the first tells you the artefact is unmodified, the second bounds what it can do once it runs. 2. **The plugin's `type` is orthogonal.** A `cli/v1` plugin can be either runtime, and so can a `getter/v1` one. `type` decides who calls the plugin; `runtime` decides how it executes. 3. **Rendering is untouched.** The WebAssembly runtime exists for plugins, not for chart rendering. Charts are still rendered only by Go text/template inside Helm; no plugin runtime changes that. ### How to decide, in order Start from what the plugin must reach. If it needs the kubeconfig, cloud credentials, or other executables, take `subprocess` and put your effort into a release pipeline that builds, signs and publishes every platform artefact reproducibly. If it is a pure transformation over inputs — linting, validating, formatting, generating — take `extism/v1`, ship one artefact, and spend the saved effort elsewhere. When both would work, prefer the sandbox for anything installed widely, because the population of machines it runs on is the real risk surface, and prefer the subprocess for a niche tool used by three people on one platform who need to iterate quickly. And for either choice, plan the distribution: a pinned version installed in the CI image build rather than at deploy time, an internal signing key, and the public key present on every laptop and runner that will install it.

  • Does choosing the WebAssembly runtime mean you no longer need to sign the plugin?
    No. The two controls answer different questions. A signature tells you the artefact is the one the publisher produced and has not been tampered with in transit; the sandbox bounds what the code can reach once it runs. You want both, and Helm gives you both regardless of runtime — helm plugin package --sign on the publishing side, and --verify defaulting to true on helm plugin install. Treating a sandbox as a reason to skip signing means you will happily run an attacker's module, just with less access.
  • Your plugin must call the Kubernetes API to compare a live release. Which runtime, and why?
    That pushes towards subprocess. The plugin needs the caller's kubeconfig, its context and any credential helper the config references — exactly the host access a sandbox exists to withhold. Fighting the sandbox for cluster access gives you the worst of both: sandbox friction with the credentials exposed anyway. Take subprocess, and pay the platform-matrix cost with a release pipeline that builds and signs every artefact.
  • How do you get an internal plugin onto 43 laptops and 17 CI runners consistently?
    Treat it as environment provisioning, not as something engineers do ad hoc. Bake a pinned version into the CI base image so every runner is identical and no deploy job reaches the network for it. For laptops, publish through whatever the team already uses to manage developer tooling, and distribute the public signing key the same way, since installs verify by default. Then make the merge gate the real enforcement point, so a laptop with a stale plugin cannot land a violation.

saying these in an interview costs you the question

  • Thinks the WASM runtime also renders charts
  • Says WebAssembly replaces the need for signing
  • Assumes a subprocess plugin is sandboxed from the kubeconfig
  • Ignores the per-OS and per-architecture build burden
  • Confuses the runtime field with the type field
  • Picks a runtime without asking what the plugin must reach

context