API Authentication using Istio Ingress Gateway, OAuth2-Proxy and Keycloak

Senthil Raja Chermapandian
6 min readAug 28, 2021

--

Money Heist Season 5 — Netflix

Introduction

In my previous blog post titled “API Access Control using Istio Ingress Gateway”, I explained how to implement an API access control solution using Istio Ingress Gateway. Istio uses JWT Access token attached to the API request, to validate the request and enforce access control (authorization) policies. This determine whether the request should be allowed or denied. The solution’s prerequisites were a successfully authenticated user (perhaps by an external system), and the user’s request having the JWT access token attached to it.

In this blog, I’ll explain how to implement a User Authentication solution using Istio Ingress Gateway, OAuth2-Proxy and Keycloak. The solution’s goals are (i) to check if the user requesting access to an Application/API is already authenticated or not, and (ii) if not already authenticated, authenticate the user and have the JWT access token generated and attached to the request.

Note: This blog doesn’t contains configuration details i.e. I’ll not cover how the individual components have to be configured for the solution to work. Configuration details are covered in part 2

Authentication vs Authorization

  • Authentication (AuthN) is the process of establishing to a specified Level Of Assurance that the Identification is authentic. It consists of two basic steps: Identification (e.g. username) and Verification (e.g. password)
  • Authorization is the process of determining whether the Digital Identity which has been through the Authentication process has the Permission to access a specific Protected Resource as requested.

Overview of the Components

Before I get into the actual solution, let me provide a brief overview of the individual components and the role they play in achieving the solution. For more detailed information on these components, use the resources in the reference section at the end.

Istio Ingress Gateway

Istio Ingress Gateway runs in the edge of the service mesh, managing traffic entering into the mesh. However it can be deployed as a stand-alone service (along with Istiod) as well, without having a mesh. It is widely used to implement a centralized API Gateway function to protect the APIs exposed by multiple micro-services running behind the Gateway.

When a user wants to access an Application from a browser, the user needs to be authenticated first (for e.g. by username and password). Istio Ingress Gateway can only authenticate an incoming request based on the JWT access token attached to the request. It cannot authenticate a user on its own, for e.g. by presenting a login form or via HTTP basic authentication. For authenticating a user, the authentication process has to be delegated to an external Identification provider like Keycloak.

Keycloak

Keycloak is a prominent open source Identity and Access Management (IAM) solution. It is capable of authenticating a user via OpenID Connect protocol. This protocol is based on OAuth2.0 standard, which prescribes several mechanisms (called grant types) for authenticating users. The use of OAuth2.0 helps in delegating the authentication to an external system, thereby relieving the application from having to do so. This is also very secure since the user needs to share his/her credentials only with the Identity Provider (Keycloak).

In the solution that I’ll be explaining, we’ll use Keycloak as the Identity Provider i.e. the user has an account in the Keycloak and it is responsible for authenticating the user by validating the username and password. In short, it performs the role of OAuth Server.

OAuth2-Proxy

OAuth2-Proxy is an open source reverse-proxy solution that performs the role of OAuth Client in a OAuth2.0 authentication flow. It is capable of detecting if the incoming request is already authenticated or not, and can orchestrate the authentication of the user with the OAuth Server (Keycloak). It receives the access token from Keycloak and stores it in its backend storage. It automatically refreshes the access token, by using refresh tokens. In our solution, we’ll make use of OAuth2-Proxy to co-ordinate the authentication flow between Istio Ingress Gateway and Keycloak

How the solution works:

Istio Ingress Gateway is responsible for processing the incoming request as per configuration we define using Istio APIs. Changes to this configuration are pushed to the Ingress Gateway from Istiod and consumed by the Ingress gateway without the need for restart. Incoming request to the OAuth server (Keycloak) admin URL will be directly forwarded to OAuth Server (Keycloak). All other requests are sent to OAuth2-Proxy for authentication (the request body is not sent since it is not required by OAuth2-Proxy). Upon receiving a 200 OK response from OAuth2-Proxy, the Ingress Gateway performs API Access control checks (Policy Enforcement Point (PEP)). The request is then sent to the correct Upstream service based on the path of the request. The Authorization header (contains the ID token) and X-Auth-Request-Access-Token header (contains the access token) are added to the request.

The OAuth2-Proxy is responsible for orchestrating the OAuth2.0 Authn/Authz flows. When it receives a request from the Ingress Gateway, it checks if the request is already authenticated or not. If the request is not already authenticated, it triggers a OAuth2.0 Authorization Code Grant flow by redirecting the request to Keycloak. Once the request is successfully authenticated, OAuth2-Proxy will store the access token, id token and refresh token in its Redis data store along with state information of the session. OAuth2-Proxy responds back to Ingress Gateway with a HTTP 200 OK response with the Authorization header (contains the ID token) and X-Auth-Request-Access-Token header (contains the access token) added to the request. The JWT access token in the X-Auth-Request-Access-Token header is consumed by Ingress Gateway to perform API Access control checks. In case the original request it received from the Ingress Gateway was already authenticated (presence of cookie), OAuth2-Proxy immediately responds back with HTTP 200 OK response with Authorization header and X-Auth-Request-Access-Token header. OAuth2-Proxy will automatically refresh access tokens in periodic intervals so users need not re-authenticate again and again with Keycloak.

Authentication Message Flow

  1. User enters the hostname of the server in the browser. The request is sent to the Istio Ingress Gateway.
  2. Ingress Gateway forwards the request to OAuth2-Proxy for authentication.
  3. The OAuth2-Proxy determines the request is not authenticated yet. It creates state in its Redis Key value store.
  4. OAuth2-Proxy redirects the browser to /auth endpoint of Keycloak.
  5. The browser sends a request to the /auth endpoint which is sent to the Ingress Gateway.
  6. Ingress Gateway forwards the request to Keycloak
  7. Keycloak serves the login screen containing fields for Username and Password.
  8. User enters Username and Password and submits the form. The browser sends a request to the /authenticate endpoint of Keycloak. The request is sent to the Ingress Gateway.
  9. Ingress Gateway forwards the request to Keycloak, which verifies the credentials of the user and generates an Authorization code.
  10. Keycloak then redirects the browser to the /callback endpoint of OAuth2-Proxy with Authorization code as query parameter in the URL.
  11. The browser sends a request to the /callback endpoint which is sent to the Ingress Gateway.
  12. Ingress Gateway forwards the request to OAuth2-Proxy
  13. OAuth2-Proxy invokes the /token endpoint of Keycloak using the Authorization code.
  14. Keycloak validates the Authorization code and responds back with access token, id token and refresh token
  15. OAuth2-Proxy persists the tokens in its Redis Key value store.
  16. OAuth2-Proxy redirects the browser to the original url requested by the user i.e. hostname. It instructs the browser to store a cookie with a specific key configured in OAuth2-Proxy
  17. The browser sends a request to hostname, this time the request will contain the cookie header containing cookie that was sent by OAuth2-Proxy. The request is sent to the Ingress Gateway.
  18. Ingress Gateway forwards the request to OAuth2-Proxy to verify if the request is authenticated properly
  19. OAuth2-Proxy responds back with a HTTP 200 OK response that contains the access token in “X-Auth-Request-Access-Token” header
  20. Ingress Gateway perform API Access control checks. It then forwards the request to upstream service with “X-Auth-Request-Access-Token” header in it.
  21. The upstream service serves the request.

References

👉 I tweet & blog regularly on Kubernetes and Cloud-Native Tech. Follow me on Twitter and Medium

👉 Check out kube-fledged, a kubernetes operator for creating and managing a cache of container images directly on the cluster worker nodes, so application pods start almost instantly

--

--

Senthil Raja Chermapandian

Principal SW Engineer @Ericsson | Architecting AI/ML Platforms | Cloud-Native Enthusiast | Maintainer: kube-fledged | Organizer: KCD Chennai