Skip to main content

Bind a workload identity

Task

An identity binding names the ServiceAccount that a registered workload's calls use. AIControls authorizes that ServiceAccount, in that cluster, and never the workload's name or labels. You bind the identity when you register the workload, or afterward with the API on this page.

Self-managed installations only

Workload Trust is available only in private, self-managed AIControls installations, on premises or in a cloud cluster that you run. It needs a dedicated cluster that you run, with Kyverno, Kyverno Runtime, and cluster OIDC and RBAC access in place. Nirmata-hosted (SaaS) workspaces don't include it. See Feature availability.

Before you begin​

  • You need an administrator session. Every request on this page requires the cluster query parameter: the UID of the cluster's kube-system namespace, which this command prints:

    kubectl get namespace kube-system -o jsonpath='{.metadata.uid}'

    Until the controller can read the kube-system namespace, it keys the cluster by its display name instead. AIControls refuses identity binding writes (create, update, and retire), access writes, mode changes, contains, and recommendation promotions and dismissals that name that display name as cluster, with 409 cluster_identity_unavailable, because configuration written under the display name wouldn't carry over once the UID resolves. Wait for the UID, then retry with it as cluster. Release stays allowed under the display name, because containment moves to the UID when it resolves. If it has already moved, a release that names the display name returns 409 cluster_identity_changed and releases nothing; retry with the UID as cluster.

  • Register the workload first. See Register a workload.

  • Give the workload its own ServiceAccount. All Pods that run as one ServiceAccount are one principal and share the same access. See Workload Blueprints and Workload Registrations.

warning

After you bind a pod_uid identity, AIControls denies the workload's calls until its registration names a Blueprint. A registration made in the wizard always does, so bind a workload you registered by another route to a Blueprint at once. A virtual_key binding stays on the legacy path: it never produces workload access and doesn't cause this denial.

Bind the identity​

  1. Send the binding. Use expectedRevision 0 to create it:

    curl -X PUT "https://YOUR_WORKSPACE_URL/api/v1/workloads/prod/Deployment/checkout/identity-binding?cluster=$CLUSTER_UID" \
    -H "Authorization: Bearer $AICONTROLS_TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"identityKey": "k8s://prod/checkout-sa", "rung": "pod_uid", "expectedRevision": 0}'
    FieldMeaning
    identityKeyFor pod_uid, k8s://<namespace>/<serviceaccount>, and the namespace must match the workload's namespace. For virtual_key, any non-empty key.
    rungpod_uid for a verified Pod-bound ServiceAccount. The virtual_key rung records a binding, but a workload bound that way doesn't get workload access.
    expectedRevision0 to create. For an update, the current revision.

    The response returns the binding id, the identityKey, the rung, and the new revision.

  2. Read the workload's access state to confirm the binding:

    curl "https://YOUR_WORKSPACE_URL/api/v1/workloads/prod/Deployment/checkout/access?cluster=$CLUSTER_UID" \
    -H "Authorization: Bearer $AICONTROLS_TOKEN"

    identityBinding shows the active binding. registration shows the rowVersion and rowToken that you need to change the workload's override.

  3. Set the workload's override if it differs from its Blueprint, and switch it to Enforce when it's ready. See Register a workload and Switch a workload to Enforce.

The web UI has no identity binding screen yet. After you bind the identity, the AI access tab on the workload detail page shows the workload's Blueprint, its two bindings, and its effective access.

Change the binding​

To update a binding, send the PUT request again with the current revision as expectedRevision. To bind a different ServiceAccount, retire the current binding, and then create a new one.

Retire a binding:

curl -X DELETE "https://YOUR_WORKSPACE_URL/api/v1/workloads/prod/Deployment/checkout/identity-binding?cluster=$CLUSTER_UID&expectedRevision=1" \
-H "Authorization: Bearer $AICONTROLS_TOKEN"

AIControls refuses to retire a binding that a registration still uses, with 409 identity_binding_pinned. Deleting the registration releases it. A PUT that changes the identityKey of an existing binding returns 409 identity_key_change; retire the binding, and then create a new one with expectedRevision 0.

Troubleshooting​

ResponseCauseFix
400For pod_uid, the identityKey isn't k8s://<namespace>/<serviceaccount> in the workload's namespace; for virtual_key, it is empty; or the rung isn't pod_uid or virtual_key.Correct the request.
409 identity_conflictAnother workload in this cluster already has a configured binding for the ServiceAccount. A discovered shared ServiceAccount alone doesn't cause this.Give each workload its own ServiceAccount, or retire the other binding.
409 conflictThe expectedRevision is stale, or you sent 0 for a workload that already has a binding.Read the current revision and retry.
409 identity_binding_pinnedYou tried to retire a binding that a registration still uses.Delete the registration, and then retire the binding.
409 identity_key_changeYou sent a different identityKey with a nonzero expectedRevision. A binding's key never changes.Retire the binding, and then create a new one with expectedRevision 0.
Calls denied by workload-registration-binding-incoherentThe registration doesn't name a Blueprint, the Blueprint's bindings are missing, or the identity binding moved to a new revision.Check the registration on the workload's AI access tab, and select a Blueprint. See Fail-closed rules.