KEP-5284: Constrained Impersonation

Implementation History
BETA Implementable
Created 2025-05-07
Latest v1.36
Milestones
Alpha v1.35
Beta v1.36
Stable v1.38
Ownership
Owning SIG
SIG Auth
Primary Authors

KEP-5284: Constrained Impersonation

Release Signoff Checklist

Items marked with (R) are required prior to targeting to a milestone / release.

  • (R) Enhancement issue in release milestone, which links to KEP dir in kubernetes/enhancements (not the initial KEP PR)
  • (R) KEP approvers have approved the KEP status as implementable
  • (R) Design details are appropriately documented
  • (R) Test plan is in place, giving consideration to SIG Architecture and SIG Testing input (including test refactors)
    • e2e Tests for all Beta API Operations (endpoints)
    • (R) Ensure GA e2e tests meet requirements for Conformance Tests
    • (R) Minimum Two Week Window for GA e2e tests to prove flake free
  • (R) Graduation criteria is in place
  • (R) Production readiness review completed
  • (R) Production readiness review approved
  • “Implementation History” section is up-to-date for milestone
  • User-facing documentation has been created in kubernetes/website , for publication to kubernetes.io
  • Supporting documentation—e.g., additional design documents, links to mailing list discussions/SIG meetings, relevant PRs/issues, release notes

Summary

This is to add additional access control over the existing impersonation action. An impersonator who impersonates another user is required to have the additional permissions to impersonate on certain group resources and verbs. In order for the request to succeed, the impersonated principal must have permission to perform the request, just like before.

Motivation

Today an impersonator can impersonate another user if the impersonator has the permission of

- verbs: ["impersonate"]
  resources: ["users"]
  resourceNames: ["someUser"]

However, current impersonation mechanism is the “unrestricted impersonation” (or “legacy impersonation”), the impersonator can get more power through impersonation. And because of this, it is strongly suggested not to allow the controller to impersonate. More detailed discussion is in this issue

There are use cases that needs a controller to be able to impersonate:

  1. A controller impersonates a node the controller is running on. This happens when per-node agents (CNI plugins for instance), want to read pods on a given node instead of unrestricted pod access.
  2. A controller runs as a deputy, receives request from the user, and impersonates the user to start/stop virtual machine or access vm console managed by kubevirt.

This proposal is to introduce additional permissions for impersonation, so that any impersonator can impersonate in a more restricted way.

Goals

  • Define required permission rules for the impersonator to impersonate on certain resource/verb.
  • Provide clear example on what permission the impersonator and user should have for the impersonator to impersonate user’s certain verbs on certain resources.
  • This is an opt-in feature and existing impersonation flows keep working as-is.
  • Client side semantics of impersonation is unchanged, the existing impersonation headers are re-used and no new headers are added.

Non-Goals

  • Adding impersonator’s info to user.Info, so authorization webhooks can know both info of impersonated user and the requester.

Proposal

Introduce a set of verbs with prefix of impersonate-on:<mode>:, e.g. impersonate-on:user-info:create and impersonate-on:arbitrary-node:get. The impersonator needs to have these verbs with certain resources to impersonate.

Introduce verbs in the impersonate:<mode> format:

  • impersonate:user-info limits the impersonator to impersonate “generic” users. The resources must be users/uids/groups/userextras and the user must not be a node (username with a prefix of system:node:) and the user must not be a service account (username with a prefix of system:serviceaccount:). The resource names must be usernames, uids, group names or values in the user extras accordingly.
  • impersonate:serviceaccount that limits the impersonator to impersonate the serviceaccount with the certain namespace/name. The resource must be serviceaccounts.
  • impersonate:arbitrary-node that limits the impersonator to impersonate the node only. The resource must be nodes, and the resourceName should be the name of the node. The impersonator must have this verb to impersonate a node.
  • impersonate:associated-node that limits the impersonator to impersonate the node the impersonator is running on. The resources must be nodes. For a controller impersonating the node that it is running on, it will need to know the node name obtained via downward API:
env:
- name: MY_NODE_NAME
  valueFrom:
    fieldRef:
    fieldPath: spec.nodeName

and then set in the kubeconfig:

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

Two permissions will be required for impersonation. An example of how to express “system:serviceaccount:default:default can impersonate a user named someUser solely to list and watch pods in the default namespace” using Kubernetes RBAC:

  1. The permission to constrained impersonate a certain user. This is a cluster scoped permission.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: constrained-impersonate-only-someUser
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - users # allowed resources are users/groups/userextras/uids
  resourceNames:
  - someUser 
  verbs:
  - impersonate:user-info
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: constrained-impersonate-only-someUser
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: constrained-impersonate-only-someUser
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
  1. The permission to impersonate on certain resource with certain verbs. This can be either cluster scoped or namespace scoped. Note that the verbs are prefixed with impersonate-on:<mode>: so that permissions from different modes do not overlap.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-allow-only-listwatch-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-allow-only-listwatch-pods
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: impersonate-allow-only-listwatch-pods
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default

These permissions define: “The impersonator can impersonate a user with the name of someUser to list and watch pods in the default namespace.”

Subject Access Review Details

When receiving an impersonation request to list pods cluster-wide from the user impersonator with the header of Impersonate-User:someUser, the apiserver:

  • Verifies if the impersonator has the permission to impersonate with the scope of the user. A subjectaccessreview is sent to the authorizer:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: users
    name: someUser
    verb: impersonate:user-info
  user: impersonator
  • Verifies if the impersonator has the permission to impersonate the target action with a subjectaccessreview request:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    resource: pods
    namespace: default
    verb: impersonate-on:user-info:list
  user: impersonator
  • Allows the impersonation if the above two conditions are met
  • If the above check fails, verifies if the impersonator has the legacy impersonate permission, allow the impersonation if the condition met. A subjectaccessreview is sent to the authorizer:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    resource: users
    name: someUser
    verb: impersonate
  user: impersonator

The impersonator does not need the permission for the target action.

workflow when the feature is enabled

flowchart TD
  A[receive request] --> |feature enabled| B{Identify the target user via impersonation header}
  B --> |Impersonate-User has the prefix of system:node:|C{The requester is on the same node}
  C --> |yes| D{Requester is authorized to impersonate the target action with impersonate-on:associated-node:< verb >}
  C --> |no| E{Requester is authorized to impersonate the target action with impersonate-on:arbitrary-node:< verb >}
  D --> |yes| F{Requester is authorized to impersonate the target user/uid/groups/extra with impersonate:< mode >}
  D --> |no| E
  E --> |yes| F
  E --> |no| H
  F -->|yes| G[Allow]
  A -->|feature disable| H{Requester has the legacy impersonate permission}
  H -->|yes| G
  F -->|no| H
  B --> |Impersonate-User has the prefix of system:serviceaccount:| I{Requester is authorized to impersonate the target action with impersonate-on:serviceaccount:< verb >}
  I --> |yes| F
  I --> |no| H
  B --> |Impersonate-User does not have the prefix of system:serviceaccount: or system:node:| J{Requester is authorized to impersonate the target action with impersonate-on:user-info:< verb >}
  J --> |yes|F
  J --> |no|H

User Stories (Optional)

Story 1

As a controller, I want to impersonate node I am running on to list/get pods on the node. The service account of the controller should have the permissions as below to perform the action:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate:arbitrary-node
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - nodes
  verbs:
  - impersonate:associated-node
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: impersonate:arbitrary-node
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate:arbitrary-node
subjects:
- kind: ServiceAccount
  name: default
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate:arbitrary-node:list
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: impersonate:arbitrary-node:list
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate:arbitrary-node:list
subjects:
- kind: ServiceAccount
  name: default
  namespace: default

Story 2

As a controller, I am working as a deputy, receiving any user’s request to access virtual machine console in the default namespace.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-user:vm:console
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - users
  verbs:
  - impersonate:user-info
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: impersonate-user:vm:console
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: impersonate-user:vm:console
subjects:
- kind: ServiceAccount
  name: deputy
  namespace: deputy-ns
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate:vm:console:get
  namespace: default
rules:
  - apiGroups:
    - subresources.kubevirt.io
    resources:
    - virtualmachines/console
    verbs:
    - impersonate-on:user-info:get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: impersonate:vm:console:get
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: impersonate:vm:console:get
subjects:
- kind: ServiceAccount
  name: deputy
  namespace: deputy-ns

Risks and Mitigations

Permissions across authorization checks are unioned

This design works around the limitations of the SubjectAccessReview API by performing multiple checks. Since the permissions are granted separately, the subject always has the union of all permissions. This means it is not possible to express something like “The impersonator can impersonate a user with the name of someUser to list and watch pods in the default namespace and can impersonate someOtherUser to create secrets in the default namespace.” Instead, you can only express the union of the permissions: “The impersonator can impersonate a user with the name of someUser or someOtherUser to list and watch pods or create secrets in the default namespace. This is an acceptable tradeoff as this design is still far safer than the existing impersonation flow and does not require any changes to authorization or the SubjectAccessReview API. We specifically include the mode in the impersonate-on:<mode>:<verb> check to prevent this unioning across modes.

The verbs with impersonate-on:<mode>: prefix has been used by other component.

There is possibility that the verbs with prefix of impersonate-on:<mode>: have been used by other component, and been set in Role/ClusterRole. Since impersonate:<mode> permission is also required for impersonator, the component will not get more power when permission of impersonate-on:<mode>: is given.

High request volume leads to high load on authorization chain.

For the associated node case, it is possible that a high request volume node agent could be constantly performing impersonated requests, each of which would add two extra authorization checks. This could put load on the authorization chain. Comparing to other alternatives which would also introduce at least one authorization check for each request call, the proposal is able to satisfy more use cases. We will include some caching with short TTLs in the implementation to amortize the cost of these checks.

Delegating permission of impersonating wildcard action or wildcard subjects is not supported

Permissions must be delegated using specified verbs with the prefix of impersonate: and impersonate-on:. Expressing a permission to impersonate ANY subject or ANY action is not possible, since the authorization model does not have the concept of partial wildcard on verbs. It should be ok since all these permission for constrained impersonation are strictly additive which means it should be added when certain impersonation requests are needed.

Design Details

Verb impersonate:user-info

Same as legacy impersonation, when the request has header of Impersonate-User, Impersonate-Group, Impersonate-Uid or Impersonate-Extra-, apiserver will check verb impersonate:user-info with the related resources.

Header Impersonate-User is set

A subjectaccessreview

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: users
    name: someUser
    verb: impersonate:user-info
  user: impersonator

will be sent to the authorizer

Header Impersonate-Group is set

A subjectaccessreview

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: groups
    name: someGroup
    verb: impersonate:user-info
  user: impersonator

will be sent to the authorizer for each group.

Header Impersonate-Uid is set

A subjectaccessreview

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: uids
    name: someUID
    verb: impersonate:user-info
  user: impersonator

will be sent to the authorizer.

Header with prefix Impersonate-Extra- is set

A subjectaccessreview

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: userextras
    subresource: extraKey
    name: extraValue
    verb: impersonate:user-info
  user: impersonator

will be sent to the authorizer for each key and value pair.

Verb impersonate:serviceaccount

Same as legacy impersonation, when the request has the header of Impersonate-User (and no other impersonation headers), and the value of the header has a prefix of system:serviceaccount:, apiserver will check verb impersonate:serviceaccount with the authorizer using the subjectaccessreview:

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: serviceaccounts
    name: serviceaccount-name
    namespace: serviceaccount-namespace
    verb: impersonate:serviceaccount
  user: impersonator

Verb impersonate:arbitrary-node and impersonate:associated-node

When the request has the header of Impersonate-User (and no other impersonation headers), and the value has the prefix of system:node:, this verb is checked instead of impersonate:user-info. The subjectaccessreview below will be sent to the authorizer:

apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: nodes
    name: someNode
    verb: impersonate:arbitrary-node
  user: impersonator

impersonate:associated-node is a special verb to check when two conditions are met:

  1. The impersonator is impersonating a node by setting the header Impersonate-User and the value has a prefix of system:node: on the request.
  2. The user info of the impersonator has an extra with key authentication.kubernetes.io/node-name, and the value should be the same as the value in the request header of Impersonate-User after removing prefix system:node:. It indicates that the impersonator is running on the same node it is impersonating.

The flow for checking these two verbs will be as following:

  1. If condition 1 is not met, verb impersonate:user-info will be checked instead if the impersonated user is not a SA or node.
  2. If both conditions are met, the verb impersonate:associated-node will be checked at first:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: nodes
    verb: impersonate:associated-node
  user: impersonator
  1. If check in step 2 is not passed, or only condition 1 is met, the verb impersonate:arbitrary-node will be checked:
apiVersion: authorization.k8s.io/v1
kind: SubjectAccessReview
spec:
  resourceAttributes:
    group: authentication.k8s.io
    resource: nodes
    name: node1
    verb: impersonate:arbitrary-node
  user: impersonator

Auditing

Audit events already contain the impersonatedUser field to denote if impersonation was used. To record the reason why the impersonation is allowed, a new sub-field impersonationConstraint will be added under a new top level object called authenticationMetadata. The value will be the constrained impersonation related verb. For example, impersonate:associated-node indicates that the impersonation request is allowed because it impersonates an associated node. The specific action such as list or get will not be included in the value given it can be inferred from the request itself. There have been other feature requests that would fit under the authenticationMetadata object, this KEP just happens to be the first design to reach implementation. When constrained impersonation is not used, the impersonationConstraint field will not be set, and since it is currently the only field in the authenticationMetadata object, that object will be omitted completely. This will keep audit events generated from existing impersonation flows unchanged.

Example audit event where the system:admin user impersonates the panda user via constrained impersonation:

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "level": "Metadata",
  "auditID": "3eb9aee5-8edd-4663-be5f-a2a734ec1644",
  "stage": "ResponseComplete",
  "requestURI": "/api/v1/namespaces/default/pods?limit=500",
  "verb": "list",
  "user": {
    "username": "system:admin",
    "groups": [
      "system:masters",
      "system:authenticated"
    ],
    "extra": {
      "authentication.kubernetes.io/credential-id": [
        "X509SHA256=29fd022fa9165a2a73d52a25f18f7752c2577898f846128668d956bf6b6cbb68"
      ]
    }
  },
  "impersonatedUser": {
    "username": "panda",
    "groups": [
      "system:authenticated"
    ]
  },
  "authenticationMetadata": {                            // this is a new object that may contain other data in the future
    "impersonationConstraint": "impersonate:user-info"   // this is the new field from this KEP
  },
  "sourceIPs": [
    "::1"
  ],
  "userAgent": "kubectl/v1.35.0 (darwin/arm64) kubernetes/801ee44",
  "objectRef": {
    "resource": "pods",
    "namespace": "default",
    "apiVersion": "v1"
  },
  "responseStatus": {
    "metadata": {},
    "status": "Failure",
    "message": "pods is forbidden: User \"panda\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"",
    "reason": "Forbidden",
    "details": {
      "kind": "pods"
    },
    "code": 403
  },
  "requestReceivedTimestamp": "2025-10-06T17:19:51.221674Z",
  "stageTimestamp": "2025-10-06T17:19:51.222195Z",
  "annotations": {
    "authorization.k8s.io/decision": "forbid",
    "authorization.k8s.io/reason": ""
  }
}

Test Plan

[x] I/we understand the owners of the involved components may require updates to existing tests to make this code solid enough prior to committing the changes necessary to implement this enhancement.

Prerequisite testing updates
Unit tests
  • k8s.io/apiserver/pkg/endpoints/filters: 2025/06/13 - 75.5%

Unit tests should cover authorization request with and without the feature enabled.

Integration tests
  • SubjectAccessReview check on impersonating user.
    • The impersonator can impersonate bob.
    • The impersonator cannot impersonate alice.
    • The impersonator can impersonate on listing and getting pods
    • The impersonator cannot impersonate on updating pods
    • The impersonator can impersonate on getting pods/exec subresource
    • The impersonator cannot impersonate on get pods/log subresource For RBAC authz mode, this might look like:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-bob
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - users
  resourceNames:
  - bob
  verbs:
  - impersonate:user-info
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-pod-action
  namespace: default
rules:
  - resources:
    - pods
    - pod/exec
    verbs:
    - impersonate-on:user-info:list
    - impersonate-on:user-info:get
  • SAR check on impersonating associated node with permissions. The impersonator has the user extra info of "authentication.kubernetes.io/node-name": "node1"

    • The impersonator can impersonate node1.
    • The impersonator cannot impersonate node2.
    • The impersonator cannot impersonate bob.
    • The impersonator can impersonate on listing pods.
    • The impersonator cannot impersonate on updating pods,

    with the permission like this:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: impersonate-associated-node
rules:
- apiGroups:
  - authentication.k8s.io
  resources:
  - nodes
  verbs:
  - impersonate:associated-node
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: impersonate-pod-action
  namespace: default
rules:
  - apiGroups:
    - ""
    resources:
    - pods
    verbs:
    - impersonate-on:associated-node:list
  • SAR check on impersonating service account
  • SAR check on impersonating nodes

Each test should cover positive and negative cases with multiple resources and verbs.

  • Permission delegation:
    • bob has the impersonate:user-info permission, and can delegate the impersonate:user-info permission to alice.
    • bob cannot delegate the impersonate:arbitrary-node permission to alice.
    • bob has the impersonate-on:user-info:list permission on pods resource, and can delegate the permission to alice.
    • bob cannot delegate the impersonate-on:user-info:update permission on pods resource to alice.
e2e tests

In addition to testing with unit and integration tests. E2E tests will be added covering below cases.

  • A user cannot impersonate a subresource until the correct constrained impersonation permissions is set for the user.
  • A sericeaccount with the correct constrained impersonation permission is able to impersonate the node to list pods.

An eventual conformance test is needed as part of GA.

Graduation Criteria

Alpha

  • Feature implemented behind a feature flag
  • Initial e2e tests completed and enabled

Beta

  • Determine if additional tests are necessary
  • Ensure reliability of existing tests
  • Determine if some mechanism should be introduced to reduce the extra permission checks
  • Alternatives have been reviewed, and we have consensus not to switch to an alternative approach.

GA

  • At least one successful adoption of each user story (node agent and deputy).
  • All bugs resolved and no new bugs requiring code change since the previous shipped release.
  • Conformance tests are added.

Upgrade / Downgrade Strategy

On upgrade to a version that enables the feature

  • the previous impersonator with impersonate permission will still work, but it is highly recommended to use the new permissions with less privilege.

  • authorization webhooks needs to recognize the verb with prefix of impersonate-on: and impersonate:.

On downgrade to a version that does not enable the feature by default, or if the feature is disabled.

  • No configuration is needed and the permission with impersonate-on:<mode>:<verb> and impersonate:<mode> verb will be ignored.
  • request sent to authorization webhooks will no longer include impersonate-on: and impersonate: verb.

Version Skew Strategy

New kube-apiserver, old impersonate permission

The impersonator will still be allowed to impersonate with unconstrained permission

Old kube-apiserver, new impersonate-on:<mode>:<verb> and impersonate:<mode> permission

The impersonator will be denied to impersonate. This is safer since the impersonator permission is not enlarged with old kube-apiserver.

Production Readiness Review Questionnaire

Feature Enablement and Rollback

How can this feature be enabled / disabled in a live cluster?
  • Feature gate (also fill in values in kep.yaml)
    • Feature gate name: ConstrainedImpersonation
    • Components depending on the feature gate:
      • kube-apiserver
Does enabling the feature change any default behavior?

No. Impersonator with existing impersonate permission will still be allowed to impersonate

Can the feature be disabled once it has been enabled (i.e. can we roll back the enablement)?

Yes. Set the feature gate to false and restart the kube-apiserver.

What happens if we reenable the feature if it was previously rolled back?

No additional configuration is needed.

Are there any tests for feature enablement/disablement?

Yes, this will be covered in the unit tests and integration tests.

Rollout, Upgrade and Rollback Planning

How can a rollout or rollback fail? Can it impact already running workloads?

There is no impact on rollout, the impersonator with existing impersonate permission can still perform the action. When the system rollback, impersonator with impersonate-on: and impersonate: permission will no longer be authorized to impersonate. Impersonator will need to have the unscoped impersonate permission.

What specific metrics should inform a rollback?

apiserver_authorization_decisions_total shows greatly increased number.

When webhook authorizer is used, if apiserver_authorization_webhook_evaluations_total and apiserver_authorization_webhook_duration_seconds shows greatly increase number, users should also pay attention.

See Monitoring Requirements below.

Were upgrade and rollback tested? Was the upgrade->downgrade->upgrade path tested?

Integration tests cover feature gate disablement and enablement.

Manual tests to cover upgrade->downgrade->upgrade:

  1. Deploy k8s 1.33
  2. create impersonate permissions for user bob and verify impersonation
  3. Upgrade to 1.34 and enable the ConstrainedImpersonation featuregate.
  4. Verify impersonation of user bob.
  5. create permission for constrained impersonation for user alice and verify impersonation
  6. Downgrade to 1.33. Verify impersonation for user bob and alice. Alice would not be able to impersonate while bob is able to.
Is the rollout accompanied by any deprecations and/or removals of features, APIs, fields of API types, flags, etc.?

No

Monitoring Requirements

There are existing metrics to record authz latency and request number:

  • authorization latency
  • authorization success
  • webhook authorizer match condition latency
  • webhook authorizer match condition success

These will be expanded to include metrics that cover the impersonation handler to give an overall sense for the cost of impersonation:

  • apiserver_impersonation_attempts_total{status}

This will be incremented whenever impersonation is attempted. On success, the status label will capture which mode was successful. On failure, the status label will be set to failed.

Labels and possible values:

status: associated-node, arbitrary-node, serviceaccount, user-info, legacy, failed

  • apiserver_impersonation_duration_seconds{status}

This is a Histogram metric that will track the time impersonation took to resolve the impersonated user whenever impersonation is attempted. On success, the status label will capture which mode was successful. On failure, the status label will be set to failed.

Note that because of the caching performed within the handler, we expect this metric to reflect the amortized cost (in latency) of impersonation requests.

Labels and possible values:

status: associated-node, arbitrary-node, serviceaccount, user-info, legacy, failed

To give a sense for how many authorization checks are being performed, the following metrics will wrap all calls to the authorizer used by the handler:

  • apiserver_impersonation_authorization_attempts_total{mode, decision}

This will be incremented whenever an impersonation attempt causes the authorizer to be used.

Labels and possible values:

mode: associated-node, arbitrary-node, serviceaccount, user-info, legacy decision: allowed, denied

  • apiserver_impersonation_authorization_duration_seconds{mode, decision}

This is a Histogram metric that will track the time the authorizer took whenever an impersonation attempt causes the authorizer to be used.

Labels and possible values:

mode: associated-node, arbitrary-node, serviceaccount, user-info, legacy decision: allowed, denied

How can an operator determine if the feature is in use by workloads?

Check the metrics mentioned above as well as the audit logs.

How can someone using this feature know that it is working for their instance?
  • Events
    • Event Reason:
  • API .status
    • Condition name:
    • Other field:
  • Other (treat as last resort)
    • Details: User creates the permission and check if the impersonate on certain action works. Confirm via audit logs that the expected impersonation mode was used.
What are the reasonable SLOs (Service Level Objectives) for the enhancement?

Use of this feature should not change existing API SLOs.

What are the SLIs (Service Level Indicators) an operator can use to determine the health of the service?

Use of this feature should not change existing API SLIs.

Are there any missing metrics that would be useful to have to improve observability of this feature?

No.

Dependencies

Does this feature depend on any specific services running in the cluster?

No.

Scalability

Will enabling / using this feature result in any new API calls?

Yes, enabling the feature will result in two additional SAR checks when kube-apiserver receives an impersonation request.

  • A SAR request to check if the impersonator is authorized to impersonate the target user.
  • A SAR request to check if the impersonater is authorized to perform the action via impersonation.

Successful impersonation attempts are cached for a short period to amortize the cost across multiple requests.

Will enabling / using this feature result in introducing new API types?

No.

Will enabling / using this feature result in any new calls to the cloud provider?

No.

Will enabling / using this feature result in increasing size or count of the existing API objects?

No.

Will enabling / using this feature result in increasing time taken by any operations covered by existing SLIs/SLOs?

The existing impersonation mechanism will introduce 1 access review for request with impersonation. While upon feature is enabled:

  • When the check is passed, it will introduce 2-3 access review checks for request with impersonation.
    • 2 access review check if the new access rule is passed.
    • 3 access review check if the new access rule is not passed, and the legacy impersonate access rule is passed.
  • When the check is disallowed, it will introduce 3 access review checks for request with impersonation.

Successful impersonation attempts are cached for a short period to amortize the cost across multiple requests.

Will enabling / using this feature result in non-negligible increase of resource usage (CPU, RAM, disk, IO, …) in any components?

NA

Can enabling / using this feature result in resource exhaustion of some node resources (PIDs, sockets, inodes, etc.)?

No, this feature does not touch nodes.

Troubleshooting

How does this feature react if the API server and/or etcd is unavailable?

This feature is fully contained within the API server.

What are other known failure modes?
  • Impersonation permission is set but request is disallowed with external authorizer.
    • Detection: metrics of authorization success will show the unauthorized requests
    • Mitigations: Stop sending the impersonation requests
    • Diagnostics: APIServer log will show the reason why the request is unauthorized.
    • Testing: There is no general test for that, user using external authorizer need to test for the specific authorizer.
What steps should be taken if SLOs are not being met to determine the problem?

Implementation History

  • Kubernetes 1.34: Alpha version of the KEP.

Drawbacks

  • Several additional authorization checks are added introducing some overhead.

Alternatives

Use impersonate:user-info instead of impersonate:serviceaccount and impersonate:arbitrary-node

Verb impersonate:serviceaccount and impersonate:arbitrary-node are special cases of verb impersonate:user-info. Without these two verbs, it is still possible to use verb impersonate:user-info with certain username, e.g. username with the prefix system:serviceaccounts: or the prerix system:nodes. However, providing the two special verbs would delegation of permissions and support more expressions:

  • Verb impersonate:serviceaccount can support a permission to allow impersonating any serviceaccounts in a certain namespace.
  • Verb impersonate:arbitrary-node can support a permission to allow impersonating any node.

Controller participation in SubjectAccessReview for impersonation

The controller can sends a SAR request, and then uses its own permission to perform the action. The main difference from impersonation is:

  1. the controller itself needs to have the permission for a certain action, while with impersonation the controller does not need these permissions, but the permissions to impersonate-on certain action.
  2. The audit log shows that controller performs the action, while with impersonatation audit log shows controller is impersonating and the target user performs the action.
  3. The admission chain is running against the controller, while with impersonation, the admission chain is running against the target user.

Setting a special APIGroup suffix instead of special verb

Instead of using the impersonate-on:<mode>:<verb> scheme, a special apigroup suffix/prefix can be set for each resource to be impersonated, e.g. setting the apigroup with a suffix of .impersonation.k8s.io:

- apiGroups:
  - apps.impersonation.k8s.io
  resources:
  - deployments
  verbs:
  - list
  - watch

It is almost the same as the verb based approach in the proposal. However, since existing impersonation flows are verb based, so making the new flow verb based as well feels more consistent.

Check permission intersection of impersonator and target user

This is an approach to check intersected permission of the impersonator and the target user, and only allow the action if both have the correct permission. Comparing to the proposed approach: this approach requires the impersonator to have the permission who is not desired to have, while in the proposed apporch, the impersonator’s permission is clearer that it can only perform the action when impersonating.

Expand RBAC/SAR

Introduce additional API to define more fine-grained access control rule, and ref the rule in SAR. One example is

{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "default",
      "verb": "get",
      "group": "example.org",
      "resource": "something"
    },
    "accessRule": {
      "kind": "ClusterAccessRule",
      "group version": "example.org/v1",
      "name": "elevation-of-privilege"
    },
    "user": "impersonator",
    "group": []
    ]
  }
}

And authorizer checks the accessRule on whether a certain impersonate action is allowed. This is a more complicated approach that requires changes on existing RBAC/SAR, while the current proposal does not introduce change on RBAC/SAR.

Conditional Authorization

Conditional authorization is the emerging work to provide more complicated authorization policy with CEL expressions. Potentially it would be able to reduce the number of permission checks for the impersonation in this proposal. The work is still in very early stage, and will bring many changes in the existing authorization model. It is possible to enhance constrained impersonation in this proposal with conditional authorization in the future.