@@ -695,8 +695,8 @@ Matching is performed in quite a few systems across Kubernetes:
695
695
| exclude | Audit (level=None) | phase 1 |
696
696
| apiVersion + kind | | phase 1 |
697
697
| 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 |
700
700
| permissions (RBAC verb) | RBAC | phase 2 see "Secondary Authz" section |
701
701
702
702
WH = Admission webhooks, P&F = Priority and Fairness
@@ -1094,7 +1094,7 @@ repeated evaluations if they are shared across validations.
1094
1094
1095
1095
# ### Secondary Authz
1096
1096
1097
- TODO : background and motivation
1097
+ We will support admission control use cases requiring permission checks :
1098
1098
1099
1099
- Validate that only a user with a specific permission can set a particular field.
1100
1100
- 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
1104
1104
which will be bound at evaluation time to an Authorizer object supporting receiver-style function
1105
1105
overloads :
1106
1106
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.
1118
1121
1119
1122
Example expressions using `authorizer` :
1120
1123
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')`
1123
1126
1124
1127
Note that this API :
1125
1128
1126
1129
- Produces errors at compilation time when parameters are missing or improperly combined
1127
1130
(e.g. subresource with non-resource path, missing path or resource).
1128
1131
- 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".
1129
1139
1130
1140
Other considerations :
1131
1141
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?
1134
1142
- Since authorization decisions depend on an apiserver's authorizer, and the
1135
1143
ValidatingAdmissionPolicy plugin is supported on [aggregated API
1136
1144
servers](#aggregated-api-servers), the evaluation result of any validation expression involving
@@ -1142,11 +1150,14 @@ Other considerations:
1142
1150
object bound to the exposed `authorizer` object (i.e. caching decisions for identical checks
1143
1151
within a single policy evaluation) in order to prevent duplicate checks across multiple validation
1144
1152
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.
1145
1158
1146
- Use cases in existing admission plugins :
1147
1159
1148
- - PodSecurityPolicy (kube)
1149
- - CertificateApproval (kube)
1160
+ CertificateApproval use case :
1150
1161
1151
1162
` ` ` yaml
1152
1163
apiVersion: admissionregistration.k8s.io/v1alpha1
@@ -1163,9 +1174,12 @@ spec:
1163
1174
validations:
1164
1175
- 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()"
1165
1176
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])"
1167
1178
` ` `
1168
1179
1180
+ Other use cases in existing admission plugins :
1181
+
1182
+ - PodSecurityPolicy (kube)
1169
1183
- CertificateSigning (kube)
1170
1184
- OwnerReferencesPermissionEnforcement (kube)
1171
1185
- network.openshift.io/ExternalIPRanger
@@ -1175,7 +1189,7 @@ spec:
1175
1189
- security.openshift.io/SecurityContextConstraint
1176
1190
- security.openshift.io/SCCExecRestrictions
1177
1191
1178
- From deads2k :
1192
+ Restricted Service Account use case (from deads2k) :
1179
1193
1180
1194
> Note that user.Extra in AdmissionReview has pod claims, which are valuable.
1181
1195
@@ -1191,9 +1205,25 @@ From deads2k:
1191
1205
> permission, then its probably better to create something specifically for the
1192
1206
> purpose.
1193
1207
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.
1197
1227
1198
1228
# ### Access to namespace metadata
1199
1229
0 commit comments