MeshOPA - OPA Policy Integration
Available with Kong Gateway Enterprise subscription - Contact Sales
Warning: This policy uses the new policy matching algorithm, it should not be mixed with the OPA Policy.
MeshOPA 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 the MeshOPA
policy is applied, the control plane configures the following:
- The embedded policy agent, with the specified policy
- Envoy, to use External Authorization that points to the embedded policy agent
TargetRef support matrix
To learn more about the information in this table, see the matching docs.
Configuration
To apply a policy with MeshOPA, you must do the following:
- Specify the group of data plane proxies to apply the policy to with the
targetRef
property. - Provide a policy with the
appendPolicies
property. Policies are defined in the Rego language. - Optionally provide custom configuration for the policy agent.
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 |
---|---|---|---|
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(*) | nil |
Configuring the authorization filter
You can configure the external authorization filter by adjusting the authConfig
section.
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:
Composing policies
In your organization, the mesh operator may want to set a policy for subset of proxies in the mesh. At the same time, service owners may want to exercise additional policies.
For example, the mesh operator may want to enable JWT token validation for all proxies in the mesh
apiVersion: kuma.io/v1alpha1
kind: MeshOPA
metadata:
name: mopa-mesh-operator
namespace: kong-mesh-system
labels:
kuma.io/mesh: default
spec:
targetRef:
kind: Mesh
default:
appendPolicies:
- rego:
inlineString: |
package operator
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"
}
Service owner wants to block all requests on path /blocked
:
apiVersion: kuma.io/v1alpha1
kind: MeshOPA
metadata:
name: mopa-service-owner
namespace: kong-mesh-system
labels:
kuma.io/mesh: default
spec:
targetRef:
kind: MeshService
name: test-server_kuma-demo_svc_80
default:
appendPolicies:
- rego:
inlineString: |
package serviceowner
default allow = true
deny {
input.parsed_path == ["blocked"]
}
appendPolicies
is a list you can append, therefore in the case of the data plane proxy test-server_kuma-demo_svc_80
service, both policies will be applied.
Kong Mesh will autogenerate an additional OPA decision policy:
package implicitkmesh
import data.operator
import data.serviceowner
allow {
data.operator.allow
not data.operator.deny
data.serviceowner.allow
not data.serviceowner.deny
}
It also configures the OPA agent decision path (plugins.envoy_ext_authz_grpc.path
) to implicitkmesh/allow
.
You can also add a rego policy which is not part of the decision.
Set a appendPolicies[*].ignoreDecision
to true so the rego policy won’t be added to autogenerated decision policy.
This way, the mesh operator can expose utility functions to service owner.
Example
The following example shows how to deploy and test a sample MeshOPA 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 -c kuma-fe -- 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 a MeshOPA policy that requires a valid JWT token:
echo " apiVersion: kuma.io/v1alpha1 kind: MeshOPA metadata: namespace: kong-mesh-system name: mopa-1 labels: kuma.io/mesh: default spec: targetRef: kind: Mesh default: appendPolicies: - rego: 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 -c kuma-fe -- 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 the token into an environment variable:
export ADMIN_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJzdWIiOiJZbTlpIiwibmJmIjoxNTE0ODUxMTM5LCJleHAiOjI1MjQ2MDgwMDB9.H0-42LYzoWyQ_4MXAcED30u6lA5JE087eECV2nxDfXo"
Make the request:
kubectl exec -i -t $(kubectl get pod -l "app=kuma-demo-frontend" -o jsonpath='{.items[0].metadata.name}' -n kuma-demo) -n kuma-demo -c kuma-fe -- 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.
All policy options
Spec is the specification of the Kuma MeshOPA resource.
Type: object
Properties
- default
- Type:
object
- Properties
- agentConfig
- AgentConfig defines bootstrap OPA agent configuration.
- Type:
object
- Properties
- inline
- Data source is inline bytes.
- Type:
string
- String format must be a "byte"
- inlineString
- Data source is inline string`
- Type:
string
- secret
- Data source is a secret with given Secret key.
- Type:
string
- inline
- appendPolicies
- Policies define OPA policies that will be applied on OPA Agent.
- Type:
array
- Items
- Type:
object
- Properties
- ignoreDecision
- If true, then policy won't be taken into account when making a decision.
- Type:
boolean
- rego
required
- OPA Policy written in Rego. Available values: secret, inline, inlineString.
- Type:
object
- Properties
- inline
- Data source is inline bytes.
- Type:
string
- String format must be a "byte"
- inlineString
- Data source is inline string`
- Type:
string
- secret
- Data source is a secret with given Secret key.
- Type:
string
- inline
- ignoreDecision
- authConfig
- AuthConfig are configurations specific to the filter.
- Type:
object
- Properties
- onAgentFailure
- OnAgentFailure either 'allow' or 'deny' (default to deny) whetherto allow requests when the authorization agent failed.
- Type:
string
- The value is restricted to the following:
- "Allow"
- "Deny"
- requestBody
- RequestBody configuration to apply on the request body sent to theauthorization agent (if absent, the body is not sent).
- Type:
object
- Properties
- maxSize
- MaxSize defines the maximum payload size sent to authorization agent. If the payloadis larger it will be truncated and there will be a header
x-envoy-auth-partial-body: true
. If it is set to 0 no body will besent to the agent. - Type:
integer
- MaxSize defines the maximum payload size sent to authorization agent. If the payloadis larger it will be truncated and there will be a header
- sendRawBody
- SendRawBody enable sending raw body instead of the body encoded into UTF-8
- Type:
boolean
- maxSize
- statusOnError
- StatusOnError is the http status to return when there's a connectionfailure between the dataplane and the authorization agent
- Type:
integer
- timeout
- Timeout for the single gRPC request from Envoy to OPA Agent.
- Type:
string
- onAgentFailure
- agentConfig
- Type:
- targetRef
- TargetRef is a reference to the resource the policy takes an effect on.The resource could be either a real store object or virtual resourcedefined inplace.
- Type:
object
- Properties
- kind
- Kind of the referenced resource
- Type:
string
- The value is restricted to the following:
- "Mesh"
- "MeshSubset"
- "MeshGateway"
- "MeshService"
- "MeshExternalService"
- "MeshMultiZoneService"
- "MeshServiceSubset"
- "MeshHTTPRoute"
- labels
- Labels are used to select group of MeshServices that match labels. Either Labels orName and Namespace can be used.
- Type:
object
- This schema accepts additional properties.
- Properties
- mesh
- Mesh is reserved for future use to identify cross mesh resources.
- Type:
string
- name
- Name of the referenced resource. Can only be used with kinds:
MeshService
,MeshServiceSubset
andMeshGatewayRoute
- Type:
string
- Name of the referenced resource. Can only be used with kinds:
- namespace
- Namespace specifies the namespace of target resource. If empty only resources in policy namespacewill be targeted.
- Type:
string
- proxyTypes
- ProxyTypes specifies the data plane types that are subject to the policy. When not specified,all data plane types are targeted by the policy.
- Type:
array
- Item Count: ≥ 1
- Items
- Type:
string
- The value is restricted to the following:
- "Sidecar"
- "Gateway"
- sectionName
- SectionName is used to target specific section of resource.For example, you can target port from MeshService.ports[] by its name. Only traffic to this port will be affected.
- Type:
string
- tags
- Tags used to select a subset of proxies by tags. Can only be used with kinds
MeshSubset
andMeshServiceSubset
- Type:
object
- This schema accepts additional properties.
- Properties
- Tags used to select a subset of proxies by tags. Can only be used with kinds
- kind
Generated with json-schema-md-doc