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.
Note:
Prior to 1.11.3 (and 1.10.7, 1.9.11),( extra name ) could only contain characters which
were legal in HTTP header labels.Note:
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"]
Note:
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.
Constrained Impersonation
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:
- Permission to impersonate a specific identity (user, UID, group, service account or node)
- Permission to perform specific actions at a particular scope when impersonating (for
example, only
listandwatchpods in thedefaultnamespace)
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 fieldimpersonate-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 accountimpersonate-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 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 node
Note:
Theimpersonate: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.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
impersonateverb, 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
impersonatepermission.
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
- Read about RBAC authorization
- Understand Kubernetes authentication