This example can be run on a local installation of Istio on Kubernetes provided by Docker Desktop. The following prerequisites are needed:
- Have Docker Desktop installed
- Configure Docker Desktop for Istio
- Configure Kubernetes on your Docker Desktop (Mac, Windows)
- Install Istio - follow just the first two steps (Download and Install), no need to deploy the sample application (this demo was written for Istio 1.4 and may require some changes for newer versions):
- On MacOS or Linux systems, this boils down to:
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.4.9 sh - cd istio-1.4.9 ./bin/istioctl manifest apply --set profile=demo
- On MacOS or Linux systems, this boils down to:
The rest of this document describes the remaining setup of the demo in steps. The entire process can also by applied at once with ./apply-all.sh
.
Before we configure Istio and OPA, let us deploy a couple of services for the example:
kubectl apply -f services/
This will deploy
netshoot
- we willexec
into this pod to test our setuphttpbin
- this will serve as our target service whose REST API we want to protectaccess-management
- this is a WireMock instance that will simulate the Access Management Service for token validation and translation.
In order to test the setup, you can run commands from within the netshoot
pod with ./exec-in-netshoot.sh
. You should see outputs similar to this:
> ./exec-in-netshoot.sh curl httpbin:8000/headers
{
"headers": {
"Accept": "*/*",
"Host": "httpbin:8000",
"User-Agent": "curl/7.65.1"
}
}
> ./exec-in-netshoot.sh curl access-management:8080/auth/api-clients/me
Invalid token
> ./exec-in-netshoot.sh curl "-HAuthorization: valid-token-1" access-management:8080/auth/api-clients/me
{"apiClientId":"8bb18d14-696d-4858-856b-2d610a48b13c","identity":{"username":"user1"}}
The final part of the example is configuration of OPA and authorization policies.
Start with opa-istio-plugin
installation in the default configuration. This will set up a couple of things, most importantly the admission controller that injects opa-istio
sidecars:
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/opa-istio-plugin/f1d4c7f6deba9212c1a125b6a43af25e991ad936/quick_start.yaml
Then apply our customizations:
kubectl delete configmap opa-policy
kubectl apply -f opa-config/
The following will be deployed:
namespace-labels.yaml
- adds labels to the default namespace enabling injection of Istio and OPA sidecars. Note that the pods need to be redeployed for this to take effect.ext-authz-envoyfilter.yaml
- modifies the default configuration ofenvoy.ext_authz
filter to deny access in case of OPA failure, and to pass validated identity information from theenvoy.lua
filter ((line 33-35).authn-lua-envoyfilter.yaml
- adds anenvoy.lua
filter before theenvoy.ext_authz
filter. Theenvoy.lua
filter is responsible for delegating token validation and translation toaccess-management
.inject-policy.yaml
- configures how OPA sidecars are injected. This is where we configure that:- the policy referenced by the
opa-policy-config-map-name
label should be used if present (line 86-89) opa-policy-default
policy should be used if the label is not presentopa-policy-common
policy should be mounted to all containers
- the policy referenced by the
policy-httpbin-opa.yaml
- defines the service-specific OPA policy for httpbin. This ConfigMap is referenced by theopa-policy-config-map-name
label on thehttpbin
pod.opa-istio-config.yaml
- turns on OPA logging with thedecision_logs
setting.
Finally, we need to redeploy the services and admission controller so that changes in configuration are applied:
kubectl delete pod $(kubectl get pod -l app=admission-controller -n opa-istio -o 'jsonpath={.items[0].metadata.name}') -n opa-istio
kubectl delete pod $(kubectl get pod -l app=httpbin -o 'jsonpath={.items[0].metadata.name}')
Every request to httpbin
now
- goes to
istio-proxy
sidecar, authn-lua
filter is executed which translates theAuthorization
header to client identity information,- the client identity information is passed along with other request metadata to
opa-istio
sidecar where the authorization decision happens, - and if successful, the request is forwarded to
httpbin
container.
You should see results similar to the following:
> ./exec-in-netshoot.sh curl -s -o /dev/null -w "%{http_code}\n" httpbin:8000/anything/unprotected
200
> ./exec-in-netshoot.sh curl -s -o /dev/null -w "%{http_code}\n" httpbin:8000/anything/protected
403
> ./exec-in-netshoot.sh curl -s -o /dev/null -w "%{http_code}\n" "-HAuthorization: valid-token-1" httpbin:8000/anything/protected
200
> ./exec-in-netshoot.sh curl -s -o /dev/null -w "%{http_code}\n" "-HAuthorization: valid-token-1" httpbin:8000/anything/user/user1
200
> ./exec-in-netshoot.sh curl -s -o /dev/null -w "%{http_code}\n" "-HAuthorization: valid-token-1" httpbin:8000/anything/user/user2
403
OPA logs can be observed with
kubectl logs -f $(kubectl get pod -l app=httpbin -o 'jsonpath={.items[0].metadata.name}') -c opa-istio
If you have any questions or comments, you can reach out to the author at LinkedIn.