Authorization rules¶
An AuthorizationPolicy
main concern is to define authorization rules to deny
or allow
requests.
Every authorization rule is made of an optional match
statement and a required response
statement. Both statements are written in CEL.
If the match
statement is present and evaluates to true
, the response
statement is used to create the response payload returned to the envoy proxy. Depending on the rule type, the response is expected to be an envoy.OkResponse or envoy.DeniedResponse.
Creating an OkResponse or DeniedResponse can be a tedious task, you need to remember the different types names and format.
The CEL engine used to evaluate the authorization rules has been extended with a library to make the creation of responses easier. Browse the available libraries documentation for details.
Evaluation order¶
- All
deny
rules are evaluated first, the first matching rule is used to send the deny response to the envoy proxy. - If no
deny
rule matched,allow
rules are evaluated and the first matching rule is used to send the response to the envoy proxy. - If no rule matched, the request is allowed by default.
Info
When multiple policies are present, deny
and allow
rules are concatenated together in policy name alphabetical order.
Authorization rules¶
The policy below will allow requests if they contain the header x-force-authorized
with the value enabled
or true
. If the header is not present or has a different value, the request will be denied.
apiVersion: envoy.kyverno.io/v1alpha1
kind: AuthorizationPolicy
metadata:
name: demo
spec:
failurePolicy: Fail
variables:
- name: force_authorized
expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("")
- name: allowed
expression: variables.force_authorized in ["enabled", "true"]
# make an authorisation decision based on the value of `variables.allowed`
# - deny the request with 403 status code if it is `false`
# - else allow the request
deny:
- match: >
!variables.allowed
response: >
envoy.Denied(403).Response()
allow:
- response: >
envoy.Allowed().Response()
In this simple rule:
-
envoy.Allowed().Response()
Creates an
OkResponse
to allow the request -
envoy.Denied(403).Response()
Creates a
DeniedResponse
to deny the request with status code403
However, we can do a lot more. Envoy can add or remove headers, query parameters, register dynamic metadata passed along the filters chain, and even change the response body.
The hard way¶
Below is the same policy, creating the envoy.OkResponse
and envoy.DeniedResponse
manually.
apiVersion: envoy.kyverno.io/v1alpha1
kind: AuthorizationPolicy
metadata:
name: demo
spec:
failurePolicy: Fail
variables:
- name: force_authorized
expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("")
- name: allowed
expression: variables.force_authorized in ["enabled", "true"]
deny:
- match: >
!variables.allowed
response: >
envoy.DeniedResponse{
status: google.rpc.Status{
code: 7
},
http_response: envoy.service.auth.v3.DeniedHttpResponse{
status: envoy.type.v3.HttpStatus{
code: 403
}
}
}
allow:
- response: >
envoy.OkResponse{
status: google.rpc.Status{
code: 0
},
http_response: envoy.service.auth.v3.OkHttpResponse{}
}
Advanced example¶
This second policy showcases a more advanced example.
apiVersion: envoy.kyverno.io/v1alpha1
kind: AuthorizationPolicy
metadata:
name: demo
spec:
variables:
- name: force_authorized
expression: object.attributes.request.http.headers[?"x-force-authorized"].orValue("") in ["enabled", "true"]
- name: force_unauthenticated
expression: object.attributes.request.http.headers[?"x-force-unauthenticated"].orValue("") in ["enabled", "true"]
- name: metadata
expression: '{"my-new-metadata": "my-new-value"}'
deny:
# if force_unauthenticated -> 401
- match: >
variables.force_unauthenticated
response: >
envoy
.Denied(401)
.WithBody("Authentication Failed")
.Response()
# if not force_authorized -> 403
- match: >
!variables.force_authorized
response: >
envoy
.Denied(403)
.WithBody("Unauthorized Request")
.Response()
allow:
# else -> 200
- response: >
envoy
.Allowed()
.WithHeader("x-validated-by", "my-security-checkpoint")
.WithoutHeader("x-force-authorized")
.WithResponseHeader("x-add-custom-response-header", "added")
.Response()
.WithMetadata(variables.metadata)
Notice this policy uses helper functions:
-
To create an OK http response
-
To create a DENIED http response
-
To create a check response from an http response
-
To add a request header
-
To remove a request header
-
To add a response header
-
To modify the response body
-
To add dynamic metadata in the envoy filter chain (this is useful when you want to pass data to another filter in the chain or you want to print it in the application logs)
Info
The full documentation of the CEL Envoy library is available here.