Attempts to demonstrate support for:
-
JWT authentication for multiple IDPs
-
RBAC on Endpoints for roles defined those JWTs
A minimal installation of Istio is required, i.e. IstioD only. Please follow the steps in the Kong Istio Gateway instructions for more on doing a 'minimal' install.
Installation instructions for Kong Istio Gateway
The pattern being applied here is sidecar injection into the service pods of the Open Policy Agent Envoy plugin.
The MutatingWebhook and Admission-controller objects are concerned with dynamically injecting the OPA Envoy plugin into the PODs, based on labels on the namespace.
The Mutating Webhook resource is watching namespaces with the opa-istio-injection
label
namespaceSelector:
matchLabels:
opa-istio-injection: enabled
Within namespaces that match that label, it is looking for pods that have been created (TODO: this could be updated to inject for PODs that have been updated also?)
rules:
- operations: ["CREATE"]
apiGroups: [""]
apiVersions: ["v1"]
resources: ["pods"]
For pods that meet that criteria, the MutatingWebhook resource then calls into the the web hook(admission-controller) in the opa-istio
namespace
clientConfig:
service:
name: admission-controller
namespace: opa-istio
path: "/v0/data/istio/inject"
See the MutatingWebhookConfiguration Kubernetes docs for more detail on this functionality
The admission-controller
deployment in the opa-istio
namespace is only concerned with injecting the OPA Envoy plugin sidecar container into the Pods that the have met the criteria defined in the MutatingWebhookConfiguration
.
The configuration of the injected container is determined by the inject.rego
file which is mounted in the inject-policy
ConfigMap.
E.g.
opa_container = {
"image": "openpolicyagent/opa:0.45.0-istio",
"name": "opa-istio",
"args": [
"run",
"--server",
"--config-file=/config/config.yaml",
"--addr=localhost:8181",
"--diagnostic-addr=0.0.0.0:8282",
"/policies/policy.rego",
"/policies/common.rego",
"/policies/data.json",
]
}
The logic here is also labelling the pod with opa-istio-injection: enabled
. This is done so that EnvoyFilter knows which pods have been injected with the OPA sidecar. TODO: review functionality
{
"op": "add",
"path": "/metadata/labels/opa-istio-injection",
"value": "enabled" }
As per the Istio docs, the EnvoyFilter is concerned with:
providing a mechanism to customize the Envoy configuration generated by Istio Pilot. Use EnvoyFilter to modify values for certain fields, add specific filters, or even add entirely new listeners, clusters, etc.
In this case this configuration is using the External Authorization HTTP filter. From the docs:
The external authorization filter calls an external gRPC or HTTP service to check whether an incoming HTTP request is authorized or not. If the request is deemed unauthorized, then the request will be denied normally with 403 (Forbidden) response.
In the configuration in this repo, the filter is calling into the OPA envoy plugin (side car), to "authorize" the request.
The configuration of the Envoyfilter is only applied to Pods with the opa-istio-injection: enabled
label.
workloadSelector:
labels:
opa-istio-injection: enabled
In the namespace containing the pods to be secured by OPA, there are three files expected in a ConfigMap called opa-policy
(see the configMapGenerator in opa-envoy-example\sample-application\kustomization.yaml). These three files contain the OPA policies to be applied to the services in the namespace.
-
policies/common.rego
- contains JWT authentication logic, this logic can be configured to authenticate JWTs from multiple IDP Authorisation servers. -
policies/policy.rego
- uses the data from data.json to determine if the role in the JWT has 'permission' to call the requested resource. -
policies/data.json
- is a static definition of the permissions (TODO: should be renamed to roles) and the resources that they are allowed invoke.
The logic in the policy.rego
basically:
-
Calls into the common.rego to authenticate the JWT.
-
Extracts the roles/permissions from the 'roles' claim in the JWT.
-
Checks each of those roles and the path requested against the data from the data.json.
-
returns its response to the EnvoyFilter, which either allows/disallows the request to proceed to the service.
-
Download the latest OPA release from here
-
Refer to the OPA CLI documentation here
kind: Namespace
apiVersion: v1
metadata:
name: opa-test
labels:
istio-injection: enabled
opa-istio-injection: enabled
-
Having to restart pods that pre-existed OPA deployment
-
Injecting based on Updates to pods
-
Identify edge cases that should be tested, i.e invalid rego, etc