- replace inventory/dmc12.yml with cloudlorean.yml (+ group_vars) and update all README/AGENTS call examples and the inventory table - move admin_password hash into encrypted vault.yml; remove plaintext copies from roles/bootstrap/defaults and group_vars/external.yml - bootstrap.yml loads vault.yml via vars_files (same pattern as monitoring) - monitoring: PSK config/registration updates, docker role defaults, os-updates logging/reboot refinements, ansible.cfg/execute.sh tweaks - add .project-wiki knowledge base and .github agent instructions
83 lines
3.3 KiB
Markdown
83 lines
3.3 KiB
Markdown
---
|
|
id: ALERT-20260909-001
|
|
type: alert
|
|
status: resolved
|
|
severity: high
|
|
title: Plaintext admin password hash committed outside vault
|
|
created: 2026-09-09
|
|
updated: 2026-09-09
|
|
resolved: 2026-09-09
|
|
tags: [alert, security, secrets]
|
|
related: [NFR-002, OQ-006, TECH-SECURITY]
|
|
source_paths:
|
|
- roles/bootstrap/defaults/main.yml
|
|
- inventory/group_vars/external.yml
|
|
- README.md
|
|
confidence: confirmed
|
|
---
|
|
|
|
# ALERT-20260909-001 - Plaintext admin password hash committed outside vault
|
|
|
|
## Summary
|
|
|
|
The SHA-512 hash of the admin password (`admin_password`) is committed in
|
|
plaintext in `roles/bootstrap/defaults/main.yml` and
|
|
`inventory/group_vars/external.yml`, while the root README states that
|
|
`admin_password` lives encrypted in `vault.yml`. The documented secret
|
|
policy (AGENTS.md, README "Beitragen") forbids plaintext secrets in
|
|
`defaults/` or `group_vars/`. The same hash is reused across both locations.
|
|
|
|
## Why It Matters
|
|
|
|
- A committed password hash allows offline guessing of the shared admin
|
|
password; reusing one hash across hosts amplifies the impact.
|
|
- It contradicts the project's own documented vault policy and misleads
|
|
contributors (README claims the value is vaulted).
|
|
|
|
## Evidence
|
|
|
|
- `roles/bootstrap/defaults/main.yml` lines 12-13 (`admin_password` hash)
|
|
- `inventory/group_vars/external.yml` lines 10-11 (same hash)
|
|
- `README.md` "Secrets & Vault" section claims `admin_password` is in
|
|
`vault.yml`
|
|
- AGENTS.md "Secrets": no plaintext secrets in `defaults/`/`group_vars/`
|
|
|
|
## Suggested Resolution
|
|
|
|
Move `admin_password` to `vault.yml` in both locations; keep no plaintext
|
|
fallback in role defaults. If a default is truly needed for bootstrap,
|
|
document it explicitly as an accepted risk and set a unique hash per site.
|
|
Verify whether `vault.yml` already overrides it (OQ-006).
|
|
|
|
## Resolution
|
|
|
|
Resolved 2026-09-09. OQ-006 was verified first: decrypting `vault.yml`
|
|
confirmed it did **not** define `admin_password` (no override existed), so the
|
|
committed hash was a policy violation, not an intended fallback. Fix applied:
|
|
|
|
- `admin_password` (SHA-512 hash) moved into encrypted `vault.yml`.
|
|
- Plaintext hash removed from `roles/bootstrap/defaults/main.yml` and
|
|
`inventory/group_vars/external.yml` (comment now points to `vault.yml`).
|
|
- `bootstrap.yml` loads `vault.yml` via `vars_files` (same pattern as
|
|
`playbooks/monitoring.yml`), so the bootstrap role still resolves the
|
|
variable for every inventory.
|
|
- Documentation updated: root `README.md` "Secrets & Vault" and
|
|
`roles/bootstrap/README.md` (variable now documented as vault-sourced).
|
|
- NFR-002 acceptance notes and evidence updated accordingly.
|
|
|
|
Remaining recommendation (hardening, not blocking): the same hash is still
|
|
shared across sites; rotating to a unique hash per site would remove the
|
|
single shared credential.
|
|
|
|
## Resolution Evidence
|
|
|
|
- `ansible-vault view vault.yml` (decrypted during resolution) now lists
|
|
`admin_password` among `PROXMOX_USER_NAME`, `PROXMOX_USER_PASS`,
|
|
`monitoring_zabbix_api_password`.
|
|
- Repository-wide search for the former hash string (salt fragment) returns
|
|
no matches - the hash exists only inside the encrypted vault file.
|
|
- `ansible-playbook --syntax-check bootstrap.yml` passes (with
|
|
`--vault-password-file .vault_pass`).
|
|
- `rg -n "admin_password"` shows the variable now only in `vault.yml`
|
|
(encrypted) and consumed at `roles/bootstrap/tasks/create-admin-user.yml:9`.
|