is
2020/04/24
 
24 Apr, 2020 | 3 min read

Istio End User Authentication with WSO2 Identity Server

  • Ajanthan Balachandiran
  • Software Engineer - WSO2

Image credits: Ricardo Gomez Angel on Unsplash

Nowadays, service meshes are becoming an essential tool to build distributed applications. You could call it microservices architecture or service-oriented architecture, but all of them are distributed application architecture where applications communicate through the network. The network is not always reliable, but the applications should be reliable and predictable. The only way we can build reliable applications over an unreliable network is by gracefully handling network failures in applications. This is where service meshes play a big role by providing a method to segregate the responsibilities of handling network failure language or framework, independently, separate from applications.

There are a variety of service mesh implementations. Istio , Linkerd, Amazon Web Services (AWS) app mesh, and Consul Connect are well-known service mesh implementations. End-user authentication is a popular service mesh feature. When the networked services or applications talk to each other, sometimes the communication will happen on behalf of the end user. In that case, the application should verify the end user’s identity to avoid unintended security issues. Traditionally, identity and access management (IAM) systems are responsible for validating user identity. Service meshes, along with IAM can validate the end user identity during any service-to-service communication. In this blog, we look at how an end user authentication can be done in Istio using WSO2 Identity Server, an open-source IAM solution.

Prerequisites

These are the prerequisites for this exercise:

  • A Kubernetes environment
  • WSO2 Identity Server deployment on Kubernetes
  • Istio on Kubernetes

There are a range of options for Kubernetes deployment, including Kubernetes-as-a-service (KaaS) from big cloud providers to Minikube. In this exercise, we will focus on testing it on Minikube, a convenient deployment to test in a developer workstation. For this exercise, please follow the Mini Kube installation documentation and have a Minikube deployment with a minimum of 8 GB memory allocated.

The next step is to deploy WSO2 Identity Server on Kubernetes. I have written a tutorial which users are free to follow to implement a functioning WSO2 identity deployment on your preferred Kubernetes deployment.

The next step is to install Istio. The official documentation for Istio is comprehensive and anyone with a little developer experience could install it. To use Istio for demo purposes, the QuickStart evaluation guide is the best.

The final step is to deploy a sample service, apply an Istio end-user authentication security policy and test it.

Deploying a Sample Service

Istio comes with many samples. Here, we can use one of them. The Httpbin sample is a proxy for the httbin site. In this exercise, we will deploy this sample. Go to the installation directory and issue the following command:

kubectl apply -f <(istioctl kube-inject -f
samples/httpbin/httpbin.yaml)

Here the assumption is that the Istio auto sidecar injection is disabled. As such, it will take a few minutes to pull the Docker images and start the Pods.

Applying Istio Authentication Traffic Rules

To access the service from outside of Kubernetes, an Ingress gateway is needed. Istio has a gateway that can act as an Ingress gateway. Here, we will use the Istio Gateway instead of other Ingress Gateways. The required Istio policies are in this GitHub repository.

Clone the repository and apply the virtual service and gateway policy as shown below:

git clone https://github.com/ajanthan/istio-enduser-authentication-
with-wso2is.git
cd istio-enduser-authentication-with-wso2is
kubectl apply -f httpbin-gateway.yaml
kubectl apply -f httpbin-virtualservice.yaml

Now the service can be accessed externally using the Ingress host and the Ingress port(follow the Istio documentation to determine the host and the port). In this stage, the service is accessible by anyone with network access. In the next step, an end user authentication policy will be applied to secure the service.

Types of Istio Authentication

Istio supports two kinds of authentication:

    1. Transport Authentication or Service to Service Authentication through Mutual TLS connection (MTLS Authentication)

Mutual TLS Authentication can be enabled without requiring service code changes. During this authentication, the client-side Envoy proxy starts a mutual TLS (MTLS) handshake with the server-side Envoy proxy. During the mutual TLS handshake, the client-side Envoy conducts a secure naming check to verify the service account presented in the server certificate during certificate generation and whether it’s authorized to run the target service. Mutual TLS provides each service with a strong identity to enable interoperability. It provides a key management system to automate key and certificate generation (key and certificate management), distribution, and rotation. The client-side Envoy and the server-side Envoy will establish a MTLS connection, and Istio forwards the traffic from the client-side to the server-side Envoy. The server side Envoy will authorize the received request. If authorized, it forwards the traffic to the backend service through local TCP connections (Transmission Control Protocol).

2. Origin Authentication or End User Authentication through JSON Web Token (JWT).

Applying End User Authentication Policies

We will now apply the following authentication policy to authenticate the service request with Json Web Token (JWT) issued by WSO2 Identity Server.

apiVersion: "authentication.istio.io/v1alpha1"
kind: "Policy"
metadata:  
  name: "jwt-example"
spec:  
  targets:  
  - name: httpbin  
  origins:  
  - jwt:      
      issuer: "https://wso2is:9443/oauth2/token"          
      jwksUri: "https://wso2is-service.default.svc.cluster.local:9763/oauth2/jwks"
  principalBinding: USE_ORIGIN

The important details here are the issuer and the jwkUri. In the case of WSO2 Identity Server, these details could be found in the OpenID connect discovery configuration. The principalBinding is also required to instruct the Istio to get the JWT from the header (in the form of Authorization: Bearer). The above policy is available in the Github repository mentioned in the previous step.

Now, we apply the policy as follows:

kubectl apply -f jwt-auth-policy.yaml

At this point, the service access control is protected by JWT authentication. Only requests with JWT issued by WSO2 Identity Server will be allowed. In the next step, we will generate a JWT and call the service using the CURL command.

Calling the Service

As mentioned before, to call the service a JWT is needed from WSO2 Identity Server. We must use the OAuth2 token API server endpoint to generate a token (an OpenId token). The first step in generating an OpenID connect token is to register an OAuth2 application. Access the WSO2 Identity Server management console and create a new service provider with OAuth/OpenID Connect Configuration inbound authentication type. Users can refer to the WSO2 Identity Server documentation for more details.

After a successful application registration, get the Client ID and the Client secret of the registered application as mentioned in the previous step. There are multiple ways users can generate a JWT using different grant types but, the easiest is the password grant type. We will use this grant type to generate an OpenID token. Make the following request to begin.

curl -vk -d 
"grant_type=password&username=admin&password=admin&scope=openid" -H 
"Authorization: Basic base64encode(OAuth Client Key:OAuth Client 
Secret)" -H "Content-Type: application/x-www-form-urlencoded" 
https://wso2is/oauth2/token

This will give a JSON response. From the response, extract id_token, this is the JWT we will use to invoke the service. Invoke the service as follows:

curl -kv  https://$INGRESS_HOST:$INGRESS_PORT/headers -H 
"Authorization: Bearer "

Here the $INGRESS_HOST and $INGRESS_PORT should be determined using the Istio documentation. This time you will get a response from the Httpbin service (a none 401 response).

Congratulations, you just called the service successfully using a JWT issued by WSO2 Identity Server!

To summarize, JWT authentication can be enforced along with an OpenID connect provider like WSO2 Identity Server in Istio through an authentication policy. To further enforce access control to your workloads, you can apply an authorization policy.

Undefined