Istio Authentication— Part 2(User Authentication)

In part-1,we discussed peer authentication which is service to service.

Request Authentication

In this article we will be exploring Istio request authentication for end users using JWT .

Pre-requisite

  1. Cluster Environment created with EKS or KOPS
  2. Kubectl installed
  3. Istio installed
  4. Need Public key to access the cluster nodes
  5. Private/Public key for token generation/validation

Steps To Generate Public/Private Key Pair using openssl

For sample, we will be using openssl for certificates. In reality you may use CA signed certificates.

openssl genrsa -out private-key.pem 2048
openssl rsa -in private-key.pem -pubout -out public-key.pem

Istio End User Authentication

For user authentication, JWT token should be set in the incoming request. Istio takes care of JWT validation. So if we implement Istio JWT authentication feature,
our application code need not to worry about JWT validation. Istio takes care of it.
We need to have separate code for token generation.

Below diagram depicts the workflow of our sample microservice.

Istio — End User Authentication

We have 2 applications developed in spring boot.

  1. welcome-app
  2. hello-app

Accessing welcome-app directly

  1. User sends request to welcome-app with JWT token.
  2. Then Istio takes care of validating the incoming request with JWT token. If it is valid request, will route the request to application welcome-app.

Accessing welcome-app via hello-app

a. User sends request to hello-app with JWT token.

b. Then Istio takes care of validating the incoming request with JWT token. If it is valid request, will route the request to application hello-app.

c. We used rest template for invoking application welcome-app from hello-app. Then hello-app will access the application welcome-app with JWT token.

Before Request Authentication

Create a namespace for our application.

kubectl create namespace namespace1

To enable automatic side car injection for our namespace, use the following command. This will instruct Istio to automatically inject Envoy proxy when we deploy our application later in the same namespace.

kubectl label namespace namespace1 istio-injection=enabled

Deploy our application in the same namespace and ensure that it is up and running.

After deploying the application, we can see that Istio has added a sidecar for every pod created.

kubectl get pods -n namespace1

kubectl command — Application Pods

As seen here, 2 containers are created for each pod, One for the application and another one for proxy.

To get the details of the container run the following command.

kubectl describe pod hello-app-********* -n namespace1

Now we will be able to see both application container as well as proxy container in our pod.

kubectl command — Describing Pods

To make our application accessible from internet, an Istio ingress gateway must be created. We use this gateway to manage inbound and outbound traffic for our mesh. Traffic routing for ingress traffic is configured using Istio routing rules, exactly in the same way as for internal service requests. A virtual service is then bound to the gateway to control the forwarding of traffic arriving at a particular host or gateway port.

  1. An ingress gateway describes a load balancer operating at the edge of the mesh that receives incoming HTTP/TCP connections.
  2. Server describes the properties of the proxy on a given load balancer port.
  3. Port describes the properties of a specific port of a service
Istio — gateway.yaml

A virtual service and a gateway is created in our namespace.

kubectl get gateways -n namespace1
kubectl get virtualservice -n namespace1
kubectl command — Gateway & Virtual Service
kubectl get svc -n istio-system
kubectl command — Istio Components

It has a service called istio ingress gateway . Using the external ip and port application can be accessed from the browser or postman.

We will be using postman as we need to set the token in the header.

hello service — Without Token
welcome service — Without Token
Metrics — Before Request Authentication

RequestAuthentication

To enable Istio to validate the JWT tokens in the incoming request, we have to define a public key in RequestAuthentication.
For JWT Authentication microservice will generate the JWT token, it will have to specify the iss field in the payload.
This iss field has to match with the issuer field in the RequestAuthentication.
We can store public key in Istio using either of the two jwtRules options.

jwks(JSON Web Key Set)
JSON Web Key Set of public keys to validate signature of the JWT.
jwksuri(JSON Web Key Set URI)
URL of the provider’s public key set to validate signature of the JWT.
Example: https://www.googleapis.com/oauth2/v1/certs

Note: We cant combine both. We have to use either jwksuri or jwks .

Our sample is based on jwks and we can directly specify the key as shown below.

Istio accepts the public key in a JWKS format.
So we need to convert public key into JSON format i.e key value pair not PEM format.

Use below link to convert PEM to JWKS format.

https://irrte.ch/jwt-js-decode/pem2jwk.html

After converting ,provide the key in keys section of the RequestAuthentication yaml.

JWT — RequestAuthentication. yaml

Now try to access both applications with and without token using postman. Token need to be set in Authorization section of the header in the postman. The outcome is detailed below.

hello service — Without Token
hello service — Invalid Token
hello service — Valid Token
welcome service — Without Token
welcome service — Invalid Token
welcome service — Valid Token
Metrics — After Request Authentication

Even though we have enabled the authentication, still we will be able to access the application without any token. To overcome this, we need to enable Authorization policy.

AuthorizationPolicy

To allow requests only with valid JWT token, need to enable an authorization policy.
Here we have specified a rule to reject incoming requests without request principals.
Request principals are available only when valid JWT tokens are provided.

In the yaml we will define the action as Deny for all the requests which does not have the request principals.

Istio — ingress gateway Authorization Policy.yaml

Now try to access both applications with and without token using postman. Token need to be set in Authorization section of the header in the postman. The outcome is detailed below.

hello service — Without Token
hello service — Invalid Token
hello service — Valid Token
welcome service — Without Token
welcome service — Invalid Token
welcome service — Valid Token
Metrics — After Authorization Policy

Reference

Conclusion

We have now successfully enabled Istio RequestAuthentication for our application using JWT.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store