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:
Simon Bärlocher 2026-05-26 14:03:38 +02:00
parent 6411f94cce
commit ce50bdb4d3
No known key found for this signature in database
GPG key ID: 63DE20495932047A
5 changed files with 110 additions and 7 deletions

View file

@ -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: