Structured Authorization Configuration in Kubernetes
Required knowledge for the CKS certification.
Kubernetes 1.32 graduated the AuthorizationConfiguration API to stable. It replaces the --authorization-mode and --authorization-webhook-* command-line flags with a declarative YAML file that lets you chain multiple authorizers in sequence, attach CEL match conditions to each webhook to restrict which requests it evaluates, and set per-webhook failure policies. Authorization configuration stored in a versioned file is auditable and reviewable in ways that scattered command-line flags are not.
This mechanism is distinct from admission control: AuthorizationConfiguration governs whether a request is allowed to proceed at all, before any admission webhook or ValidatingAdmissionPolicy runs. It does not replace ValidatingWebhookConfiguration or MutatingWebhookConfiguration.
1. The Legacy Flag Approach
Before AuthorizationConfiguration, the API server's authorization chain was specified entirely via command-line flags:
kube-apiserver \
--authorization-mode=Node,RBAC,Webhook \
--authorization-webhook-config-file=/etc/kubernetes/webhook-config.yaml \
--authorization-webhook-cache-authorized-ttl=5m \
--authorization-webhook-cache-unauthorized-ttl=30s
Before: All authorization settings live in API server flags — no versioned format, no per-webhook tuning, and only one webhook can be configured. Changing the authorization chain requires restarting the API server with different flags.
After: A single --authorization-config file replaces all those flags, supports multiple webhook entries, and can be managed as a Kubernetes configuration object in version control.
You cannot use both approaches simultaneously. Setting --authorization-config alongside --authorization-mode or --authorization-webhook-config-file causes the API server to exit on startup with an error.
2. The AuthorizationConfiguration File
Enable structured authorization by passing the file path to the API server:
kube-apiserver --authorization-config=/etc/kubernetes/authorization-config.yaml
The file uses apiVersion: apiserver.config.k8s.io/v1 and kind: AuthorizationConfiguration:
apiVersion: apiserver.config.k8s.io/v1
kind: AuthorizationConfiguration
authorizers:
- type: Node
name: node
- type: RBAC
name: rbac
- type: Webhook
name: custom-authz
webhook:
timeout: 3s
subjectAccessReviewVersion: v1
failurePolicy: Deny
connectionInfo:
type: KubeConfigFile
kubeConfigFile: /etc/kubernetes/webhook-authz.kubeconfig
authorizedTTL: 5m
unauthorizedTTL: 30s
Evaluation order: Authorizers run in the order listed. Each returns Allow, Deny, or NoOpinion. The first Allow or Deny terminates evaluation. If every authorizer returns NoOpinion, the request is denied (HTTP 403).
3. Authorizer Types and Webhook Fields
Authorizer entry fields
Every entry in authorizers requires type and name. The name field is used in metrics and must be a DNS label.
| Field | Description |
|---|---|
type | Node, RBAC, Webhook, AlwaysAllow, or AlwaysDeny |
name | DNS label, unique across the list, used in monitoring metrics |
webhook | Required when type: Webhook; must be omitted for all other types |
Webhook-specific fields
| Field | Default | Description |
|---|---|---|
timeout | — | Max 30 s. Required. |
subjectAccessReviewVersion | — | v1 or v1beta1. Required. |
failurePolicy | — | Deny or NoOpinion on webhook error or timeout. Required. |
connectionInfo.type | — | KubeConfigFile or InClusterConfig. Required. |
connectionInfo.kubeConfigFile | — | Path to kubeconfig file. Required when type: KubeConfigFile. |
authorizedTTL | 5m | How long to cache allowed decisions. |
unauthorizedTTL | 30s | How long to cache denied decisions. |
matchConditions | — | CEL conditions for selective webhook invocation. Optional. |
matchConditionSubjectAccessReviewVersion | — | Required when matchConditions is non-empty; valid value: v1. |
connectionInfo.type: InClusterConfig selects the in-cluster configuration to call the SubjectAccessReview API hosted by kube-apiserver; this mode is not allowed for kube-apiserver, so authorization webhook entries must use KubeConfigFile.
4. CEL Match Conditions
matchConditions attaches CEL expressions to a webhook entry. All expressions must evaluate to true for the webhook to be called; if any expression evaluates to false, the webhook is skipped and the next authorizer in the chain is tried.
webhook:
timeout: 3s
subjectAccessReviewVersion: v1
matchConditionSubjectAccessReviewVersion: v1
failurePolicy: Deny
connectionInfo:
type: KubeConfigFile
kubeConfigFile: /etc/kubernetes/webhook-authz.kubeconfig
matchConditions:
- expression: "has(request.resourceAttributes)"
- expression: "request.resourceAttributes.resource == 'secrets'"
- expression: "request.resourceAttributes.verb in ['get', 'list', 'watch']"
The CEL expressions evaluate the fields of a SubjectAccessReview object:
| Variable | Available for | Fields |
|---|---|---|
request.user | All requests | Username string |
request.groups | All requests | List of group strings |
request.uid | All requests | User UID string |
request.extra | All requests | Map of extra user attributes |
request.resourceAttributes | Resource requests | .namespace, .name, .resource, .verb, .group, .version, .subresource |
request.nonResourceAttributes | Non-resource requests (e.g., /healthz) | .path, .verb |
Use has(request.resourceAttributes) before accessing its sub-fields; it is unset for non-resource requests.
Security benefit: A webhook that only authorizes access to secrets does not need to see every pod list or node get request. CEL match conditions prevent unrelated request metadata from reaching external services, reducing the attack surface if the webhook service is compromised.
If a CEL expression itself errors and failurePolicy is Deny, the request is rejected. If failurePolicy is NoOpinion, the webhook is skipped.
5. Failure Policy
failurePolicy controls behavior when the webhook is unreachable, times out, or returns a malformed response:
Deny — Reject the request immediately without consulting remaining authorizers. Use for webhooks that are the authoritative gate for a specific resource type.
NoOpinion — Skip this webhook and continue to the next authorizer. Use for supplementary webhooks where unavailability should not block access.
Issue: A webhook with failurePolicy: NoOpinion that is the sole authorization control for a sensitive resource class allows those resources to remain accessible if the webhook fails.
Fix: Set failurePolicy: Deny for webhooks that enforce mandatory policy on sensitive resources. Deploy webhook services with sufficient replicas and PodDisruptionBudgets to prevent accidental lockout.
6. Migrating from Legacy Flags
To migrate from --authorization-mode flags to a configuration file:
- Create the file replicating the existing authorizer order:
apiVersion: apiserver.config.k8s.io/v1
kind: AuthorizationConfiguration
authorizers:
- type: Node
name: node
- type: RBAC
name: rbac
- type: Webhook
name: legacy-webhook
webhook:
timeout: 10s
subjectAccessReviewVersion: v1
failurePolicy: NoOpinion
connectionInfo:
type: KubeConfigFile
kubeConfigFile: /etc/kubernetes/webhook-config.yaml
authorizedTTL: 5m
unauthorizedTTL: 30s
- Write the file to each control-plane node (e.g.,
/etc/kubernetes/authorization-config.yaml). - Update the static pod manifest for
kube-apiserver(typically/etc/kubernetes/manifests/kube-apiserver.yaml): remove--authorization-mode,--authorization-webhook-config-file,--authorization-webhook-cache-authorized-ttl, and--authorization-webhook-cache-unauthorized-ttl, then add--authorization-config=/etc/kubernetes/authorization-config.yaml. - The kubelet detects the manifest change and restarts the API server. Verify authorization behavior before considering the migration complete.
Note: Managed Kubernetes offerings (EKS, GKE, AKS) control the API server flags on your behalf. On those platforms, AuthorizationConfiguration adoption timelines depend on the provider's version rollout — check provider documentation before relying on this flag.
7. Verifying Authorization
After applying the configuration, use kubectl auth can-i to confirm expected behavior:
# Verify a service account still has a required permission
kubectl auth can-i get secrets \
--namespace=production \
--as=system:serviceaccount:production:app-sa
# Verify an unauthorized action is still denied
kubectl auth can-i delete nodes \
--as=system:serviceaccount:production:app-sa
# Verify a user permission across namespaces
kubectl auth can-i list pods \
--as=developer@example.com \
--namespace=staging
Expected output for an allowed action: yes. For a denied action: no.
If authorization behavior changes unexpectedly after migration, check that the authorizers order in the configuration file matches the previous --authorization-mode sequence — evaluation order is significant.

References
This article is based on information from the following official sources:
- Authorization - Kubernetes - Kubernetes
- Webhook Authorization - Kubernetes - Kubernetes