You are browsing documentation for an older version. See the latest documentation here.
Kong Mesh - OPA Policy Integration
OPA policy plugin
Kong Mesh integrates the Open Policy Agent (OPA) to provide access control for your services.
The agent is included in the data plane proxy sidecar, instead of the more common deployment as a separate sidecar.
When OPAPolicy
is applied, the control plane configures:
- the embedded policy agent, with the specified policy
- Envoy, to use External Authorization that points to the embedded policy agent
Usage
To apply a policy with OPA:
- Specify the group of data plane proxies to apply the policy to with the
selectors
property. - Provide a policy with the
conf
property. Policies are defined in the Rego language.
Note: You cannot currently apply multiple OPA policies. This limitation will be addressed in the future.
- Optionally provide custom configuration for the policy agent.
You must also specify the HTTP protocol in your mesh configuration:
For more information, see the Kuma documentation about protocol support.
Inline
With Secrets
Encoding the policy in a Secret) provides some security for policies that contain sensitive data.
Configuration
Kong Mesh defines a default configuration for OPA, but you can adjust the configuration to meet your environment’s requirements.
The following environment variables are available:
Variable | Type | What it configures | Default value {:width=25%:} |
---|---|---|---|
KMESH_OPA_ADDR | string | Address OPA API server listens on | localhost:8181 |
KMESH_OPA_CONFIG_PATH | string | Path to file of initial config | N/A |
KMESH_OPA_DIAGNOSTIC_ADDR | string | Address of OPA diagnostics server | 0.0.0.0:8282 |
KMESH_OPA_ENABLED | bool | Whether kuma-dp starts embedded OPA |
true |
KMESH_OPA_EXT_AUTHZ_ADDR | string | Address of Envoy External AuthZ service | localhost:9191 |
KMESH_OPA_CONFIG_OVERRIDES | strings | Overrides for OPA configuration, in addition to config file(*) | [plugins.envoy_ext_authz_grpc. query=data.envoy.authz.allow] |
- Override the config for individual data plane proxies by placing the appropriate annotations on the Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: example-app
namespace: kuma-example
spec:
...
template:
metadata:
...
annotations:
# indicate to Kuma that this Pod doesn't need a sidecar
kuma.io/sidecar-env-vars: "KMESH_OPA_ENABLED=false;KMESH_OPA_ADDR=:8888;KMESH_OPA_CONFIG_OVERRIDES=config1:x,config2:y"
Configuring the authorization filter
By default, the body will not be sent to the agent.
To send it, set authConfig.requestBody.maxSize
to the maximum size of your body.
If the request body is larger than this parameter, it will be truncated and the header x-envoy-auth-partial-body
will be set to true
.
Support for external API management servers
The agentConfig
field lets you define a custom configuration that points to an external management server:
Example
The following example shows how to deploy and test a sample OPA Policy on Kubernetes, using the kuma-demo application.
-
Deploy the example application:
kubectl apply -f https://bit.ly/demokuma
-
Make a request from the frontend to the backend:
$ kubectl exec -i -t $(kubectl get pod -l "app=kuma-demo-frontend" -o jsonpath='{.items[0].metadata.name}' -n kuma-demo) -n kuma-demo -- curl backend:3001 -v
The output looks like:
Defaulting container name to kuma-fe. Use 'kubectl describe pod/kuma-demo-app-6787b4f7f5-m428c -n kuma-demo' to see all of the containers in this pod. * Trying 10.111.108.218:3001... * TCP_NODELAY set * Connected to backend (10.111.108.218) port 3001 (#0) > GET / HTTP/1.1 > Host: backend:3001 > User-Agent: curl/7.67.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < x-powered-by: Express < cache-control: no-store, no-cache, must-revalidate, private < access-control-allow-origin: * < access-control-allow-methods: PUT, GET, POST, DELETE, OPTIONS < access-control-allow-headers: * < host: backend:3001 < user-agent: curl/7.67.0 < accept: */* < x-forwarded-proto: http < x-request-id: 1717af9c-2587-43b9-897f-f8061bba5ad4 < content-length: 90 < content-type: text/html; charset=utf-8 < date: Tue, 16 Mar 2021 15:33:18 GMT < x-envoy-upstream-service-time: 1521 < server: envoy < * Connection #0 to host backend left intact Hello World! Marketplace with sales and reviews made with <3 by the OCTO team at Kong Inc.
-
Apply an OPA Policy that requires a valid JWT token:
echo " apiVersion: kuma.io/v1alpha1 kind: OPAPolicy mesh: default metadata: name: opa-1 spec: selectors: - match: kuma.io/service: '*' conf: policies: - inlineString: | package envoy.authz import input.attributes.request.http as http_request default allow = false token = {\"valid\": valid, \"payload\": payload} { [_, encoded] := split(http_request.headers.authorization, \" \") [valid, _, payload] := io.jwt.decode_verify(encoded, {\"secret\": \"secret\"}) } allow { is_token_valid action_allowed } is_token_valid { token.valid now := time.now_ns() / 1000000000 token.payload.nbf <= now now < token.payload.exp } action_allowed { http_request.method == \"GET\" token.payload.role == \"admin\" } " | kubectl apply -f -
-
Make an invalid request from the frontend to the backend:
$ kubectl exec -i -t $(kubectl get pod -l "app=kuma-demo-frontend" -o jsonpath='{.items[0].metadata.name}' -n kuma-demo) -n kuma-demo -- curl backend:3001 -v
The output looks like:
Defaulting container name to kuma-fe. Use 'kubectl describe pod/kuma-demo-app-6787b4f7f5-bwvnb -n kuma-demo' to see all of the containers in this pod. * Trying 10.105.146.164:3001... * TCP_NODELAY set * Connected to backend (10.105.146.164) port 3001 (#0) > GET / HTTP/1.1 > Host: backend:3001 > User-Agent: curl/7.67.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 403 Forbidden < date: Tue, 09 Mar 2021 16:50:40 GMT < server: envoy < x-envoy-upstream-service-time: 2 < content-length: 0 < * Connection #0 to host backend left intact
Note the
HTTP/1.1 403 Forbidden
message. The application doesn’t allow a request without a valid token.The policy can take up to 30 seconds to propagate, so if this request succeeds the first time, wait and then try again.
-
Make a valid request from the frontend to the backend:
$ export ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJzdWIiOiJZbTlpIiwibmJmIjoxNTE0ODUxMTM5LCJleHAiOjI1MjQ2MDgwMDB9.H0-42LYzoWyQ_4MXAcED30u6lA5JE087eECV2nxDfXo" $ kubectl exec -i -t $(kubectl get pod -l "app=kuma-demo-frontend" -o jsonpath='{.items[0].metadata.name}' -n kuma-demo) -n kuma-demo -- curl -H "Authorization: Bearer $ADMIN_TOKEN" backend:3001
The output looks like:
Defaulting container name to kuma-fe. Use 'kubectl describe pod/kuma-demo-app-6787b4f7f5-m428c -n kuma-demo' to see all of the containers in this pod. * Trying 10.111.108.218:3001... * TCP_NODELAY set * Connected to backend (10.111.108.218) port 3001 (#0) > GET / HTTP/1.1 > Host: backend:3001 > User-Agent: curl/7.67.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < x-powered-by: Express < cache-control: no-store, no-cache, must-revalidate, private < access-control-allow-origin: * < access-control-allow-methods: PUT, GET, POST, DELETE, OPTIONS < access-control-allow-headers: * < host: backend:3001 < user-agent: curl/7.67.0 < accept: */* < x-forwarded-proto: http < x-request-id: 8fd7b398-1ba2-4c2e-b229-5159d04d782e < content-length: 90 < content-type: text/html; charset=utf-8 < date: Tue, 16 Mar 2021 17:26:00 GMT < x-envoy-upstream-service-time: 261 < server: envoy < * Connection #0 to host backend left intact Hello World! Marketplace with sales and reviews made with <3 by the OCTO team at Kong Inc.
The request is valid again because the token is signed with the
secret
private key, its payload includes the admin role, and it is not expired.