Files
computer-playbook/roles/web-app-semaphore/tasks/02_breakglass.yml
kevinveenbirkenbachandClaude Opus 5 ff73f66b21 fix(semaphore): carry the break-glass password into the app on every deploy
SEMAPHORE_ADMIN_PASSWORD resolves to the web-app-semaphore-breakglass user password, and the deploy hands it to Semaphore only when the account is first created. The swarm matrix rotates credentials between the sync and the async pass, and --except administrator exempts the literal user key 'administrator', not this one, so the async pass typed a password the app had never been told about. In run 33923190220 semaphore#1 failed with 'Incorrect login or password' after 15.6 minutes of onion-scaled retries.

The realign runs ungated by SSO: the break-glass account exists precisely for the case where the OIDC path is unavailable. Both account operations now share one stack-host block instead of repeating the condition.

Verified end to end against semaphore v2.19.12 on postgres: the CLI accepts --password as a non-interactive flag, change-by-login reports the user changed, the stored hash moves, and it then verifies against the rotated password and no longer against the seeded one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-09 00:05:09 +02:00

30 lines
1.3 KiB
YAML

---
- name: "🔍 Resolve {{ application_id }} hosting node + container id"
ansible.builtin.include_tasks: "{{ lookup('path_absolute', 'roles/sys-svc-compose/tasks/utils/swarm/resolve_host_cid.yml') }}"
vars:
resolve_service_key: semaphore
resolve_output_prefix: SEMAPHORE
resolve_compose_cid: "{{ SEMAPHORE_NAME }}"
- name: "⏳ Wait until the Semaphore API/DB is ready"
ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec {{ SEMAPHORE_LOCAL_CID | quote }}
semaphore user list
register: semaphore_breakglass_ready
changed_when: false
retries: 30
delay: 5
until: semaphore_breakglass_ready.rc == 0
delegate_to: "{{ SEMAPHORE_HOST_NODE }}"
- name: "🔑 Realign the break-glass administrator password"
ansible.builtin.shell: > # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec {{ SEMAPHORE_LOCAL_CID | quote }}
semaphore user change-by-login
--login {{ SEMAPHORE_ADMIN_USERNAME | quote }}
--password {{ SEMAPHORE_ADMIN_PASSWORD | quote }}
register: semaphore_breakglass_password
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
changed_when: semaphore_breakglass_password.rc == 0
delegate_to: "{{ SEMAPHORE_HOST_NODE }}"