User Impersonation

User impersonation is a method of allowing authenticated users to act as another user, group, or service account through HTTP headers.

A user can act as another user through impersonation headers. These let requests manually override the user info a request authenticates as. For example, an admin could use this feature to debug an authorization policy by temporarily impersonating another user and seeing if a request was denied.

Impersonation requests first authenticate as the requesting user, then switch to the impersonated user info.

  • A user makes an API call with their credentials and impersonation headers.
  • API server authenticates the user.
  • API server ensures the authenticated users have impersonation privileges.
  • Request user info is replaced with impersonation values.
  • Request is evaluated, authorization acts on impersonated user info.

The following HTTP headers can be used to performing an impersonation request:

  • Impersonate-User: The username to act as.
  • Impersonate-Uid: A unique identifier that represents the user being impersonated. Optional. Requires "Impersonate-User". Kubernetes does not impose any format requirements on this string.
  • Impersonate-Group: A group name to act as. Can be provided multiple times to set multiple groups. Optional. Requires "Impersonate-User".
  • Impersonate-Extra-( extra name ): A dynamic header used to associate extra fields with the user. Optional. Requires "Impersonate-User". In order to be preserved consistently, ( extra name ) must be lower-case, and any characters which aren't legal in HTTP header labels MUST be utf8 and percent-encoded.

An example of the impersonation headers used when impersonating a user with groups:

Impersonate-User: jane.doe@example.com
Impersonate-Group: developers
Impersonate-Group: admins

An example of the impersonation headers used when impersonating a user with a UID and extra fields:

Impersonate-User: jane.doe@example.com
Impersonate-Uid: 06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b
Impersonate-Extra-dn: cn=jane,ou=engineers,dc=example,dc=com
Impersonate-Extra-acme.com%2Fproject: some-project
Impersonate-Extra-scopes: view
Impersonate-Extra-scopes: development

When using kubectl set the --as command line argument to configure the Impersonate-User header, you can also set the --as-group flag to configure the Impersonate-Group header, set the --as-uid flag (1.23) to configure Impersonate-Uid header, and set the --as-user-extra flag (1.35) to configure Impersonate-Extra-( extra name ) header.

kubectl drain mynode
Error from server (Forbidden): User "clark" cannot get nodes at the cluster scope. (get nodes mynode)

Set the --as and --as-group flag:

kubectl drain mynode --as=superman --as-group=system:masters
node/mynode cordoned
node/mynode drained

To impersonate a user, user identifier (UID), group or extra fields, the impersonating user must have the ability to perform the impersonate verb on the kind of attribute being impersonated ("user", "uid", "group", etc.). For clusters that enable the RBAC authorization plugin, the following ClusterRole encompasses the rules needed to set user and group impersonation headers:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonator
rules:
- apiGroups: [""]
  resources: ["users", "groups", "serviceaccounts"]
  verbs: ["impersonate"]

For impersonation, extra fields and impersonated UIDs are both under the "authentication.k8s.io" apiGroup. Extra fields are evaluated as sub-resources of the resource "userextras". To allow a user to use impersonation headers for the extra field scopes and for UIDs, a user should be granted the following role:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: scopes-and-uid-impersonator
rules:
# Can set "Impersonate-Extra-scopes" header and the "Impersonate-Uid" header.
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes", "uids"]
  verbs: ["impersonate"]

The values of impersonation headers can also be restricted by limiting the set of resourceNames a resource can take.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: limited-impersonator
rules:
# Can impersonate the user "jane.doe@example.com"
- apiGroups: [""]
  resources: ["users"]
  verbs: ["impersonate"]
  resourceNames: ["jane.doe@example.com"]

# Can impersonate the groups "developers" and "admins"
- apiGroups: [""]
  resources: ["groups"]
  verbs: ["impersonate"]
  resourceNames: ["developers","admins"]

# Can impersonate the extras field "scopes" with the values "view" and "development"
- apiGroups: ["authentication.k8s.io"]
  resources: ["userextras/scopes"]
  verbs: ["impersonate"]
  resourceNames: ["view", "development"]

# Can impersonate the uid "06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b"
- apiGroups: ["authentication.k8s.io"]
  resources: ["uids"]
  verbs: ["impersonate"]
  resourceNames: ["06f6ce97-e2c5-4ab8-7ba5-7654dd08d52b"]

Constrained Impersonation

FEATURE STATE: Kubernetes v1.35 [alpha] (enabled by default: false)

With the impersonate verb, impersonation cannot be limited or scoped. It either grants full impersonation or none at all. Once granted permission to impersonate a user, you can perform any action that user can perform across all resources and namespaces.

With constrained impersonation, an impersonator can be limited to impersonate another user only for specific actions on specific resources, rather than being able to perform all actions that the impersonated user can perform.

This feature is enabled by setting the ConstrainedImpersonation feature gate.

Understanding constrained impersonation

Constrained impersonation requires two separate permissions:

  1. Permission to impersonate a specific identity (user, UID, group, service account or node)
  2. Permission to perform specific actions at a particular scope when impersonating (for example, only list and watch pods in the default namespace)

This means an impersonator can be limited to impersonate another user only for specific operations.

Impersonation modes

Constrained impersonation defines three distinct modes, each with its own set of verbs:

user-info mode

Use this mode to impersonate generic users (not service accounts or nodes). This mode applies when the Impersonate-User header value:

  • Does not start with system:serviceaccount:
  • Does not start with system:node:

Verbs:

  • impersonate:user-info - Permission to impersonate a specific user, group, UID, or extra field
  • impersonate-on:user-info:<verb> - Permission to perform <verb> when impersonating a generic user

ServiceAccount mode

Use this mode to impersonate ServiceAccounts.

Verbs:

  • impersonate:serviceaccount - Permission to impersonate a specific service account
  • impersonate-on:serviceaccount:<verb> - Permission to perform <verb> when impersonating a service account

arbitrary-node and associated-node modes

Use these modes to impersonate nodes. This mode applies when the Impersonate-User header value starts with system:node:.

Verbs:

  • impersonate:arbitrary-node - Permission to impersonate any specified node
  • impersonate:associated-node - Permission to impersonate only the node to which the impersonator is bound
  • impersonate-on:arbitrary-node:<verb> - Permission to perform <verb> when impersonating any node
  • impersonate-on:associated-node:<verb> - Permission to perform <verb> when impersonating the associated node

Configuring constrained impersonation with RBAC

All constrained impersonation permissions use the authentication.k8s.io API group. Here's how to configure the different modes.

Example: Impersonate a user for specific actions

This example shows how to allow a service account to impersonate a user named jane.doe@example.com, but only to list and watch pods in the default namespace. You need both a ClusterRoleBinding for the identity permission and a RoleBinding for the action permission

Step 1: Grant permission to impersonate the user identity

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-jane-identity
rules:
- apiGroups: ["authentication.k8s.io"]
  resources: ["users"]
  resourceNames: ["jane.doe@example.com"]
  verbs: ["impersonate:user-info"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: impersonate-jane-identity
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-jane-identity
subjects:
- kind: ServiceAccount
  name: my-controller
  namespace: default

Step 2: Grant permission to perform specific actions when impersonating

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-list-watch-pods
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "impersonate-on:user-info:list"
  - "impersonate-on:user-info:watch"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: impersonate-list-watch-pods
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: impersonate-list-watch-pods
subjects:
- kind: ServiceAccount
  name: my-controller
  namespace: default

Now the my-controller service account can impersonate jane.doe@example.com to list and watch pods in the default namespace, but cannot perform other actions like deleting pods or accessing resources in other namespaces.

Example: Impersonate a ServiceAccount

To allow impersonating a service account named app-sa in the production namespace to create and update deployments:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-app-sa
  namespace: default
rules:
- apiGroups: ["authentication.k8s.io"]
  resources: ["serviceaccounts"]
  resourceNames: ["app-sa"]
  # For service accounts, you must specify the namespace in the RoleBinding
  verbs: ["impersonate:serviceaccount"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-manage-deployments
  namespace: production
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs:
  - "impersonate-on:serviceaccount:create"
  - "impersonate-on:serviceaccount:update"
  - "impersonate-on:serviceaccount:patch"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: impersonate-app-sa
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: impersonate-app-sa
subjects:
- kind: ServiceAccount
  name: deputy-controller
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: impersonate-manage-deployments
  namespace: production
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: impersonate-manage-deployments
subjects:
- kind: ServiceAccount
  name: deputy-controller
  namespace: default

Example: Impersonate a node

To allow node-impersonator ServiceAccount in default namespace impersonating a node named mynode to get and list pods:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-node-sa
rules:
- apiGroups: ["authentication.k8s.io"]
  resources: ["nodes"]
  resourceNames: ["mynode"]
  verbs: ["impersonate:arbitrary-node"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-list-pods
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs:
      - "impersonate-on:arbitrary-node:list"
      - "impersonate-on:arbitrary-node:get"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: impersonate-node-sa
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-node-sa
subjects:
- kind: ServiceAccount
  name: node-impersonator
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: impersonate-list-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-list-pods
subjects:
  - kind: ServiceAccount
    name: node-impersonator
    namespace: default

Example: Node agent impersonating the associated node

This is a common pattern for node agents (like CNI plugins) that need to read pods on their node without having cluster-wide pod access.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-associated-node-identity
rules:
- apiGroups: ["authentication.k8s.io"]
  resources: ["nodes"]
  verbs: ["impersonate:associated-node"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-list-pods-on-node
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs:
  - "impersonate-on:associated-node:list"
  - "impersonate-on:associated-node:get"
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: node-agent-impersonate-node
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-associated-node-identity
subjects:
- kind: ServiceAccount
  name: node-agent
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: node-agent-impersonate-list-pods
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-list-pods-on-node
subjects:
- kind: ServiceAccount
  name: node-agent
  namespace: kube-system

The controller would get the node name using the downward API:

env:
- name: MY_NODE_NAME
  valueFrom:
    fieldRef:
      fieldPath: spec.nodeName

Then configure the kubeconfig to impersonate:

kubeConfig, _ := clientcmd.BuildConfigFromFlags("", "")
kubeConfig.Impersonate = rest.ImpersonationConfig{
    UserName: "system:node:" + os.Getenv("MY_NODE_NAME"),
}

Using constrained impersonation

From a client perspective, using constrained impersonation is identical to using traditional impersonation. You use the same impersonation headers:

Impersonate-User: jane.doe@example.com

Or with kubectl:

kubectl get pods -n default --as=jane.doe@example.com

The difference is entirely in the authorization checks performed by the API server.

Working with impersonate verb

  • If you have existing RBAC rules using the impersonate verb, they continue to function when the feature gate is enabled.

  • When an impersonation request is made, the API server first checks for constrained impersonation permissions. If those checks fail, it falls back to checking the impersonate permission.

Auditing

An audit event is logged for each impersonation request to help track how impersonation is used.

When a request uses constrained impersonation, the audit event includes authenticationMetadata object with an impersonationConstraint field that indicates which constrained impersonation verb was used to authorize the request.

Example audit event:

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "user": {
    "username": "system:serviceaccount:default:my-controller"
  },
  "impersonatedUser": {
    "username": "jane.doe@example.com"
  },
  "authenticationMetadata": {
    "impersonationConstraint": "impersonate:user-info"
  },
  "verb": "list",
  "objectRef": {
    "resource": "pods",
    "namespace": "default"
  }
}

The impersonationConstraint value indicates which mode was used (for example, impersonate:user-info, impersonate:associated-node). The specific action (for example, list) can be determined from the verb field in the audit event.

What's next

Last modified November 21, 2025 at 4:01 PM PST: Resolve review comments (aa6ec11c3b)