Files
computer-playbook/roles/web-app-gitea/tasks/setup/oidc.yml
kevinveenbirkenbachandClaude Opus 5 b3ce43a596 fix(security): require no_log on every task that carries a credential
At -vvv Ansible prints each module argument and result, so a password in
a command line, a request body, a header or a fact lands in the deploy
log. Nothing enforced masking outside the MCP task files, and no check
looked at parents at all.

A new lint, test_credential_tasks_are_masked, finds tasks whose printed
parts (module arguments, environment, loop) reference an identifier ending
in password, secret, token, api_key or private_key, or
secrets.credentials. A task passes when it or an enclosing block sets
no_log, when every file that pulls it in does so through include_tasks
with apply.no_log or import_tasks with no_log (transitively), when the
secret only reaches a parameter the module masks itself, or when the
module masks its values. no_log on an include_tasks task itself does not
count, because it does not reach the included tasks. The rule can be
suppressed per task with `# nocheck: credential-masking`, now listed in
the suppression catalog, and the lint tests its parent and suppression
logic on synthetic cases.

It found 39 unmasked tasks in 19 roles, all real: join tokens, client
secrets, API tokens in Cloudflare headers, database passwords in
command lines, the ChatGPT bot login body and more. Each now sets
no_log from MASK_CREDENTIALS_IN_LOGS. The sys-dns-hetzner-rdns alias
hetzner_no_log, which only restated that switch, is gone.

Not covered yet: template and copy tasks whose rendered file carries a
secret print it as a diff under --diff.

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

50 lines
2.1 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
- name: "➕ Add Keycloak OIDC Provider"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i --user {{ GITEA_USER }} {{ GITEA_LOCAL_CID | quote }} \
gitea admin auth add-oauth \
--provider openidConnect \
--name "{{ OIDC.BUTTON_TEXT }}" \
--key "{{ OIDC.CLIENT.ID }}" \
--secret "{{ OIDC.CLIENT.SECRET }}" \
--auto-discover-url "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}" \
--scopes "openid profile email"
delegate_to: "{{ GITEA_HOST_NODE }}"
register: oidc_manage
failed_when: oidc_manage.rc != 0 and not (oidc_manage.stderr | gitea_auth_noop)
- name: "🔍 Lookup existing Keycloak auth source ID"
shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i --user {{ GITEA_USER }} {{ GITEA_LOCAL_CID | quote }} \
/app/gitea/gitea admin auth list \
| tail -n +2 \
| grep -F "{{ OIDC.BUTTON_TEXT }}" \
| awk '{print $1; exit}'
delegate_to: "{{ GITEA_HOST_NODE }}"
register: oidc_source_id_raw
failed_when:
- oidc_source_id_raw.rc != 0
- oidc_source_id_raw.stdout == ""
changed_when: false
- name: "🔧 Set Keycloak source ID fact"
set_fact:
oidc_source_id: "{{ oidc_source_id_raw.stdout }}"
- name: "🔄 Update Keycloak OIDC Provider"
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
shell: | # nocheck: container-exec-resolver runtime-resolved CID, delegated to the hosting node
container exec -i --user {{ GITEA_USER }} {{ GITEA_LOCAL_CID | quote }} \
gitea admin auth update-oauth \
--id {{ oidc_source_id }}\
--provider openidConnect \
--name "{{ OIDC.BUTTON_TEXT }}" \
--key "{{ OIDC.CLIENT.ID }}" \
--secret "{{ OIDC.CLIENT.SECRET }}" \
--auto-discover-url "{{ OIDC.CLIENT.DISCOVERY_DOCUMENT }}" \
--scopes "openid profile email"
delegate_to: "{{ GITEA_HOST_NODE }}"
register: oidc_manage
failed_when: oidc_manage.rc != 0