Skip to content

Commit d82bb10

Browse files
committed
Expand documentation, add some notes
1 parent ed71967 commit d82bb10

File tree

1 file changed

+56
-26
lines changed
  • keps/sig-api-machinery/3488-cel-admission-control

1 file changed

+56
-26
lines changed

keps/sig-api-machinery/3488-cel-admission-control/README.md

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -695,8 +695,8 @@ Matching is performed in quite a few systems across Kubernetes:
695695
| exclude | Audit (level=None) | phase 1 |
696696
| apiVersion + kind | | phase 1 |
697697
| NonResourceURLs | Audit/RBAC/P&F | No |
698-
| user/userGroup | Audit | phase 2 see "Secondary Authz" section |
699-
| user.Extra | (in WH AdmissionReview) | phase 2 see "Secondary Authz" section |
698+
| user/userGroup | Audit | phase 1 - request.userInfo.groups |
699+
| user.Extra | (in WH AdmissionReview) | phase 1 - request.userInfo.extra |
700700
| permissions (RBAC verb) | RBAC | phase 2 see "Secondary Authz" section |
701701

702702
WH = Admission webhooks, P&F = Priority and Fairness
@@ -1094,7 +1094,7 @@ repeated evaluations if they are shared across validations.
10941094

10951095
#### Secondary Authz
10961096

1097-
TODO: background and motivation
1097+
We will support admission control use cases requiring permission checks:
10981098

10991099
- Validate that only a user with a specific permission can set a particular field.
11001100
- Validate that only a controller responsible for a finalizer can remove it from the finalizers
@@ -1104,33 +1104,41 @@ To depend on an authz decision, validation expressions can reference the identif
11041104
which will be bound at evaluation time to an Authorizer object supporting receiver-style function
11051105
overloads:
11061106

1107-
| Symbol | Type | Description |
1108-
|-------------|------------------------------------------------------|-------------|
1109-
| path | Authorizer.(string) -> PathCheck | todo |
1110-
| check | PathCheck.(string) -> Decision | todo |
1111-
| resource | Authorizer.(string, string, string) -> ResourceCheck | todo |
1112-
| subresource | ResourceCheck.(string) -> ResourceCheck | todo |
1113-
| namespace | ResourceCheck.(string) -> ResourceCheck | todo |
1114-
| name | ResourceCheck.(string) -> ResourceCheck | todo |
1115-
| check | ResourceCheck.(string) -> Decision | todo |
1116-
| allowed | Decision.() -> bool | todo |
1117-
| denied | Decision.() -> bool | todo |
1107+
| Symbol | Type | Description |
1108+
|-------------|-------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|
1109+
| path | Authorizer.(path string) -> PathCheck | Defines a check for an non-resource request path (e.g. /healthz) |
1110+
| check | PathCheck.(httpRequestVerb string) -> Decision | Checks if the user is authorized for the HTTP request verb on the path |
1111+
| resource | Authorizer.(kind string, group string, version string) -> ResourceCheck | Defines a check for API resources |
1112+
| subresource | ResourceCheck.(subresource string) -> ResourceCheck | Specifies thath the check is for a subresource |
1113+
| namespace | ResourceCheck.(namespace string) -> ResourceCheck | Specifies that the check is for a namespace (if not called, the check is for the cluster scope) |
1114+
| name | ResourceCheck.(name string) -> ResourceCheck | Specifies that the check is for a specific resource name |
1115+
| check | ResourceCheck.(apiVerb string) -> Decision | Checks if the user is authorized for the API verb on the resource |
1116+
| allowed | Decision.() -> bool | Is the user authorized? |
1117+
| denied | Decision.() -> bool | Is the user denied authorization? |
1118+
1119+
xref: https://kubernetes.io/docs/reference/access-authn-authz/authorization/#review-your-request-attributes for a details on
1120+
authorization attributes.
11181121

11191122
Example expressions using `authorizer`:
11201123

1121-
- `authorizer.resource('signers', 'certificates.k8s.io', '*').name(oldObject.spec.signerName).check('approve').allowed()`
1122-
- `authorizer.path('/metrics').check('get').denied()`
1124+
- `authorizer.resource('signers', 'certificates.k8s.io', '*').name(oldObject.spec.signerName).allowed('approve')`
1125+
- `authorizer.path('/metrics').denied('get')`
11231126

11241127
Note that this API:
11251128

11261129
- Produces errors at compilation time when parameters are missing or improperly combined
11271130
(e.g. subresource with non-resource path, missing path or resource).
11281131
- Is open to the addition of future knobs (e.g. impersonation).
1132+
- Will have a limit on the number of authz checks generated during expression
1133+
evaluation, this will be enforced by setting a CEL evaluation cost to
1134+
performing each authz check that is high enough serve as an effective limit to
1135+
the total authz checks that can be performed. The limit will be picked
1136+
emperically by evaluating the resource costs (CPU cost primarily) of authz
1137+
checks. This will need to be set high enough to handle policies like "You must
1138+
be authorized to read every secret your pod mounts".
11291139

11301140
Other considerations:
11311141

1132-
- Does there need to be a special limit on the number of authz checks generated during expression
1133-
evaluation, or is it sufficient to assign an appropriate fixed cost?
11341142
- Since authorization decisions depend on an apiserver's authorizer, and the
11351143
ValidatingAdmissionPolicy plugin is supported on [aggregated API
11361144
servers](#aggregated-api-servers), the evaluation result of any validation expression involving
@@ -1142,11 +1150,14 @@ Other considerations:
11421150
object bound to the exposed `authorizer` object (i.e. caching decisions for identical checks
11431151
within a single policy evaluation) in order to prevent duplicate checks across multiple validation
11441152
expressions.
1153+
- Authorization checks that require information from resources other than the
1154+
resource being admitted are possible but will be limited by eventual
1155+
consistency. Information from other resources can be accumulated by a controller
1156+
and written to a custom resources which can then be referenced by the `paramSource`
1157+
of a policy binding and accessed in CEL expressions via the `params` variable.
11451158

1146-
Use cases in existing admission plugins:
11471159

1148-
- PodSecurityPolicy (kube)
1149-
- CertificateApproval (kube)
1160+
CertificateApproval use case:
11501161

11511162
```yaml
11521163
apiVersion: admissionregistration.k8s.io/v1alpha1
@@ -1163,9 +1174,12 @@ spec:
11631174
validations:
11641175
- expression: "authorizer.resource('signers', 'certificates.k8s.io', '*').name(oldObject.spec.signerName).check('approve').allowed() || authorizer.resource('signers', 'certificates.k8s.io', '*').name([oldObject.spec.signerName.split('/')[0], '*'].join('/')).check('approve').allowed()"
11651176
reason: Forbidden
1166-
messageExpression: "user not permitted to approve requests with signerName %q".format([oldObject.spec.signerName])"
1177+
messageExpression: "user not permitted to approve requests with signerName %s".format([oldObject.spec.signerName])"
11671178
```
11681179

1180+
Other use cases in existing admission plugins:
1181+
1182+
- PodSecurityPolicy (kube)
11691183
- CertificateSigning (kube)
11701184
- OwnerReferencesPermissionEnforcement (kube)
11711185
- network.openshift.io/ExternalIPRanger
@@ -1175,7 +1189,7 @@ spec:
11751189
- security.openshift.io/SecurityContextConstraint
11761190
- security.openshift.io/SCCExecRestrictions
11771191

1178-
From deads2k:
1192+
Restricted Service Account use case (from deads2k):
11791193

11801194
> Note that user.Extra in AdmissionReview has pod claims, which are valuable.
11811195

@@ -1191,9 +1205,25 @@ From deads2k:
11911205
> permission, then its probably better to create something specifically for the
11921206
> purpose.
11931207

1194-
Looking up the pod (or any other additional resources) is not something we are
1195-
currently planning to support in this KEP, but the use case is interesting and
1196-
we should investigate with sig-auth.
1208+
This enhancement makes
1209+
`request.userInfo.extra['authentication.kubernetes.io/pod-uid']` available to
1210+
admission policies. Looking up the pod (or any other additional resources) is
1211+
makes this use case challenging. A controller that accumulates a `pod-uid ->
1212+
node-name` map in a custom resource by watching all pods could then make the
1213+
mapping available in a custom resource for the admission policy to consume using
1214+
`paramSource`.
1215+
1216+
This would result in a CEL expression like:
1217+
1218+
```
1219+
object.spec.NodeName == params.nodeNamebyPodUID[request.userInfo.extra['authentication.kubernetes.io/pod-uid']]
1220+
```
1221+
1222+
But this would not scale well to clusters with large pod counts.
1223+
1224+
If we were to offer a way to lookup arbitrary other resources, or even if
1225+
we provided selective access to just some resources, this might become
1226+
easier. This can explored as future work.
11971227

11981228
#### Access to namespace metadata
11991229

0 commit comments

Comments
 (0)