Skip to main content

GitOps Policies

Self-Hosted Kubernetes

The kubernetes policy source loads governance policies from Kubernetes custom resources in the cluster AIControls runs in. Your platform team manages AI policy the same way it manages every other Kyverno policy — as version-controlled YAML applied by your GitOps tooling — with no new CRD and no calls to the AIControls API.

What the kubernetes policy source loads​

When configured, AIControls watches three policies.kyverno.io/v1 resource kinds:

KindScopeUsed for
ValidatingPolicyClusterGovernance rules evaluated on every AI request
MutatingPolicyClusterRequest mutation rules
PolicyExceptionNamespacedScoped exceptions to specific policies

Policies loaded from the cluster join policies from your other configured sources (files, the built-in policy library, and policies created in the UI) in one evaluation set. When two sources define a policy with the same name, the one loaded later wins. Sources in your policy.sources list load in list order, and database policies (the built-in policy library, policies seeded from files, and policies created in the UI) load after every policy.sources entry, so a database policy replaces a cluster policy with the same name.

Label required

Only resources labelled aicontrols.nirmata.io/policy: "true" are loaded (or your own selector — see below). This filter is what keeps AIControls from ingesting the cluster's ordinary Kyverno admission policies, which target the Kubernetes resource schema rather than the AI request schema and cannot be evaluated by the AI gateway.

Enable the source​

Add a kubernetes entry to policy.sources in your Helm values:

policy:
sources:
- type: kubernetes
# Optional. Defaults to aicontrols.nirmata.io/policy=true.
labelSelector: aicontrols.nirmata.io/policy=true
# Optional. Restricts the PolicyException watch to one namespace.
# Empty watches all namespaces. ValidatingPolicy and MutatingPolicy
# are cluster-scoped and unaffected.
namespace: ""

Then upgrade the release:

helm upgrade aicontrols nirmata/aicontrols -n aicontrols -f values.yaml

Configuring the source also renders a dedicated, read-only ClusterRole (get, list, watch on the three resource kinds) bound to the AIControls ServiceAccount. The grant appears only when the source is configured — a cluster that has not asked for the feature is not asked for the permission.

Author a policy as a custom resource​

Any AIControls ValidatingPolicy works unchanged as a cluster resource — add the label and apply it:

apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
name: block-production-database-tools
labels:
aicontrols.nirmata.io/policy: "true"
spec:
evaluation:
mode: JSON
validationActions: [Deny]
matchConditions:
- name: is-mcp-call
expression: object.mcp.tool != ""
validations:
- expression: "!object.tool.name.startsWith('prod_db_')"
message: Production database tools are blocked by platform policy.

evaluation.mode: JSON keeps the policy out of Kyverno admission when Kyverno runs in the same cluster; Kyverno still compiles the policy and writes its status.

Changes you push are picked up automatically — an applied, edited, or deleted resource is reflected on the next policy cache refresh (within the policy cache TTL, 60 seconds by default). There is no restart and no sync command.

Failure behavior​

The source is deliberately fail-closed:

  • At startup, AIControls refuses to start if the source is configured but cannot complete its first load — the CRDs are missing, the RBAC grant is absent, or the API server is unreachable. A policy source you configured is never silently skipped.
  • After startup, losing the API server connection does not drop your policies: every replica keeps serving the last-known-good set from its in-memory watch cache, reconnects automatically, and records the degradation in its logs.
  • A malformed resource (one that no longer parses as its kind) is skipped and reported loudly rather than blocking the rest of the policy set.

Each AIControls replica runs its own watch, so every replica always has its own complete copy of the policy set regardless of what happens to its peers.

Check the source's status​

GET /api/v1/policy-sources/kubernetes/status on the admin API reports each configured kubernetes source's live health: whether its initial sync completed, whether it's currently healthy, and the most recent watch error if it's degraded. A synced: true, healthy: false result means the source is running on the last-known-good policy set described above — it does not mean policies stopped being enforced.

The same status also appears as a component row on the Health page's Services tab whenever a kubernetes policy source is configured, and, because the source is a required service, as a degraded issue on that tab while the source is degraded — which also degrades the overall health rollup.