How to Set Up Oauth2 Proxy for Central Authentication in Kubernetes with Gitlab

Oauth2 Proxy is a reverse proxy and static file server that provides authentication using Providers (Google, GitHub, and others) to validate accounts by email, domain or group.

In this post, we will learn how to set up one central OAuth2 Proxy as authentication proxy for multiple services inside your Kubernetes Cluster. We will use Gitlab OpenID Connect application as our identity provider.

This is how oauth2-proxy works:

  • Any request passing through the proxy (and not matched by --skip-auth-regex) is checked for the proxy’s session cookie (--cookie-name) (or, if allowed, a JWT token - see --skip-jwt-bearer-tokens).
  • If authentication is required but missing then the user is asked to log in and redirected to the authentication provider (unless it is an Ajax request, i.e. one with Accept: application/json, in which case 401 Unauthorized is returned)
  • After returning from the authentication provider, the oauth tokens are stored in the configured session store (cookie, redis, …) and a cookie is set
  • The request is forwarded to the upstream server with added user info and authentication headers (depending on the configuration)

Kubernetes Ingress external authentication is a mechanism that enables authentication for incoming requests to services deployed within a Kubernetes cluster through an Ingress controller. It allows you to enforce authentication before granting access to your applications, providing an additional layer of security and control.

Benefits of using Kubernetes Ingress external authentication:

  • Centralized Authentication: With external authentication, you can centralize the authentication logic for multiple services deployed within your Kubernetes cluster. This eliminates the need for individual authentication mechanisms for each service.
  • Flexible Authentication Providers: Kubernetes Ingress supports various authentication providers, including OAuth2 providers like Google, GitHub, or OpenID Connect providers. This flexibility allows you to leverage existing authentication systems or choose the one that best suits your needs.
  • Simplified User Experience: External authentication allows users to authenticate using their existing credentials from well-known providers. This simplifies the user experience, as users don’t need to create new accounts or remember additional usernames and passwords.
  • Centralized Management and Configuration: Ingress controllers provide a centralized point for managing and configuring external authentication rules for all the services within your cluster. This simplifies the management and ensures consistency across your applications.
  • Integration with Existing Identity Providers: If you already have an identity provider or authentication system in place, Kubernetes Ingress external authentication allows you to integrate seamlessly with it, leveraging your existing user management infrastructure.

# Configure a GitLab OpenID Application as identity provider

Before doing anything else, you need to create a GitLab OpenID Connect application.

GitLab includes support for allowing other applications to authenticate users via OpenID connect

You can create a new application by opening the Applications dashboard in the Admin Area or the Profile preferences section.. From there, click on the New Application button, You will be prompted to provide an application name, a redirect URI, and to set the applications permissions. As you do, keep in mind:

  • name is an application label for your reference
  • redirect_uri is the endpoint to which GitLab should send users after they have authenticated, and should be of the form https://<my-cloud-application-url>/oauth2/callback
  • Scopes define what level of access the application will have to the GitLab user profile. For most applications, you will want to check openid, profile, and email.

Once done, please take note of the Application ID and Secret they are important for future steps:

Next, we need to generate a Cookie Secret for NGINX. The cookie secret is used by NGINX as a seed string to generate secure cookies, which are used by NGINX to identify users who are interacting with the gateway.

The code in the listing below can be used to generate a Base64 encoded string that will serve as the --cookie-secret option for the proxy.

1
python -c 'import os,base64; print(base64.b64encode(os.urandom(16)).decode("ascii"))'

# Installing oauth2-proxy

We will use the official helm chart found here https://github.com/oauth2-proxy/manifests to install the proxy. We will need to do some customization to the helm chart, so let’s create a values file with the following content:

Open values file with your prefered text editor, I am using vim.

1
vim values.yaml

Then add the following content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
config:
  clientID: "YourClientID"
 clientSecret: "YourClientSecret"
 cookieSecret: "GenerateMe"

configFile: |-
   provider = "gitlab"
   provider_display_name = "whatever"
   redirect_url = "https://oauth.citizix.com/oauth2/callback" # the same as in Gitlab !!!
   login_url = "https://gitlab.com/oauth/authorize"
   redeem_url="https://gitlab.com/oauth/token"
   oidc_jwks_url="https://gitlab.com/oauth/discovery/keys"
   validate_url="https://gitlab.com/api/v4/user"
   cookie_refresh=0
   cookie_secure=true
   oidc_issuer_url="https://gitlab.com"
   set_xauthrequest=true
   pass_host_header=true
   pass_user_headers=true
   request_logging=true   

extraArgs:
 whitelist-domain: ".citizix.com"
 upstream: "file:///dev/null"
 cookie-domain: ".citizix.com"
 email-domain: "*"
 gitlab-group: ""
 cookie-name: "chocolate-cookie"

ingress:
  enabled: true
  path: /
  hosts:
    - oauth.citizix.com
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod-issuer
  tls:
    - secretName: oauth-tls-cert
      hosts:
        - oauth.citizix.com

In the above yaml, we are defining an ingress that will dictate how we access the oauth2-proxy. In my case I am defining a domain oauth.citizix.com and I have nginx ingress set up and a cert manager with the issuer letsencrypt-prod-issuer for tls.

As the OAuth2 Proxy documentation explains how to set up the different authentication providers, I will focus on the Ingress setup here.

To install, use this helm command:

First add the oauth2-proxy repository:

1
2
helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
helm repo update

To know which version of oauth2-proxy are present, you can search:

1
2
3
4

$ helm search repo oauth2-proxy
NAME                     	CHART VERSION	APP VERSION	DESCRIPTION
oauth2-proxy/oauth2-proxy	6.16.1       	7.4.0      	A reverse proxy that provides authentication wi...

In my case, the latest version is 6.16.1, let us install this version:

1
2
3
4
5
6
7
helm upgrade -i oauth2-proxy oauth2-proxy/oauth2-proxy \
    --create-namespace \
    -n oauth2-proxy \
    --version 6.16.1 \
    --wait \
    --timeout 300s \
    -f values.yaml

Once the install is successful, you should confirm using this command:

1
2
3
$ helm ls
NAME        	NAMESPACE   	REVISION	UPDATED                             	STATUS  	CHART              	APP VERSION
oauth2-proxy	oauth2-proxy	2       	2023-09-04 22:45:05.504429 +0300 EAT	deployed	oauth2-proxy-6.16.1	7.4.0

Also confirm that the pod is running

1
2
3
$ k get po
NAME                            READY   STATUS    RESTARTS   AGE
oauth2-proxy-6ffbcb85d7-mqcdq   1/1     Running   0          9h

If you are a fan of IaC and you can use helmfile to define the installation. Create a file called helmfile.yaml with the following content:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
helmDefaults:
  createNamespace: true
  wait: false
  timeout: 300

repositories:
- name: oauth2-proxy
  url: https://oauth2-proxy.github.io/manifests

releases:
- name: oauth2-proxy
  namespace: oauth2-proxy
  chart: oauth2-proxy/oauth2-proxy
  version: 6.16.1
  values:
  - ./values.yaml

Then you can apply using this command:

1
helmfile sync oauth2-proxy

The above values result in this Ingress object:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod-issuer
    kubernetes.io/ingress.class: nginx
  generation: 1
  labels:
    app: oauth2-proxy
    app.kubernetes.io/component: authentication-proxy
    app.kubernetes.io/instance: oauth2-proxy
    app.kubernetes.io/name: oauth2-proxy
    app.kubernetes.io/part-of: oauth2-proxy
  name: oauth2-proxy
  namespace: oauth2-proxy
spec:
  rules:
  - host: oauth.citizix.com
    http:
      paths:
      - backend:
          service:
            name: oauth2-proxy
            port:
              number: 80
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - oauth.citizix.com
    secretName: oauth-tls-cert

This Ingress will handle all authentication request as we will see in the next Ingress definition.

For services that you want to secure, add the below annotations to the Ingress:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/auth-signin: https://oauth.citizix.com/oauth2/start
    nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.auth-namespace.svc.cluster.local/oauth2/auth
  name: alertmanager
spec:
  rules:
  - host: alertmanager.citizix.com
    http:
      paths:
      - backend:
          serviceName: alertmanager
          servicePort: 9093
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - alertmanager.citizix.com
    secretName: tls-cert

Try to enter alertmanager.citizix.com in browser. You should see Gitlab auth page.

Please note the annotations:

1
2
nginx.ingress.kubernetes.io/auth-signin: https://oauth.citizix.com/oauth2/start
nginx.ingress.kubernetes.io/auth-url: http://oauth2-proxy.auth-namespace.svc.cluster.local/oauth2/auth

The auth-sigin redirects any needed login to the OAuth2 Proxy Ingress. The auth-url annotation can access the OAuth2 Proxy internally via its service to verify a submitted token.

The OAuth2 Proxy will handle the authentication and later redirect you to the protected service again.

An additional advantage of this setup is, that you only need to specify one valid redirect URL in your OIDC client. OAuth2 Proxy will handle the service specific redirects.

# Conclusion

In this guide, we learnt how to secure multiple services with just one central OAuth2 Proxy. I hope this helps you to reduce the complexity of how you handle authentication within your system.

Oauth2 Proxy is useful when you want:

  • One or more of your applications to be accessible only by authenticated users, for instance, users using a specific domain, emails whitelisting, and more
  • To rely on a third-party provider to handle the authentication process (Google, GitHub, etc.)
  • To keep a clear separation between the authentication service and the rest of your applications
comments powered by Disqus
Citizix Ltd
Built with Hugo
Theme Stack designed by Jimmy