kubernetes reference liggitt contenttype concept enj title Managing Service Accounts reviewers overview weight 50

Answer:
---
reviewers:
  - liggitt
  - enj
title: Managing Service Accounts
content_type: concept
weight: 50
---

<!-- overview -->

A _ServiceAccount_ provides an identity for processes that run in a Pod.

A process inside a Pod can use the identity of its associated service account to
authenticate to the cluster's API server.

For an introduction to service accounts, read [configure service accounts](/docs/tasks/configure-pod-container/configure-service-account/).

This task guide explains some of the concepts behind ServiceAccounts. The
guide also explains how to obtain or revoke tokens that represent
ServiceAccounts.

<!-- body -->

##

To be able to follow these steps exactly, ensure you have a namespace named
`examplens`.
If you don't, create one by running:

```shell
kubectl create namespace examplens
```

## User accounts versus service accounts

Kubernetes distinguishes between the concept of a user account and a service account
for a number of reasons:

- User accounts are for humans. Service accounts are for application processes,
  which (for Kubernetes) run in containers that are part of pods.
- User accounts are intended to be global: names must be unique across all
  namespaces of a cluster. No matter what namespace you look at, a particular
  username that represents a user represents the same user.
  In Kubernetes, service accounts are namespaced: two different namespaces can
  contain ServiceAccounts that have identical names.
- Typically, a cluster's user accounts might be synchronised from a corporate
  database, where new user account creation requires special privileges and is
  tied to complex business processes. By contrast, service account creation is
  intended to be more lightweight, allowing cluster users to create service accounts
  for specific tasks on demand. Separating ServiceAccount creation from the steps to
  onboard human users makes it easier for workloads to follow the principle of
  least privilege.
- Auditing considerations for humans and service accounts may differ; the separation
  makes that easier to achieve.
- A configuration bundle for a complex system may include definition of various service
  accounts for components of that system. Because service accounts can be created
  without many constraints and have namespaced names, such configuration is
  usually portable.

## Bound service account tokens

ServiceAccount tokens can be bound to API objects that exist in the kube-apiserver.
This can be used to tie the validity of a token to the existence of another API object.
Supported object types are as follows:

* Pod (used for projected volume mounts, see below)
* Secret (can be used to allow revoking a token by deleting the Secret)
* Node (in v1.30, creating new node-bound tokens is alpha, using existing node-bound tokens is beta)

When a token is bound to an object, the object's `metadata.name` and `metadata.uid` are
stored as extra 'private claims' in the issued JWT.

When a bound token is presented to the kube-apiserver, the service account authenticator
will extract and verify these claims.
If the referenced object or the ServiceAccount is pending deletion (for example, due to finalizers),
then for any instant that is 60 seconds (or more) after the `.metadata.deletionTimestamp` date,
authentication with that token would fail.
If the referenced object no longer exists (or its `metadata.uid` does not match),
the request will not be authenticated.

### Additional metadata in Pod bound tokens

When a service account token is bound to a Pod object, additional metadata is also
embedded into the token that indicates the value of the bound pod's `spec.nodeName` field,
and the uid of that Node, if available.

This node information is **not** verified by the kube-apiserver when the token is used for authentication.
It is included so integrators do not have to fetch Pod or Node API objects to check the associated Node name
and uid when inspecting a JWT.

### Verifying and inspecting private claims

The `TokenReview` API can be used to verify and extract private claims from a token:

1. First, assume you have a pod named `test-pod` and a service account named `my-sa`.
2. Create a token that is bound to this Pod:

```shell
kubectl create token my-sa --bound-object-kind="Pod" --bound-object-name="test-pod"
```

3. Copy this token into a new file named `tokenreview.yaml`:

```yaml
apiVersion: authentication.k8s.io/v1
kind: TokenReview
spec:
  token: <token from step 2>
```

4. Submit this resource to the apiserver for review:

```shell
kubectl create -o yaml -f tokenreview.yaml # we use '-o yaml' so we can inspect the output
```

You should see an output like below:

```yaml
apiVersion: authentication.k8s.io/v1
kind: TokenReview
metadata:
  creationTimestamp: null
spec:
  token: <token>
status:
  audiences:
  - https://kubernetes.default.svc.cluster.local
  authenticated: true
  user:
    extra:
      authentication.kubernetes.io/credential-id:
      - JTI=7ee52be0-9045-4653-aa5e-0da57b8dccdc
      authentication.kubernetes.io/node-name:
      - kind-control-plane
      authentication.kubernetes.io/node-uid:
      - 497e9d9a-47aa-4930-b0f6-9f2fb574c8c6
      authentication.kubernetes.io/pod-name:
      - test-pod
      authentication.kubernetes.io/pod-uid:
      - e87dbbd6-3d7e-45db-aafb-72b24627dff5
    groups:
    - system:serviceaccounts
    - system:serviceaccounts:default
    - system:authenticated
    uid: f8b4161b-2e2b-11e9-86b7-2afc33b31a7e
    username: system:serviceaccount:default:my-sa
```

Despite using `kubectl create -f` to create this resource, and defining it similar to
other resource types in Kubernetes, TokenReview is a special type and the kube-apiserver
does not actually persist the TokenReview object into etcd.
Hence `kubectl get tokenreview` is not a valid command.

## Bound service account token volume mechanism {#bound-service-account-token-volume}

By default, the Kubernetes control plane (specifically, the
[ServiceAccount admission controller](#serviceaccount-admission-controller))
adds a [projected volume](/docs/concepts/storage/projected-volumes/) to Pods,
and this volume includes a token for Kubernetes API access.

Here's an example of how that looks for a launched Pod:

```yaml
...
  - name: kube-api-access-<random-suffix>
    projected:
      sources:
        - serviceAccountToken:
            path: token # must match the path the app expects
        - configMap:
            items:
              - key: ca.crt
                path: ca.crt
            name: kube-root-ca.crt
        - downwardAPI:
            items:
              - fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
                path: namespace
```

That manifest snippet defines a projected volume that consists of three sources. In this case,
each source also represents a single path within that volume. The three sources are:

1. A `serviceAccountToken` source, that contains a token that the kubelet acquires from kube-apiserver.
   The kubelet fetches time-bound tokens using the TokenRequest API. A token served for a TokenRequest expires
   either when the pod is deleted or after a defined lifespan (by default, that is 1 hour).
   The kubelet also refreshes that token before the token expires.
   The token is bound to the specific Pod and has the kube-apiserver as its audience.
   This mechanism superseded an earlier mechanism that added a volume based on a Secret,
   where the Secret represented the ServiceAccount for the Pod, but did not expire.
1. A `configMap` source. The ConfigMap contains a bundle of certificate authority data. Pods can use these
   certificates to make sure that they are connecting to your cluster's kube-apiserver (and not to middlebox
   or an accidentally misconfigured peer).
1. A `downwardAPI` source that looks up the name of the namespace containing the Pod, and makes
   that name information available to application code running inside the Pod.

Any container within the Pod that mounts this particular volume can access the above information.

There is no specific mechanism to invalidate a token issued via TokenRequest. If you no longer
trust a bound service account token for a Pod, you can delete that Pod. Deleting a Pod expires
its bound service account tokens.

## Manual Secret management for ServiceAccounts

Versions of Kubernetes before v1.22 automatically created credentials for accessing
the Kubernetes API. This older mechanism was based on creating token Secrets that
could then be mounted into running Pods.

In more recent versions, including Kubernetes v, API credentials
are [obtained directly](#bound-service-account-token-volume) using the
[TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/) API,
and are mounted into Pods using a projected volume.
The tokens obtained using this method have bounded lifetimes, and are automatically
invalidated when the Pod they are mounted into is deleted.

You can still [manually create](/docs/tasks/configure-pod-container/configure-service-account/#manually-create-an-api-token-for-a-serviceaccount) a Secret to hold a service account token; for example, if you need a token that never expires.

Once you manually create a Secret and link it to a ServiceAccount, the Kubernetes control plane automatically populates the token into that Secret.

Although the manual mechanism for creating a long-lived ServiceAccount token exists,
using [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/)
to obtain short-lived API access tokens is recommended instead.

## Auto-generated legacy ServiceAccount token clean up {#auto-generated-legacy-serviceaccount-token-clean-up}

Before version 1.24, Kubernetes automatically generated Secret-based tokens for
ServiceAccounts. To distinguish between automatically generated tokens and
manually created ones, Kubernetes checks for a reference from the
ServiceAccount's secrets field. If the Secret is referenced in the `secrets`
field, it is considered an auto-generated legacy token. Otherwise, it is
considered a manually created legacy token. For example:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: build-robot
  namespace: default
secrets:
  - name: build-robot-secret # usually NOT present for a manually generated token
```

Beginning from version 1.29, legacy ServiceAccount tokens that were generated
automatically will be marked as invalid if they remain unused for a certain
period of time (set to default at one year). Tokens that continue to be unused
for this defined period (again, by default, one year) will subsequently be
purged by the control plane.

If users use an invalidated auto-generated token, the token validator will

1. add an audit annotation for the key-value pair
  `authentication.k8s.io/legacy-token-invalidated: <secret name>/<namespace>`,
1. increment the `invalid_legacy_auto_token_uses_total` metric count,
1. update the Secret label `kubernetes.io/legacy-token-last-used` with the new
   date,
1. return an error indicating that the token has been invalidated.

When receiving this validation error, users can update the Secret to remove the
`kubernetes.io/legacy-token-invalid-since` label to temporarily allow use of
this token.

Here's an example of an auto-generated legacy token that has been marked with the
`kubernetes.io/legacy-token-last-used` and `kubernetes.io/legacy-token-invalid-since`
labels:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: build-robot-secret
  namespace: default
  labels:
    kubernetes.io/legacy-token-last-used: 2022-10-24
    kubernetes.io/legacy-token-invalid-since: 2023-10-25
  annotations:
    kubernetes.io/service-account.name: build-robot
type: kubernetes.io/service-account-token
```

## Control plane details

### ServiceAccount controller

A ServiceAccount controller manages the ServiceAccounts inside namespaces, and
ensures a ServiceAccount named "default" exists in every active namespace.

### Token controller

The service account token controller runs as part of `kube-controller-manager`.
This controller acts asynchronously. It:

- watches for ServiceAccount deletion and deletes all corresponding ServiceAccount
  token Secrets.
- watches for ServiceAccount token Secret addition, and ensures the referenced
  ServiceAccount exists, and adds a token to the Secret if needed.
- watches for Secret deletion and removes a reference from the corresponding
  ServiceAccount if needed.

You must pass a service account private key file to the token controller in
the `kube-controller-manager` using the `--service-account-private-key-file`
flag. The private key is used to sign generated service account tokens.
Similarly, you must pass the corresponding public key to the `kube-apiserver`
using the `--service-account-key-file` flag. The public key will be used to
verify the tokens during authentication.

### ServiceAccount admission controller

The modification of pods is implemented via a plugin
called an [Admission Controller](/docs/reference/access-authn-authz/admission-controllers/).
It is part of the API server.
This admission controller acts synchronously to modify pods as they are created.
When this plugin is active (and it is by default on most distributions), then
it does the following when a Pod is created:

1. If the pod does not have a `.spec.serviceAccountName` set, the admission controller sets the name of the
   ServiceAccount for this incoming Pod to `default`.
1. The admission controller ensures that the ServiceAccount referenced by the incoming Pod exists. If there
   is no ServiceAccount with a matching name, the admission controller rejects the incoming Pod. That check
   applies even for the `default` ServiceAccount.
1. Provided that neither the ServiceAccount's `automountServiceAccountToken` field nor the
   Pod's `automountServiceAccountToken` field is set to `false`:
   - the admission controller mutates the incoming Pod, adding an extra
      that contains
     a token for API access.
   - the admission controller adds a `volumeMount` to each container in the Pod,
     skipping any containers that already have a volume mount defined for the path
     `/var/run/secrets/kubernetes.io/serviceaccount`.
     For Linux containers, that volume is mounted at `/var/run/secrets/kubernetes.io/serviceaccount`;
     on Windows nodes, the mount is at the equivalent path.
1. If the spec of the incoming Pod doesn't already contain any `imagePullSecrets`, then the
   admission controller adds `imagePullSecrets`, copying them from the `ServiceAccount`.

### Legacy ServiceAccount token tracking controller

This controller generates a ConfigMap called
`kube-system/kube-apiserver-legacy-service-account-token-tracking` in the
`kube-system` namespace. The ConfigMap records the timestamp when legacy service
account tokens began to be monitored by the system.

### Legacy ServiceAccount token cleaner

The legacy ServiceAccount token cleaner runs as part of the
`kube-controller-manager` and checks every 24 hours to see if any auto-generated
legacy ServiceAccount token has not been used in a *specified amount of time*.
If so, the cleaner marks those tokens as invalid.

The cleaner works by first checking the ConfigMap created by the control plane
(provided that `LegacyServiceAccountTokenTracking` is enabled). If the current
time is a *specified amount of time* after the date in the ConfigMap, the
cleaner then loops through the list of Secrets in the cluster and evaluates each
Secret that has the type `kubernetes.io/service-account-token`.

If a Secret meets all of the following conditions, the cleaner marks it as
invalid:

- The Secret is auto-generated, meaning that it is bi-directionally referenced
  by a ServiceAccount.
- The Secret is not currently mounted by any pods.
- The Secret has not been used in a *specified amount of time* since it was
  created or since it was last used.

The cleaner marks a Secret invalid by adding a label called
`kubernetes.io/legacy-token-invalid-since` to the Secret, with the current date
as the value. If an invalid Secret is not used in a *specified amount of time*,
the cleaner will delete it.

All the *specified amount of time* above defaults to one year. The cluster
administrator can configure this value through the
`--legacy-service-account-token-clean-up-period` command line argument for the
`kube-controller-manager` component.

### TokenRequest API

You use the [TokenRequest](/docs/reference/kubernetes-api/authentication-resources/token-request-v1/)
subresource of a ServiceAccount to obtain a time-bound token for that ServiceAccount.
You don't need to call this to obtain an API token for use within a container, since
the kubelet sets this up for you using a _projected volume_.

If you want to use the TokenRequest API from `kubectl`, see
[Manually create an API token for a ServiceAccount](/docs/tasks/configure-pod-container/configure-service-account/#manually-create-an-api-token-for-a-serviceaccount).

The Kubernetes control plane (specifically, the ServiceAccount admission controller)
adds a projected volume to Pods, and the kubelet ensures that this volume contains a token
that lets containers authenticate as the right ServiceAccount.

(This mechanism superseded an earlier mechanism that added a volume based on a Secret,
where the Secret represented the ServiceAccount for the Pod but did not expire.)

Here's an example of how that looks for a launched Pod:

```yaml
...
  - name: kube-api-access-<random-suffix>
    projected:
      defaultMode: 420 # decimal equivalent of octal 0644
      sources:
        - serviceAccountToken:
            expirationSeconds: 3607
            path: token
        - configMap:
            items:
              - key: ca.crt
                path: ca.crt
            name: kube-root-ca.crt
        - downwardAPI:
            items:
              - fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
                path: namespace
```

That manifest snippet defines a projected volume that combines information from three sources:

1. A `serviceAccountToken` source, that contains a token that the kubelet acquires from kube-apiserver.
   The kubelet fetches time-bound tokens using the TokenRequest API. A token served for a TokenRequest expires
   either when the pod is deleted or after a defined lifespan (by default, that is 1 hour).
   The token is bound to the specific Pod and has the kube-apiserver as its audience.
1. A `configMap` source. The ConfigMap contains a bundle of certificate authority data. Pods can use these
   certificates to make sure that they are connecting to your cluster's kube-apiserver (and not to middlebox
   or an accidentally misconfigured peer).
1. A `downwardAPI` source. This `downwardAPI` volume makes the name of the namespace containing the Pod available
   to application code running inside the Pod.

Any container within the Pod that mounts this volume can access the above information.

## Create additional API tokens {#create-token}

Only create long-lived API tokens if the [token request](#tokenrequest-api) mechanism
is not suitable. The token request mechanism provides time-limited tokens; because these
expire, they represent a lower risk to information security.

To create a non-expiring, persisted API token for a ServiceAccount, create a
Secret of type `kubernetes.io/service-account-token` with an annotation
referencing the ServiceAccount. The control plane then generates a long-lived token and
updates that Secret with that generated token data.

Here is a sample manifest for such a Secret:

To create a Secret based on this example, run:

```shell
kubectl -n examplens create -f https://k8s.io/examples/secret/serviceaccount/mysecretname.yaml
```

To see the details for that Secret, run:

```shell
kubectl -n examplens describe secret mysecretname
```

The output is similar to:

```
Name:           mysecretname
Namespace:      examplens
Labels:         <none>
Annotations:    kubernetes.io/service-account.name=myserviceaccount
                kubernetes.io/service-account.uid=8a85c4c4-8483-11e9-bc42-526af7764f64

Type:   kubernetes.io/service-account-token

Data
====
ca.crt:         1362 bytes
namespace:      9 bytes
token:          ...
```

If you launch a new Pod into the `examplens` namespace, it can use the `myserviceaccount`
service-account-token Secret that you just created.

Do not reference manually created Secrets in the `secrets` field of a
ServiceAccount. Or the manually created Secrets will be cleaned if it is not used for a long
time. Please refer to [auto-generated legacy ServiceAccount token clean up](#auto-generated-legacy-serviceaccount-token-clean-up).

## Delete/invalidate a ServiceAccount token {#delete-token}

If you know the name of the Secret that contains the token you want to remove:

```shell
kubectl delete secret name-of-secret
```

Otherwise, first find the Secret for the ServiceAccount.

```shell
# This assumes that you already have a namespace named 'examplens'
kubectl -n examplens get serviceaccount/example-automated-thing -o yaml
```

The output is similar to:

```yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"name":"example-automated-thing","namespace":"examplens"}}
  creationTimestamp: "2019-07-21T07:07:07Z"
  name: example-automated-thing
  namespace: examplens
  resourceVersion: "777"
  selfLink: /api/v1/namespaces/examplens/serviceaccounts/example-automated-thing
  uid: f23fd170-66f2-4697-b049-e1e266b7f835
secrets:
  - name: example-automated-thing-token-zyxwv
```

Then, delete the Secret you now know the name of:

```shell
kubectl -n examplens delete secret/example-automated-thing-token-zyxwv
```

## Clean up

If you created a namespace `examplens` to experiment with, you can remove it:

```shell
kubectl delete namespace examplens
```

##

- Read more details about [projected volumes](/docs/concepts/storage/projected-volumes/).

reviewers      liggitt     enj title  Managing Service Accounts content type  concept weight  50           overview      A  ServiceAccount  provides an identity for processes that run in a Pod   A process inside a Pod can use the identity of its associated service account to authenticate to the cluster s API server   For an introduction to service accounts  read  configure service accounts   docs tasks configure pod container configure service account     This task guide explains some of the concepts behind ServiceAccounts  The guide also explains how to obtain or revoke tokens that represent ServiceAccounts        body             To be able to follow these steps exactly  ensure you have a namespace named  examplens   If you don t  create one by running      shell kubectl create namespace examplens         User accounts versus service accounts  Kubernetes distinguishes between the concept of a user account and a service account for a number of reasons     User accounts are for humans  Service accounts are for application processes    which  for Kubernetes  run in containers that are part of pods    User accounts are intended to be global  names must be unique across all   namespaces of a cluster  No matter what namespace you look at  a particular   username that represents a user represents the same user    In Kubernetes  service accounts are namespaced  two different namespaces can   contain ServiceAccounts that have identical names    Typically  a cluster s user accounts might be synchronised from a corporate   database  where new user account creation requires special privileges and is   tied to complex business processes  By contrast  service account creation is   intended to be more lightweight  allowing cluster users to create service accounts   for specific tasks on demand  Separating ServiceAccount creation from the steps to   onboard human users makes it easier for workloads to follow the principle of   least privilege    Auditing considerations for humans and service accounts may differ  the separation   makes that easier to achieve    A configuration bundle for a complex system may include definition of various service   accounts for components of that system  Because service accounts can be created   without many constraints and have namespaced names  such configuration is   usually portable      Bound service account tokens  ServiceAccount tokens can be bound to API objects that exist in the kube apiserver  This can be used to tie the validity of a token to the existence of another API object  Supported object types are as follows     Pod  used for projected volume mounts  see below    Secret  can be used to allow revoking a token by deleting the Secret    Node  in v1 30  creating new node bound tokens is alpha  using existing node bound tokens is beta   When a token is bound to an object  the object s  metadata name  and  metadata uid  are stored as extra  private claims  in the issued JWT   When a bound token is presented to the kube apiserver  the service account authenticator will extract and verify these claims  If the referenced object or the ServiceAccount is pending deletion  for example  due to finalizers   then for any instant that is 60 seconds  or more  after the   metadata deletionTimestamp  date  authentication with that token would fail  If the referenced object no longer exists  or its  metadata uid  does not match   the request will not be authenticated       Additional metadata in Pod bound tokens    When a service account token is bound to a Pod object  additional metadata is also embedded into the token that indicates the value of the bound pod s  spec nodeName  field  and the uid of that Node  if available   This node information is   not   verified by the kube apiserver when the token is used for authentication  It is included so integrators do not have to fetch Pod or Node API objects to check the associated Node name and uid when inspecting a JWT       Verifying and inspecting private claims  The  TokenReview  API can be used to verify and extract private claims from a token   1  First  assume you have a pod named  test pod  and a service account named  my sa   2  Create a token that is bound to this Pod      shell kubectl create token my sa   bound object kind  Pod    bound object name  test pod       3  Copy this token into a new file named  tokenreview yaml       yaml apiVersion  authentication k8s io v1 kind  TokenReview spec    token   token from step 2       4  Submit this resource to the apiserver for review      shell kubectl create  o yaml  f tokenreview yaml   we use   o yaml  so we can inspect the output      You should see an output like below      yaml apiVersion  authentication k8s io v1 kind  TokenReview metadata    creationTimestamp  null spec    token   token  status    audiences      https   kubernetes default svc cluster local   authenticated  true   user      extra        authentication kubernetes io credential id          JTI 7ee52be0 9045 4653 aa5e 0da57b8dccdc       authentication kubernetes io node name          kind control plane       authentication kubernetes io node uid          497e9d9a 47aa 4930 b0f6 9f2fb574c8c6       authentication kubernetes io pod name          test pod       authentication kubernetes io pod uid          e87dbbd6 3d7e 45db aafb 72b24627dff5     groups        system serviceaccounts       system serviceaccounts default       system authenticated     uid  f8b4161b 2e2b 11e9 86b7 2afc33b31a7e     username  system serviceaccount default my sa       Despite using  kubectl create  f  to create this resource  and defining it similar to other resource types in Kubernetes  TokenReview is a special type and the kube apiserver does not actually persist the TokenReview object into etcd  Hence  kubectl get tokenreview  is not a valid command       Bound service account token volume mechanism   bound service account token volume     By default  the Kubernetes control plane  specifically  the  ServiceAccount admission controller   serviceaccount admission controller    adds a  projected volume   docs concepts storage projected volumes   to Pods  and this volume includes a token for Kubernetes API access   Here s an example of how that looks for a launched Pod      yaml         name  kube api access  random suffix      projected        sources            serviceAccountToken              path  token   must match the path the app expects           configMap              items                  key  ca crt                 path  ca crt             name  kube root ca crt           downwardAPI              items                  fieldRef                    apiVersion  v1                   fieldPath  metadata namespace                 path  namespace      That manifest snippet defines a projected volume that consists of three sources  In this case  each source also represents a single path within that volume  The three sources are   1  A  serviceAccountToken  source  that contains a token that the kubelet acquires from kube apiserver     The kubelet fetches time bound tokens using the TokenRequest API  A token served for a TokenRequest expires    either when the pod is deleted or after a defined lifespan  by default  that is 1 hour      The kubelet also refreshes that token before the token expires     The token is bound to the specific Pod and has the kube apiserver as its audience     This mechanism superseded an earlier mechanism that added a volume based on a Secret     where the Secret represented the ServiceAccount for the Pod  but did not expire  1  A  configMap  source  The ConfigMap contains a bundle of certificate authority data  Pods can use these    certificates to make sure that they are connecting to your cluster s kube apiserver  and not to middlebox    or an accidentally misconfigured peer   1  A  downwardAPI  source that looks up the name of the namespace containing the Pod  and makes    that name information available to application code running inside the Pod   Any container within the Pod that mounts this particular volume can access the above information    There is no specific mechanism to invalidate a token issued via TokenRequest  If you no longer trust a bound service account token for a Pod  you can delete that Pod  Deleting a Pod expires its bound service account tokens       Manual Secret management for ServiceAccounts  Versions of Kubernetes before v1 22 automatically created credentials for accessing the Kubernetes API  This older mechanism was based on creating token Secrets that could then be mounted into running Pods   In more recent versions  including Kubernetes v  API credentials are  obtained directly   bound service account token volume  using the  TokenRequest   docs reference kubernetes api authentication resources token request v1   API  and are mounted into Pods using a projected volume  The tokens obtained using this method have bounded lifetimes  and are automatically invalidated when the Pod they are mounted into is deleted   You can still  manually create   docs tasks configure pod container configure service account  manually create an api token for a serviceaccount  a Secret to hold a service account token  for example  if you need a token that never expires   Once you manually create a Secret and link it to a ServiceAccount  the Kubernetes control plane automatically populates the token into that Secret    Although the manual mechanism for creating a long lived ServiceAccount token exists  using  TokenRequest   docs reference kubernetes api authentication resources token request v1   to obtain short lived API access tokens is recommended instead       Auto generated legacy ServiceAccount token clean up   auto generated legacy serviceaccount token clean up   Before version 1 24  Kubernetes automatically generated Secret based tokens for ServiceAccounts  To distinguish between automatically generated tokens and manually created ones  Kubernetes checks for a reference from the ServiceAccount s secrets field  If the Secret is referenced in the  secrets  field  it is considered an auto generated legacy token  Otherwise  it is considered a manually created legacy token  For example      yaml apiVersion  v1 kind  ServiceAccount metadata    name  build robot   namespace  default secrets      name  build robot secret   usually NOT present for a manually generated token                               Beginning from version 1 29  legacy ServiceAccount tokens that were generated automatically will be marked as invalid if they remain unused for a certain period of time  set to default at one year   Tokens that continue to be unused for this defined period  again  by default  one year  will subsequently be purged by the control plane   If users use an invalidated auto generated token  the token validator will  1  add an audit annotation for the key value pair    authentication k8s io legacy token invalidated   secret name   namespace    1  increment the  invalid legacy auto token uses total  metric count  1  update the Secret label  kubernetes io legacy token last used  with the new    date  1  return an error indicating that the token has been invalidated   When receiving this validation error  users can update the Secret to remove the  kubernetes io legacy token invalid since  label to temporarily allow use of this token   Here s an example of an auto generated legacy token that has been marked with the  kubernetes io legacy token last used  and  kubernetes io legacy token invalid since  labels      yaml apiVersion  v1 kind  Secret metadata    name  build robot secret   namespace  default   labels      kubernetes io legacy token last used  2022 10 24     kubernetes io legacy token invalid since  2023 10 25   annotations      kubernetes io service account name  build robot type  kubernetes io service account token         Control plane details      ServiceAccount controller  A ServiceAccount controller manages the ServiceAccounts inside namespaces  and ensures a ServiceAccount named  default  exists in every active namespace       Token controller  The service account token controller runs as part of  kube controller manager   This controller acts asynchronously  It     watches for ServiceAccount deletion and deletes all corresponding ServiceAccount   token Secrets    watches for ServiceAccount token Secret addition  and ensures the referenced   ServiceAccount exists  and adds a token to the Secret if needed    watches for Secret deletion and removes a reference from the corresponding   ServiceAccount if needed   You must pass a service account private key file to the token controller in the  kube controller manager  using the    service account private key file  flag  The private key is used to sign generated service account tokens  Similarly  you must pass the corresponding public key to the  kube apiserver  using the    service account key file  flag  The public key will be used to verify the tokens during authentication       ServiceAccount admission controller  The modification of pods is implemented via a plugin called an  Admission Controller   docs reference access authn authz admission controllers    It is part of the API server  This admission controller acts synchronously to modify pods as they are created  When this plugin is active  and it is by default on most distributions   then it does the following when a Pod is created   1  If the pod does not have a   spec serviceAccountName  set  the admission controller sets the name of the    ServiceAccount for this incoming Pod to  default   1  The admission controller ensures that the ServiceAccount referenced by the incoming Pod exists  If there    is no ServiceAccount with a matching name  the admission controller rejects the incoming Pod  That check    applies even for the  default  ServiceAccount  1  Provided that neither the ServiceAccount s  automountServiceAccountToken  field nor the    Pod s  automountServiceAccountToken  field is set to  false        the admission controller mutates the incoming Pod  adding an extra       that contains      a token for API access       the admission controller adds a  volumeMount  to each container in the Pod       skipping any containers that already have a volume mount defined for the path        var run secrets kubernetes io serviceaccount        For Linux containers  that volume is mounted at   var run secrets kubernetes io serviceaccount        on Windows nodes  the mount is at the equivalent path  1  If the spec of the incoming Pod doesn t already contain any  imagePullSecrets   then the    admission controller adds  imagePullSecrets   copying them from the  ServiceAccount        Legacy ServiceAccount token tracking controller    This controller generates a ConfigMap called  kube system kube apiserver legacy service account token tracking  in the  kube system  namespace  The ConfigMap records the timestamp when legacy service account tokens began to be monitored by the system       Legacy ServiceAccount token cleaner    The legacy ServiceAccount token cleaner runs as part of the  kube controller manager  and checks every 24 hours to see if any auto generated legacy ServiceAccount token has not been used in a  specified amount of time   If so  the cleaner marks those tokens as invalid   The cleaner works by first checking the ConfigMap created by the control plane  provided that  LegacyServiceAccountTokenTracking  is enabled   If the current time is a  specified amount of time  after the date in the ConfigMap  the cleaner then loops through the list of Secrets in the cluster and evaluates each Secret that has the type  kubernetes io service account token    If a Secret meets all of the following conditions  the cleaner marks it as invalid     The Secret is auto generated  meaning that it is bi directionally referenced   by a ServiceAccount    The Secret is not currently mounted by any pods    The Secret has not been used in a  specified amount of time  since it was   created or since it was last used   The cleaner marks a Secret invalid by adding a label called  kubernetes io legacy token invalid since  to the Secret  with the current date as the value  If an invalid Secret is not used in a  specified amount of time   the cleaner will delete it    All the  specified amount of time  above defaults to one year  The cluster administrator can configure this value through the    legacy service account token clean up period  command line argument for the  kube controller manager  component        TokenRequest API    You use the  TokenRequest   docs reference kubernetes api authentication resources token request v1   subresource of a ServiceAccount to obtain a time bound token for that ServiceAccount  You don t need to call this to obtain an API token for use within a container  since the kubelet sets this up for you using a  projected volume    If you want to use the TokenRequest API from  kubectl   see  Manually create an API token for a ServiceAccount   docs tasks configure pod container configure service account  manually create an api token for a serviceaccount    The Kubernetes control plane  specifically  the ServiceAccount admission controller  adds a projected volume to Pods  and the kubelet ensures that this volume contains a token that lets containers authenticate as the right ServiceAccount    This mechanism superseded an earlier mechanism that added a volume based on a Secret  where the Secret represented the ServiceAccount for the Pod but did not expire    Here s an example of how that looks for a launched Pod      yaml         name  kube api access  random suffix      projected        defaultMode  420   decimal equivalent of octal 0644       sources            serviceAccountToken              expirationSeconds  3607             path  token           configMap              items                  key  ca crt                 path  ca crt             name  kube root ca crt           downwardAPI              items                  fieldRef                    apiVersion  v1                   fieldPath  metadata namespace                 path  namespace      That manifest snippet defines a projected volume that combines information from three sources   1  A  serviceAccountToken  source  that contains a token that the kubelet acquires from kube apiserver     The kubelet fetches time bound tokens using the TokenRequest API  A token served for a TokenRequest expires    either when the pod is deleted or after a defined lifespan  by default  that is 1 hour      The token is bound to the specific Pod and has the kube apiserver as its audience  1  A  configMap  source  The ConfigMap contains a bundle of certificate authority data  Pods can use these    certificates to make sure that they are connecting to your cluster s kube apiserver  and not to middlebox    or an accidentally misconfigured peer   1  A  downwardAPI  source  This  downwardAPI  volume makes the name of the namespace containing the Pod available    to application code running inside the Pod   Any container within the Pod that mounts this volume can access the above information      Create additional API tokens   create token    Only create long lived API tokens if the  token request   tokenrequest api  mechanism is not suitable  The token request mechanism provides time limited tokens  because these expire  they represent a lower risk to information security    To create a non expiring  persisted API token for a ServiceAccount  create a Secret of type  kubernetes io service account token  with an annotation referencing the ServiceAccount  The control plane then generates a long lived token and updates that Secret with that generated token data   Here is a sample manifest for such a Secret     To create a Secret based on this example  run      shell kubectl  n examplens create  f https   k8s io examples secret serviceaccount mysecretname yaml      To see the details for that Secret  run      shell kubectl  n examplens describe secret mysecretname      The output is similar to       Name            mysecretname Namespace       examplens Labels           none  Annotations     kubernetes io service account name myserviceaccount                 kubernetes io service account uid 8a85c4c4 8483 11e9 bc42 526af7764f64  Type    kubernetes io service account token  Data      ca crt          1362 bytes namespace       9 bytes token                    If you launch a new Pod into the  examplens  namespace  it can use the  myserviceaccount  service account token Secret that you just created    Do not reference manually created Secrets in the  secrets  field of a ServiceAccount  Or the manually created Secrets will be cleaned if it is not used for a long time  Please refer to  auto generated legacy ServiceAccount token clean up   auto generated legacy serviceaccount token clean up        Delete invalidate a ServiceAccount token   delete token   If you know the name of the Secret that contains the token you want to remove      shell kubectl delete secret name of secret      Otherwise  first find the Secret for the ServiceAccount      shell   This assumes that you already have a namespace named  examplens  kubectl  n examplens get serviceaccount example automated thing  o yaml      The output is similar to      yaml apiVersion  v1 kind  ServiceAccount metadata    annotations      kubectl kubernetes io last applied configuration            apiVersion   v1   kind   ServiceAccount   metadata    annotations      name   example automated thing   namespace   examplens      creationTimestamp   2019 07 21T07 07 07Z    name  example automated thing   namespace  examplens   resourceVersion   777    selfLink   api v1 namespaces examplens serviceaccounts example automated thing   uid  f23fd170 66f2 4697 b049 e1e266b7f835 secrets      name  example automated thing token zyxwv      Then  delete the Secret you now know the name of      shell kubectl  n examplens delete secret example automated thing token zyxwv         Clean up  If you created a namespace  examplens  to experiment with  you can remove it      shell kubectl delete namespace examplens             Read more details about  projected volumes   docs concepts storage projected volumes


kubernetes reference cici37 title Validating Admission Policy liggitt contenttype concept reviewers jpbetz overview

Answer:
---
reviewers:
- liggitt
- jpbetz
- cici37
title: Validating Admission Policy
content_type: concept
---

<!-- overview -->

This page provides an overview of Validating Admission Policy.

<!-- body -->

## What is Validating Admission Policy?

Validating admission policies offer a declarative, in-process alternative to validating admission webhooks.

Validating admission policies use the Common Expression Language (CEL) to declare the validation
rules of a policy.
Validation admission policies are highly configurable, enabling policy authors to define policies
that can be parameterized and scoped to resources as needed by cluster administrators.

## What Resources Make a Policy

A policy is generally made up of three resources:

- The `ValidatingAdmissionPolicy` describes the abstract logic of a policy
  (think: "this policy makes sure a particular label is set to a particular value").

- A `ValidatingAdmissionPolicyBinding` links the above resources together and provides scoping.
  If you only want to require an `owner` label to be set for `Pods`, the binding is where you would
  specify this restriction.

- A parameter resource provides information to a ValidatingAdmissionPolicy to make it a concrete
  statement (think "the `owner` label must be set to something that ends in `.company.com`").
  A native type such as ConfigMap or a CRD defines the schema of a parameter resource.
  `ValidatingAdmissionPolicy` objects specify what Kind they are expecting for their parameter resource.

At least a `ValidatingAdmissionPolicy` and a corresponding  `ValidatingAdmissionPolicyBinding`
must be defined for a policy to have an effect.

If a `ValidatingAdmissionPolicy` does not need to be configured via parameters, simply leave
`spec.paramKind` in  `ValidatingAdmissionPolicy` not specified.

## Getting Started with Validating Admission Policy

Validating Admission Policy is part of the cluster control-plane. You should write and deploy them
with great caution. The following describes how to quickly experiment with Validating Admission Policy.

### Creating a ValidatingAdmissionPolicy

The following is an example of a ValidatingAdmissionPolicy.

`spec.validations` contains CEL expressions which use the [Common Expression Language (CEL)](https://github.com/google/cel-spec)
to validate the request. If an expression evaluates to false, the validation check is enforced
according to the `spec.failurePolicy` field.

You can quickly test CEL expressions in [CEL Playground](https://playcel.undistro.io).

To configure a validating admission policy for use in a cluster, a binding is required.
The following is an example of a ValidatingAdmissionPolicyBinding.:

When trying to create a deployment with replicas set not satisfying the validation expression, an
error will return containing message:

```none
ValidatingAdmissionPolicy 'demo-policy.example.com' with binding 'demo-binding-test.example.com' denied request: failed expression: object.spec.replicas <= 5
```

The above provides a simple example of using ValidatingAdmissionPolicy without a parameter configured.

#### Validation actions

Each `ValidatingAdmissionPolicyBinding` must specify one or more
`validationActions` to declare how `validations` of a policy are enforced.

The supported `validationActions` are:

- `Deny`: Validation failure results in a denied request.
- `Warn`: Validation failure is reported to the request client
  as a [warning](/blog/2020/09/03/warnings/).
- `Audit`: Validation failure is included in the audit event for the API request.

For example, to both warn clients about a validation failure and to audit the
validation failures, use:

```yaml
validationActions: [Warn, Audit]
```

`Deny` and `Warn` may not be used together since this combination
needlessly duplicates the validation failure both in the
API response body and the HTTP warning headers.

A `validation` that evaluates to false is always enforced according to these
actions. Failures defined by the `failurePolicy` are enforced
according to these actions only if the `failurePolicy` is set to `Fail` (or not specified),
otherwise the failures are ignored.

See [Audit Annotations: validation failures](/docs/reference/labels-annotations-taints/audit-annotations/#validation-policy-admission-k8s-io-validation-failure)
for more details about the validation failure audit annotation.

### Parameter resources

Parameter resources allow a policy configuration to be separate from its definition.
A policy can define paramKind, which outlines GVK of the parameter resource,
and then a policy binding ties a policy by name (via policyName) to a particular parameter resource via paramRef.

If parameter configuration is needed, the following is an example of a ValidatingAdmissionPolicy
with parameter configuration.

The `spec.paramKind` field of the ValidatingAdmissionPolicy specifies the kind of resources used
to parameterize this policy. For this example, it is configured by ReplicaLimit custom resources.
Note in this example how the CEL expression references the parameters via the CEL params variable,
e.g. `params.maxReplicas`. `spec.matchConstraints` specifies what resources this policy is
designed to validate. Note that the native types such like `ConfigMap` could also be used as
parameter reference.

The `spec.validations` fields contain CEL expressions. If an expression evaluates to false, the
validation check is enforced according to the `spec.failurePolicy` field.

The validating admission policy author is responsible for providing the ReplicaLimit parameter CRD.

To configure an validating admission policy for use in a cluster, a binding and parameter resource
are created. The following is an example of a ValidatingAdmissionPolicyBinding
that uses a **cluster-wide** param - the same param will be used to validate
every resource request that matches the binding:

Notice this binding applies a parameter to the policy for all resources which
are in the `test` environment.

The parameter resource could be as following:

This policy parameter resource limits deployments to a max of 3 replicas.

An admission policy may have multiple bindings. To bind all other environments
to have a maxReplicas limit of 100, create another ValidatingAdmissionPolicyBinding:

Notice this binding applies a different parameter to resources which
are not in the `test` environment.

And have a parameter resource:

For each admission request, the API server evaluates CEL expressions of each
(policy, binding, param) combination that match the request. For a request
to be admitted it must pass **all** evaluations.

If multiple bindings match the request, the policy will be evaluated for each,
and they must all pass evaluation for the policy to be considered passed.

If multiple parameters match a single binding, the policy rules will be evaluated
for each param, and they too must all pass for the binding to be considered passed.
Bindings can have overlapping match criteria. The policy is evaluated for each
matching binding-parameter combination. A policy may even be evaluated multiple
times if multiple bindings match it, or a single binding that matches multiple
parameters.

The params object representing a parameter resource will not be set if a parameter resource has
not been bound, so for policies requiring a parameter resource, it can be useful to add a check to
ensure one has been bound. A parameter resource will not be bound and `params` will be null
if `paramKind` of the policy, or `paramRef` of the binding are not specified.

For the use cases require parameter configuration, we recommend to add a param check in
`spec.validations[0].expression`:

```
- expression: "params != null"
  message: "params missing but required to bind to this policy"
```

#### Optional parameters

It can be convenient to be able to have optional parameters as part of a parameter resource, and
only validate them if present. CEL provides `has()`, which checks if the key passed to it exists.
CEL also implements Boolean short-circuiting. If the first half of a logical OR evaluates to true,
it won’t evaluate the other half (since the result of the entire OR will be true regardless).

Combining the two, we can provide a way to validate optional parameters:

`!has(params.optionalNumber) || (params.optionalNumber >= 5 && params.optionalNumber <= 10)`

Here, we first check that the optional parameter is present with `!has(params.optionalNumber)`.

- If `optionalNumber` hasn’t been defined, then the expression short-circuits since
  `!has(params.optionalNumber)` will evaluate to true.
- If `optionalNumber` has been defined, then the latter half of the CEL expression will be
  evaluated, and optionalNumber will be checked to ensure that it contains a value between 5 and
  10 inclusive.

#### Per-namespace Parameters

As the author of a ValidatingAdmissionPolicy and its ValidatingAdmissionPolicyBinding,
you can choose to specify cluster-wide, or per-namespace parameters.
If you specify a `namespace` for the binding's `paramRef`, the control plane only
searches for parameters in that namespace.

However, if `namespace` is not specified in the ValidatingAdmissionPolicyBinding, the
API server can search for relevant parameters in the namespace that a request is against.
For example, if you make a request to modify a ConfigMap in the `default` namespace and
there is a relevant ValidatingAdmissionPolicyBinding with no `namespace` set, then the
API server looks for a parameter object in `default`.
This design enables policy configuration that depends on the namespace
of the resource being manipulated, for more fine-tuned control.

#### Parameter selector

In addition to specify a parameter in a binding by `name`, you may
choose instead to specify label selector, such that all resources of the
policy's `paramKind`, and the param's `namespace` (if applicable) that match the
label selector are selected for evaluation. See  for more information on how label selectors match resources.

If multiple parameters are found to meet the condition, the policy's rules are
evaluated for each parameter found and the results will be ANDed together.

If `namespace` is provided, only objects of the `paramKind` in the provided
namespace are eligible for selection. Otherwise, when `namespace` is empty and
`paramKind` is namespace-scoped, the `namespace` used in the request being
admitted will be used.

#### Authorization checks {#authorization-check}

We introduced the authorization check for parameter resources.
User is expected to have `read` access to the resources referenced by `paramKind` in
`ValidatingAdmissionPolicy` and `paramRef` in `ValidatingAdmissionPolicyBinding`.

Note that if a resource in `paramKind` fails resolving via the restmapper, `read` access to all
resources of groups is required.

### Failure Policy

`failurePolicy` defines how mis-configurations and CEL expressions evaluating to error from the
admission policy are handled. Allowed values are `Ignore` or `Fail`.

- `Ignore` means that an error calling the ValidatingAdmissionPolicy is ignored and the API
  request is allowed to continue.
- `Fail` means that an error calling the ValidatingAdmissionPolicy causes the admission to fail
  and the API request to be rejected.

Note that the `failurePolicy` is defined inside `ValidatingAdmissionPolicy`:

### Validation Expression

`spec.validations[i].expression` represents the expression which will be evaluated by CEL.
To learn more, see the [CEL language specification](https://github.com/google/cel-spec)
CEL expressions have access to the contents of the Admission request/response, organized into CEL
variables as well as some other useful variables:

- 'object' - The object from the incoming request. The value is null for DELETE requests.
- 'oldObject' - The existing object. The value is null for CREATE requests.
- 'request' - Attributes of the [admission request](/docs/reference/config-api/apiserver-admission.v1/#admission-k8s-io-v1-AdmissionRequest).
- 'params' - Parameter resource referred to by the policy binding being evaluated. The value is
  null if `ParamKind` is not specified.
- `namespaceObject` - The namespace, as a Kubernetes resource, that the incoming object belongs to.
  The value is null if the incoming object is cluster-scoped.
- `authorizer` - A CEL Authorizer. May be used to perform authorization checks for the principal
  (authenticated user) of the request. See
  [AuthzSelectors](https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#AuthzSelectors) and
  [Authz](https://pkg.go.dev/k8s.io/apiserver/pkg/cel/library#Authz) in the Kubernetes CEL library
  documentation for more details.
- `authorizer.requestResource` - A shortcut for an authorization check configured with the request
  resource (group, resource, (subresource), namespace, name).

The `apiVersion`, `kind`, `metadata.name` and `metadata.generateName` are always accessible from
the root of the object. No other metadata properties are accessible.

Equality on arrays with list type of 'set' or 'map' ignores element order, i.e. [1, 2] == [2, 1].
Concatenation on arrays with x-kubernetes-list-type use the semantics of the list type:

- 'set': `X + Y` performs a union where the array positions of all elements in `X` are preserved and
  non-intersecting elements in `Y` are appended, retaining their partial order.
- 'map': `X + Y` performs a merge where the array positions of all keys in `X` are preserved but the values
  are overwritten by values in `Y` when the key sets of `X` and `Y` intersect. Elements in `Y` with
  non-intersecting keys are appended, retaining their partial order.

#### Validation expression examples

| Expression                                                                                | Purpose                                                                           |
|----------------------------------------------------------------------------------------------| ------------                                                                      |
| `object.minReplicas <= object.replicas && object.replicas <= object.maxReplicas`             | Validate that the three fields defining replicas are ordered appropriately        |
| `'Available' in object.stateCounts`                                                          | Validate that an entry with the 'Available' key exists in a map                   |
| `(size(object.list1) == 0) != (size(object.list2) == 0)`                                     | Validate that one of two lists is non-empty, but not both                         |
| <code>!('MY_KEY' in object.map1) || object['MY_KEY'].matches('^[a-zA-Z]*$')</code> | Validate the value of a map for a specific key, if it is in the map               |
| `object.envars.filter(e, e.name == 'MY_ENV').all(e, e.value.matches('^[a-zA-Z]*$')`          | Validate the 'value' field of a listMap entry where key field 'name' is 'MY_ENV'  |
| `has(object.expired) && object.created + object.ttl < object.expired`                        | Validate that 'expired' date is after a 'create' date plus a 'ttl' duration       |
| `object.health.startsWith('ok')`                                                             | Validate a 'health' string field has the prefix 'ok'                              |
| `object.widgets.exists(w, w.key == 'x' && w.foo < 10)`                                       | Validate that the 'foo' property of a listMap item with a key 'x' is less than 10 |
| `type(object) == string ? object == '100%' : object == 1000`                                 | Validate an int-or-string field for both the int and string cases             |
| `object.metadata.name.startsWith(object.prefix)`                                             | Validate that an object's name has the prefix of another field value              |
| `object.set1.all(e, !(e in object.set2))`                                                    | Validate that two listSets are disjoint                                           |
| `size(object.names) == size(object.details) && object.names.all(n, n in object.details)`     | Validate the 'details' map is keyed by the items in the 'names' listSet           |
| `size(object.clusters.filter(c, c.name == object.primary)) == 1`                             | Validate that the 'primary' property has one and only one occurrence in the 'clusters' listMap           |

Read [Supported evaluation on CEL](https://github.com/google/cel-spec/blob/v0.6.0/doc/langdef.md#evaluation)
for more information about CEL rules.

`spec.validation[i].reason` represents a machine-readable description of why this validation failed.
If this is the first validation in the list to fail, this reason, as well as the corresponding
HTTP response code, are used in the HTTP response to the client.
The currently supported reasons are: `Unauthorized`, `Forbidden`, `Invalid`, `RequestEntityTooLarge`.
If not set, `StatusReasonInvalid` is used in the response to the client.

### Matching requests: `matchConditions`

You can define _match conditions_ for a `ValidatingAdmissionPolicy` if you need fine-grained request filtering. These
conditions are useful if you find that match rules, `objectSelectors` and `namespaceSelectors` still
doesn't provide the filtering you want. Match conditions are
[CEL expressions](/docs/reference/using-api/cel/). All match conditions must evaluate to true for the
resource to be evaluated.

Here is an example illustrating a few different uses for match conditions:

Match conditions have access to the same CEL variables as validation expressions.

In the event of an error evaluating a match condition the policy is not evaluated. Whether to reject
the request is determined as follows:

1. If **any** match condition evaluated to `false` (regardless of other errors), the API server skips the policy.
2. Otherwise:
   - for [`failurePolicy: Fail`](#failure-policy), reject the request (without evaluating the policy).
   - for [`failurePolicy: Ignore`](#failure-policy), proceed with the request but skip the policy.

### Audit annotations

`auditAnnotations` may be used to include audit annotations in the audit event of the API request.

For example, here is an admission policy with an audit annotation:

When an API request is validated with this admission policy, the resulting audit event will look like:

```
# the audit event recorded
{
    "kind": "Event",
    "apiVersion": "audit.k8s.io/v1",
    "annotations": {
        "demo-policy.example.com/high-replica-count": "Deployment spec.replicas set to 128"
        # other annotations
        ...
    }
    # other fields
    ...
}
```

In this example the annotation will only be included if the `spec.replicas` of the Deployment is more than
50, otherwise the CEL expression evaluates to null and the annotation will not be included.

Note that audit annotation keys are prefixed by the name of the `ValidatingAdmissionWebhook` and a `/`. If
another admission controller, such as an admission webhook, uses the exact same audit annotation key, the
value of the first admission controller to include the audit annotation will be included in the audit
event and all other values will be ignored.

### Message expression

To return a more friendly message when the policy rejects a request, we can use a CEL expression
to composite a message with `spec.validations[i].messageExpression`. Similar to the validation expression,
a message expression has access to `object`, `oldObject`, `request`, `params`, and `namespaceObject`.
Unlike validations, message expression must evaluate to a string.

For example, to better inform the user of the reason of denial when the policy refers to a parameter,
we can have the following validation:

After creating a params object that limits the replicas to 3 and setting up the binding,
when we try to create a deployment with 5 replicas, we will receive the following message.

```
$ kubectl create deploy --image=nginx nginx --replicas=5
error: failed to create deployment: deployments.apps "nginx" is forbidden: ValidatingAdmissionPolicy 'deploy-replica-policy.example.com' with binding 'demo-binding-test.example.com' denied request: object.spec.replicas must be no greater than 3
```

This is more informative than a static message of "too many replicas".

The message expression takes precedence over the static message defined in `spec.validations[i].message` if both are defined.
However, if the message expression fails to evaluate, the static message will be used instead.
Additionally, if the message expression evaluates to a multi-line string,
the evaluation result will be discarded and the static message will be used if present.
Note that static message is validated against multi-line strings.

### Type checking

When a policy definition is created or updated, the validation process parses the expressions it contains
and reports any syntax errors, rejecting the definition if any errors are found.
Afterward, the referred variables are checked for type errors, including missing fields and type confusion,
against the matched types of `spec.matchConstraints`.
The result of type checking can be retrieved from `status.typeChecking`.
The presence of `status.typeChecking` indicates the completion of type checking,
and an empty `status.typeChecking` means that no errors were detected.

For example, given the following policy definition:

The status will yield the following information:

```yaml
status:
  typeChecking:
    expressionWarnings:
    - fieldRef: spec.validations[0].expression
      warning: |-
        apps/v1, Kind=Deployment: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^
```

If multiple resources are matched in `spec.matchConstraints`, all of matched resources will be checked against.
For example, the following policy definition

will have multiple types and type checking result of each type in the warning message.

```yaml
status:
  typeChecking:
    expressionWarnings:
    - fieldRef: spec.validations[0].expression
      warning: |-
        apps/v1, Kind=Deployment: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^
        apps/v1, Kind=ReplicaSet: ERROR: <input>:1:7: undefined field 'replicas'
         | object.replicas > 1
         | ......^
```

Type Checking has the following limitation:

- No wildcard matching. If `spec.matchConstraints.resourceRules` contains `"*"` in any of `apiGroups`, `apiVersions` or `resources`,
  the types that `"*"` matches will not be checked.
- The number of matched types is limited to 10. This is to prevent a policy that manually specifying too many types.
  to consume excessive computing resources. In the order of ascending group, version, and then resource, 11th combination and beyond are ignored.
- Type Checking does not affect the policy behavior in any way. Even if the type checking detects errors, the policy will continue
  to evaluate. If errors do occur during evaluate, the failure policy will decide its outcome.
- Type Checking does not apply to CRDs, including matched CRD types and reference of paramKind. The support for CRDs will come in future release.

### Variable composition

If an expression grows too complicated, or part of the expression is reusable and computationally expensive to evaluate,
you can extract some part of the expressions into variables. A variable is a named expression that can be referred later
in `variables` in other expressions.

```yaml
spec:
  variables:
    - name: foo
      expression: "'foo' in object.spec.metadata.labels ? object.spec.metadata.labels['foo'] : 'default'"
  validations:
    - expression: variables.foo == 'bar'
```

A variable is lazily evaluated when it is first referred. Any error that occurs during the evaluation will be
reported during the evaluation of the referring expression. Both the result and potential error are memorized and
count only once towards the runtime cost.

The order of variables are important because a variable can refer to other variables that are defined before it.
This ordering prevents circular references.

The following is a more complex example of enforcing that image repo names match the environment defined in its namespace.

With the policy bound to the namespace `default`, which is labeled `environment: prod`,
the following attempt to create a deployment would be rejected.
```shell
kubectl create deploy --image=dev.example.com/nginx invalid
```
The error message is similar to this.
```console
error: failed to create deployment: deployments.apps "invalid" is forbidden: ValidatingAdmissionPolicy 'image-matches-namespace-environment.policy.example.com' with binding 'demo-binding-test.example.com' denied request: only prod images are allowed in namespace default
```

reviewers    liggitt   jpbetz   cici37 title  Validating Admission Policy content type  concept           overview        This page provides an overview of Validating Admission Policy         body         What is Validating Admission Policy   Validating admission policies offer a declarative  in process alternative to validating admission webhooks   Validating admission policies use the Common Expression Language  CEL  to declare the validation rules of a policy   Validation admission policies are highly configurable  enabling policy authors to define policies that can be parameterized and scoped to resources as needed by cluster administrators      What Resources Make a Policy  A policy is generally made up of three resources     The  ValidatingAdmissionPolicy  describes the abstract logic of a policy    think   this policy makes sure a particular label is set to a particular value       A  ValidatingAdmissionPolicyBinding  links the above resources together and provides scoping    If you only want to require an  owner  label to be set for  Pods   the binding is where you would   specify this restriction     A parameter resource provides information to a ValidatingAdmissionPolicy to make it a concrete   statement  think  the  owner  label must be set to something that ends in   company com       A native type such as ConfigMap or a CRD defines the schema of a parameter resource     ValidatingAdmissionPolicy  objects specify what Kind they are expecting for their parameter resource   At least a  ValidatingAdmissionPolicy  and a corresponding   ValidatingAdmissionPolicyBinding  must be defined for a policy to have an effect   If a  ValidatingAdmissionPolicy  does not need to be configured via parameters  simply leave  spec paramKind  in   ValidatingAdmissionPolicy  not specified      Getting Started with Validating Admission Policy  Validating Admission Policy is part of the cluster control plane  You should write and deploy them with great caution  The following describes how to quickly experiment with Validating Admission Policy       Creating a ValidatingAdmissionPolicy  The following is an example of a ValidatingAdmissionPolicy      spec validations  contains CEL expressions which use the  Common Expression Language  CEL   https   github com google cel spec  to validate the request  If an expression evaluates to false  the validation check is enforced according to the  spec failurePolicy  field    You can quickly test CEL expressions in  CEL Playground  https   playcel undistro io     To configure a validating admission policy for use in a cluster  a binding is required  The following is an example of a ValidatingAdmissionPolicyBinding      When trying to create a deployment with replicas set not satisfying the validation expression  an error will return containing message      none ValidatingAdmissionPolicy  demo policy example com  with binding  demo binding test example com  denied request  failed expression  object spec replicas    5      The above provides a simple example of using ValidatingAdmissionPolicy without a parameter configured        Validation actions  Each  ValidatingAdmissionPolicyBinding  must specify one or more  validationActions  to declare how  validations  of a policy are enforced   The supported  validationActions  are      Deny   Validation failure results in a denied request     Warn   Validation failure is reported to the request client   as a  warning   blog 2020 09 03 warnings       Audit   Validation failure is included in the audit event for the API request   For example  to both warn clients about a validation failure and to audit the validation failures  use      yaml validationActions   Warn  Audit        Deny  and  Warn  may not be used together since this combination needlessly duplicates the validation failure both in the API response body and the HTTP warning headers   A  validation  that evaluates to false is always enforced according to these actions  Failures defined by the  failurePolicy  are enforced according to these actions only if the  failurePolicy  is set to  Fail   or not specified   otherwise the failures are ignored   See  Audit Annotations  validation failures   docs reference labels annotations taints audit annotations  validation policy admission k8s io validation failure  for more details about the validation failure audit annotation       Parameter resources  Parameter resources allow a policy configuration to be separate from its definition   A policy can define paramKind  which outlines GVK of the parameter resource   and then a policy binding ties a policy by name  via policyName  to a particular parameter resource via paramRef   If parameter configuration is needed  the following is an example of a ValidatingAdmissionPolicy with parameter configuration     The  spec paramKind  field of the ValidatingAdmissionPolicy specifies the kind of resources used to parameterize this policy  For this example  it is configured by ReplicaLimit custom resources   Note in this example how the CEL expression references the parameters via the CEL params variable  e g   params maxReplicas    spec matchConstraints  specifies what resources this policy is designed to validate  Note that the native types such like  ConfigMap  could also be used as parameter reference   The  spec validations  fields contain CEL expressions  If an expression evaluates to false  the validation check is enforced according to the  spec failurePolicy  field   The validating admission policy author is responsible for providing the ReplicaLimit parameter CRD   To configure an validating admission policy for use in a cluster  a binding and parameter resource are created  The following is an example of a ValidatingAdmissionPolicyBinding  that uses a   cluster wide   param   the same param will be used to validate every resource request that matches the binding     Notice this binding applies a parameter to the policy for all resources which are in the  test  environment   The parameter resource could be as following     This policy parameter resource limits deployments to a max of 3 replicas   An admission policy may have multiple bindings  To bind all other environments to have a maxReplicas limit of 100  create another ValidatingAdmissionPolicyBinding     Notice this binding applies a different parameter to resources which are not in the  test  environment   And have a parameter resource     For each admission request  the API server evaluates CEL expressions of each   policy  binding  param  combination that match the request  For a request to be admitted it must pass   all   evaluations   If multiple bindings match the request  the policy will be evaluated for each  and they must all pass evaluation for the policy to be considered passed    If multiple parameters match a single binding  the policy rules will be evaluated for each param  and they too must all pass for the binding to be considered passed  Bindings can have overlapping match criteria  The policy is evaluated for each  matching binding parameter combination  A policy may even be evaluated multiple times if multiple bindings match it  or a single binding that matches multiple  parameters   The params object representing a parameter resource will not be set if a parameter resource has not been bound  so for policies requiring a parameter resource  it can be useful to add a check to ensure one has been bound  A parameter resource will not be bound and  params  will be null if  paramKind  of the policy  or  paramRef  of the binding are not specified   For the use cases require parameter configuration  we recommend to add a param check in  spec validations 0  expression          expression   params    null    message   params missing but required to bind to this policy            Optional parameters  It can be convenient to be able to have optional parameters as part of a parameter resource  and only validate them if present  CEL provides  has     which checks if the key passed to it exists  CEL also implements Boolean short circuiting  If the first half of a logical OR evaluates to true  it won t evaluate the other half  since the result of the entire OR will be true regardless     Combining the two  we can provide a way to validate optional parameters     has params optionalNumber      params optionalNumber    5    params optionalNumber    10    Here  we first check that the optional parameter is present with   has params optionalNumber        If  optionalNumber  hasn t been defined  then the expression short circuits since     has params optionalNumber   will evaluate to true     If  optionalNumber  has been defined  then the latter half of the CEL expression will be   evaluated  and optionalNumber will be checked to ensure that it contains a value between 5 and   10 inclusive         Per namespace Parameters  As the author of a ValidatingAdmissionPolicy and its ValidatingAdmissionPolicyBinding   you can choose to specify cluster wide  or per namespace parameters   If you specify a  namespace  for the binding s  paramRef   the control plane only searches for parameters in that namespace   However  if  namespace  is not specified in the ValidatingAdmissionPolicyBinding  the API server can search for relevant parameters in the namespace that a request is against  For example  if you make a request to modify a ConfigMap in the  default  namespace and there is a relevant ValidatingAdmissionPolicyBinding with no  namespace  set  then the API server looks for a parameter object in  default   This design enables policy configuration that depends on the namespace of the resource being manipulated  for more fine tuned control        Parameter selector  In addition to specify a parameter in a binding by  name   you may choose instead to specify label selector  such that all resources of the policy s  paramKind   and the param s  namespace   if applicable  that match the label selector are selected for evaluation  See  for more information on how label selectors match resources   If multiple parameters are found to meet the condition  the policy s rules are evaluated for each parameter found and the results will be ANDed together   If  namespace  is provided  only objects of the  paramKind  in the provided namespace are eligible for selection  Otherwise  when  namespace  is empty and   paramKind  is namespace scoped  the  namespace  used in the request being  admitted will be used        Authorization checks   authorization check    We introduced the authorization check for parameter resources  User is expected to have  read  access to the resources referenced by  paramKind  in  ValidatingAdmissionPolicy  and  paramRef  in  ValidatingAdmissionPolicyBinding    Note that if a resource in  paramKind  fails resolving via the restmapper   read  access to all resources of groups is required       Failure Policy   failurePolicy  defines how mis configurations and CEL expressions evaluating to error from the admission policy are handled  Allowed values are  Ignore  or  Fail       Ignore  means that an error calling the ValidatingAdmissionPolicy is ignored and the API   request is allowed to continue     Fail  means that an error calling the ValidatingAdmissionPolicy causes the admission to fail   and the API request to be rejected   Note that the  failurePolicy  is defined inside  ValidatingAdmissionPolicy          Validation Expression   spec validations i  expression  represents the expression which will be evaluated by CEL  To learn more  see the  CEL language specification  https   github com google cel spec  CEL expressions have access to the contents of the Admission request response  organized into CEL variables as well as some other useful variables      object    The object from the incoming request  The value is null for DELETE requests     oldObject    The existing object  The value is null for CREATE requests     request    Attributes of the  admission request   docs reference config api apiserver admission v1  admission k8s io v1 AdmissionRequest      params    Parameter resource referred to by the policy binding being evaluated  The value is   null if  ParamKind  is not specified     namespaceObject    The namespace  as a Kubernetes resource  that the incoming object belongs to    The value is null if the incoming object is cluster scoped     authorizer    A CEL Authorizer  May be used to perform authorization checks for the principal    authenticated user  of the request  See    AuthzSelectors  https   pkg go dev k8s io apiserver pkg cel library AuthzSelectors  and    Authz  https   pkg go dev k8s io apiserver pkg cel library Authz  in the Kubernetes CEL library   documentation for more details     authorizer requestResource    A shortcut for an authorization check configured with the request   resource  group  resource   subresource   namespace  name     The  apiVersion    kind    metadata name  and  metadata generateName  are always accessible from the root of the object  No other metadata properties are accessible    Equality on arrays with list type of  set  or  map  ignores element order  i e   1  2      2  1   Concatenation on arrays with x kubernetes list type use the semantics of the list type      set    X   Y  performs a union where the array positions of all elements in  X  are preserved and   non intersecting elements in  Y  are appended  retaining their partial order     map    X   Y  performs a merge where the array positions of all keys in  X  are preserved but the values   are overwritten by values in  Y  when the key sets of  X  and  Y  intersect  Elements in  Y  with   non intersecting keys are appended  retaining their partial order        Validation expression examples    Expression                                                                                Purpose                                                                                object minReplicas    object replicas    object replicas    object maxReplicas                Validate that the three fields defining replicas are ordered appropriately              Available  in object stateCounts                                                             Validate that an entry with the  Available  key exists in a map                         size object list1     0      size object list2     0                                         Validate that one of two lists is non empty  but not both                              code    MY KEY  in object map1    124   124  object  MY KEY   matches    a zA Z       code    Validate the value of a map for a specific key  if it is in the map                    object envars filter e  e name     MY ENV   all e  e value matches    a zA Z                  Validate the  value  field of a listMap entry where key field  name  is  MY ENV        has object expired     object created   object ttl   object expired                           Validate that  expired  date is after a  create  date plus a  ttl  duration            object health startsWith  ok                                                                  Validate a  health  string field has the prefix  ok                                    object widgets exists w  w key     x     w foo   10                                           Validate that the  foo  property of a listMap item with a key  x  is less than 10      type object     string   object     100     object    1000                                    Validate an int or string field for both the int and string cases                  object metadata name startsWith object prefix                                                 Validate that an object s name has the prefix of another field value                   object set1 all e    e in object set2                                                         Validate that two listSets are disjoint                                                size object names     size object details     object names all n  n in object details         Validate the  details  map is keyed by the items in the  names  listSet                size object clusters filter c  c name    object primary      1                                Validate that the  primary  property has one and only one occurrence in the  clusters  listMap              Read  Supported evaluation on CEL  https   github com google cel spec blob v0 6 0 doc langdef md evaluation  for more information about CEL rules    spec validation i  reason  represents a machine readable description of why this validation failed  If this is the first validation in the list to fail  this reason  as well as the corresponding HTTP response code  are used in the HTTP response to the client  The currently supported reasons are   Unauthorized    Forbidden    Invalid    RequestEntityTooLarge   If not set   StatusReasonInvalid  is used in the response to the client       Matching requests   matchConditions   You can define  match conditions  for a  ValidatingAdmissionPolicy  if you need fine grained request filtering  These conditions are useful if you find that match rules   objectSelectors  and  namespaceSelectors  still doesn t provide the filtering you want  Match conditions are  CEL expressions   docs reference using api cel    All match conditions must evaluate to true for the resource to be evaluated   Here is an example illustrating a few different uses for match conditions     Match conditions have access to the same CEL variables as validation expressions   In the event of an error evaluating a match condition the policy is not evaluated  Whether to reject the request is determined as follows   1  If   any   match condition evaluated to  false   regardless of other errors   the API server skips the policy  2  Otherwise       for   failurePolicy  Fail    failure policy   reject the request  without evaluating the policy        for   failurePolicy  Ignore    failure policy   proceed with the request but skip the policy       Audit annotations   auditAnnotations  may be used to include audit annotations in the audit event of the API request   For example  here is an admission policy with an audit annotation     When an API request is validated with this admission policy  the resulting audit event will look like         the audit event recorded        kind    Event        apiVersion    audit k8s io v1        annotations              demo policy example com high replica count    Deployment spec replicas set to 128            other annotations                         other fields                In this example the annotation will only be included if the  spec replicas  of the Deployment is more than 50  otherwise the CEL expression evaluates to null and the annotation will not be included   Note that audit annotation keys are prefixed by the name of the  ValidatingAdmissionWebhook  and a      If another admission controller  such as an admission webhook  uses the exact same audit annotation key  the  value of the first admission controller to include the audit annotation will be included in the audit event and all other values will be ignored       Message expression  To return a more friendly message when the policy rejects a request  we can use a CEL expression to composite a message with  spec validations i  messageExpression   Similar to the validation expression  a message expression has access to  object    oldObject    request    params   and  namespaceObject   Unlike validations  message expression must evaluate to a string   For example  to better inform the user of the reason of denial when the policy refers to a parameter  we can have the following validation     After creating a params object that limits the replicas to 3 and setting up the binding  when we try to create a deployment with 5 replicas  we will receive the following message         kubectl create deploy   image nginx nginx   replicas 5 error  failed to create deployment  deployments apps  nginx  is forbidden  ValidatingAdmissionPolicy  deploy replica policy example com  with binding  demo binding test example com  denied request  object spec replicas must be no greater than 3      This is more informative than a static message of  too many replicas    The message expression takes precedence over the static message defined in  spec validations i  message  if both are defined  However  if the message expression fails to evaluate  the static message will be used instead  Additionally  if the message expression evaluates to a multi line string  the evaluation result will be discarded and the static message will be used if present  Note that static message is validated against multi line strings       Type checking  When a policy definition is created or updated  the validation process parses the expressions it contains and reports any syntax errors  rejecting the definition if any errors are found   Afterward  the referred variables are checked for type errors  including missing fields and type confusion  against the matched types of  spec matchConstraints   The result of type checking can be retrieved from  status typeChecking   The presence of  status typeChecking  indicates the completion of type checking  and an empty  status typeChecking  means that no errors were detected   For example  given the following policy definition     The status will yield the following information      yaml status    typeChecking      expressionWarnings        fieldRef  spec validations 0  expression       warning             apps v1  Kind Deployment  ERROR   input  1 7  undefined field  replicas             object replicas   1                         If multiple resources are matched in  spec matchConstraints   all of matched resources will be checked against  For example  the following policy definition      will have multiple types and type checking result of each type in the warning message      yaml status    typeChecking      expressionWarnings        fieldRef  spec validations 0  expression       warning             apps v1  Kind Deployment  ERROR   input  1 7  undefined field  replicas             object replicas   1                            apps v1  Kind ReplicaSet  ERROR   input  1 7  undefined field  replicas             object replicas   1                         Type Checking has the following limitation     No wildcard matching  If  spec matchConstraints resourceRules  contains       in any of  apiGroups    apiVersions  or  resources     the types that       matches will not be checked    The number of matched types is limited to 10  This is to prevent a policy that manually specifying too many types    to consume excessive computing resources  In the order of ascending group  version  and then resource  11th combination and beyond are ignored    Type Checking does not affect the policy behavior in any way  Even if the type checking detects errors  the policy will continue   to evaluate  If errors do occur during evaluate  the failure policy will decide its outcome    Type Checking does not apply to CRDs  including matched CRD types and reference of paramKind  The support for CRDs will come in future release       Variable composition  If an expression grows too complicated  or part of the expression is reusable and computationally expensive to evaluate  you can extract some part of the expressions into variables  A variable is a named expression that can be referred later in  variables  in other expressions      yaml spec    variables        name  foo       expression    foo  in object spec metadata labels   object spec metadata labels  foo      default     validations        expression  variables foo     bar       A variable is lazily evaluated when it is first referred  Any error that occurs during the evaluation will be reported during the evaluation of the referring expression  Both the result and potential error are memorized and count only once towards the runtime cost   The order of variables are important because a variable can refer to other variables that are defined before it  This ordering prevents circular references   The following is a more complex example of enforcing that image repo names match the environment defined in its namespace     With the policy bound to the namespace  default   which is labeled  environment  prod   the following attempt to create a deployment would be rejected     shell kubectl create deploy   image dev example com nginx invalid     The error message is similar to this     console error  failed to create deployment  deployments apps  invalid  is forbidden  ValidatingAdmissionPolicy  image matches namespace environment policy example com  with binding  demo binding test example com  denied request  only prod images are allowed in namespace default