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.
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.( extra name ) could only contain characters which
were legal in HTTP header labels.Impersonate-Uid is only available in versions 1.22.0 and higher.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"]
Impersonating a user or group allows you to perform any action as if you were that user or group; for that reason, impersonation is not namespace scoped. If you want to allow impersonation using Kubernetes RBAC, this requires using a ClusterRole and a ClusterRoleBinding, not a Role and RoleBinding.
Granting impersonation over ServiceAccounts is namespace scoped, but the impersonated ServiceAccount could perform actions outside of namespace.
Kubernetes v1.35 [alpha](disabled by default)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.
Constrained impersonation requires two separate permissions:
list and watch pods in the default namespace)This means an impersonator can be limited to impersonate another user only for specific operations.
Constrained impersonation defines three distinct modes, each with its own set of verbs:
Use this mode to impersonate generic users (not service accounts or nodes). This mode applies when
the Impersonate-User header value:
system:serviceaccount:system:node:Verbs:
impersonate:user-info - Permission to impersonate a specific user, group, UID, or extra fieldimpersonate-on:user-info:<verb> - Permission to perform <verb> when impersonating a generic userUse this mode to impersonate ServiceAccounts.
Verbs:
impersonate:serviceaccount - Permission to impersonate a specific service accountimpersonate-on:serviceaccount:<verb> - Permission to perform <verb> when impersonating a service accountUse 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 nodeimpersonate:associated-node - Permission to impersonate only the node to which the impersonator is boundimpersonate-on:arbitrary-node:<verb> - Permission to perform <verb> when impersonating any nodeimpersonate-on:associated-node:<verb> - Permission to perform <verb> when impersonating the associated nodeimpersonate:associated-node verb only applies when the impersonator is a service account bound to the
node it's trying to impersonate. This is determined by checking if the service account's user info
contains an extra field with key authentication.kubernetes.io/node-name that matches the node
being impersonated.All constrained impersonation permissions use the authentication.k8s.io API group. Here's how to
configure the different modes.
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.
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
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
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"),
}
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.
impersonate verbIf 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.
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.