heimdall icon indicating copy to clipboard operation
heimdall copied to clipboard

Document decision mode & oauth2-proxy integration

Open aslafy-z opened this issue 1 year ago • 1 comments

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.

aslafy-z avatar Feb 21 '25 17:02 aslafy-z

Awesome! Thank you very much! Looking forward to see that in the docs ;)

dadrus avatar Feb 21 '25 17:02 dadrus