Using Istio as an external authorizer. Part 2: The implementation

Posted on Oct 16, 2022
Note: This article was written a while ago and may contain outdated information. Please verify the details before relying on it. If I express opinions or recommendations, they might not reflect my current views. For this reason, I recommend checking for more recent articles on the same topic.

This is the second part of a series about using Istio as an external authorizer. Here’s part 1.

Prerequisite

To follow and understand this guide you need the following prerequisites:

  1. Read and understand the authorization concepts of Istio.
  2. Important: Setup your local cluster accordingly to this guide, as I’ll use the application as an example.

The external authorizer

The external authorizer needs to implement the Protobuf interface defined by Envoy.

I’ll write more of the implementation of it as a Java service in another post, but let’s use the sample application by Istio.

This one allows all requests with the x-ext-authz: allow header.

Step 1: Deploy extauthz service

Deploy the ext-authz service:

kubectl apply -n sidecar-test -f https://raw.githubusercontent.com/istio/istio/release-1.15/samples/extauthz/ext-authz.yaml

Make sure, that the namespace (-n parameter) is the one where your application runs!

Step 2: Apply the service entry

Add an additional entry to Istios internal service registry. This can be done via the ServiceEntry CRD.

Apply the following ServiceEntry:

apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
  name: external-authz-grpc-local
  namespace: sidecar-test
spec:
  hosts:
    - "external-authz-grpc.local" # The service name to be used in the extension provider in the mesh config.
  endpoints:
    - address: "127.0.0.1"
  ports:
    - name: grpc # Important part: THis needs to be grpc
      number: 9191 # The port number to be used in the extension provider in the mesh config.
      protocol: GRPC
  resolution: STATIC

Step 3: Edit Istio config

Open the edit mode of the Istio configmap:

kubectl edit configmap istio -n istio-system

And append the mesh part with the following lines:

data:
  mesh: |-
    extensionProviders:
    - name: "sample-ext-authz-grpc"
      envoyExtAuthzGrpc:
        service: "ext-authz.sidecar-test.svc.cluster.local"
        port: "9000"
    - name: "sample-ext-authz-http"
      envoyExtAuthzHttp:
        service: "ext-authz.sidecar-test.svc.cluster.local"
        port: "8000"
        includeRequestHeadersInCheck: ["x-ext-authz"]    

Restart the istio daemon:

kubectl rollout restart deployment/istiod -n istio-system

Step 4: Apply the AuthorizationPolicy

Apply the AuthorizationPolicy:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: ext-authz
  namespace: sidecar-test
spec:
  selector:
    matchLabels:
      app: demo
  action: CUSTOM
  provider:
    # The provider name must match the extension provider defined in the mesh config.
    # You can also replace this with sample-ext-authz-http to test the other external authorizer definition.
    name: sample-ext-authz-grpc
  rules:
  # The rules specify when to trigger the external authorizer.
  - to:
    - operation:
        paths: ["/books"]

Step 5: Verify that it works

Verify the configuration via cURL:

This should work:

curl localhost/books -H "x-ext-authz: allow" -s

This should also work:

curl localhost

This should not work:

curl localhost/books -H "x-ext-authz: disallow" -s

And print the following:

denied by ext_authz for not found header `x-ext-authz: allow` in the request

Conclusion

This opens up many possibilities of configurations!

For example you can allow only specific request types or allow only specific hosts or allow only specific routes to be accessed to the outside.

Writing the external authorizer provides you a central point of secure access logic. You need only to manage one application and one point to secure your services from outside access.

Update: Here’s the post of the Java implementation of an ext-authz service

Further reading