Document decision mode & oauth2-proxy integration
https://dadrus.github.io/heimdall/v0.15.6/guides/authn/oidc_first_party_auth/ guide works nicely but only shows an integration with the proxy mode.
Here's a integration with the decision mode, demonstrated with nginx auth_request:
# docker-compose.yaml
services:
proxy:
image: nginx:latest
ports:
- "8888:8080"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
links:
- heimdall
- upstream
heimdall:
image: dadrus/heimdall:0.15.6
command: -c /etc/heimdall/config.yaml serve decision
volumes:
- ./heimdall-config.yaml:/etc/heimdall/config.yaml:ro
- ./rules:/etc/heimdall/rules:ro
- ./signer.pem:/etc/heimdall/signer.pem:ro
upstream:
image: containous/whoami:latest
command: --port=8081
oauth2-proxy:
depends_on:
- keycloak
image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0-amd64
command:
- --http-address
- 0.0.0.0:4180
ports:
- "4180:4180"
environment:
OAUTH2_PROXY_CLIENT_ID: placeholder
OAUTH2_PROXY_CLIENT_SECRET: placeholder
OAUTH2_PROXY_REDIRECT_URL: http://127.0.0.1:4180/oauth2/callback
OAUTH2_PROXY_PROVIDER: keycloak-oidc
OAUTH2_PROXY_SKIP_PROVIDER_BUTTON: true
OAUTH2_PROXY_COOKIE_SECRET: VerySecure!!!!!!
OAUTH2_PROXY_COOKIE_NAME: SESSION
OAUTH2_PROXY_WHITELIST_DOMAINS: 127.0.0.1:8888
OAUTH2_PROXY_OIDC_ISSUER_URL: http://keycloak:8080/realms/test
OAUTH2_PROXY_INSECURE_OIDC_ALLOW_UNVERIFIED_EMAIL: true
OAUTH2_PROXY_EMAIL_DOMAINS: '*'
OAUTH2_PROXY_OIDC_EXTRA_AUDIENCES: account
OAUTH2_PROXY_LOGIN_URL: http://127.0.0.1:8080/realms/test/protocol/openid-connect/auth
OAUTH2_PROXY_OIDC_JWKS_URL: http://keycloak:8080/realms/test/protocol/openid-connect/certs
OAUTH2_PROXY_REDEEM_URL: http://keycloak:8080/realms/test/protocol/openid-connect/token
OAUTH2_PROXY_INSECURE_OIDC_SKIP_ISSUER_VERIFICATION: true
OAUTH2_PROXY_SKIP_OIDC_DISCOVERY: true
OAUTH2_PROXY_SESSION_COOKIE_MINIMAL: true
keycloak:
image: quay.io/keycloak/keycloak:25.0.4
command: [ "start-dev", "--http-port", "8080" ]
ports:
- "8080:8080"
environment:
KC_HOSTNAME: 127.0.0.1
KC_HOSTNAME_PORT: 8080
KC_HOSTNAME_STRICT_BACKCHANNEL: "true"
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_HEALTH_ENABLED: "true"
KC_LOG_LEVEL: info
KC_DB_URL_HOST: postgresql
KC_DB: postgres
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
depends_on:
- postgresql
postgresql:
image: postgres:13.11
volumes:
- type: volume
source: postgres-db
target: /var/lib/postgresql/data
read_only: false
- ./initdb:/docker-entrypoint-initdb.d
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
volumes:
postgres-db:
# heimdall-config.yaml
log:
level: debug
tracing:
enabled: false
metrics:
enabled: false
mechanisms:
authenticators:
- id: deny_all
type: unauthorized
- id: anon
type: anonymous
- id: auth
type: generic
config:
identity_info_endpoint: http://oauth2-proxy:4180/oauth2/userinfo
authentication_data_source:
- cookie: SESSION
forward_cookies:
- SESSION
subject:
id: "user"
authorizers:
- id: cel
type: cel
config:
expressions:
- expression: "true == false"
finalizers:
- id: create_jwt
type: jwt
config:
signer:
key_store:
path: /etc/heimdall/signer.pem
claims: |
{{- dict "attrs" .Subject.Attributes | toJson -}}
- id: noop
type: noop
default_rule:
execute:
- authenticator: deny_all
- finalizer: create_jwt
providers:
file_system:
src: /etc/heimdall/rules
watch: true
# rules/upstream-rules.yaml
version: "1alpha4"
rules:
- id: upstream:public
match:
routes:
- path: /
- path: /favicon.ico
execute:
- authenticator: anon
- finalizer: noop
- id: upstream:protected
match:
routes:
- path: /user
- path: /admin
execute:
- authenticator: auth
- authorizer: cel
if: Request.URL.Path == '/admin'
config:
expressions:
- expression: |
has(Subject.Attributes.groups) &&
"role:admin" in Subject.Attributes.groups
message: User is not admin
- finalizer: create_jwt
# nginx.conf
events {
worker_connections 4096;
}
http {
upstream heimdall {
server heimdall:4456;
}
upstream upstream {
server upstream:8081;
}
server {
listen 8080;
location /_auth {
internal;
proxy_pass http://heimdall$request_uri;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Forwarded-Method $request_method;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Cookie $http_cookie;
}
location @error401 {
return 302 http://127.0.0.1:4180/oauth2/start?rd=$scheme://$http_host$request_uri;
}
location / {
auth_request /_auth;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
auth_request_set $auth_header_authorization $upstream_http_authorization;
proxy_set_header Authorization $auth_header_authorization;
proxy_set_header Proxy "";
error_page 401 = @error401;
proxy_pass http://upstream;
}
}
}
Almost the same keycloak initialization steps and files than listed in this guide https://dadrus.github.io/heimdall/v0.15.6/guides/authn/oidc_first_party_auth/ are needed, changes are the following:
- oauth2-proxy instead of heimdall endpoint has to be referenced in the Keycloak client Home URL: http://127.0.0.1:4180/
- oauth2-proxy has to be referenced in the Keycloak client Redirect URLs: http://127.0.0.1:4180/oauth2/callback
Note that this implementation sets OAUTH2_PROXY_SESSION_COOKIE_MINIMAL: true to overcome issue explained at #2204.
I may find some time to create a guide page for this model, storing this here in case someone is looking for it in the meantime.
Awesome! Thank you very much! Looking forward to see that in the docs ;)