feat(drawio,garage): optional Authentik ForwardAuth in front of UIs
Add `*_authentik_forward_auth` + `*_authentik_forward_auth_url` knobs to both roles. When enabled: * drawio: traefik attaches a ForwardAuth middleware pointing at the authentik embedded outpost; unauthenticated requests get redirected to log in and downstream sees X-Authentik-* identity headers. * garage WebUI: same ForwardAuth wiring, and `AUTH_USER_PASS` is dropped from the container env so authentik is the only gate. Tasks now key the htpasswd hash workflow off `_garage_webui_htpasswd_active` (`webui_enabled AND NOT authentik_forward_auth`); when authentik fronts the UI we skip hashing entirely. htpasswd hash is also now cached on disk and re-verified via `htpasswd -vbB` so unchanged passwords stop showing as `changed=true` on every run. Both knobs default to `false`, preserving existing htpasswd/plain behaviour.
This commit is contained in:
parent
da103a59f2
commit
c27584cd9c
5 changed files with 110 additions and 7 deletions
|
|
@ -17,4 +17,11 @@ drawio_extra_hosts: []
|
|||
|
||||
# Traefik configuration
|
||||
drawio_traefik_network: "proxy"
|
||||
drawio_use_ssl: true
|
||||
drawio_use_ssl: true
|
||||
|
||||
# Optional Authentik ForwardAuth (set to true and provide the URL to gate
|
||||
# drawio behind an authentik proxy provider). Expects the authentik
|
||||
# embedded outpost to expose the /outpost.goauthentik.io/auth/traefik
|
||||
# endpoint on the configured URL (typically the public auth.* FQDN).
|
||||
drawio_authentik_forward_auth: false
|
||||
drawio_authentik_forward_auth_url: ""
|
||||
|
|
@ -22,6 +22,15 @@ services:
|
|||
{% else %}
|
||||
- traefik.http.routers.{{ drawio_service_name }}.entrypoints=web
|
||||
{% endif %}
|
||||
{% if drawio_authentik_forward_auth | default(false) %}
|
||||
# ForwardAuth via the authentik embedded outpost. Unauthenticated
|
||||
# requests get redirected to authentik to log in; authentik then
|
||||
# sets X-Authentik-* headers traefik forwards downstream.
|
||||
- traefik.http.middlewares.{{ drawio_service_name }}-authentik.forwardauth.address={{ drawio_authentik_forward_auth_url }}
|
||||
- traefik.http.middlewares.{{ drawio_service_name }}-authentik.forwardauth.trustForwardHeader=true
|
||||
- traefik.http.middlewares.{{ drawio_service_name }}-authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version
|
||||
- traefik.http.routers.{{ drawio_service_name }}.middlewares={{ drawio_service_name }}-authentik
|
||||
{% endif %}
|
||||
|
||||
networks:
|
||||
{{ drawio_traefik_network }}:
|
||||
|
|
|
|||
|
|
@ -25,10 +25,20 @@ garage_webui_domain: "console.storage.local.test"
|
|||
garage_webui_enabled: true
|
||||
garage_webui_image: "khairul169/garage-webui:latest"
|
||||
garage_webui_port: 3909
|
||||
# WebUI basic auth credentials (plaintext, will be hashed automatically)
|
||||
# WebUI basic auth credentials (plaintext, will be hashed automatically).
|
||||
# Ignored when garage_webui_authentik_forward_auth is true — in that case
|
||||
# authentik handles authentication via the ForwardAuth middleware below.
|
||||
garage_webui_username: "admin"
|
||||
garage_webui_password: "admin"
|
||||
|
||||
# Optional Authentik ForwardAuth in front of the WebUI. When true:
|
||||
# - the AUTH_USER_PASS env-var is dropped from the container so htpasswd
|
||||
# isn't enforced; authentik is the only gate.
|
||||
# - traefik attaches a ForwardAuth middleware pointing at the URL below.
|
||||
# Leave false to keep classic htpasswd protection.
|
||||
garage_webui_authentik_forward_auth: false
|
||||
garage_webui_authentik_forward_auth_url: ""
|
||||
|
||||
# Garage ports
|
||||
garage_s3_api_port: 3900
|
||||
garage_s3_web_port: 3902
|
||||
|
|
|
|||
|
|
@ -26,12 +26,77 @@
|
|||
dest: "{{ garage_docker_compose_dir }}/garage.toml"
|
||||
mode: '0644'
|
||||
|
||||
- name: Generate bcrypt hash for webui password using htpasswd
|
||||
ansible.builtin.shell: |
|
||||
htpasswd -nbBC 10 "{{ garage_webui_username }}" "{{ garage_webui_password }}"
|
||||
register: _garage_webui_password_hash
|
||||
- name: Set webui htpasswd activation fact
|
||||
ansible.builtin.set_fact:
|
||||
# htpasswd only runs when the WebUI is enabled AND authentik ForwardAuth
|
||||
# is not handling authentication. When authentik is in front, the
|
||||
# compose template drops AUTH_USER_PASS so no hash is needed.
|
||||
_garage_webui_htpasswd_active: >-
|
||||
{{
|
||||
garage_webui_enabled
|
||||
and not (garage_webui_authentik_forward_auth | default(false))
|
||||
}}
|
||||
|
||||
- name: Read cached webui htpasswd hash
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ garage_docker_compose_dir }}/webui.htpasswd"
|
||||
register: _garage_webui_htpasswd_cached
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
when: garage_webui_enabled
|
||||
when: _garage_webui_htpasswd_active
|
||||
|
||||
- name: Verify cached webui htpasswd hash still matches password
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- htpasswd
|
||||
- -vbB
|
||||
- "{{ garage_docker_compose_dir }}/webui.htpasswd"
|
||||
- "{{ garage_webui_username }}"
|
||||
- "{{ garage_webui_password }}"
|
||||
register: _garage_webui_htpasswd_verify
|
||||
failed_when: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
when:
|
||||
- _garage_webui_htpasswd_active
|
||||
- _garage_webui_htpasswd_cached.content is defined
|
||||
|
||||
- name: Generate bcrypt hash for webui password using htpasswd
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- htpasswd
|
||||
- -nbBC
|
||||
- "10"
|
||||
- "{{ garage_webui_username }}"
|
||||
- "{{ garage_webui_password }}"
|
||||
register: _garage_webui_password_hash_new
|
||||
changed_when: true
|
||||
when:
|
||||
- _garage_webui_htpasswd_active
|
||||
- (_garage_webui_htpasswd_cached.content is not defined)
|
||||
or (_garage_webui_htpasswd_verify.rc | default(1) != 0)
|
||||
|
||||
- name: Persist webui htpasswd hash on disk
|
||||
ansible.builtin.copy:
|
||||
content: "{{ _garage_webui_password_hash_new.stdout }}\n"
|
||||
dest: "{{ garage_docker_compose_dir }}/webui.htpasswd"
|
||||
mode: '0600'
|
||||
when:
|
||||
- _garage_webui_htpasswd_active
|
||||
- _garage_webui_password_hash_new is changed
|
||||
|
||||
- name: Load current webui htpasswd hash
|
||||
ansible.builtin.slurp:
|
||||
src: "{{ garage_docker_compose_dir }}/webui.htpasswd"
|
||||
register: _garage_webui_htpasswd_current
|
||||
changed_when: false
|
||||
when: _garage_webui_htpasswd_active
|
||||
|
||||
- name: Expose current webui htpasswd hash to template
|
||||
ansible.builtin.set_fact:
|
||||
_garage_webui_password_hash:
|
||||
stdout: "{{ (_garage_webui_htpasswd_current.content | b64decode).strip() }}"
|
||||
when: _garage_webui_htpasswd_active
|
||||
|
||||
- name: Create docker-compose file for garage
|
||||
template:
|
||||
|
|
|
|||
|
|
@ -38,7 +38,9 @@ services:
|
|||
environment:
|
||||
API_BASE_URL: "http://{{ garage_service_name }}:{{ garage_admin_port }}"
|
||||
S3_ENDPOINT_URL: "http://{{ garage_service_name }}:{{ garage_s3_api_port }}"
|
||||
{% if not (garage_webui_authentik_forward_auth | default(false)) %}
|
||||
AUTH_USER_PASS: '{{ _garage_webui_password_hash.stdout | replace("$", "$$") }}'
|
||||
{% endif %}
|
||||
volumes:
|
||||
- {{ garage_docker_compose_dir }}/garage.toml:/etc/garage.toml:ro
|
||||
networks:
|
||||
|
|
@ -60,6 +62,16 @@ services:
|
|||
- traefik.http.routers.{{ garage_service_name }}-console.service={{ garage_service_name }}-console
|
||||
- traefik.http.routers.{{ garage_service_name }}-console.priority=10
|
||||
- traefik.http.services.{{ garage_service_name }}-console.loadbalancer.server.port={{ garage_webui_port }}
|
||||
{% if garage_webui_authentik_forward_auth | default(false) %}
|
||||
# ForwardAuth via the authentik embedded outpost. Unauthenticated
|
||||
# requests are redirected to authentik; authentik then forwards
|
||||
# X-Authentik-* identity headers downstream. htpasswd is disabled
|
||||
# in the env block above so authentik is the only gate.
|
||||
- traefik.http.middlewares.{{ garage_service_name }}-console-authentik.forwardauth.address={{ garage_webui_authentik_forward_auth_url }}
|
||||
- traefik.http.middlewares.{{ garage_service_name }}-console-authentik.forwardauth.trustForwardHeader=true
|
||||
- traefik.http.middlewares.{{ garage_service_name }}-console-authentik.forwardauth.authResponseHeaders=X-authentik-username,X-authentik-groups,X-authentik-entitlements,X-authentik-email,X-authentik-name,X-authentik-uid,X-authentik-jwt,X-authentik-meta-jwks,X-authentik-meta-outpost,X-authentik-meta-provider,X-authentik-meta-app,X-authentik-meta-version
|
||||
- traefik.http.routers.{{ garage_service_name }}-console.middlewares={{ garage_service_name }}-console-authentik
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
networks:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue