Decionis
Kubernetes · Execution authority

Govern kubectl apply before the API server commits it.

A validating admission webhook in your cluster asks the Decionis authority whether the exact operation — this actor, this object, this namespace, right now — is authorized. ALLOW admits on a consumed single-use grant. HOLD and BLOCK deny with the Decision Dossier reference in the response, and every evaluated admission carries the dossier ID and hash in its Kubernetes audit annotations.

RBAC answers whether an identity may call an API operation. This answers a different question: should this exact operation happen now — and can you prove the answer later.

An admission webhook, shadow-first

The webhook sees the post-mutation AdmissionReview object — the exact thing the API server is about to commit, whether it arrived from kubectl, GitOps, CI, or an agent. It normalizes the operation into a canonical intent, evaluates it against your policy graph, and maps the result onto the admission response. It starts in shadow: every protected operation is admitted while the verdicts, dossier links and timings accumulate, and you promote to enforcement only after the would-hold and would-block results match the policy you approved.

VerdictEnforcement modeShadow mode
ALLOWThe webhook consumes the exact single-use Ed25519 grant — unique jti, short expiry, atomic one-time consumption — then admits the request.Admitted, with the verdict recorded in audit annotations.
HOLDDenied with the approval requirement ID and identical-retry guidance. Obtain the approval, retry the identical operation; any object change requires a new decision.Admitted, with the would-hold outcome recorded.
BLOCKDenied with the stable reason codes and the Decision Dossier ID in the response message.Admitted, with the would-block outcome recorded.
Only what you opt in is intercepted

The webhook only fires in namespaces you label decionis.com/execution-authority=protected, and only for the operations your selectors name. kube-system, kube-public, kube-node-lease and the release namespace are excluded by default, so the gate can never lock you out of recovering it.

Your manifests stay in your cluster

The authority receives bounded derived facts — replica counts, privilege flags, GPU counts, hashed identities — never container images, Secret values, tokens, kubeconfigs or raw manifests. Full objects exist only long enough to compute local digests, and structured logs carry hashes and opaque IDs, not object content.

The six selectors in the reference values

The chart ships opt-in selectors for the operations platform teams most often want a second authority on. Selectors decide what reaches Decionis; your policy graph still owns ALLOW, HOLD and BLOCK.

Production workload changes

CREATE / UPDATE / DELETE on Deployments, StatefulSets and DaemonSets.

Privileged pods

Pod creation and updates in production namespaces.

RBAC escalation

Roles, RoleBindings, ClusterRoles and ClusterRoleBindings, cluster-wide.

Namespace deletion

DELETE on namespaces, with system namespaces excluded.

Critical-service scaling

Scale subresource updates on workloads you label critical.

High-cost GPU jobs

Jobs and CronJobs you label high-cost, in production and ML namespaces.

Install in shadow

One Helm value between shadow and enforcement

The admission controller is one optional service of the Decionis Helm chart — the same chart that runs the control plane in your own VPC or cluster. Enabling it adds the validating webhook, TLS configuration, narrowly scoped RBAC, a dedicated NetworkPolicy and the recovery-safe namespace exclusions. This is the install path from the chart's own runbook:

docs/runbooks/kubernetes-execution-authority.md · Install in SHADOW
kubectl create namespace decionis
kubectl -n decionis create secret generic decionis-kubernetes-secrets \
  --from-literal=DECIONIS_API_KEY='<organization-api-key>'

# Copy the chart's examples/kubernetes-authority-values.yaml, set your
# organization, cluster ID, authority URL and selectors. Keep mode: SHADOW.
helm upgrade --install decionis deploy/helm/decionis \
  --namespace decionis \
  --values deploy/helm/decionis/examples/kubernetes-authority-values.yaml

# Opt namespaces in only after the webhook is ready
kubectl -n decionis rollout status deployment/decionis-kubernetes
kubectl label namespace production decionis.com/execution-authority=protected

Review the shadow outcomes, verify sampled dossiers independently, then promote — the rollback is the same value in reverse, which keeps the evidence while removing the enforcement:

promote to enforcement
helm upgrade decionis deploy/helm/decionis --namespace decionis \
  --reuse-values --set kubernetesAuthority.policy.mode=ENFORCEMENT

The chart never pulls from a Decionis-hosted registry: you mirror the images into a registry your cluster can pull from, bring your own Postgres and your own Secrets, and air-gapped installs are a supported path. The chart and its reference values ship with your deployment — ask for them in the rollout review, or start from the self-hosted deployment page.

To put the AgentSafe gateway in front of one Service instead, its chart is public: AgentSafe on Kubernetes.

What happens when Decionis is unreachable

The failure policy is yours — stated exactly

Shadow mode is fail-open by definition; enforcement is fail-open or fail-closed by your failureBehavior setting, and every fail-open admission is warned and recorded.

const failOpen =
  this.policy.mode === "SHADOW" ||
  this.policy.failureBehavior === "FAIL_OPEN";
With failureBehavior: FAIL_CLOSED

A protected operation is denied when Decionis cannot produce verified authority evidence — the response says exactly that. The runbook's guidance: never choose fail-open for high-stakes protected operations without a documented outage exception, and run two or more replicas because fail-closed trades availability for certainty.

With failureBehavior: FAIL_OPEN — or in shadow

The request is admitted, an admission warning names the reason and says the request was admitted by configured fail-open behavior, and the ERROR outcome lands in both the audit annotations and the structured decision log. A fail-open admission is never silent.

Fail-open covers authority unavailability and evaluation errors — nothing else. In enforcement, evidence that does not verify against the exact request — an action-hash, mode or policy-version mismatch, a missing dossier reference, an invalid or already-consumed grant — is denied regardless of the failure setting. In the webhook registration itself, shadow always renders failurePolicy: Ignore and enforcement renders failurePolicy: Fail unless you explicitly choose otherwise.

The documents your platform review will ask for

The admission controller ships with the review set written first: a threat model that states residual limitations next to every control, an installation and recovery runbook, and an architecture note that draws the responsibility boundary against RBAC and CEL. The implementation repository is not public today, so these are shared under a design review rather than linked here — the package list says exactly what is open.

Threat model

Assets, trust boundaries, and a threat-by-threat table with the control and the residual limitation stated side by side — replayed ALLOW grants, actor and digest substitution, TOCTOU between policy and commit, webhook outage, recovery deadlock, sensitive-manifest disclosure. It says plainly what the webhook cannot do: a hostile cluster-admin can remove the admission configuration, and the default rules deliberately do not intercept admissionregistration resources, so an unavailable webhook can never block its own removal.

Installation and recovery runbook

Shadow install, TLS options (cert-manager or your own Secret), promotion criteria, health diagnosis by reason code, and a rollback path that keeps evidence while removing enforcement — one Helm value returns the webhook to shadow.

Architecture note

The responsibility boundary in one page: Kubernetes RBAC answers whether an identity may call the API; Decionis answers whether that exact, already-authenticated operation should happen now. Includes the exact-action contract — every field the intent hash covers — and where CEL ValidatingAdmissionPolicy is the better tool.

What is public without asking anyone: every evaluated admission is correlated to a signed Decision Dossier, and npx @decionis/verify checks its proof bundle offline against the published JWKS — no Decionis account, and no need to trust that we are reachable or honest.
Agent-driven operations go through the same gate

The @decionis/mcp server ships opt-in Kubernetes tools: k8s_plan resolves the exact manifest into digests and bounded facts, k8s_request_authority returns the verdict and dossier references, and k8s_apply runs kubectl only after consuming an ALLOW grant. The admission webhook remains the independent cluster-side gate — an agent that skips the tools still hits it.

The audit annotation is the honest claim

Each evaluated admission writes the decision, dossier ID and SHA-256, policy version, mode and reason code into Kubernetes audit annotations. That correlates the admission decision to signed evidence — it deliberately does not claim that a later controller rollout succeeded, because admission cannot prove that.

Self-hosted · no hosted admission offering

Runs in your cluster, answers to your policy, leaves evidence you can verify without us.

There is no hosted admission controller: the webhook and the control plane deploy from the Helm chart into infrastructure you run. Start free to mint your organization API key and seed policies — evaluations start in shadow — and bring your platform team to a rollout review before anything enforces.