From 08e92ca3b8ee6c38c3e19126378e51b46cf63b16 Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Mon, 11 Aug 2025 18:39:55 -0700 Subject: Oauth proxy and monitoring init --- .../traefik/templates/stacks/docker-compose.yml | 100 ++++++++++++++++++--- .../roles/traefik/templates/stacks/traefik.yml | 17 ++-- .../templates/volumes/oauth2proxy/oauth_proxy.cfg | 26 ++++++ .../volumes/oauth2proxy/oauth_proxy_alpha.yml | 75 ++++++++++++++++ .../volumes/oauth2proxy/templates/error.html | 96 ++++++++++++++++++++ .../volumes/oauth2proxy/templates/sign_in.html | 72 +++++++++++++++ .../roles/traefik/templates/volumes/redis/.gitkeep | 0 7 files changed, 367 insertions(+), 19 deletions(-) create mode 100644 playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy.cfg create mode 100644 playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy_alpha.yml create mode 100644 playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/error.html create mode 100644 playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/sign_in.html create mode 100644 playbooks/roles/traefik/templates/volumes/redis/.gitkeep (limited to 'playbooks/roles/traefik/templates') diff --git a/playbooks/roles/traefik/templates/stacks/docker-compose.yml b/playbooks/roles/traefik/templates/stacks/docker-compose.yml index 6362b31..46f5503 100644 --- a/playbooks/roles/traefik/templates/stacks/docker-compose.yml +++ b/playbooks/roles/traefik/templates/stacks/docker-compose.yml @@ -15,7 +15,7 @@ services: timeout: 5s retries: 10 volumes: - - {{ traefik_base }}/volumes/headscale:/var/lib/tailscale + - "{{ traefik_base }}/volumes/headscale:/var/lib/tailscale" - /dev/net/tun:/dev/net/tun cap_add: - NET_ADMIN @@ -53,10 +53,12 @@ services: - CF_DNS_API_TOKEN={{ cloudflare_dns_api_token }} volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - - {{ traefik_base }}/stacks/traefik.yml:/traefik.yml - - {{ traefik_base }}/volumes/certs:/certs + - "{{ traefik_base }}/stacks/traefik.yml:/traefik.yml" + - "{{ traefik_base }}/volumes/certs:/certs" networks: + - metrics - proxy + - oauth_proxy - headnet deploy: mode: global @@ -66,21 +68,91 @@ services: failure_action: rollback monitor: 2s # go go go. labels: - - traefik.enable=true - - traefik.http.routers.dashboard.rule=Host(`{{ traefik_domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`)) - - traefik.http.routers.dashboard.service=api@internal - - traefik.http.routers.dashboard.tls=true - - traefik.http.routers.dashboard.tls.certresolver=letsencrypt - - traefik.http.routers.ping.rule=Host(`{{ traefik_domain }}`) && PathPrefix(`/ping`) - - traefik.http.routers.ping.service=ping@internal - - traefik.http.routers.ping.tls=true - - traefik.http.routers.ping.tls.certresolver=letsencrypt - - traefik.http.services.dashboard.loadbalancer.server.port=8080 - - traefik.http.services.ping.loadbalancer.server.port=8080 + - "traefik.enable=true" + - "traefik.http.routers.dashboard.rule=Host(`{{ traefik_domain }}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))" + - "traefik.http.routers.dashboard.service=api@internal" + - "traefik.http.routers.dashboard.tls=true" + - "traefik.http.routers.dashboard.tls.certresolver=letsencrypt" + - "traefik.http.services.dashboard.loadbalancer.server.port=8080" + - "traefik.http.routers.ping.rule=Host(`{{ traefik_domain }}`) && PathPrefix(`/ping`)" + - "traefik.http.routers.ping.service=ping@internal" + - "traefik.http.routers.ping.tls=true" + - "traefik.http.routers.ping.tls.certresolver=letsencrypt" + - "traefik.http.services.ping.loadbalancer.server.port=8080" + + - "traefik.http.middlewares.auth-headers.headers.stsSeconds=315360000" + - "traefik.http.middlewares.auth-headers.headers.browserXssFilter=true" + - "traefik.http.middlewares.auth-headers.headers.contentTypeNosniff=true" + - "traefik.http.middlewares.auth-headers.headers.forceSTSHeader=true" + - "traefik.http.middlewares.auth-headers.headers.stsIncludeSubdomains=true" + - "traefik.http.middlewares.auth-headers.headers.stsPreload=true" + - "traefik.http.middlewares.auth-headers.headers.frameDeny=true" + + - "traefik.http.middlewares.oauth-verify.forwardAuth.address=http://oauth2-proxy:4180" + - "traefik.http.middlewares.oauth-verify.forwardAuth.trustForwardHeader=true" + - "traefik.http.middlewares.oauth-verify.forwardAuth.authResponseHeaders={{ forwardauth_headers }}" + + - "traefik.http.middlewares.oauth-verify-noredirect.forwardAuth.address=http://oauth2-proxy:4180/oauth2/auth" + - "traefik.http.middlewares.oauth-verify-noredirect.forwardAuth.trustForwardHeader=true" + - "traefik.http.middlewares.oauth-verify-noredirect.forwardAuth.authResponseHeaders={{ forwardauth_headers }}" + + oauth2-proxy: + image: quay.io/oauth2-proxy/oauth2-proxy:latest + command: --alpha-config /conf/oauth_proxy_alpha.yml --config /conf/oauth_proxy.cfg + volumes: + - "{{ traefik_base }}/volumes/oauth2proxy:/conf" + environment: + - TZ={{ timezone }} + - DEPLOYMENT_TIME={{ deployment_time }} + networks: + - oauth_cache + - proxy + - oauth_proxy + - metrics + deploy: + mode: replicated + update_config: + parallelism: 1 + failure_action: rollback + order: start-first + delay: 5s + replicas: 1 + labels: + "traefik.enable": "true" + "traefik.swarm.network": "proxy" + "traefik.http.routers.fwdauth.tls": "true" + "traefik.http.routers.fwdauth.tls.certResolver": "letsencrypt" + "traefik.http.routers.fwdauth.rule": "!Host(`{{ idm_domain }}`) && (PathPrefix(`/oauth2`) || Host(`{{ oauth_proxy_domain }}`))" + "traefik.http.routers.fwdauth.entrypoints": "websecure" + "traefik.http.routers.fwdauth.middlewares": "auth-headers" + "traefik.http.services.fwdauth.loadbalancer.server.port": "4180" + oauth2-cache: + image: redis:8-alpine + restart: always + command: redis-server --save 20 1 --loglevel warning + volumes: + - "{{ traefik_base }}/volumes/redis:/data" + environment: + - TZ={{ timezone }} + - DEPLOYMENT_TIME={{ deployment_time }} + networks: + - oauth_cache + deploy: + mode: replicated + update_config: + parallelism: 1 + failure_action: rollback + order: start-first + delay: 5s + replicas: 1 networks: + metrics: + external: true proxy: name: proxy driver: overlay attachable: true + oauth_proxy: + oauth_cache: headnet: diff --git a/playbooks/roles/traefik/templates/stacks/traefik.yml b/playbooks/roles/traefik/templates/stacks/traefik.yml index 09588b3..68235e4 100644 --- a/playbooks/roles/traefik/templates/stacks/traefik.yml +++ b/playbooks/roles/traefik/templates/stacks/traefik.yml @@ -1,12 +1,18 @@ ping: {} -accessLog: {} +accessLog: + format: "json" log: - level: INFO + level: info +metrics: + prometheus: + entryPoint: metrics api: dashboard: true - insecure: true - debug: true + insecure: false + debug: false entryPoints: + metrics: + address: ":5577" web: address: ":80" forwardedHeaders: @@ -41,4 +47,5 @@ certificatesResolvers: # caServer: https://acme-staging-v02.api.letsencrypt.org/directory # staging dnsChallenge: provider: cloudflare - delayBeforeCheck: 10 + propagation: + delayBeforeChecks: 12s diff --git a/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy.cfg b/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy.cfg new file mode 100644 index 0000000..3c412de --- /dev/null +++ b/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy.cfg @@ -0,0 +1,26 @@ +## OAuth2 Proxy Config File + +request_logging = true +email_domains = "*" +reverse_proxy = true +redirect_url = "https://{{ oauth_proxy_domain }}/oauth2/callback" +real_client_ip_header = "X-Forwarded-For" +trusted_ips = "{{ homelab_network }}" + +## Cookie Settings +cookie_name = "_oauth2_proxy" +cookie_secret = "{{ oauth_proxy_cookie_secret }}" +cookie_domains = [".{{ domain }}", "{{ domain }}"] +whitelist_domains = [".{{ domain }}", "{{ domain }}"] +cookie_expire = "24h" +cookie_refresh = "1h" +cookie_secure = true +session_store_type = "redis" +redis_connection_url = "redis://oauth2-cache" + +## Templating + +banner = "-" +footer = "-" +custom_sign_in_logo="-" +custom_templates_dir="/conf/templates" diff --git a/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy_alpha.yml b/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy_alpha.yml new file mode 100644 index 0000000..0f1b1ab --- /dev/null +++ b/playbooks/roles/traefik/templates/volumes/oauth2proxy/oauth_proxy_alpha.yml @@ -0,0 +1,75 @@ +injectRequestHeaders: +- name: X-Forwarded-User + values: + - claim: user +- name: X-Forwarded-Email + values: + - claim: email +- name: X-Forwarded-Preferred-Username + values: + - claim: preferred_username +- name: X-Forwarded-Groups + values: + - claim: groups +- name: Authorization + values: + - claim: id_token + prefix: 'Bearer ' +- name: "X-Forwarded-{{ oauth_proxy_super_secret_header }}" + values: + - value: "{{ oauth_proxy_super_secret_header | b64encode }}" +injectResponseHeaders: +- name: X-Auth-Request-User + values: + - claim: user +- name: X-Auth-Request-Email + values: + - claim: email +- name: X-Auth-Request-Preferred-Username + values: + - claim: preferred_username +- name: X-Auth-Request-Groups + values: + - claim: groups +- name: "X-Auth-Request-{{ oauth_proxy_super_secret_header }}" + values: + - value: "{{ oauth_proxy_super_secret_header | b64encode }}" +- name: Authorization + values: + - claim: id_token + prefix: 'Bearer ' +metricsServer: + BindAddress: 0.0.0.0:5577 + SecureBindAddress: "" + TLS: null +providers: +- id: kanidm + name: "{{ domain }} <3" + provider: oidc + clientID: "{{ oauth_proxy_client_id }}" + clientSecret: "{{ oauth_proxy_client_secret }}" + allowedGroups: + - "{{ oauth_proxy_group }}" + code_challenge_method: "S256" + scope: "openid profile groups email" + oidcConfig: + issuerURL: "https://{{ idm_domain }}/oauth2/openid/{{ oauth_proxy_client_id }}" + insecureSkipNonce: false + insecureAllowUnverifiedEmail: false + extraAudiences: + - "{{ oauth_proxy_client_id }}" + audienceClaims: + - aud + userIDClaim: sub + emailClaim: email + groupsClaim: groups +server: + BindAddress: 0.0.0.0:4180 + SecureBindAddress: "" + TLS: null +upstreamConfig: + upstreams: + - id: "traefik" + static: true + path: "/" + staticCode: 202 diff --git a/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/error.html b/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/error.html new file mode 100644 index 0000000..d202d83 --- /dev/null +++ b/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/error.html @@ -0,0 +1,96 @@ +{{ '{{' }}define "error.html"{{ '}}' }} + + + + + + + {{ '{{' }} .StatusCode {{ '}}' }} {{ '{{' }} .Title {{ '}}' }} + + + +
+
{{ '{{' }} .StatusCode {{ '}}' }}
+
{{ '{{' }} .Title {{ '}}' }}
+ {{ '{{' }} if or .Message .RequestID {{ '}}' }} +
+ {{ '{{' }} if .Message {{ '}}' }} + {{ '{{' }} .Message {{ '}}' }} + {{ '{{' }} end {{ '}}' }} + {{ '{{' }} if .RequestID {{ '}}' }} + Request ID: {{ '{{' }} .RequestID {{ '}}' }} + {{ '{{' }} end {{ '}}' }} +
+ {{ '{{' }} end {{ '}}' }} + {{ '{{' }} if .Redirect {{ '}}' }} +
+ +
+ {{ '{{' }} end {{ '}}' }} +
+ + +{{ '{{' }}end{{ '}}' }} diff --git a/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/sign_in.html b/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/sign_in.html new file mode 100644 index 0000000..17d3718 --- /dev/null +++ b/playbooks/roles/traefik/templates/volumes/oauth2proxy/templates/sign_in.html @@ -0,0 +1,72 @@ +{{ '{{' }}define "sign_in.html"{{ '}}' }} + + + + + + + Sign In + + + +
+ +
+ + {{ '{{' }} if .SignInMessage {{ '}}' }} +

{{ '{{' }} .SignInMessage {{ '}}' }}

+ {{ '{{' }} end {{ '}}' }} + +
+
+ + +{{ '{{' }}end{{ '}}' }} diff --git a/playbooks/roles/traefik/templates/volumes/redis/.gitkeep b/playbooks/roles/traefik/templates/volumes/redis/.gitkeep new file mode 100644 index 0000000..e69de29 -- cgit v1.2.3-70-g09d2