Istio - End User Authentication

February 10, 2020 | 4 minute read
Text Size 100%:

VanveenJF

Say you have a large monolithic application that you have decided to re-implement as microservices, and you have zeroed in on Istio as your Service Mesh platform.

Istio is a Service Mesh that allows managing and securing microservices. It has a policy-driven Control Plane and an Envoy-proxy based data plane.

Your monolithic application may have had its own traditional security infrastructure that supported end-user authentication and authorization. But how do you implement the same behavior with Istio in a modern, declarative, and cloud-native way? This blog will help you with that, specifically uncovering the authentication strategies.

To be concrete, say we have an internet-facing helloworld microservice deployed in Istio, how do we secure the API using Cloud Identity services such as Oracle IDCS, or Okta?

To demonstrate this, we will do the following :

  • Create a Kubernetes(OKE) cluster in OCI and install Istio on it,
  • Build and deploy a Java helloworld microservice using Helidon , and
  • Secure the API using IDCS such that only the user identities residing in the IDCS instance can access the API.

Create the OKE and Istio cluster

  • Create the OKE cluster in OCI, choosing Kubernetes version 1.14.8 or higher (You may also refer to this tutorial to setup OKE).
  • Setup kubectl on your laptop to connect to the OKE cluster we just created.
  • Download and Istio on your laptop :

  • Verify that Istio is installed correctly

    istioctl verify-install -f $HOME/generated-manifest.yaml

Build and Deploy a sample microservice

  • We will now build and deploy a Java(specifically Helidon) based hello-world microservice. The steps below create a default Helidon project based on a maven archetype, build the project, and build a docker image off of it.

  • Now we upload the built docker image to OCI Docker repository in order to deploy it to our Istio Mesh. You can follow this tutorial link for detailed steps, the gist below has the main steps:

  • Register your docker registry secret in the OKE cluster as well :

    kubectl create secret docker-registry oci-registry-secret --docker-server=iad.ocir.io\ --docker-username='[TENANCY_NAME]/oracleidentitycloudservice/[USERNAME]'\ --docker-password='<PASSWORD>' #single quotes are required. #Output : Secret oci-registry-secret created. Username above is your IDCS-originated and OCI-synced username

  • Now update the Kubernetes app.yaml inside the helidon-quickstart-se directory to reflect the newly created docker registry and OKE secret. Specifically, update imagePullPolicy to ‘Always’ , update containers→image to point to the new registry, and add imagePullSecrets section with the name ‘oci-registry-secret’.

  • Now with the updated app.yaml we deploy the Helidon microservice to our cluster :

    cd <ROOT_DIRECTORY>/helidon-quickstart-se kubectl apply -f app.yaml

  • The Istio Ingress gateway was installed already. Let’s get its public IP :

    kubectl get svc -n istio-system -l istio=ingressgateway\ export EXTERNAL_IP=$(kubectl get svc -n istio-system\ -l app=istio-ingressgateway -o jsonpath='{.items[0].status.loadBalancer.ingress[0].ip}')

  • Enable the ingress gateway to allow traffic on port 80. Save the contents of the gist below to a file called istio-http-gateway.yaml

  • Apply the yaml file kubectl apply -f istio-http-gateway.yaml , thus enabling traffic on port 80.
  • Now we need to create the Istio Virtual Service for our Helidon microservice, for which we copy the gist below to a file ‘istio-virtual-service.yaml’

  • kubectl apply -f istio-virtualservice.yaml
  • Now we can access our microservice from the internet. Let’s verify this by invoking curl -X GET http://$EXTERNAL_IP/greet

With this, our basic setup is complete. We created and Istio Mesh, deployed a microservice on it, and exposed it to the internet.

The next task, and the crux of this blog, is to secure the service.

End User Authentication

There are two ways of enabling authentication in Istio so that only known users have access:

  • We use the Istio-provided end-user authentication policy
  • Or we write an Istio Envoy Filter and customize the Envoy proxy directly.

Istio uses Envoy Proxy as a sidecar, and delegates all the network, security, load-balancing work to Envoy.
So much so that #1 above actually ends up as an Envoy configuration in the sidecar attached to the Istio Ingress Gateway.

End User Authentication Policy

  • Istio allows for JWT-based end-user authentication. We need to create a ‘Policy’ object that contains the identity service’s (IDCS) issuer name, and its jwks URL . We can use the script below to setup the policy (save it as ‘istio-authn-policy.yaml’ )

  • After applying this policy, kubectl apply -f istio-authn-policy.yaml , if you invoke the /greet endpoint again you’ll receive a 401 unauthorized error. The API is not open anymore.

In order to access the API, now you’ll have to generate a JWT Bearer token from IDCS, and pass it as Authorization header when invoking the API :

export TOKEN=<IDCS_JWT_TOKEN> curl -X GET -H "Authorization: Bearer $TOKEN" http://$EXTERNAL_IP/greet

Envoy Filter

Exactly the same behavior as above can be reached by using Envoy Filter to setup JWT Authentication. This option allows much more configuration flexibility(as listed in the Envoy documentation here), such as fully offline JWKS URI. A sample Envoy Filter configuration is provided below.

For most of the scenarios though, using the Istio End User Authentication Policy suffices.

Conclusion

In this blog we described how to enable authentication in Istio microservices . In the next blog we will discuss enabling authorization as well.

Ashish Singh


Previous Post

Paginate Records using an Advanced Postman Collection

Tim Melander | 5 min read

Next Post


Part 1: About Desktop SSO using Azure AD, IDCS, and the App Gateway

Tim Melander | 4 min read