Skip to main content

Admission Policies

Admission policies let you enforce your own rules on the Argo CD objects of an instance. For example, you can require every Application to use automated sync with self-heal, or forbid Applications in the default project.

A policy is a Kubernetes ValidatingAdmissionPolicy. Each rule is a CEL expression that must be true for a change to be allowed. The Akuity Platform installs your policies into the instance control plane, where Argo CD stores its Applications. The policies then check every create, update or delete of a matching object, no matter where it comes from: the Argo CD UI or CLI, declarative management, Terraform, or Argo CD itself.

The settings can be located by navigating to Argo CD → your instance → Settings → Admission Policies.

What a policy can match​

Policies may only match these resources, in the argoproj.io API group:

  • applications

  • applicationsets

The other rules:

  • Operations must be CREATE, UPDATE or DELETE. Wildcards (*) and subresources are not allowed in the matched resources.

  • paramKind and paramRef are not supported.

  • A policy needs at least one binding. A binding activates the policy and sets what happens when a validation fails, with validationActions. Use Deny (see the note at the end of this page).

  • An instance can have up to 50 policies. One policy with its bindings can be up to 64 KiB, and all policies together up to 512 KiB.

The policy is checked when you save it, including compiling every CEL expression, so a typo or an unsupported field is rejected with an error before anything reaches the instance. A saved policy takes effect once the instance finishes reconciling, usually within a minute.

Example​

This policy requires every Application to use automated sync with self-heal:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: require-autosync-selfheal
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["argoproj.io"]
apiVersions: ["v1alpha1"]
operations: ["CREATE", "UPDATE"]
resources: ["applications"]
matchConditions:
# Only check spec changes, so Argo CD's own status updates are never blocked.
# object is null on DELETE and oldObject on CREATE, so check both first.
- name: spec-changed
expression: "object == null || oldObject == null || object.spec != oldObject.spec"
validations:
- expression: >-
has(object.spec.syncPolicy) && has(object.spec.syncPolicy.automated)
&& (!has(object.spec.syncPolicy.automated.enabled) || object.spec.syncPolicy.automated.enabled)
&& has(object.spec.syncPolicy.automated.selfHeal) && object.spec.syncPolicy.automated.selfHeal
message: all Applications must use automated sync with selfHeal enabled
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: require-autosync-selfheal
spec:
policyName: require-autosync-selfheal
validationActions: ["Deny"]

When someone creates an Application without automated sync and self-heal, or changes one to turn either off, the change is refused with the policy's message.

Manage policies​

  1. Go to Settings → Admission Policies.

  2. Click Add Admission Policy.

  3. Enter a Name.

  4. Under Admission Policy Definition, leave Type set to Validating, the only type today, and enter the Spec in YAML. The spec is the spec of a ValidatingAdmissionPolicy, as in the example above.

  5. Under Admission Policy Bindings, click + to add a binding, and enter its Name and Spec, for example validationActions: ["Deny"]. A policy needs at least one binding. You do not need to set policyName; it is set to this policy.

  6. Click Add.

The list shows every policy with its bindings and validation actions:

Admission policies

Use the edit and delete buttons next to a policy to change or remove it. Editing opens the same form, with Save instead of Add. Deleting a policy also deletes its bindings.

Editing an admission policy

Things to watch out for​

Policies apply to every change, including the ones Argo CD and the Akuity Platform make. A policy that is too broad can stop Argo CD from working, so keep these in mind:

  • Argo CD updates Applications all the time. Application status (sync and health) is stored in the Application object itself, so each status change is an UPDATE. A policy that matches UPDATE without a match condition also checks those updates, and blocks them for every Application that does not comply. Sync and health status then stop updating. Use a match condition like spec-changed in the example to check only changes to the spec.

  • On DELETE, object is null. Only oldObject is set, so an expression that reads object.spec fails, and with failurePolicy: Fail that refuses every delete. If you add DELETE to a policy, check object == null first in the match condition, as in the example, and use oldObject in the validations.

  • Removing finalizers is an UPDATE. A strict UPDATE rule can leave Applications stuck in deletion.

  • DELETE rules can block deletion of Applications, cascade deletes, and ApplicationSet pruning. The ApplicationSet controller can also be refused when it creates or updates the Applications it generates. That shows up as an ApplicationSet error, not as an obvious policy denial.

  • Existing objects are not fixed by a new policy. Every later change to an object that does not comply is refused, including changes by Argo CD.

  • With failurePolicy: Fail, an expression error refuses the change. For example, reading a field that is not set fails the expression. Check optional fields with has() first, as in the example.

  • Your own tools are checked too. Declarative apply, Terraform and edits in the Argo CD UI can start failing after you add a policy.

  • An instance on an unsupported Argo CD version can't change its policies until it is upgraded.

To roll out a new policy safely, try it on a non-production instance first, and start narrow: match only CREATE, or only objects with a label, using objectSelector in the binding's matchResources. Widen it once you are sure it only refuses what you expect.

note

Warn and Audit are accepted, but only Deny has a visible effect. Warnings go to clients that call the instance control plane directly, and audit annotations go to the control plane's audit log, which are not exposed to you.