Open
Description
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.