--- id: SCAN-20260909 type: scan-report status: active title: Codebase Scan 2026-09-09 created: 2026-09-09 updated: 2026-09-09 tags: [scan] related: [PROJECT, TECH-CODEBASE-MAP, TECH-ARCHITECTURE, ALERT-20260909-001, ALERT-20260909-002] source_paths: - README.md - AGENTS.md - ansible.cfg - bootstrap.yml - execute.sh - docker/ - inventory/ - playbooks/ - roles/ confidence: confirmed --- # Codebase Scan 2026-09-09 ## Scope Root configuration (`ansible.cfg`, `execute.sh`), Docker runtime (`docker/`), all inventories and group_vars, all 6 playbooks plus `bootstrap.yml`, and all 7 roles (`tasks/`, `defaults/`, `templates/`, `handlers/`). Git history inspected for inventory renames. Vault-encrypted files (`vault.yml`) were not decrypted. ## Confirmed Findings ### Project Shape - Central Ansible collection for provisioning, hardening, updating, and monitoring Debian hosts; 7 roles, 1 top-level playbook (`bootstrap.yml`) and 5 playbooks under `playbooks/`. - Execution environment: Docker image `ansible:deb13` built from `debian:trixie-slim` with `ansible-core~=2.20.6`; collections pinned in `docker/requirements.yml` (`ansible.posix` 2.2.0, `community.general` 13.0.1, `community.docker` 5.2.0, `community.zabbix` 4.2.0). - `execute.sh` creates an IPv6-enabled bridge network `ansible-dualstack`, starts an interactive container with the repo mounted at `/ansible` and an `ansible_ssh_keys` volume at `/root/.ssh`, injects SSH client config with host-key checking disabled, then attaches. - `ansible.cfg`: `host_key_checking = False`, `roles_path = ./roles`, `forks = 20`, `gathering = smart`, `internal_poll_interval = 0.001`, SSH pipelining and `ControlPersist=60s`, known hosts set to `/dev/null`. ### Playbooks - All playbooks run `hosts: all`, `user: admin`, `become: true`, and start with a Debian `os_family` guard that fails non-Debian hosts. - Exception: `playbooks/hardening/manage-ssh-keys.yml` has **no** Debian guard, no `become`, and no `vars_files`; it binds the `manage-ssh-keys` role directly. - `playbooks/monitoring.yml` loads `../vault.yml` via a playbook-relative path; other playbooks do not load vault.yml explicitly. - `playbooks/os-updates-deb.yml` chains `os-updates` then `healthcheck` (post-update quality gate). ### Roles - `bootstrap`: subtasks for basic packages, admin user (+sudo, authorized keys), MOTD, keyboard layout, OpenSSH install/config/keys, bashrc, sysctl; then composes the `docker` role (skippable via `skip_docker`) and the `monitoring` role (skippable via `skip_monitoring`). Tags: `motd`, `ssh`, `bashrc`, `sysctl`. - `docker`: official Docker apt repository + `docker-ce`, CLI, `containerd.io`, buildx and compose plugins; template `sources.list.j2`; codename derived from facts. - `os-updates`: optional mirror rewrite (`os_also_update_mirror`, deb822 + legacy templates, codename whitelist `trixie|bookworm|bullseye`), full apt upgrade, kernel-comparison reboot decision with async reboot + `wait_for_connection` (600s timeout), reboot **deferred** on hosts in the `proxmox` group unless `os_update_reboot_on_proxmox` is true, LXC hosts skip kernel/reboot logic; preflight/postflight logging delegated to the controller (`logs///update.log`). - `healthcheck`: compares `docker ps -a` vs running containers, writes a `quality_gate` section into the same update log, fails the play when `healthcheck_fail_on_unhealthy` is true (default false). - `monitoring`: Zabbix 7.0 release package from repo.zabbix.com, `zabbix-agent2`, Docker plugin config when socket exists, per-host PSK generated on the controller (persisted in `.zabbix-psk/.psk`, mode 0700, `openssl rand -hex 32`), deployed to `/etc/zabbix/ zabbix_agent2.psk` (0600), TLS connect/accept = PSK, and API host registration via `community.zabbix.zabbix_host` over httpapi with template union including `Docker by Zabbix agent 2` when the Docker socket is present. - `hawser`: requires existing Docker host + compose file at `/opt/hawser/docker-compose.yml`, re-renders it from template, then `docker_compose_v2` with `pull: always`. - `manage-ssh-keys`: ensures `~/.ssh` (0700), adds `good_keys`, removes `bad_keys` from the admin user's authorized keys. ### Inventories And Variables - `inventory/cloudlorean.yml` (untracked): site with groups `debian` (13 hosts, 192.168.212.0/24) and `proxmox` (`dmc12` 192.168.212.10, `pbs` 192.168.212.11); per-host `ssh_service_name: ssh` on `gitea` and `ipam`. - `inventory/home.yml`: site `home`, 6 Debian hosts + `tardis` (Proxmox), 10.13.37.0/24. - `inventory/external.yml`: 4 IPv6-only Debian hosts. - `inventory/dmc12.yml` is **deleted in the working tree but not committed** (`git status: D`); `inventory/cloudlorean.yml` and `inventory/group_vars/cloudlorean.yml` are untracked. Git history confirms `dmc12.yml` was added in `d2e8ce4` and never tracked as renamed. - group_vars per site override Zabbix servers, API URL (`https://mon.cloudlorean.de/api_jsonrpc.php`), proxy (`gatekeeper.cloudlorean.de` / `gatekeeper.meyer-kempen.de`), host groups and templates. `group_vars/debian.yml` hardcodes `os_update_version_codename: "trixie"` (AGENTS.md warns about this). - `admin_authorized_keys` and the SHA-512 `admin_password` hash appear in **plaintext** in `roles/bootstrap/defaults/main.yml` and `inventory/group_vars/external.yml` (see ALERT-20260909-001). - `vault.yml` is tracked but encrypted; `.vault_pass`, `setenv.sh`, `.zabbix-psk/`, `logs/` are git-ignored (verified via `git check-ignore`). ## Inferred Findings - The environment formerly called `dmc12` was renamed to `cloudlorean`; host `dmc12` is now a Proxmox node within the `cloudlorean` site (confidence: inferred from logs/.zabbix-psk paths and git status). - Operators appear to be "Niklas" and "Dennis" (SSH key comments in bootstrap defaults). Formal ownership not documented. - All sites share one Zabbix server (`mon.cloudlorean.de`) with optional per-site proxies (confidence: inferred from group_vars). - Home site is referred to as "Meyer-Kempen" in Zabbix host groups/proxy name (confidence: inferred). ## Unknowns - Whether `vault.yml` also defines `admin_password` (overriding the committed defaults hash) - vault not decrypted. - Whether `monitoring_zabbix_passive_servers` in `inventory/group_vars/external.yml` (`2a01:4f8:1c1e:62dd::1`, the `healthcheck` host's own address) is intentional (Zabbix server/proxy on that host) or a misconfiguration. - Which Docker template name exists on the Zabbix server: role default `Docker by Zabbix agent2` vs group_vars `Docker by Zabbix agent 2`. - Formal stakeholders and success criteria beyond the healthcheck gate. ## Important Paths - `bootstrap.yml`, `playbooks/*.yml` - entrypoints - `roles/bootstrap/`, `roles/docker/`, `roles/monitoring/`, `roles/os-updates/`, `roles/healthcheck/`, `roles/hawser/`, `roles/manage-ssh-keys/` - role implementations - `roles/*/README.md` - per-role documentation (documentation duty) - `inventory/*.yml`, `inventory/group_vars/*.yml` - host data - `docker/Dockerfile`, `docker/requirements.yml`, `execute.sh` - runtime - `vault.yml` (encrypted), `.vault_pass`, `setenv.sh`, `.zabbix-psk/`, `logs/` - secrets and audit artifacts (git-ignored except vault.yml) ## Suggested Wiki Updates - Populated during this scan: technical docs (architecture, codebase map, module docs, integrations, security, deployment, testing), requirement records, open questions reconciliation, alerts ALERT-20260909-001 / ALERT-20260909-002, traceability maps, indexes, REGISTRY.yml, STATUS.md.