# Edge proxy for the whole server. Deployed first by deploy/deploy.sh, which # exports TRAEFIK_CONFIG_HASH from the release's ARTIFACTS file. # # Any stack joins by attaching a service to the external network "proxy" and # setting traefik.* labels; apps without their own login can add the "sso" # middleware (Keycloak client petrolyst, role checked by oauth2-proxy). name: traefik services: socket-proxy: image: tecnativa/docker-socket-proxy:v0.5.0 environment: CONTAINERS: "1" EVENTS: "1" PING: "1" VERSION: "1" POST: "0" LOG_LEVEL: warning volumes: - /var/run/docker.sock:/var/run/docker.sock:ro networks: - socket restart: unless-stopped mem_limit: 64m traefik: image: traefik:v3.7.16 command: ["--configFile=/etc/traefik/static/traefik.yml"] ports: - "80:80" - "443:443" # Folders, not single files: promotion replaces files by renaming, which a # single-file bind mount would not follow. volumes: - ./static:/etc/traefik/static:ro - ./dynamic:/etc/traefik/dynamic:ro - letsencrypt:/letsencrypt depends_on: - socket-proxy networks: - proxy - socket restart: unless-stopped mem_limit: 256m healthcheck: test: ["CMD", "traefik", "healthcheck", "--configFile=/etc/traefik/static/traefik.yml"] interval: 10s timeout: 5s retries: 6 labels: petrolyst.config-hash: ${TRAEFIK_CONFIG_HASH:?TRAEFIK_CONFIG_HASH unset - run through deploy/deploy.sh} traefik.enable: "true" traefik.http.routers.dashboard.rule: Host(`${TRAEFIK_HOST:-traefik.petrolyst.com}`) traefik.http.routers.dashboard.entrypoints: websecure traefik.http.routers.dashboard.tls.certresolver: le traefik.http.routers.dashboard.service: api@internal # secure-headers first: sso answers unauthenticated requests itself, and # middlewares after it never see that response. traefik.http.routers.dashboard.middlewares: secure-headers@file,sso # Keycloak gate for the dashboard host only (cookie, return hosts and # role are tied to it; README "Adding a project"): unauthenticated # requests are sent to Keycloak, users without petrolyst:traefik-admin # get 403. traefik.http.middlewares.sso.forwardauth.address: http://oauth2-proxy:4180/ traefik.http.middlewares.sso.forwardauth.trustForwardHeader: "true" traefik.http.middlewares.sso.forwardauth.authResponseHeaders: X-Auth-Request-User,X-Auth-Request-Email oauth2-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.15.5 command: - --provider=keycloak-oidc - --oidc-issuer-url=${KEYCLOAK_REALM_URL:-https://iam.thedigitalbridge.io/realms/petrolyst} - --client-id=petrolyst - --client-secret-file=/run/secrets/keycloak_petrolyst_client_secret - --cookie-secret-file=/run/secrets/oauth2_proxy_cookie_secret - --code-challenge-method=S256 - --allowed-role=petrolyst:traefik-admin # Required by oauth2-proxy at startup; access is decided by the role above. - --email-domain=* - --redirect-url=https://${TRAEFIK_HOST:-traefik.petrolyst.com}/oauth2/callback - --whitelist-domain=${TRAEFIK_HOST:-traefik.petrolyst.com} - --cookie-domain=${TRAEFIK_HOST:-traefik.petrolyst.com} - --cookie-secure=true - --cookie-samesite=lax - --reverse-proxy=true - --upstream=static://202 - --skip-provider-button=true - --set-xauthrequest=true - --http-address=0.0.0.0:4180 secrets: - keycloak_petrolyst_client_secret - oauth2_proxy_cookie_secret networks: - proxy restart: unless-stopped mem_limit: 128m labels: traefik.enable: "true" traefik.docker.network: proxy traefik.http.routers.oauth2.rule: Host(`${TRAEFIK_HOST:-traefik.petrolyst.com}`) && PathPrefix(`/oauth2/`) traefik.http.routers.oauth2.entrypoints: websecure traefik.http.routers.oauth2.tls.certresolver: le traefik.http.routers.oauth2.middlewares: secure-headers@file traefik.http.services.oauth2.loadbalancer.server.port: "4180" networks: proxy: external: true socket: internal: true volumes: letsencrypt: secrets: keycloak_petrolyst_client_secret: file: ${PETROLYST_ROOT:-/opt/petrolyst}/secrets/shared/keycloak_petrolyst_realm_client_secret oauth2_proxy_cookie_secret: file: ${PETROLYST_ROOT:-/opt/petrolyst}/secrets/traefik/oauth2_proxy_cookie_secret