Implement Oauth2 Proxy on Kubernetes
Sometimes, we may want to add authentication features to our service running on Kubernetes, but the application itself does not include authentication capabilities.
Fortunately, there is a third-party application that we can use to address this issue, called oauth2-proxy.
Oauth2-proxy is a third-party application that we can use as centralized authentication for other services in Kubernetes.
Oauth2-proxy is a reverse proxy and static file server that provides authentication using Providers (Google, Keycloak, GitHub and others) to validate accounts by email, domain or group.
![](https://rjhaikal.my.id/content/images/2024/03/image-35.png)
Requirements
- Kubernetes Cluster v1.18+
- Public Domain for oauth2-proxy ingress
- Nginx Ingress Controller
- Helm Installed
- Cert Manager for TLS Ingress
Diagram
![](https://rjhaikal.my.id/content/images/2024/03/diagram.png)
![](https://rjhaikal.my.id/content/images/2024/03/image-36.png)
Preparation
The public domains I've set up as example are oauth.rjhaikal.my.id for oauth2-proxy and code.rjhaikal.my.id for the app.
You can also see how I deploy the applications used in this example on the following blog.
![](https://rjhaikal.my.id/content/images/2023/12/ihor-dvoretskyi-GCFuprAvC6A-unsplash-1.jpg)
Setup Azure AD
1. Register an application
![](https://rjhaikal.my.id/content/images/2024/03/image-37.png)
Update the redirect URI to your suit your domain and protocol.
https://<yourdomain>/oauth2/callback
![](https://rjhaikal.my.id/content/images/2024/03/image-38.png)
Once your application is created take a note of the Application (client) ID on the overview page. We will need this later.
![](https://rjhaikal.my.id/content/images/2024/03/image-39.png)
Within our application registration we will also need to create a client secret to be used to identify our application. We could also use a certificate for higher assurance however for this example a secret will suffice.
![](https://rjhaikal.my.id/content/images/2024/03/image-40.png)
Save this secret, and denote the following information under the 'Overview' Tab for later
- Secret Key
- App (Client) ID
- Directory (Tenant) ID
Setup Redis
1. Create namespace
kubectl create ns rj-oauth2
2. Add Redis repo
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
3. edit values
vim values.yml
---
global:
storageClass: <your storageclass>
redis:
password: "YourSecurePassword!"
helm install redis bitnami/redis --values=values.yml -n rj-oauth2
export REDIS_PASSWORD=$(kubectl get secret --namespace rj-oauth2 redis -o jsonpath="{.data.redis-password}" | base64 --decode)
Oauth2 Proxy Installation
1. Collate and Deploy Secrets
dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64 | tr -d -- '\n' | tr -- '+/' '-_'; echo
SGEOwUnlydJJGWG3YYcrxLUscUdv00Cg4Jb_ewcvAx4=
export COOKIE_SECRET="SGEOwUnlydJJGWG3YYcrxLUscUdv00Cg4Jb_ewcvAx4="
export AZURE_TENANT_ID="yyyyyyyyyyyyyyy"
export AZURE_CLIENT_ID="xxxxxxxxxxxxxxx"
export AZURE_CLIENT_SECRET="zzzzzzzzzzzzzz"
kubectl create secret generic oauth2-proxy-creds -n rj-oauth2 \
--from-literal=cookie-secret="$COOKIE_SECRET" \
--from-literal=azure-tenant="$AZURE_TENANT_ID" \
--from-literal=client-id="$AZURE_CLIENT_ID" \
--from-literal=client-secret="$AZURE_CLIENT_SECRET"
2. Install Oauth2 Proxy
vim oauth2-proxy.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
application: oauth2-proxy
name: oauth2-proxy
namespace: rj-oauth2
spec:
replicas: 1
selector:
matchLabels:
application: oauth2-proxy
template:
metadata:
labels:
application: oauth2-proxy
spec:
containers:
- args:
- --provider=azure
- --azure-tenant=<tenant-id> # Microsoft Entra ID OAuth2 Proxy application Tenant ID
- --pass-access-token=true
- --cookie-name=_proxycookie # this can be any name of your choice which you would like OAuth2 Proxy to use for the session cookie
- --email-domain=*
- --upstream=file:///dev/null
- --http-address=0.0.0.0:4180
- --oidc-issuer-url=https://login.microsoftonline.com/<tenant-id>/v2.0
- --whitelist-domain=.rjhaikal.my.id
- --cookie-domain=.rjhaikal.my.id
- --cookie-secure=false
- --cookie-csrf-per-request=true
- --cookie-csrf-expire=5m
- --redirect-url=https://oauth.rjhaikal.my.id/oauth2/callback
- --session-store-type=redis
- --reverse-proxy=true
- --redis-connection-url=redis://redis-master.rj-oauth2.svc.cluster.local:6379
- --redis-password=<redis-password>
name: oauth2-proxy
image: quay.io/oauth2-proxy/oauth2-proxy:v7.5.1
imagePullPolicy: Always
env:
- name: OAUTH2_PROXY_CLIENT_ID # keep this name - it's required to be defined like this by OAuth2 Proxy
valueFrom:
secretKeyRef:
name: oauth2-proxy-creds
key: client-id
- name: OAUTH2_PROXY_CLIENT_SECRET # keep this name - it's required to be defined like this by OAuth2 Proxy
valueFrom:
secretKeyRef:
name: oauth2-proxy-creds
key: client-secret
- name: OAUTH2_PROXY_COOKIE_SECRET # keep this name - it's required to be defined like this by OAuth2 Proxy
valueFrom:
secretKeyRef:
name: oauth2-proxy-creds
key: cookie-secret
ports:
- containerPort: 4180
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
labels:
application: oauth2-proxy
name: oauth2-proxy-svc
namespace: rj-oauth2
spec:
ports:
- name: http
port: 4180
protocol: TCP
targetPort: 4180
selector:
application: oauth2-proxy
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/proxy-body-size: "2000m"
nginx.ingress.kubernetes.io/proxy-buffer-size: "32k"
name: oauth2-proxy-ingress
namespace: rj-oauth2
spec:
ingressClassName: nginx
tls:
- hosts:
- 'oauth.rjhaikal.my.id'
secretName: rjhaikal.my.id
rules:
- host: oauth.rjhaikal.my.id
http:
paths:
- path: /oauth2
pathType: Prefix
backend:
service:
name: oauth2-proxy-svc
port:
number: 4180
Reconfigure Code Server (Application)
Changing the authentication to "none" because I will be using External Authentication.
sudo vim /home/code-user/.config/code-server/config.yaml
---
bind-addr: 127.0.0.1:8080
auth: none # change to this
password: [REDACTED]
cert: false
sudo systemctl restart [email protected]
Add OAuth2 Proxy annotations for Code Server Ingress
This service will depend on oauth2-proxy. If a user accesses the ingress of this service, the service will redirect the user's request to oauth2-proxy to check whether the user has been authenticated or not.
1. Add proper OAuth2 Proxy annotations to Code Server Ingress
cat<<EOF | kubectl replace -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: letsencrypt
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/auth-url: "https://oauth.rjhaikal.my.id/oauth2/auth" # <- Add this
nginx.ingress.kubernetes.io/auth-signin: "https://oauth.rjhaikal.my.id/oauth2/start" # <- Add this
name: rj-codeserver-ingress
spec:
ingressClassName: nginx
rules:
- host: code.rjhaikal.my.id
http:
paths:
- backend:
service:
name: rj-codeserver-service
port:
number: 8080
path: /
pathType: Prefix
tls:
- hosts:
- 'code.rjhaikal.my.id'
secretName: code-rjhaikal-secret
EOF
Try accessing code.rjhaikal.my.id and ensure that the request is redirected to oauth.rjhaikal.my.id, then further redirected to Azure AD. After login, it should be redirected back to code.rjhaikal.my.id.
![](https://rjhaikal.my.id/content/images/2024/03/image-41.png)
![](https://rjhaikal.my.id/content/images/2024/03/image-42.png)
Member discussion