Accessing using Identity-Aware Proxies
You can put Headlamp behind an identity-aware proxy (IAP) such as Pomerium, oauth2-proxy, or Google Cloud IAP. Headlamp then trusts the user information in the proxy headers and bypasses its login screen.
The proxy must inject the correct headers and must be the only network path to Headlamp. Headlamp does not maintain a separate proxy-authentication session. It reads the headers in each request.
Important: the trusted proxy or ingress must strip, reject, or overwrite any incoming client-supplied identity headers before forwarding the request to Headlamp. This includes the default X-Forwarded-* headers as well as any custom headers configured with -proxy-auth-username-header, -proxy-auth-group-header, -proxy-auth-email-header, or -proxy-auth-token-header. Otherwise, a client could spoof these headers and impersonate another user if Headlamp is reachable without that protection at the edge.
Configuration
To enable identity-aware proxy authentication, set the following argument or environment variable on the Headlamp server:
-proxy-auth=trueor env varHEADLAMP_CONFIG_PROXY_AUTH=true
By default, Headlamp expects the proxy to pass the authenticated username in the X-Forwarded-User header. When Headlamp finds a valid username, the UI treats the request as authenticated and bypasses the login screen.
You can customize the headers Headlamp looks for using the following flags:
-proxy-auth-username-header: Header name for the username (default:X-Forwarded-User)-proxy-auth-group-header: Header name for the user's groups (default:X-Forwarded-Group)-proxy-auth-email-header: Header name for the user's email (default:X-Forwarded-Email)-proxy-auth-token-header: Header name for the user's token (default:X-Forwarded-Id-Token)
Kubernetes API server authentication
The proxy handles user identification for the UI, but Headlamp still needs credentials for the Kubernetes API server. If all proxy-authenticated users can share one Kubernetes identity, enable config.unsafeUseServiceAccountToken in the Helm values. Headlamp then uses its pod's service account for every user. Bind that account to the smallest suitable role.
If users need separate Kubernetes permissions, configure the proxy to provide a token that the Kubernetes API server accepts. Do not enable the shared service account option in that mode.
To forward the proxy token instead, specify the header that contains the raw token:
-proxy-auth-token-header: Header name containing the raw token only (default:X-Forwarded-Id-Token). Do not include theBearerprefix in the header value. If set, Headlamp will extract the token and send it asAuthorization: Bearer <token>for requests to the Kubernetes API server.
Examples
The following examples show how to configure identity-aware proxy authentication with Traefik and oauth2-proxy, followed by Pomerium.
Example: Traefik and oauth2-proxy Middleware
A common pattern in Kubernetes is to use an Ingress Controller like Traefik alongside oauth2-proxy as an authentication middleware (ForwardAuth).
In this setup:
- A user attempts to access Headlamp via Traefik.
- Traefik sends the request to
oauth2-proxyfor authentication. oauth2-proxyauthenticates the user with your designated Identity Provider (OIDC, GitHub, Google, etc.).oauth2-proxyreturns a successful response to Traefik, injecting headers likeX-Forwarded-UserandX-Forwarded-Email.- Traefik forwards the original request, along with the injected user headers, to Headlamp.
- Headlamp reads
X-Forwarded-User, logs the user in, and serves the UI.
1. Deploy OAuth2Proxy via Helm
Add the Helm repo:
helm repo add oauth2-proxy https://oauth2-proxy.github.io/manifests
helm repo update
Prepare your values.yaml
Below is an example configuration you can start with. Be sure to replace placeholders like <Client-ID>, <Client-Secret>, <Tenant-ID>, etc.
config:
configFile: |-
email_domains = ["*"]
cookie_secret = <Cookie-Secret>
alphaConfig:
enabled: true
configData:
injectResponseHeaders:
- name: Authorization
values:
- claim: access_token
prefix: 'Bearer '
- name: X-Forwarded-Id-Token
values:
- claimSource:
claim: id_token
- name: X-Forwarded-Email
values:
- claimSource:
claim: email
- name: X-Forwarded-Group
values:
- claimSource:
claim: groups
providers:
- id: entra
provider: oidc
clientID: "<clientid>"
clientSecret: "<clientsecret>"
loginURL: "https://login.microsoftonline.com/<tenantid>/oauth2/authorize"
redeemURL: "https://login.microsoftonline.com/<tenantid>/oauth2/token"
scope: "openid email profile"
oidcConfig:
issuerURL: "https://sts.windows.net/<tenantid>/"
jwksURL: "https://login.microsoftonline.com/<tenantid>/discovery/keys?appid=<clientid>"
insecureAllowUnverifiedEmail: true
skipDiscovery: true
emailClaim: upn
audienceClaims:
- aud
extraArgs:
redirect-url: "https://oauth.example.com/oauth2/callback"
reverse-proxy: "true"
cookie-secure: "true"
cookie-samesite: "lax"
cookie-domain: ".example.com"
whitelist-domain: ".example.com"
Deploy OAuth2Proxy:
helm install my-release oauth2-proxy/oauth2-proxy -f values.yaml
Verify it's up:
kubectl get pods
2. Configure Traefik ForwardAuth
Create a Traefik Middleware and Ingress that points to your oauth2-proxy service, ensuring it forwards the authentication headers:
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: headlamp-proxy-auth
namespace: oauth2-proxy
spec:
forwardAuth:
address: http://oauth2-proxy.auth-namespace.svc.cluster.local:4180/oauth2/auth
trustForwardHeader: true
authResponseHeaders:
- X-Forwarded-User
- X-Forwarded-Email
- X-Forwarded-Group
- X-Forwarded-Id-Token
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: headlamp-error-redir
namespace: oauth2-proxy
spec:
errors:
# 401 is what the ForwardAuth middleware returns when not logged in
status:
- "401-403"
# This sends the user to the login start page and preserves their original URL
query: "/oauth2/sign_in?rd=https://headlamp.example.com{url}"
service:
name: oauth2-proxy
port: 80
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: auth-headers
namespace: oauth2-proxy
spec:
headers:
sslRedirect: true
stsSeconds: 315360000
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
sslHost: example.com
stsIncludeSubdomains: true
stsPreload: true
frameDeny: true
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: oauth2-proxy-auth-headers@kubernetescrd
name: headlamp-oauth2
namespace: oauth2-proxy
spec:
ingressClassName: traefik-mgmt-blue
rules:
- host: headlamp.example.com
http:
paths:
- backend:
service:
name: oauth2-proxy
port:
number: 80
path: /oauth2/
pathType: Prefix
3. Configure Headlamp Ingress and Deployment
Attach the middleware to your Headlamp IngressRoute and ensure the Headlamp deployment has -proxy-auth=true enabled:
# Headlamp IngressRoute
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: web
traefik.ingress.kubernetes.io/router.middlewares: oauth2-proxy-headlamp-error-redir@kubernetescrd,oauth2-proxy-headlamp-proxy-auth@kubernetescrd
name: headlamp
namespace: kube-system
spec:
ingressClassName: traefik
rules:
- host: headlamp.example.com
http:
paths:
- backend:
service:
name: headlamp
port:
number: 80
4. Deploy Headlamp with the proxy-auth flag enabled:
# Headlamp Helm Values (values.yaml)
config:
extraArgs:
- "-proxy-auth=true"
Example: Pomerium
This example uses Pomerium Core for Kubernetes as the ingress controller. Pomerium forwards the authenticated user's email to Headlamp. Headlamp uses its service account for read-only Kubernetes access.
1. Configure the identity header
Add a JWT claim header to the global Pomerium resource. Keep the other settings from your existing Pomerium configuration.
apiVersion: ingress.pomerium.io/v1
kind: Pomerium
metadata:
name: global
spec:
jwtClaimHeaders:
X-Pomerium-Claim-Email: email
# Keep your existing secrets, certificate, and identity provider settings.
The route-level pass_identity_headers setting in the next step forwards this header. Pomerium replaces inbound X-Pomerium-* headers with the authenticated user's values.
2. Configure Headlamp
Create a Helm values file. Replace the host, TLS secret, and authorization policy for your environment.
config:
inCluster: true
unsafeUseServiceAccountToken: true
extraArgs:
- -proxy-auth=true
- -proxy-auth-username-header=X-Pomerium-Claim-Email
- -proxy-auth-email-header=X-Pomerium-Claim-Email
clusterRoleBinding:
# Replace "view" with a custom ClusterRole if Headlamp needs other permissions.
clusterRoleName: view
ingress:
enabled: true
ingressClassName: pomerium
annotations:
ingress.pomerium.io/allow_any_authenticated_user: "true"
ingress.pomerium.io/pass_identity_headers: "true"
hosts:
- host: headlamp.example.com
paths:
- path: /
type: Prefix
tls:
- secretName: headlamp-tls
hosts:
- headlamp.example.com
Before enabling proxy authentication, apply a NetworkPolicy that selects the Headlamp pods and allows inbound traffic only from the Pomerium proxy pods. Your cluster's CNI must enforce NetworkPolicy. A ClusterIP Service alone does not block other pods from reaching Headlamp, forging the unsigned identity header, and using its shared service account permissions.
Install or update Headlamp with the values file:
helm upgrade --install headlamp headlamp/headlamp \
--namespace kube-system \
--values values.yaml
Verify that access through Pomerium succeeds and that other pods cannot reach Headlamp through either its Service or pod IP. Use a narrower Pomerium policy when only specific users or groups should reach Headlamp.