Compare commits

...
2 Commits
Author SHA1 Message Date
DerLinkman ceda1ae4a6 record alert resolution commit in wiki evidence 2026-09-09 14:14:43 +02:00
DerLinkman 30f3e9a4c6 rename dmc12 inventory to cloudlorean and vault admin_password
- 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
2026-09-09 14:14:18 +02:00
96 changed files with 3603 additions and 138 deletions
+13
View File
@@ -0,0 +1,13 @@
# Copilot Instructions
Repository-specific conventions live in `AGENTS.md` at the repository root.
<!-- PROJECT-WIKI:BEGIN -->
## Project Wiki (Automatic Instructions)
- Before implementing, modifying, debugging, refactoring, testing, documenting, or planning code, read `.project-wiki/INDEX.md` and follow its routing to the smallest relevant set of wiki documents (automatic context preflight).
- After making source changes, update the affected `.project-wiki/` records (technical docs, traceability maps, section indexes, `REGISTRY.yml`, `STATUS.md`) as part of the same task.
- Use the wiki `sync` mode only for manual or externally changed code; agent-made changes are updated directly (automatic post-implementation wiki update).
- After every meaningful wiki edit, reconcile affected indexes, `REGISTRY.yml`, `STATUS.md`, traceability, and append an entry to `.project-wiki/logs/wiki-log-YYYY-MM.md`.
- Write all wiki content and generated instruction blocks in English; reply to the user in their chat language.
<!-- PROJECT-WIKI:END -->
+2 -1
View File
@@ -4,4 +4,5 @@ proxmox.*
.vault_pass
logs
.zabbix-psk
setenv.sh
setenv.sh
.agents
+17
View File
@@ -0,0 +1,17 @@
---
id: GLOSSARY
type: note
status: placeholder
title: Glossary
created: '2026-09-09'
updated: '2026-09-09'
tags:
- glossary
related: []
source_paths: []
confidence: unknown
---
# Glossary
No project-specific terms have been captured yet.
+48
View File
@@ -0,0 +1,48 @@
# Project Wiki Index
This wiki stores the project knowledge base for requirements, changes, technical documentation, implementation state, and traceability. Use this file as the routing entrypoint; open only the linked files needed for the current task.
Last updated: 2026-09-09
## Current State
- Status: [STATUS.md](./STATUS.md)
- Project brief: [PROJECT.md](./PROJECT.md)
- Registry: [REGISTRY.yml](./REGISTRY.yml)
## Task Routing
| Task | Start Here |
| --- | --- |
| Understand project goals | [PROJECT.md](./PROJECT.md), [requirements/INDEX.md](./requirements/INDEX.md) |
| Work with requirements | [requirements/INDEX.md](./requirements/INDEX.md), [traceability/requirement-map.md](./traceability/requirement-map.md) |
| Process meeting notes or new docs | [changes/INDEX.md](./changes/INDEX.md), [implementation/INDEX.md](./implementation/INDEX.md) |
| Process external requirements document | [sources/INDEX.md](./sources/INDEX.md), [intake/INDEX.md](./intake/INDEX.md), [changes/INDEX.md](./changes/INDEX.md), [requirements/INDEX.md](./requirements/INDEX.md) |
| Review active alerts | [alerts/INDEX.md](./alerts/INDEX.md), [STATUS.md](./STATUS.md) |
| Review durable analyses | [analysis/INDEX.md](./analysis/INDEX.md) |
| Run wiki maintenance lint | [maintenance/INDEX.md](./maintenance/INDEX.md) |
| Analyze change impact | [changes/CHANGELOG.md](./changes/CHANGELOG.md), [traceability/change-impact-map.md](./traceability/change-impact-map.md) |
| Modify code | [technical/codebase-map.md](./technical/codebase-map.md), [traceability/code-map.md](./traceability/code-map.md) |
| Work on architecture | [technical/architecture.md](./technical/architecture.md), [changes/decisions/](./changes/decisions/) |
| Work on APIs | [technical/api/](./technical/api/) |
| Work on data | [technical/data/](./technical/data/) |
| Work on tests | [technical/testing.md](./technical/testing.md) |
| Work on deployment | [technical/deployment.md](./technical/deployment.md) |
| Work on security | [technical/security.md](./technical/security.md) |
| Review active work | [implementation/current-plan.md](./implementation/current-plan.md), [implementation/work-items/](./implementation/work-items/) |
| Sync manual code changes | [technical/codebase-map.md](./technical/codebase-map.md), [traceability/code-map.md](./traceability/code-map.md), [implementation/scans/](./implementation/scans/) |
| Review wiki audit history | [logs/INDEX.md](./logs/INDEX.md) |
## Sections
- [Requirements](./requirements/INDEX.md)
- [Changes](./changes/INDEX.md)
- [Technical Documentation](./technical/INDEX.md)
- [Implementation](./implementation/INDEX.md)
- [Traceability](./traceability/INDEX.md)
- [Analysis](./analysis/INDEX.md)
- [Maintenance](./maintenance/INDEX.md)
- [Alerts](./alerts/INDEX.md)
- [Sources](./sources/INDEX.md)
- [Document Intake](./intake/INDEX.md)
- [Wiki Audit Log](./logs/INDEX.md)
+66
View File
@@ -0,0 +1,66 @@
---
id: PROJECT
type: project
status: active
title: Project Overview
created: '2026-09-09'
updated: '2026-09-09'
tags:
- project
- ansible
- infrastructure
related:
- PRODUCT-BRIEF
- CONSTRAINTS
source_paths:
- AGENTS.md
- README.md
confidence: confirmed
---
# Project Overview
## Name
`ansible-playbooks` - central Ansible collection for Debian host management.
## Goal
Provide a single, reusable Ansible repository to provision, harden, update,
and monitor Debian hosts in a consistent, documented, and repeatable way.
## Domain
Infrastructure automation and IT operations:
- Target hosts are Debian systems, partially running as LXC containers on
Proxmox.
- Execution happens in a controlled Docker runtime environment
(`execute.sh`, `docker/`).
- Secrets are managed via Ansible Vault (`vault.yml`, git-ignored `.vault_pass`).
## Roles (building blocks)
| Role | Purpose |
|--------------------|----------------------------------------------------------------|
| `bootstrap` | Initial setup: packages, admin user, SSH, MOTD, sysctl, Docker, monitoring |
| `docker` | Docker Engine installation from the official repository |
| `hawser` | Update of the Hawser Docker Compose stack |
| `healthcheck` | Quality gate: verify running containers after updates |
| `manage-ssh-keys` | SSH key management (hardening) |
| `monitoring` | Zabbix Agent 2: installation, TLS-PSK, Docker plugin, API registration |
| `os-updates` | Debian package updates with mirror switch, reboot, and logging |
## Constraints
See [Constraints](./requirements/constraints.md). Key points: Debian-only
playbooks, LXC-aware skips for `sysctl`/`reboot`, mandatory documentation of
every change, FQCN module usage, secrets never committed in plain text.
## Stakeholders
Not explicitly documented yet. See [STATUS.md](./STATUS.md) open questions.
## Success Criteria
Not explicitly documented yet. See [STATUS.md](./STATUS.md) open questions.
+364
View File
@@ -0,0 +1,364 @@
version: 1
updated: '2026-09-09'
documents:
- id: GLOSSARY
type: note
title: Glossary
path: GLOSSARY.md
status: placeholder
tags:
- glossary
related: []
source_paths: []
confidence: unknown
- id: PROJECT
type: project
title: Project Overview
path: PROJECT.md
status: active
tags:
- project
- ansible
- infrastructure
related:
- PRODUCT-BRIEF
- CONSTRAINTS
source_paths:
- AGENTS.md
- README.md
confidence: confirmed
- id: CURRENT-PLAN
type: note
title: Current Plan
path: implementation/current-plan.md
status: placeholder
tags:
- implementation
- plan
related: []
source_paths: []
confidence: unknown
- id: SCAN-20260909
type: scan-report
title: Codebase Scan 2026-09-09
path: implementation/scans/scan-20260909.md
status: active
tags:
- scan
related:
- PROJECT
- TECH-CODEBASE-MAP
- ALERT-20260909-001
- ALERT-20260909-002
source_paths:
- README.md
- roles/
- playbooks/
- inventory/
- docker/
confidence: confirmed
- id: CONSTRAINTS
type: note
title: Constraints
path: requirements/constraints.md
status: active
tags:
- requirements
- constraints
related:
- PROJECT
source_paths:
- AGENTS.md
confidence: confirmed
- id: OPEN-QUESTIONS
type: note
title: Open Questions
path: requirements/open-questions.md
status: active
tags:
- requirements
- open-questions
related:
- SCAN-20260909
- ALERT-20260909-001
- ALERT-20260909-002
source_paths:
- AGENTS.md
- README.md
- inventory/group_vars/external.yml
confidence: confirmed
- id: PRODUCT-BRIEF
type: note
title: Product Brief
path: requirements/product-brief.md
status: placeholder
tags:
- requirements
- product
related: []
source_paths: []
confidence: unknown
- id: REQ-FUNC-HOST-LIFECYCLE
type: requirements
title: Host Lifecycle Operations
path: requirements/functional/host-lifecycle-operations.md
status: active
tags:
- requirements
- functional
related:
- PROJECT
- CONSTRAINTS
source_paths:
- README.md
- AGENTS.md
confidence: confirmed
- id: NFR-OPERATIONAL-POLICIES
type: requirements
title: Operational Policies
path: requirements/non-functional/operational-policies.md
status: active
tags:
- requirements
- non-functional
related:
- PROJECT
- CONSTRAINTS
source_paths:
- README.md
- AGENTS.md
confidence: confirmed
- id: TECH-ARCHITECTURE
type: technical
title: Architecture
path: technical/architecture.md
status: active
tags:
- technical
- architecture
- ansible
related:
- TECH-CODEBASE-MAP
- TECH-DEPLOYMENT
source_paths:
- ansible.cfg
- execute.sh
- roles/
confidence: confirmed
- id: TECH-CODEBASE-MAP
type: technical
title: Codebase Map
path: technical/codebase-map.md
status: active
tags:
- technical
- codebase
related:
- TECH-ARCHITECTURE
source_paths:
- roles/
- playbooks/
- inventory/
confidence: confirmed
- id: TECH-DEPLOYMENT
type: technical
title: Deployment
path: technical/deployment.md
status: active
tags:
- technical
- deployment
- docker
related:
- TECH-ARCHITECTURE
source_paths:
- execute.sh
- docker/
confidence: confirmed
- id: TECH-SECURITY
type: technical
title: Security
path: technical/security.md
status: active
tags:
- technical
- security
related:
- ALERT-20260909-001
- NFR-002
source_paths:
- vault.yml
- roles/bootstrap/defaults/main.yml
- ansible.cfg
confidence: confirmed
- id: TECH-TESTING
type: technical
title: Testing
path: technical/testing.md
status: active
tags:
- technical
- testing
related:
- MOD-005
source_paths: []
confidence: confirmed
- id: TECH-INTEGRATIONS-ZABBIX
type: technical
title: Integrations - Zabbix
path: technical/integrations/zabbix.md
status: active
tags:
- technical
- integration
- zabbix
related:
- MOD-003
source_paths:
- roles/monitoring/
- inventory/group_vars/
confidence: confirmed
- id: MOD-001
type: module
title: Bootstrap Role
path: technical/modules/MOD-001-bootstrap-role.md
status: active
tags:
- module
- bootstrap
related:
- MOD-002
- MOD-003
- REQ-001
source_paths:
- roles/bootstrap/
confidence: confirmed
- id: MOD-002
type: module
title: Docker Role
path: technical/modules/MOD-002-docker-role.md
status: active
tags:
- module
- docker
related:
- MOD-001
- MOD-006
- REQ-002
source_paths:
- roles/docker/
confidence: confirmed
- id: MOD-003
type: module
title: Monitoring Role (Zabbix Agent 2)
path: technical/modules/MOD-003-monitoring-role.md
status: active
tags:
- module
- monitoring
- zabbix
related:
- MOD-001
- TECH-INTEGRATIONS-ZABBIX
- REQ-003
source_paths:
- roles/monitoring/
confidence: confirmed
- id: MOD-004
type: module
title: OS Updates Role
path: technical/modules/MOD-004-os-updates-role.md
status: active
tags:
- module
- os-updates
related:
- MOD-005
- REQ-004
- NFR-006
source_paths:
- roles/os-updates/
confidence: confirmed
- id: MOD-005
type: module
title: Healthcheck Role
path: technical/modules/MOD-005-healthcheck-role.md
status: active
tags:
- module
- healthcheck
- docker
related:
- MOD-004
- REQ-004
source_paths:
- roles/healthcheck/
confidence: confirmed
- id: MOD-006
type: module
title: Hawser Role
path: technical/modules/MOD-006-hawser-role.md
status: active
tags:
- module
- hawser
- docker
related:
- MOD-002
- REQ-005
source_paths:
- roles/hawser/
confidence: confirmed
- id: MOD-007
type: module
title: Manage SSH Keys Role
path: technical/modules/MOD-007-manage-ssh-keys-role.md
status: active
tags:
- module
- ssh
- hardening
related:
- REQ-006
source_paths:
- roles/manage-ssh-keys/
confidence: confirmed
- id: ALERT-20260909-001
type: alert
title: Plaintext admin password hash committed outside vault
path: alerts/ALERT-20260909-001.md
status: resolved
resolved: '2026-09-09'
severity: high
tags:
- alert
- security
- secrets
related:
- NFR-002
- OQ-006
- TECH-SECURITY
source_paths:
- roles/bootstrap/defaults/main.yml
- inventory/group_vars/external.yml
confidence: confirmed
- id: ALERT-20260909-002
type: alert
title: Uncommitted dmc12-to-cloudlorean rename and stale documentation
path: alerts/ALERT-20260909-002.md
status: resolved
resolved: '2026-09-09'
severity: medium
tags:
- alert
- consistency
- git
related:
- OQ-003
- SCAN-20260909
source_paths:
- inventory/dmc12.yml
- inventory/cloudlorean.yml
- README.md
- AGENTS.md
confidence: confirmed
+43
View File
@@ -0,0 +1,43 @@
# Project Status
Last updated: 2026-09-09
## Scaffold State
- Canonical scaffold created: yes
- Project initialization complete: yes
- Scan workflow: performed 2026-09-09 ([scan report](./implementation/scans/scan-20260909.md))
- Technical documentation, requirements, traceability: populated
## Current State
- Repository fully scanned (root config, docker runtime, 3 inventories,
6 playbooks, 7 roles). Findings and module docs confirmed against source.
- Open alerts: 0 (2 resolved on 2026-09-09) - see
[alerts/INDEX.md](./alerts/INDEX.md).
- Open questions: 2 open / 2 partially-resolved / 2 resolved - see
[open-questions.md](./requirements/open-questions.md).
## Next Documentation Steps
- Confirm OQ-004 (external Zabbix passive server) and OQ-005 (Docker
template name) with the Zabbix server.
- Fill `requirements/product-brief.md` and `GLOSSARY.md` when product-intent
sources allow, or remove them as placeholders.
## Active Alerts
- None. ALERT-20260909-001 (high) and ALERT-20260909-002 (medium) were
resolved on 2026-09-09: `admin_password` moved to encrypted `vault.yml`
(loaded via `vars_files` in `bootstrap.yml`), documentation updated to the
`cloudlorean` inventory, and the rename/change set committed coherently.
## Blockers And Open Questions
- OQ-004: external site Zabbix passive server points to the `healthcheck`
host's own IPv6 address - intentional or misconfiguration?
- OQ-005: Docker Zabbix template name mismatch (`Docker by Zabbix agent2`
vs `Docker by Zabbix agent 2`).
- OQ-001 / OQ-002: formal stakeholders and success criteria remain
undocumented (partially resolved: operators inferred as Niklas/Dennis;
update-run success defined by the healthcheck gate).
+6
View File
@@ -0,0 +1,6 @@
schema: project-wiki
schema_version: 1.5.1
schema_updated: '2026-09-02'
last_migrated: '2026-09-09'
maintained_by_skill: project-wiki
notes: Current schema applied.
@@ -0,0 +1,83 @@
---
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`).
- Resolved within coherent change-set commit `30f3e9a` (2026-09-09).
- `rg -n "admin_password"` shows the variable now only in `vault.yml`
(encrypted) and consumed at `roles/bootstrap/tasks/create-admin-user.yml:9`.
@@ -0,0 +1,85 @@
---
id: ALERT-20260909-002
type: alert
status: resolved
severity: medium
title: Uncommitted dmc12-to-cloudlorean rename and stale documentation
created: 2026-09-09
updated: 2026-09-09
resolved: 2026-09-09
tags: [alert, consistency, git]
related: [OQ-003, SCAN-20260909, TECH-CODEBASE-MAP]
source_paths:
- inventory/dmc12.yml
- inventory/cloudlorean.yml
- inventory/group_vars/cloudlorean.yml
- README.md
- AGENTS.md
confidence: confirmed
---
# ALERT-20260909-002 - Uncommitted dmc12-to-cloudlorean rename and stale documentation
## Summary
The working tree carries a large uncommitted change set (23 modified files,
203 insertions / 148 deletions) including the deletion of
`inventory/dmc12.yml` and the addition of untracked
`inventory/cloudlorean.yml` + `inventory/group_vars/cloudlorean.yml`
(git log confirms no rename commit). `README.md` (inventory table, call
examples) and `AGENTS.md` (fallstricke) still reference `inventory/dmc12.yml`
and `group_vars/dmc12.yml`, which no longer exist.
## Why It Matters
- Documentation, examples, and agent instructions point to a non-existent
inventory; commands copied from README fail.
- The rename plus modifications exist only in the working tree; losing or
partially committing them would leave the repo internally inconsistent.
- Git history will not record a rename (delete + untracked add), which
complicates tracing inventory history.
## Evidence
- `git status --short`: `D inventory/dmc12.yml`, `?? inventory/cloudlorean.yml`,
`?? inventory/group_vars/cloudlorean.yml`, plus modified roles/ansible.cfg/
execute.sh/README/AGENTS
- `git log --follow -- inventory/dmc12.yml`: only add commit `d2e8ce4`
- `README.md` inventory table lists `dmc12.yml` / `group_vars/dmc12.yml`
- `logs/cloudlorean/dmc12/` and `.zabbix-psk/dmc12.psk` exist for host
`dmc12` under the new site name
## Suggested Resolution
1. Update `README.md` and `AGENTS.md` to the `cloudlorean` inventory.
2. Review and commit the rename together with the modified files as one
coherent change (owner decision).
## Resolution
Resolved 2026-09-09 (owner decision confirmed during the session):
1. Documentation updated to the `cloudlorean` inventory:
- `README.md` - inventory table (Cloudlorean row:
`cloudlorean.yml` / `group_vars/cloudlorean.yml` + `debian.yml`),
all call examples, "Secrets & Vault" example command.
- `AGENTS.md` - "Häufige Fallstricke": `ssh_service_name` reference now
points to `inventory/cloudlorean.yml` (`gitea`, `ipam`).
- Role READMEs (bootstrap, monitoring, docker, os-updates, healthcheck,
manage-ssh-keys, hawser): all `inventory/dmc12.yml` call examples
replaced with `inventory/cloudlorean.yml`.
2. The rename and the full working-tree change set (23 modified files,
untracked `inventory/cloudlorean.yml` + `inventory/group_vars/
cloudlorean.yml`, plus this resolution's documentation/vault fixes) were
committed together as one coherent change, as suggested.
## Resolution Evidence
- `rg -n "dmc12\.yml"` across `README.md`, `AGENTS.md`, and `roles/`
returns no matches.
- `git status --short` is clean after the commit `30f3e9a` ("rename dmc12
inventory to cloudlorean and vault admin_password", 2026-09-09); the
change set - including the inventory rename and this resolution - is
recorded as one commit.
- README inventory table lists Cloudlorean with `group_vars/cloudlorean.yml`
and `debian.yml`, matching `inventory/` contents.
+22
View File
@@ -0,0 +1,22 @@
# Alerts
This section tracks significant warning conditions: risks, contradictions, blocking gaps, undocumented assumptions, and inconsistencies that could affect requirements, architecture, implementation, security, compliance, data handling, or project planning.
## Open Alerts
- None.
## Resolved, Dismissed, Or Accepted-Risk Alerts
- [ALERT-20260909-001](./ALERT-20260909-001.md) - **resolved (2026-09-09)**:
plaintext `admin_password` SHA-512 hash moved to encrypted `vault.yml`
(`bootstrap.yml` loads it via `vars_files`); plaintext copies removed.
- [ALERT-20260909-002](./ALERT-20260909-002.md) - **resolved (2026-09-09)**:
README/AGENTS/role READMEs updated to the `cloudlorean` inventory; the
rename and the working-tree change set committed as one coherent change.
## Rules
- Do not create alerts for every suggested question.
- Resolve alerts with evidence instead of deleting them.
- Keep `STATUS.md` updated with compact active alert counts.
+18
View File
@@ -0,0 +1,18 @@
# Analysis
This section stores durable, non-canonical synthesis produced from meaningful project questions or agent analysis. Prefer updating canonical docs when the information clearly belongs in requirements, changes, ADRs, technical docs, implementation docs, or traceability maps.
## When To Read
- Review stable tradeoff analyses, impact maps, or exploratory syntheses.
- Understand connections across requirements, changes, decisions, technical docs, alerts, and source paths.
## Rules
- Do not create isolated analysis pages.
- Every analysis page must link to related wiki records or source paths.
- Do not store routine chat answers, generic explanations, transient debugging notes, or duplicated content here.
## Analysis Pages
- None yet.
+3
View File
@@ -0,0 +1,3 @@
# Project Changelog
No project changes have been captured yet.
+17
View File
@@ -0,0 +1,17 @@
# Changes
This section preserves project changes, change requests, and architectural decisions.
## When To Read
- Review how requirements, scope, or technical direction changed over time.
## Key Files
- [Project changelog](./CHANGELOG.md)
- [Change requests](./requests/)
- [Architectural decisions](./decisions/)
## Placeholders Or Stale Areas
- No project changes or decisions have been captured yet.
+18
View File
@@ -0,0 +1,18 @@
# Implementation
This section tracks current plans, work items, scans, and synchronization reports.
## When To Read
- Review active implementation work or repository scan history.
## Key Files
- [Current plan](./current-plan.md)
- [Work items](./work-items/)
- [Scans and sync reports](./scans/)
- [Scan 2026-09-09](./scans/scan-20260909.md) - full repository scan with confirmed/inferred/unknown findings
## Placeholders Or Stale Areas
- `current-plan.md` is still a placeholder; no active plan captured yet.
@@ -0,0 +1,18 @@
---
id: CURRENT-PLAN
type: note
status: placeholder
title: Current Plan
created: '2026-09-09'
updated: '2026-09-09'
tags:
- implementation
- plan
related: []
source_paths: []
confidence: unknown
---
# Current Plan
No project-specific implementation plan has been captured yet.
@@ -0,0 +1,163 @@
---
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/<inventory>/<hostname>/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/<hostname>.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.
+28
View File
@@ -0,0 +1,28 @@
# Document Intake
This section stores external source documents imported for project-wiki update workflows. Intake documents are provenance, not canonical project knowledge until accepted information is integrated into requirements, changes, technical docs, implementation docs, or traceability maps.
## When To Read
- Process a new PDF, DOCX, text, or Markdown requirements document.
- Review the source provenance behind a requirement, CR, ADR, or open question.
- Investigate conflicts between an imported document and the current KB or as-is technical state.
## Routing Rules
- Read active and reviewed intake documents only when working on document-based updates, provenance, audits, or conflict investigation.
- Read the compact `intake-report.md`, then use `review_progress.py inspect` for structure and coverage. Do not load `chunks.json`, `review-progress.yml`, or generated chunk wrappers directly unless troubleshooting.
- Use `view --section SEC-NNN` only for reliable source-defined sections reported by `inspect`; review every listed section and unsectioned unit. Use `view --all` whenever structure is absent, incomplete, ambiguous, or full-document context may matter.
- After complete coverage, run `review_progress.py audit`; require `review-complete` and record its ledger summary and SHA-256. Rerun after ledger corrections.
- Before a terminal intake status, run `audit --expect-ledger-sha256 <final-ledger-sha256>` with the digest from the reviewed audit.
- Do not mark an intake reviewed or integrated until the ledger is complete. Every classified integrated chunk must link to its registered target IDs; every skipped chunk needs a reason.
- Do not read integrated, archived, superseded, or rejected intake documents during normal coding tasks unless explicitly requested.
- Use canonical KB files, not intake documents, as the source of truth after integration.
## Active Intake Documents
- None yet.
## Reviewed, Integrated, Archived, Superseded, Or Rejected Documents
- None yet.
+15
View File
@@ -0,0 +1,15 @@
# Maintenance
This section stores semantic lint and wiki health reports.
## Latest Report
- None yet.
## Schema Migration Reports
- None yet.
## Reports
- None yet.
+20
View File
@@ -0,0 +1,20 @@
# Requirements
This section stores explicit product intent, constraints, and open questions.
## When To Read
- Understand confirmed project behavior, scope, constraints, or unresolved product intent.
## Key Files
- [Product brief](./product-brief.md)
- [Functional requirements](./functional/INDEX.md)
- [Non-functional requirements](./non-functional/INDEX.md)
- [Constraints](./constraints.md)
- [Open questions](./open-questions.md)
## Placeholders Or Stale Areas
- `product-brief.md` is still a placeholder (project identity lives in
[PROJECT.md](../PROJECT.md)); fill or remove during the next update.
+47
View File
@@ -0,0 +1,47 @@
---
id: CONSTRAINTS
type: note
status: active
title: Constraints
created: '2026-09-09'
updated: '2026-09-09'
tags:
- requirements
- constraints
related:
- PROJECT
source_paths:
- AGENTS.md
confidence: confirmed
---
# Constraints
Explicitly documented constraints for this repository (source: `AGENTS.md`).
## Technical Constraints
- **Debian-only**: every playbook must check
`ansible_facts['os_family'] == "Debian"` and abort on non-Debian hosts.
- **LXC containers**: tasks affecting `sysctl` or `reboot` must check
`virtualization_type != "lxc"` and be skipped there.
- **Ansible style**: modules use FQCN (`ansible.builtin.apt`, ...);
variable defaults live in `roles/<name>/defaults/main.yml`, never hardcoded
in tasks; role logic is split into `tasks/<name>.yml` subtask files with
`tasks/main.yml` containing only imports.
- **Templates** use `# {{ ansible_managed }}` as header.
- **Execution environment**: changes to collections require updating
`docker/requirements.yml` and rebuilding the Docker image.
## Process Constraints
- **Documentation duty**: every new feature, parameter, or variable must be
documented in the corresponding README before commit (see `AGENTS.md`
mapping table).
- **Code language**: documentation in German, code (variable names, task
names) in English.
- **Secrets**: sensitive values belong in encrypted `vault.yml`; `.vault_pass`,
`setenv.sh`, `logs/`, and `.zabbix-psk/` are git-ignored and must never be
committed. No plaintext secrets in `defaults/` or `group_vars/`.
- **Testing**: changes are tested in the Docker container (`./execute.sh`),
with `ansible-lint` and `--check` dry runs where sensible.
@@ -0,0 +1,15 @@
# Functional Requirements
This index routes to functional requirement topics; atomic REQ records live only in linked topic files.
## When To Read
- Work with product capabilities, workflows, integrations, or other functional behavior.
## Key Files
- [Host lifecycle operations](./host-lifecycle-operations.md) - REQ-001..REQ-006 (provisioning, docker, monitoring, updates, hawser, ssh keys)
## Placeholders Or Stale Areas
- None.
@@ -0,0 +1,163 @@
---
id: REQ-FUNC-HOST-LIFECYCLE
type: requirements
status: active
title: Host Lifecycle Operations
created: '2026-09-09'
updated: '2026-09-09'
tags:
- requirements
- functional
related:
- PROJECT
- PRODUCT-BRIEF
source_paths:
- README.md
- AGENTS.md
confidence: confirmed
---
# Host Lifecycle Operations
Explicitly stated functional scope of the collection (source: root
`README.md` purpose statement and playbook table; evidence linked in
[requirement-evidence.yml](../../traceability/requirement-evidence.yml)).
<a id="req-001"></a>
## REQ-001 - Initial provisioning of Debian hosts
Status: active
Tags: [provisioning, bootstrap]
Related: [MOD-001]
Confidence: confirmed
### Statement
The collection provides a complete initial setup ("Ersteinrichtung") for
Debian hosts via `bootstrap.yml` (packages, admin user, SSH, MOTD, sysctl,
Docker, monitoring).
### Rationale
README.md: "bootstrap.yml | Vollständige Ersteinrichtung eines Debian-Hosts";
README purpose statement: "Bereitstellung, Härtung, Aktualisierung und
Überwachung von Debian-Hosts".
### Acceptance Notes
- Runs against the three sites in `inventory/`; composes docker and
monitoring roles with skip flags.
<a id="req-002"></a>
## REQ-002 - Docker Engine installation
Status: active
Tags: [docker]
Related: [MOD-002]
Confidence: confirmed
### Statement
Install Docker Engine from the official Docker repository
(`playbooks/docker.yml` / role `docker`).
### Rationale
README playbook table: "docker | Docker Engine installieren".
### Acceptance Notes
- Official repository, not distribution packages.
<a id="req-003"></a>
## REQ-003 - Zabbix Agent 2 installation and registration
Status: active
Tags: [monitoring, zabbix]
Related: [MOD-003, TECH-INTEGRATIONS-ZABBIX]
Confidence: confirmed
### Statement
Install Zabbix Agent 2 and register the host on the Zabbix server
(`playbooks/monitoring.yml` / role `monitoring`).
### Rationale
README playbook table: "monitoring | Zabbix Agent 2 installieren &
registrieren".
### Acceptance Notes
- Includes TLS-PSK and Docker plugin support per implementation.
<a id="req-004"></a>
## REQ-004 - Package updates with healthcheck
Status: active
Tags: [updates, healthcheck]
Related: [MOD-004, MOD-005]
Confidence: confirmed
### Statement
Update Debian packages and verify running containers afterwards
(`playbooks/os-updates-deb.yml`: roles `os-updates` + `healthcheck`).
### Rationale
README playbook table: "os-updates, healthcheck | Pakete aktualisieren +
Healthcheck".
### Acceptance Notes
- Mirror switch, reboot and logging are part of the implemented update flow.
<a id="req-005"></a>
## REQ-005 - Hawser stack update
Status: active
Tags: [docker, hawser]
Related: [MOD-006]
Confidence: confirmed
### Statement
Update the Hawser Docker Compose stack (`playbooks/upgrade-hawser.yml` /
role `hawser`).
### Rationale
README playbook table: "hawser | Hawser-Stack aktualisieren".
### Acceptance Notes
- None.
<a id="req-006"></a>
## REQ-006 - SSH key hardening
Status: active
Tags: [ssh, hardening]
Related: [MOD-007]
Confidence: confirmed
### Statement
Manage desired and undesired SSH keys on hosts
(`playbooks/hardening/manage-ssh-keys.yml` / role `manage-ssh-keys`).
### Rationale
README playbook table: "manage-ssh-keys | SSH-Schlüssel hartieren"; role
name/description in README roles table.
### Acceptance Notes
- None.
@@ -0,0 +1,15 @@
# Non-Functional Requirements
This index routes to non-functional requirement topics; atomic NFR records live only in linked topic files.
## When To Read
- Work with quality attributes, operations, security, resilience, performance, or service levels.
## Key Files
- [Operational policies](./operational-policies.md) - NFR-001..NFR-006 (platform, secrets, logging, runtime, documentation, LXC)
## Placeholders Or Stale Areas
- None.
@@ -0,0 +1,167 @@
---
id: NFR-OPERATIONAL-POLICIES
type: requirements
status: active
title: Operational Policies
created: '2026-09-09'
updated: '2026-09-09'
tags:
- requirements
- non-functional
related:
- PROJECT
- CONSTRAINTS
source_paths:
- README.md
- AGENTS.md
confidence: confirmed
---
# Operational Policies
Explicitly stated non-functional requirements (sources: root `README.md`,
`AGENTS.md`; evidence linked in
[requirement-evidence.yml](../../traceability/requirement-evidence.yml)).
<a id="nfr-001"></a>
## NFR-001 - Debian-only target platforms
Status: active
Tags: [platform]
Related: [REQ-001]
Confidence: confirmed
### Statement
All playbooks must target Debian only and verify
`ansible_facts['os_family'] == "Debian"`, aborting on other systems.
### Rationale
README "Voraussetzungen": "Ziel-Hosts: Debian (alle Playbooks prüfen
`os_family == "Debian"`)".
### Acceptance Notes
- Exception observed: `playbooks/hardening/manage-ssh-keys.yml` lacks the
guard (tracked in the scan report).
<a id="nfr-002"></a>
## NFR-002 - Secrets never committed unencrypted
Status: active
Tags: [security, vault]
Related: [TECH-SECURITY, ALERT-20260909-001]
Confidence: confirmed
### Statement
Sensitive values (passwords, API keys) belong in encrypted `vault.yml`;
no plaintext secrets in `defaults/`, `group_vars/`, or commits.
### Rationale
README "Secrets & Vault" and "Beitragen" rule 3; AGENTS.md "Secrets"
section.
### Acceptance Notes
- Resolved 2026-09-09: `admin_password` moved to encrypted `vault.yml`
(ALERT-20260909-001); no plaintext secrets remain in `defaults/` or
`group_vars/`.
<a id="nfr-003"></a>
## NFR-003 - Per-host update audit log
Status: active
Tags: [logging, audit]
Related: [MOD-004, MOD-005]
Confidence: confirmed
### Statement
The `os-updates` and `healthcheck` roles write one update log per host to
`logs/<inventory>/<hostname>/update.log` on the controller as a local
audit trail.
### Rationale
README "Logging" section.
### Acceptance Notes
- `logs/` is git-ignored.
<a id="nfr-004"></a>
## NFR-004 - Docker-based execution environment
Status: active
Tags: [runtime, docker]
Related: [TECH-DEPLOYMENT]
Confidence: confirmed
### Statement
Playbooks must be runnable from the provided Docker environment without a
local Ansible installation (`execute.sh`, `docker/Dockerfile`).
### Rationale
README "Docker-Ausführungsumgebung": "Damit Playbooks nicht lokal
installiert werden müssen, liefert das Repository ein fertiges Docker-Image."
### Acceptance Notes
- Collections pinned in `docker/requirements.yml`; image rebuild on
collection changes.
<a id="nfr-005"></a>
## NFR-005 - Documentation duty for every change
Status: active
Tags: [documentation, process]
Related: [CONSTRAINTS]
Confidence: confirmed
### Statement
Every new feature, parameter, and variable must be documented in the
corresponding role README before commit; playbook changes update the root
README.
### Rationale
README "Beitragen" rule 2; AGENTS.md "WICHTIG: Dokumentationspflicht bei
Änderungen".
### Acceptance Notes
- None.
<a id="nfr-006"></a>
## NFR-006 - LXC-aware execution
Status: active
Tags: [platform, lxc]
Related: [MOD-004]
Confidence: confirmed
### Statement
Tasks affecting `sysctl` or `reboot` must be skipped on LXC containers
(`virtualization_type != "lxc"`).
### Rationale
AGENTS.md "OS-Unterstützung": "LXC-Container: Tasks, die `sysctl` oder
`reboot` betreffen, müssen ... übersprungen werden."
### Acceptance Notes
- Implemented in `roles/os-updates/tasks/reboot.yml`.
@@ -0,0 +1,110 @@
---
id: OPEN-QUESTIONS
type: note
status: active
title: Open Questions
created: '2026-09-09'
updated: '2026-09-09'
tags:
- requirements
- open-questions
related:
- SCAN-20260909
- ALERT-20260909-001
- ALERT-20260909-002
source_paths:
- AGENTS.md
- README.md
- inventory/group_vars/external.yml
confidence: confirmed
---
# Open Questions
Reconciliation state after the 2026-09-09 scan (workflow: Open Questions
Reconciliation). Anchors are stable; statuses follow the schema
(`open`, `partially-resolved`, `resolved`, ...).
<a id="oq-001"></a>
## OQ-001 - Who are the stakeholders/owners of this repository?
Status: partially-resolved
Updated: 2026-09-09
Related: [SCAN-20260909]
Resolution (partial): Operators appear to be "Niklas" and "Dennis"
(SSH key comments in `roles/bootstrap/defaults/main.yml`,
`confidence: inferred`). Formal ownership and roles remain undocumented.
Remaining question: Who formally owns and operates the playbooks, and who
approves changes?
<a id="oq-002"></a>
## OQ-002 - What are the explicit success criteria?
Status: partially-resolved
Updated: 2026-09-09
Related: [SCAN-20260909], MOD-005
Resolution (partial): For update runs, success is defined by the
`healthcheck` quality gate (all Docker containers running; fails the play
only when `healthcheck_fail_on_unhealthy` is true). No success criteria for
the overall project are documented.
Remaining question: What defines success beyond a passing update-run gate?
<a id="oq-003"></a>
## OQ-003 - Is `AGENTS.md`/`README.md` stale regarding `inventory/dmc12.yml`?
Status: resolved
Updated: 2026-09-09
Related: [ALERT-20260909-002], SCAN-20260909
Resolution: Yes. Git status shows `D inventory/dmc12.yml` (uncommitted) and
untracked `inventory/cloudlorean.yml`; `dmc12` is now a Proxmox host inside
the `cloudlorean` site. `README.md` (inventory table, examples) and
`AGENTS.md` still reference `dmc12.yml`. Documentation updates and the
commit of the rename are tracked in ALERT-20260909-002.
<a id="oq-004"></a>
## OQ-004 - Is the external site's Zabbix passive server correct?
Status: open
Created: 2026-09-09
Related: [SCAN-20260909], MOD-003
`inventory/group_vars/external.yml` sets
`monitoring_zabbix_passive_servers: ["2a01:4f8:1c1e:62dd::1"]`, which is the
`healthcheck` host's own address. Is a Zabbix server/proxy intentionally
running on that host, or is this a misconfiguration? (`confidence: unknown`)
<a id="oq-005"></a>
## OQ-005 - Which Docker template name exists on the Zabbix server?
Status: open
Created: 2026-09-09
Related: [SCAN-20260909], MOD-003
Role default `monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]`
(no space) vs group_vars `["Docker by Zabbix agent 2"]` (with space). One of
the two will fail host linking at registration. Which name does the Zabbix
server actually use? (`confidence: unknown`)
<a id="oq-006"></a>
## OQ-006 - Is the committed `admin_password` hash intended or a policy violation?
Status: resolved
Updated: 2026-09-09
Related: [ALERT-20260909-001], NFR-002
Resolution: Policy violation. Decrypting `vault.yml` during the alert
resolution confirmed it did not define `admin_password` (no override); the
hash existed only as plaintext in role defaults and group_vars. Resolved with
[ALERT-20260909-001]: hash moved into encrypted `vault.yml`, plaintext copies
removed, `bootstrap.yml` loads the vault via `vars_files`.
@@ -0,0 +1,18 @@
---
id: PRODUCT-BRIEF
type: note
status: placeholder
title: Product Brief
created: '2026-09-09'
updated: '2026-09-09'
tags:
- requirements
- product
related: []
source_paths: []
confidence: unknown
---
# Product Brief
No explicit product brief has been captured yet.
+30
View File
@@ -0,0 +1,30 @@
# Sources
This section stores raw source documents used by document-based update workflows. Source documents are raw input, not canonical project knowledge.
## How To Use
- Drop new PDF, DOCX, text, or Markdown files into [inbox/](./inbox/).
- Run `/project-wiki update`.
- The agent runs the project-wiki deterministic inbox preflight with skip quarantine, registers only files classified `process` in [SOURCE_REGISTRY.yml](./SOURCE_REGISTRY.yml), runs document ingestion, and moves successfully processed files to `processed/YYYY-MM/` when possible.
- Keep human instructions in this file. Do not create `README.md` or other guide files inside `inbox/`.
## Routing Rules
- Never read PDF/DOCX source files directly into model context.
- Use source files only through the document ingestion script.
- Treat the inbox preflight report as authoritative for SHA-256 hashes, validated registry and intake-history matches, retry-record selection, inbox duplicates, and quarantine destinations; use agent review only for changed content at a historical path, ambiguous registry history, or explicit reprocessing.
- Use `intake/` artifacts for review and canonical KB integration.
- Ignore inbox housekeeping files such as `README.md`, `.gitkeep`, `.DS_Store`, hidden files, files beginning with `_`, and temporary or partial download files.
## Inbox
- No pending source files registered yet.
## Processed Sources
- None yet.
## Failed, Rejected, Ignored, Or Superseded Sources
- None yet.
@@ -0,0 +1,3 @@
version: 1
updated: '2026-09-09'
sources: []
+34
View File
@@ -0,0 +1,34 @@
# Technical Documentation
This section records implemented or observed code behavior and technical structure.
## When To Read
- Work with architecture, modules, APIs, data, integrations, tests, deployment, or security.
## Key Files
- [Architecture](./architecture.md)
- [Codebase map](./codebase-map.md)
- [Testing](./testing.md)
- [Deployment](./deployment.md)
- [Security](./security.md)
## Modules
- [Bootstrap role](./modules/MOD-001-bootstrap-role.md)
- [Docker role](./modules/MOD-002-docker-role.md)
- [Monitoring role (Zabbix Agent 2)](./modules/MOD-003-monitoring-role.md)
- [OS updates role](./modules/MOD-004-os-updates-role.md)
- [Healthcheck role](./modules/MOD-005-healthcheck-role.md)
- [Hawser role](./modules/MOD-006-hawser-role.md)
- [Manage SSH keys role](./modules/MOD-007-manage-ssh-keys-role.md)
## Integrations
- [Zabbix](./integrations/zabbix.md)
## Placeholders Or Stale Areas
- None. `technical/api/` and `technical/data/` remain empty (no public APIs
or data schemas in an Ansible repository).
+102
View File
@@ -0,0 +1,102 @@
---
id: TECH-ARCHITECTURE
type: technical
status: active
title: Architecture
created: '2026-09-09'
updated: '2026-09-09'
tags:
- technical
- architecture
- ansible
related:
- TECH-CODEBASE-MAP
- TECH-DEPLOYMENT
- TECH-INTEGRATIONS-ZABBIX
- SCAN-20260909
source_paths:
- ansible.cfg
- execute.sh
- bootstrap.yml
- playbooks/
- roles/
confidence: confirmed
---
# Architecture
## Overview
A push-based Ansible controller-in-container setup: an interactive Docker
container (built from `debian:trixie-slim`, `ansible-core 2.20.x`) runs the
playbooks from the mounted repository and connects over SSH to Debian hosts
(`user: admin`, `become: true`). No agent is pushed except Zabbix Agent 2.
Unverified claims are marked `confidence: inferred`.
## Layered View
```
Docker runtime (execute.sh)
└─ ansible-playbook -i inventory/<site>.yml <playbook>
└─ SSH (admin, pipelining, no host-key checking) → Debian hosts
├─ roles/bootstrap ── composes ──► roles/docker
│ └─► roles/monitoring
├─ roles/docker (Docker Engine from download.docker.com)
├─ roles/monitoring (zabbix-agent2 → repo.zabbix.com, PSK,
│ Zabbix API registration via httpapi)
├─ roles/os-updates (apt full upgrade, reboot, controller logs)
├─ roles/healthcheck (container quality gate, controller logs)
├─ roles/hawser (docker_compose_v2, pull: always)
└─ roles/manage-ssh-keys (authorized_keys allow/deny lists)
```
## Role Composition
- `bootstrap` is the only composing role: it imports the `docker` role and
the `monitoring` role unless `skip_docker` / `skip_monitoring` are set.
- `os-updates` and `healthcheck` are paired at playbook level
(`playbooks/os-updates-deb.yml`); healthcheck reuses os-updates logging
defaults (`healthcheck_log_file` derives from `os_update_log_dir`).
## Inventory Model
- Three sites: `cloudlorean` (LAN 192.168.212.0/24, groups `debian` +
`proxmox`), `home` (10.13.37.0/24, groups `debian` + `proxmox`),
`external` (IPv6-only, group `debian` only).
- `proxmox` group membership drives reboot deferral in `os-updates`
(`'proxmox' in group_names`); `virtualization_type != lxc` skips kernel
and reboot logic for LXC containers.
- Per-site `group_vars/<site>.yml` override Zabbix connectivity (server,
API URL, proxy), host groups/templates; `group_vars/debian.yml` holds
os-update defaults including the hardcoded
`os_update_version_codename: "trixie"`.
- Secrets: `vault.yml` (encrypted, tracked) provides
`monitoring_zabbix_api_password` (and possibly more; vault not decrypted -
`confidence: unknown`).
## Controller-Side State
- `.zabbix-psk/<hostname>.psk` - per-host PSKs generated once on the
controller and reused across runs (keeps agent and Zabbix registration in
sync).
- `logs/<inventory>/<hostname>/update.log` - append-only update + quality
gate log written via `delegate_to: localhost` / `blockinfile`.
## Execution Flow (os-updates-deb.yml)
1. Debian guard (fail non-Debian).
2. `os-updates`: optional mirror rewrite → preflight logging (upgradable
list, start time) → `apt upgrade: full` → kernel-comparison reboot
decision (async reboot + `wait_for_connection`, deferred on `proxmox`
group unless `os_update_reboot_on_proxmox`) → postflight logging.
3. `healthcheck`: docker presence check → container comparison →
`quality_gate` log section → optional failure
(`healthcheck_fail_on_unhealthy`).
## Dependencies
- Collections: `ansible.posix`, `community.general`, `community.docker`,
`community.zabbix` (pinned in `docker/requirements.yml`).
- External services: repo.zabbix.com, download.docker.com, Debian mirrors,
Zabbix API (`mon.cloudlorean.de`). See
[Integrations: Zabbix](./integrations/zabbix.md).
+90
View File
@@ -0,0 +1,90 @@
---
id: TECH-CODEBASE-MAP
type: technical
status: active
title: Codebase Map
created: '2026-09-09'
updated: '2026-09-09'
tags:
- technical
- codebase
related:
- TECH-ARCHITECTURE
- SCAN-20260909
source_paths: []
confidence: confirmed
---
# Codebase Map
Ansible repository, no application source code. Structure as of 2026-09-09.
## Root Files
| Path | Purpose |
| --- | --- |
| `ansible.cfg` | Global Ansible config: no host key checking, `roles_path=./roles`, `forks=20`, smart gathering, SSH pipelining |
| `bootstrap.yml` | Top-level playbook, binds the `bootstrap` role with Debian guard |
| `execute.sh` | Starts the interactive Docker runtime container (`ansible:deb13`) |
| `vault.yml` | Ansible-Vault encrypted secrets (tracked, encrypted) |
| `setenv.sh` | Proxmox credentials (git-ignored, not in repo) |
| `.vault_pass`, `.zabbix-psk/`, `logs/` | Vault password, per-host PSKs, update logs (git-ignored) |
## Directories
```
docker/ Dockerfile (debian:trixie-slim + ansible-core 2.20.x),
requirements.yml (pinned collections), ansible-functs.sh
(aliases ap/ag/av)
inventory/ cloudlorean.yml, home.yml, external.yml + group_vars/
playbooks/ docker.yml, monitoring.yml, os-updates-deb.yml,
upgrade-hawser.yml, hardening/manage-ssh-keys.yml
roles/bootstrap/ tasks/ (8 subtasks), templates/ (4), handlers/, README.md
roles/docker/ tasks/ (2), templates/sources.list.j2, handlers/, README.md
roles/hawser/ tasks/ (2), templates/docker-compose.yml.j2, handlers/, README.md
roles/healthcheck/ tasks/main.yml, defaults/, README.md (no handlers/templates)
roles/manage-ssh-keys/ tasks/ (4), handlers/, defaults/, README.md
roles/monitoring/ tasks/ (8), templates/ (2: zabbix_agent2.conf.j2, docker.conf.j2),
handlers/, README.md
roles/os-updates/ tasks/ (6), templates/ (2: sources.list.j2, sources.list-deb822.j2),
handlers/, README.md
```
## Entry Points
| Playbook | Role(s) | Notes |
| --- | --- | --- |
| `bootstrap.yml` | bootstrap (+ docker, monitoring) | Full initial setup |
| `playbooks/docker.yml` | docker | Docker Engine install |
| `playbooks/monitoring.yml` | monitoring | Loads `../vault.yml` |
| `playbooks/os-updates-deb.yml` | os-updates, healthcheck | Update + quality gate |
| `playbooks/upgrade-hawser.yml` | hawser | Compose stack update |
| `playbooks/hardening/manage-ssh-keys.yml` | manage-ssh-keys | No Debian guard, no become |
## Conventions (Observed)
- Roles split logic into `tasks/<name>.yml` subtasks; `tasks/main.yml` only
imports/includes (`bootstrap`, `os-updates`) or delegates to a single
subtask (`docker`, `hawser`).
- Newer tasks use FQCN; older tasks (apt, file, blockinfile, set_fact,
include_role) still use short names.
- Per-role README documents variables, templates, handlers, tags.
- Tags observed: `motd`, `ssh`, `bashrc`, `sysctl` (bootstrap),
`monitoring` (monitoring role).
## Tests
- No automated test suite. Verification is manual: run in the Docker
container, optional `ansible-lint`, `--check` dry runs. See
[Testing](./testing.md).
## Inventories
| Site | File | Groups | Hosts |
| --- | --- | --- | --- |
| cloudlorean | `inventory/cloudlorean.yml` | debian (13), proxmox (2: dmc12, pbs) | 192.168.212.0/24 |
| home | `inventory/home.yml` | debian (6), proxmox (1: tardis) | 10.13.37.0/24 |
| external | `inventory/external.yml` | debian (4) | IPv6-only |
Per-site `group_vars/<site>.yml` override Zabbix servers, API URL, proxy,
host groups and templates. See [Architecture](./architecture.md).
+59
View File
@@ -0,0 +1,59 @@
---
id: TECH-DEPLOYMENT
type: technical
status: active
title: Deployment (Runtime Environment)
created: '2026-09-09'
updated: '2026-09-09'
tags:
- technical
- deployment
- docker
related:
- TECH-ARCHITECTURE
source_paths:
- execute.sh
- docker/Dockerfile
- docker/requirements.yml
- docker/ansible-functs.sh
- ansible.cfg
confidence: confirmed
---
# Deployment (Runtime Environment)
## Docker Image
- `docker/Dockerfile`: `debian:trixie-slim`, `TZ=Europe/Berlin`,
`ANSIBLE_VERSION=2.20.6` → `pip3 install ansible-core~=2.20.6`.
- Utilities: nano, git, wget, unzip, curl, python3-pip, tzdata, openssh-client,
ping, vim, less.
- Bakes SSH client policy: `StrictHostKeyChecking no`,
`UserKnownHostsFile /dev/null` (`/etc/ssh/ssh_config.d/99-no-hostkey-check.conf`).
- Installs pinned collections from `docker/requirements.yml`:
`ansible.posix` 2.2.0, `community.general` 13.0.1, `community.docker`
5.2.0, `community.zabbix` 4.2.0.
- Copies `ansible-functs.sh` into `/root/.bashrc.d/` providing aliases
`ap` (ansible-playbook), `ag` (ansible-galaxy), `av` (ansible-vault).
## Launch Flow (execute.sh)
1. Pick next free container name `ansible-<n>`.
2. Ensure IPv6-enabled bridge network `ansible-dualstack` (fails fast with
a clear message if the network exists without IPv6).
3. Run the container detached: repo mounted at `/ansible` (workdir), SSH
keys from the `ansible_ssh_keys` volume into `/root/.ssh`, env
`ANSIBLE_HOST_KEY_CHECKING=False`, `ANSIBLE_CONFIG=./ansible.cfg`.
4. Write a per-container SSH client config, print name/IPv4/IPv6/OS, then
`docker attach` for interactive use.
## Controller-Side Artifacts
- `.zabbix-psk/` and `logs/` are written by delegation from the container
into the mounted repo (git-ignored).
## Operational Notes
- Changing collections requires updating `docker/requirements.yml` and an
image rebuild (AGENTS.md).
- Default image tag: `ansible:deb13`.
@@ -0,0 +1,63 @@
---
id: TECH-INTEGRATIONS-ZABBIX
type: technical
status: active
title: Integrations - Zabbix
created: 2026-09-09
updated: 2026-09-09
tags:
- technical
- integration
- zabbix
related:
- MOD-003
source_paths:
- roles/monitoring/
- inventory/group_vars/
confidence: confirmed
---
# Integrations - Zabbix
## Agent Side (outbound/inbound to monitored hosts)
- Package source: `repo.zabbix.com` (release package for Zabbix 7.0 on
Debian, downloaded to `/tmp` and installed).
- Agent: `zabbix-agent2`, listen port 10050, config
`/etc/zabbix/zabbix_agent2.conf`.
- TLS: PSK only (`tls_connect=psk`, `tls_accept=psk`), identity per host,
PSK file `/etc/zabbix/zabbix_agent2.psk`.
- Docker monitoring: plugin config `/etc/zabbix/zabbix_agent2.d/plugins.d/
docker.conf` pointing at `unix:///var/run/docker.sock`, deployed when the
socket exists.
- Passive/active server lists come from site group_vars
(`monitoring_zabbix_passive_servers`).
## Controller Side (Zabbix API registration)
- API endpoint per site: `https://mon.cloudlorean.de/api_jsonrpc.php`
(group_vars); credentials `monitoring_zabbix_api_user: Admin` +
`monitoring_zabbix_api_password` from `vault.yml`.
- Module: `community.zabbix.zabbix_host` over `httpapi`; connection
parameters derived from the API URL with `urlsplit` (scheme, port, path).
- Host object: name = `monitoring_zabbix_host_name` (default
`inventory_hostname`), agent interface IP = `ansible_host`, host groups
and templates per site, `inventory_mode: manual`, TLS PSK identity/value
from the deployed PSK, `status: enabled`, `state: present` (idempotent
register-or-update).
- Optional proxy: when `monitoring_zabbix_proxy` is set, `monitored_by`
switches to the proxy (`gatekeeper.cloudlorean.de` for cloudlorean,
`gatekeeper.meyer-kempen.de` for home).
## Site Overrides (observed)
| Site | Passive servers | Proxy | Host groups |
| --- | --- | --- | --- |
| cloudlorean | 192.168.212.1 | gatekeeper.cloudlorean.de (192.168.212.1) | Linux servers, Cloudlorean |
| home | 10.13.37.1 | gatekeeper.meyer-kempen.de (10.13.37.1) | Linux servers, Meyer-Kempen |
| external | 2a01:4f8:1c1e:62dd::1 (see OQ-004) | none | Linux servers, Cloudlorean |
## Other External Services
- `download.docker.com` (docker role apt repository), Debian mirrors
(`deb.debian.org`, `security.debian.org` default; site-overridable).
@@ -0,0 +1,65 @@
---
id: MOD-001
type: module
status: active
title: Bootstrap Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, bootstrap, ansible]
related: [MOD-002, MOD-003, REQ-001]
source_paths:
- roles/bootstrap/
confidence: confirmed
---
# Bootstrap Role
## Responsibility
Full initial setup of a Debian host: packages, admin user, SSH, MOTD,
keyboard layout, bashrc, sysctl; then composes Docker and monitoring.
## Source Paths
- `roles/bootstrap/tasks/main.yml` - orchestration only
- Subtasks: `install-basicpackages.yml`, `create-admin-user.yml`,
`set-motd.yml`, `set-keyboardlayout.yml`, `install-openssh.yml`,
`configure-ssh.yml`, `add-ssh-keys.yml`, `setup-bashrc.yml`,
`configure-sysctl.yml`
- Templates: `authorized_keys.j2`, `keyboard.j2`, `sshd.conf.j2`,
`sudoers-admin.j2`
## Public Interfaces
- Playbook: `bootstrap.yml` (top level, Debian guard, `become`, `user: admin`,
`vars_files: vault.yml`)
- Skip flags: `skip_docker`, `skip_monitoring` (control role composition)
- Tags: `motd`, `ssh`, `bashrc`, `sysctl`
## Important Flows
1. Basic packages → admin user (+sudo via `sudoers-admin.j2`, authorized
keys via `authorized_keys.j2`) → MOTD → keyboard layout.
2. OpenSSH install, hardening config (`sshd.conf.j2`), authorized keys.
3. bashrc, sysctl.
4. `import_role: docker` (when `not skip_docker`), then
`import_role: monitoring` (when `not skip_monitoring`).
## Dependencies
- Composed roles: [docker](./MOD-002-docker-role.md),
[monitoring](./MOD-003-monitoring-role.md).
- `admin_authorized_keys` (public keys, plaintext OK) from
`defaults/main.yml`; `admin_password` (SHA-512 hash) lives encrypted in
`vault.yml`, loaded via `vars_files` in `bootstrap.yml` (resolved
ALERT-20260909-001).
## Tests
- None automated; manual runs via `./execute.sh`.
## Notes For Agents
- `sshd` service name differs per host (`ssh_service_name`, set for `gitea`
and `ipam` in `inventory/cloudlorean.yml`).
- Keep `tasks/main.yml` as pure import list when extending.
@@ -0,0 +1,52 @@
---
id: MOD-002
type: module
status: active
title: Docker Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, docker, ansible]
related: [MOD-001, MOD-006, REQ-002]
source_paths:
- roles/docker/
confidence: confirmed
---
# Docker Role
## Responsibility
Install Docker Engine from the official Docker apt repository.
## Source Paths
- `roles/docker/tasks/main.yml` → `install-docker.yml`
- Template: `roles/docker/templates/sources.list.j2`
- Handlers: `roles/docker/handlers/main.yml`
## Public Interfaces
- Playbook: `playbooks/docker.yml`
- Defaults: `docker_mirror` (download.docker.com/linux/debian),
`os_version_codename` (derived from `ansible_facts['distribution_release']`),
`docker_packages` (docker-ce, docker-ce-cli, containerd.io, buildx and
compose plugins).
## Important Flows
1. Set up the official Docker apt repository (key + `sources.list.j2`).
2. Install `docker_packages` (handlers restart the service when needed).
## Dependencies
- Used standalone (`playbooks/docker.yml`) and composed by
[bootstrap](./MOD-001-bootstrap-role.md). Prerequisite for
[hawser](./MOD-006-hawser-role.md).
## Tests
- None automated.
## Notes For Agents
- Codename comes from host facts; no LXC-specific handling observed.
@@ -0,0 +1,77 @@
---
id: MOD-003
type: module
status: active
title: Monitoring Role (Zabbix Agent 2)
created: 2026-09-09
updated: 2026-09-09
tags: [module, monitoring, zabbix, ansible]
related: [MOD-001, TECH-INTEGRATIONS-ZABBIX, REQ-003, NFR-002]
source_paths:
- roles/monitoring/
confidence: confirmed
---
# Monitoring Role (Zabbix Agent 2)
## Responsibility
Install Zabbix Agent 2, configure TLS-PSK and the Docker plugin, and
register/update the host on the Zabbix server via the API.
## Source Paths
- `roles/monitoring/tasks/main.yml` → `validate.yml`,
`install-repository.yml`, `install-agent.yml`, `configure-docker.yml`,
`configure-psk.yml`, `configure-agent.yml`, `register-host.yml`
- Templates: `zabbix_agent2.conf.j2`, `docker.conf.j2`
## Public Interfaces
- Playbook: `playbooks/monitoring.yml` (loads `../vault.yml`)
- Tag: `monitoring`
- Key variables (`defaults/main.yml`, overridden per site in
`inventory/group_vars/<site>.yml`): `monitoring_zabbix_version` (7.0),
`monitoring_zabbix_passive_servers`, `monitoring_zabbix_active_servers`,
`monitoring_zabbix_api_url`, `monitoring_zabbix_api_user`,
`monitoring_zabbix_api_password` (vault), `monitoring_zabbix_register_host`,
`monitoring_zabbix_proxy` / `monitoring_zabbix_proxy_address`,
`monitoring_zabbix_host_groups`, `monitoring_zabbix_templates`,
`monitoring_zabbix_docker_templates`, PSK settings
(`monitoring_zabbix_psk_bits: 256`,
`monitoring_zabbix_psk_store: {{ role_path }}/../../.zabbix-psk`).
## Important Flows
1. Validate inputs → add repo.zabbix.com repo → install `zabbix-agent2`.
2. Docker plugin config when `/var/run/docker.sock` exists.
3. PSK: generate once on the controller (`openssl rand -hex 32`, umask 077,
`creates:` guard), persist under `.zabbix-psk/<hostname>.psk` (0700),
validate hex format/length, deploy to `/etc/zabbix/zabbix_agent2.psk`
(0600), notify restart handler.
4. Agent config: TLS connect/accept = PSK, identity =
`monitoring_zabbix_host_name`, passive/active servers, listen port 10050.
5. Registration: `community.zabbix.zabbix_host` over httpapi (connection
params derived from `monitoring_zabbix_api_url` via `urlsplit`), agent
interface from `ansible_host`, template union adds
`monitoring_zabbix_docker_templates` when the Docker socket is present,
`monitored_by` switches to proxy when `monitoring_zabbix_proxy` is set.
## Dependencies
- `community.zabbix` collection; vault variable
`monitoring_zabbix_api_password`.
- Composed by [bootstrap](./MOD-001-bootstrap-role.md) unless
`skip_monitoring`.
## Tests
- None automated.
## Notes For Agents
- PSK store is controller-side state; never commit it (git-ignored). When
renaming a host, migrate/regenerate the PSK, otherwise registration
drifts (documented in AGENTS.md).
- Template name mismatch between role default (`Docker by Zabbix agent2`)
and group_vars (`Docker by Zabbix agent 2`) - see open question OQ-005.
@@ -0,0 +1,73 @@
---
id: MOD-004
type: module
status: active
title: OS Updates Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, os-updates, ansible]
related: [MOD-005, NFR-003, NFR-006, REQ-004]
source_paths:
- roles/os-updates/
confidence: confirmed
---
# OS Updates Role
## Responsibility
Upgrade Debian packages with optional mirror rewrite, kernel-based reboot
handling, and controller-side update logging.
## Source Paths
- `roles/os-updates/tasks/main.yml` → `update_mirrors.yml` (optional),
`upgrade_packages.yml` → `logging_preflight.yml`, `reboot.yml`,
`logging_postflight.yml`
- Templates: `sources.list.j2`, `sources.list-deb822.j2`
- Handlers: apt cleanup, apt autoremove
## Public Interfaces
- Playbook: `playbooks/os-updates-deb.yml` (chains
[healthcheck](./MOD-005-healthcheck-role.md))
- Key variables: `os_update_auto_upgrade`, `os_also_update_mirror` (false),
`os_update_mirrors` (main + security mirror),
`os_update_version_codename` (role default: host facts;
`group_vars/debian.yml` hardcodes `trixie`),
`os_update_debian_codenames` (trixie, bookworm, bullseye),
`os_update_reboot_on_proxmox` (false),
`os_update_logging_enabled` (true), `os_update_log_dir` (/ansible/logs),
`os_update_log_file` (logs/<inventory>/<hostname>/update.log).
## Important Flows
1. Mirror rewrite (only when `os_also_update_mirror`) with
`ignore_errors: true`; only whitelisted Debian codenames are rewritten in
`sources.list.d`.
2. Preflight logging: refresh cache, record start epoch/ISO, parse
`apt list --upgradable` into names/versions/count.
3. `apt upgrade: full` (notifies cleanup/autoremove handlers).
4. Reboot decision: compare running kernel (`uname -r`) vs newest installed
`linux-image-*`; skipped on LXC (`virtualization_type != lxc`). On
`proxmox` group hosts the reboot is deferred unless
`os_update_reboot_on_proxmox`. Otherwise: async `/sbin/reboot`,
`wait_for_connection` (10s delay, 600s timeout), downtime and kernel
after reboot recorded.
5. Postflight logging: duration, upgrade result, reboot details, kernel
before/after appended to the update log (`delegate_to: localhost`).
## Dependencies
- None (ansible.builtin only). Paired with healthcheck at playbook level.
## Tests
- None automated.
## Notes For Agents
- Logging facts are shared with the healthcheck role via the same log file
and start timestamp conventions.
- Old-style module names (apt, file, blockinfile) remain here; use FQCN for
new tasks.
@@ -0,0 +1,59 @@
---
id: MOD-005
type: module
status: active
title: Healthcheck Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, healthcheck, docker, ansible]
related: [MOD-004, REQ-004, NFR-003]
source_paths:
- roles/healthcheck/
confidence: confirmed
---
# Healthcheck Role
## Responsibility
Post-update quality gate: verify that every Docker container on the host is
running and record the result in the update log.
## Source Paths
- `roles/healthcheck/tasks/main.yml` (single file, no subtasks)
- `roles/healthcheck/defaults/main.yml`
## Public Interfaces
- Playbook: `playbooks/os-updates-deb.yml` (runs after os-updates)
- Key variables: `healthcheck_fail_on_unhealthy` (default false),
`healthcheck_logging_enabled` (derives from `os_update_logging_enabled`),
`healthcheck_log_file` (reuses os-updates log path conventions).
## Important Flows
1. Detect Docker binary (`which docker`, tolerant).
2. If Docker present: list all container names and running container names
(`docker ps -a` / `docker ps --filter status=running`), compute
non-running set.
3. If Docker absent: neutral result (0 containers, passed).
4. Append a `quality_gate:` section (docker_installed, total/running counts,
non-running list, healthcheck_passed) to
`logs/<inventory>/<hostname>/update.log` via `blockinfile` delegated to
localhost.
5. Fail the play when `healthcheck_fail_on_unhealthy` is true and any
container is not running.
## Dependencies
- Shares log file conventions with [os-updates](./MOD-004-os-updates-role.md).
## Tests
- None automated.
## Notes For Agents
- The gate does not fail by default; set `healthcheck_fail_on_unhealthy`
to make failures visible in CI-like runs.
@@ -0,0 +1,57 @@
---
id: MOD-006
type: module
status: active
title: Hawser Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, hawser, docker, ansible]
related: [MOD-002, REQ-005]
source_paths:
- roles/hawser/
confidence: confirmed
---
# Hawser Role
## Responsibility
Update the Hawser Docker Compose stack on a host that already runs Docker.
## Source Paths
- `roles/hawser/tasks/main.yml` → `update-stack.yml`
- Template: `roles/hawser/templates/docker-compose.yml.j2`
- Handlers: `roles/hawser/handlers/main.yml`
## Public Interfaces
- Playbook: `playbooks/upgrade-hawser.yml`
- Key variables: `hawser_project_name` (hawser),
`hawser_compose_dir` (/opt/hawser), `hawser_port` (2376),
`hawser_stacks_volume` (hawser_stacks),
`hawser_allow_insecure_no_auth` (true - documented as requiring an
otherwise secured network).
## Important Flows
1. Gather Docker host info (`community.docker.docker_host_info`,
`ignore_errors: true`).
2. Require existing compose file at `<hawser_compose_dir>/docker-compose.yml`;
re-render it from the template.
3. `community.docker.docker_compose_v2` with `state: present`,
`pull: always` to pull latest images and recreate the stack.
## Dependencies
- Requires Docker on the target (role skips gracefully when Docker is not
reachable). Collection: `community.docker`.
## Tests
- None automated.
## Notes For Agents
- `hawser_allow_insecure_no_auth: true` allows token-less standard mode on
non-loopback addresses; treat as a deliberate, documented trade-off.
@@ -0,0 +1,58 @@
---
id: MOD-007
type: module
status: active
title: Manage SSH Keys Role
created: 2026-09-09
updated: 2026-09-09
tags: [module, ssh, hardening, ansible]
related: [REQ-006, ALERT-20260909-001]
source_paths:
- roles/manage-ssh-keys/
confidence: confirmed
---
# Manage SSH Keys Role
## Responsibility
Harden SSH access by enforcing an allow list (`good_keys`) and removing
deny-listed keys (`bad_keys`) from the target user's authorized keys.
## Source Paths
- `roles/manage-ssh-keys/tasks/main.yml` → `validate-authorized-keys.yml`,
`add-goodkeys.yml`, `remove-badkeys.yml`
- Handlers: `roles/manage-ssh-keys/handlers/main.yml`
## Public Interfaces
- Playbook: `playbooks/hardening/manage-ssh-keys.yml`
(binds the role directly; **no Debian guard, no `become`**)
- Key variables: `ssh_user` (admin), `good_keys` (allow list),
`bad_keys` (deny list; supports env-provided JSON overrides via commented
vars in the playbook).
- Conditional execution: `good_keys.defined and good_keys | length > 0`
(same for `bad_keys`).
## Important Flows
1. Validate/ensure `~/.ssh` of the logged-in user (0700).
2. Add `good_keys` to authorized keys.
3. Remove `bad_keys` from authorized keys.
## Dependencies
- None (ansible.builtin).
## Tests
- None automated.
## Notes For Agents
- The playbook deviates from the documented convention (Debian guard,
`become: true`); treat as an intentional gap to confirm before adding
more hardening playbooks.
- Keys in `defaults/main.yml` are public keys (not secrets); the same allow
list also exists in `roles/bootstrap/defaults/main.yml`.
+69
View File
@@ -0,0 +1,69 @@
---
id: TECH-SECURITY
type: technical
status: active
title: Security
created: '2026-09-09'
updated: '2026-09-09'
tags:
- technical
- security
related:
- ALERT-20260909-001
- ALERT-20260909-002
- NFR-002
- MOD-003
- MOD-007
source_paths:
- vault.yml
- roles/monitoring/tasks/configure-psk.yml
- roles/bootstrap/defaults/main.yml
- ansible.cfg
confidence: confirmed
---
# Security
## Secrets Handling
- `vault.yml` (tracked, encrypted) holds `admin_password` (SHA-512 hash),
`monitoring_zabbix_api_password`, and Proxmox credentials
(`PROXMOX_USER_NAME`, `PROXMOX_USER_PASS`); it is loaded via playbook-level
`vars_files` in `bootstrap.yml` and `playbooks/monitoring.yml`.
- Git-ignored (verified): `.vault_pass`, `setenv.sh` (Proxmox credentials),
`.zabbix-psk/` (per-host PSKs), `logs/`.
- Resolved 2026-09-09: the `admin_password` SHA-512 hash that was committed
in plaintext in `roles/bootstrap/defaults/main.yml` and
`inventory/group_vars/external.yml` was moved to encrypted `vault.yml`
(see [ALERT-20260909-001](../alerts/ALERT-20260909-001.md)).
## SSH Posture
- Controller/transport: `host_key_checking = False`,
`StrictHostKeyChecking=no`, `UserKnownHostsFile=/dev/null` (ansible.cfg,
execute.sh, Dockerfile). Deliberate for first-time provisioning; README
explicitly warns to restrict this in production.
- Host hardening: `manage-ssh-keys` role enforces allow/deny key lists;
bootstrap deploys hardened `sshd.conf.j2` and per-host authorized keys.
- Per-host exceptions: `ssh_service_name: ssh` on `gitea`/`ipam`.
## Zabbix Agent TLS
- PSK-only encryption (TLS connect + accept), 256-bit PSKs generated with
`openssl rand -hex 32` on the controller, persisted with umask 077 in a
0700 directory, deployed 0600 to the agent host. Identity = host name.
## Risky Defaults (documented trade-offs)
- `hawser_allow_insecure_no_auth: true` - Hawser standard mode without token
on non-loopback addresses; comment in defaults demands other network
protections.
- `execute.sh` disables host key checking inside the runtime container.
- Mirror rewrite runs with `ignore_errors: true` in os-updates.
## Git Hygiene
- Resolved 2026-09-09: the previously uncommitted change set (including the
`dmc12` → `cloudlorean` inventory rename and stale documentation) was
committed as one coherent change; see
[ALERT-20260909-002](../alerts/ALERT-20260909-002.md).
+41
View File
@@ -0,0 +1,41 @@
---
id: TECH-TESTING
type: technical
status: active
title: Testing
created: '2026-09-09'
updated: 2026-09-09
tags:
- technical
- testing
related:
- MOD-005
source_paths: []
confidence: confirmed
---
# Testing
## Automated Tests
- None found. The repository has no test suite, no CI configuration, and no
lint config (`confidence: confirmed` for absence in the working tree).
## Verification Approach (documented in AGENTS.md / README)
1. Run changes in the Docker container: `./execute.sh` (image
`ansible:deb13`, repo mounted at `/ansible`).
2. Optional lint: `ansible-lint` (recommended by AGENTS.md, not installed in
the image by default).
3. Dry runs with `ansible-playbook --check` where sensible.
4. Role-level documentation duty: update the role README with every
variable/task/template change.
## Built-In Quality Gates
- Playbook-level Debian guard (`os_family` check) on all playbooks except
`playbooks/hardening/manage-ssh-keys.yml`.
- `healthcheck` role: post-update container quality gate, optionally failing
the play (`healthcheck_fail_on_unhealthy`, default false).
- `monitoring` role: PSK format/length assertion, role input validation task
(`validate.yml`).
+34
View File
@@ -0,0 +1,34 @@
---
id: ADR-0001
type: decision
status: active
title: Short decision title
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: []
related: []
source_paths: []
confidence: confirmed
---
# ADR-0001 - Short Decision Title
## Context
TBD
## Decision
TBD
## Alternatives Considered
- TBD
## Consequences
- TBD
## Related
- TBD
+40
View File
@@ -0,0 +1,40 @@
---
id: ALERT-YYYYMMDD-001
type: alert
status: open
severity: medium
title: Short Alert Title
created: YYYY-MM-DD
updated: YYYY-MM-DD
resolved: null
tags: [alert]
related: []
source_paths: []
confidence: inferred
---
# ALERT-YYYYMMDD-001 - Short Alert Title
## Summary
TBD
## Why It Matters
TBD
## Evidence
- TBD
## Suggested Resolution
TBD
## Resolution
Pending.
## Resolution Evidence
- TBD
+34
View File
@@ -0,0 +1,34 @@
---
id: AN-YYYYMMDD-001
type: analysis
status: active
title: Short Analysis Title
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [analysis]
related: []
source_paths: []
confidence: inferred
---
# Short Analysis Title
## Why This Was Filed
TBD
## Summary
TBD
## Related Evidence
- TBD
## Implications
TBD
## Follow-Up
- TBD
+38
View File
@@ -0,0 +1,38 @@
---
id: API-001
type: api
status: active
title: API Name
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: []
related: []
source_paths: []
confidence: inferred
---
# API Name
## Purpose
TBD
## Endpoints Or Operations
TBD
## Contracts
TBD
## Authentication And Authorization
TBD
## Error Handling
TBD
## Related Code
TBD
+41
View File
@@ -0,0 +1,41 @@
---
id: CR-YYYYMMDD-001
type: change-request
status: active
title: Short change title
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: []
related: []
source_paths: []
confidence: confirmed
---
# CR-YYYYMMDD-001 - Short Change Title
## Summary
TBD
## Source
- Meeting, document, chat note, or user request: TBD
## What Changed
TBD
## Reason
TBD
## Impact
- Requirements: TBD
- Technical docs: TBD
- Implementation: TBD
- Tests: TBD
## Follow-Up
- TBD
@@ -0,0 +1,28 @@
# Document Intake
This section stores external source documents imported for project-wiki update workflows. Intake documents are provenance, not canonical project knowledge until accepted information is integrated into requirements, changes, technical docs, implementation docs, or traceability maps.
## When To Read
- Process a new PDF, DOCX, text, or Markdown requirements document.
- Review the source provenance behind a requirement, CR, ADR, or open question.
- Investigate conflicts between an imported document and the current KB or as-is technical state.
## Routing Rules
- Read active and reviewed intake documents only when working on document-based updates, provenance, audits, or conflict investigation.
- Read the compact `intake-report.md`, then use `review_progress.py inspect` for structure and coverage. Do not load `chunks.json`, `review-progress.yml`, or generated chunk wrappers directly unless troubleshooting.
- Use `view --section SEC-NNN` only for reliable source-defined sections reported by `inspect`; review every listed section and unsectioned unit. Use `view --all` whenever structure is absent, incomplete, ambiguous, or full-document context may matter.
- After complete coverage, run `review_progress.py audit`; require `review-complete` and record its ledger summary and SHA-256. Rerun after ledger corrections.
- Before a terminal intake status, run `audit --expect-ledger-sha256 <final-ledger-sha256>` with the digest from the reviewed audit.
- Do not mark an intake reviewed or integrated until the ledger is complete. Every classified integrated chunk must link to its registered target IDs; every skipped chunk needs a reason.
- Do not read integrated, archived, superseded, or rejected intake documents during normal coding tasks unless explicitly requested.
- Use canonical KB files, not intake documents, as the source of truth after integration.
## Active Intake Documents
- None yet.
## Reviewed, Integrated, Archived, Superseded, Or Rejected Documents
- None yet.
@@ -0,0 +1,58 @@
---
id: DOCIN-YYYYMMDD-001-REVIEW
type: intake-review
status: reviewed
title: Review - Source Document Title
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [intake, review]
related: [DOCIN-YYYYMMDD-001]
source_paths: []
confidence: inferred
---
# Document Intake Review - Source Document Title
## Review Coverage
- Ledger: [review-progress.yml](./review-progress.yml)
- Total chunks: TBD
- Classified: TBD
- Skipped with reason: TBD
- Pending or reviewed: 0
- Validator result: passed
## Blocking Decision Needed
- Exact question: TBD
- Why conservative integration cannot proceed: TBD
- Approval authority: TBD
## Options And Consequences
| Option | Canonical Effect | Risks Or Trade-Offs | Evidence |
| --- | --- | --- | --- |
| TBD | TBD | TBD | TBD |
## Affected Canonical Scope
| Candidate | Proposed Target | Action | Rationale |
| --- | --- | --- | --- |
| DOCIN-YYYYMMDD-001-CH-001 | requirements/functional/<project-topic>.md or requirements/non-functional/<project-topic>.md | Add requirement | TBD |
## Affected Atomic Requirement Plan
Include this section only when the blocking decision changes requirement topic scope, target files, or permitted ID ranges. Complete the full decomposition plan after approval and before canonical authoring.
| Family | Topic | Target File | Reserved IDs | Planned Atomic Records | Evidence Chunks |
| --- | --- | --- | --- | ---: | --- |
| functional | Authentication | requirements/functional/authentication.md | REQ-001..REQ-005 | 5 | DOCIN-YYYYMMDD-001-CH-001, DOCIN-YYYYMMDD-001-CH-002 |
| non-functional | Security | requirements/non-functional/security.md | NFR-001..NFR-003 | 3 | DOCIN-YYYYMMDD-001-CH-003 |
## Related Durable Records
- Open questions, alerts, blocked records, or alternatives that preserve non-blocking uncertainty: TBD
## Approval Outcome
Pending user confirmation.
@@ -0,0 +1,70 @@
---
id: LINT-YYYYMMDD
type: maintenance-lint
status: active
title: Wiki Maintenance Lint YYYY-MM-DD
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [maintenance, lint]
related: []
source_paths: []
confidence: inferred
---
# Wiki Maintenance Lint YYYY-MM-DD
## Deterministic Validation
- Command: `python3 /path/to/project-wiki/scripts/validate_wiki.py --wiki-root .project-wiki --format json`
- Result: passed | findings-remain | validator-error
- Errors: TBD
- Warnings: TBD
- Unresolved finding codes: TBD
## Structural Fixes Applied
- TBD
## Structural Issues Requiring Review
- TBD
## Contradictions
- TBD
## Stale Claims
- TBD
## Traceability Gaps
- TBD
## Orphan Pages
- TBD
## Suggested Follow-Up Questions
| Question | Why It Matters | Related Docs | Suggested Action |
| --- | --- | --- | --- |
| TBD | TBD | TBD | TBD |
## Missing Source Material
| Gap | Impact | Related Docs | Suggested Source |
| --- | --- | --- | --- |
| TBD | TBD | TBD | TBD |
## Risky Assumptions
| Assumption | Risk | Evidence | Proposed Action |
| --- | --- | --- | --- |
| TBD | TBD | TBD | TBD |
## Alert Candidates
| Candidate Alert | Severity | Why It Matters | Related Evidence |
| --- | --- | --- | --- |
| TBD | medium | TBD | TBD |
+42
View File
@@ -0,0 +1,42 @@
---
id: MOD-001
type: module
status: active
title: Module Name
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: []
related: []
source_paths: []
confidence: inferred
---
# Module Name
## Responsibility
TBD
## Source Paths
- TBD
## Public Interfaces
TBD
## Important Flows
TBD
## Dependencies
TBD
## Tests
TBD
## Notes For Agents
TBD
+20
View File
@@ -0,0 +1,20 @@
<a id="req-001"></a>
## REQ-001 - Requirement Title
Status: active
Tags: []
Related: []
Confidence: confirmed
### Statement
TBD
### Rationale
TBD
### Acceptance Notes
TBD
+38
View File
@@ -0,0 +1,38 @@
---
id: SCAN-YYYYMMDD
type: scan-report
status: active
title: Codebase Scan YYYY-MM-DD
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [scan]
related: []
source_paths: []
confidence: inferred
---
# Codebase Scan YYYY-MM-DD
## Scope
TBD
## Confirmed Findings
- TBD
## Inferred Findings
- TBD
## Unknowns
- TBD
## Important Paths
- TBD
## Suggested Wiki Updates
- TBD
@@ -0,0 +1,40 @@
---
id: MIGRATION-YYYYMMDD
type: schema-migration
status: active
title: Schema Migration YYYY-MM-DD
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [maintenance, schema-migration]
related: []
source_paths: []
confidence: confirmed
---
# Schema Migration YYYY-MM-DD
## Version Check
- Previous schema version: TBD
- Target schema version: 1.5.1
- Migration needed: yes | no
## Actions Applied
- TBD
## Actions Requiring User Confirmation
- TBD
## Legacy Items Detected
- TBD
## Files Changed
- TBD
## Result
TBD
+30
View File
@@ -0,0 +1,30 @@
# Sources
This section stores raw source documents used by document-based update workflows. Source documents are raw input, not canonical project knowledge.
## How To Use
- Drop new PDF, DOCX, text, or Markdown files into [inbox/](./inbox/).
- Run `/project-wiki update`.
- The agent runs the project-wiki deterministic inbox preflight with skip quarantine, registers only files classified `process` in [SOURCE_REGISTRY.yml](./SOURCE_REGISTRY.yml), runs document ingestion, and moves successfully processed files to `processed/YYYY-MM/` when possible.
- Keep human instructions in this file. Do not create `README.md` or other guide files inside `inbox/`.
## Routing Rules
- Never read PDF/DOCX source files directly into model context.
- Use source files only through the document ingestion script.
- Treat the inbox preflight report as authoritative for SHA-256 hashes, validated registry and intake-history matches, retry-record selection, inbox duplicates, and quarantine destinations; use agent review only for changed content at a historical path, ambiguous registry history, or explicit reprocessing.
- Use `intake/` artifacts for review and canonical KB integration.
- Ignore inbox housekeeping files such as `README.md`, `.gitkeep`, `.DS_Store`, hidden files, files beginning with `_`, and temporary or partial download files.
## Inbox
- No pending source files registered yet.
## Processed Sources
- None yet.
## Failed, Rejected, Ignored, Or Superseded Sources
- None yet.
@@ -0,0 +1,3 @@
version: 1
updated: YYYY-MM-DD
sources: []
+38
View File
@@ -0,0 +1,38 @@
---
id: SYNC-YYYYMMDD-001
type: sync-report
status: active
title: Manual Code Sync YYYY-MM-DD
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: [sync]
related: []
source_paths: []
confidence: inferred
---
# Manual Code Sync YYYY-MM-DD
## Baseline
TBD
## Changed Source Paths
- TBD
## Confirmed Wiki Updates
- TBD
## Inferred Wiki Updates
- TBD
## Open Questions
- TBD
## Traceability Updates
- TBD
+33
View File
@@ -0,0 +1,33 @@
# Wiki Log YYYY-MM
This file is an append-only monthly audit trail of meaningful `.project-wiki/` updates for YYYY-MM.
## [YYYY-MM-DD] mode | WLOG-YYYYMMDD-001 | Short Summary
Date: YYYY-MM-DD
Agent: TBD
Mode: init | scan | update | sync | maintain | auto-post-implementation
Trigger: TBD
Changed wiki documents:
- TBD
Related source paths:
- TBD
Related IDs:
- TBD
Open question reconciliation:
- Resolved: TBD
- Partially resolved: TBD
- Superseded: TBD
- Dismissed: TBD
- Duplicated: TBD
- Newly created: TBD
Summary:
TBD
Open questions:
- TBD
+38
View File
@@ -0,0 +1,38 @@
---
id: WI-YYYYMMDD-001
type: work-item
status: active
title: Short work item title
created: YYYY-MM-DD
updated: YYYY-MM-DD
tags: []
related: []
source_paths: []
confidence: confirmed
---
# WI-YYYYMMDD-001 - Short Work Item Title
## Goal
TBD
## Context
TBD
## Scope
TBD
## Out Of Scope
TBD
## Acceptance Notes
TBD
## Related Wiki Docs
- TBD
+18
View File
@@ -0,0 +1,18 @@
# Traceability
This section connects requirements, changes, decisions, technical documentation, and source paths.
## When To Read
- Analyze implementation coverage or change impact.
## Key Files
- [Requirement map](./requirement-map.md)
- [Requirement evidence](./requirement-evidence.yml)
- [Change impact map](./change-impact-map.md)
- [Code map](./code-map.md)
## Placeholders Or Stale Areas
- `change-impact-map.md` still placeholder (no change requests yet).
@@ -0,0 +1,3 @@
# Change Impact Map
No change impact traceability has been captured yet.
+20
View File
@@ -0,0 +1,20 @@
# Code Traceability Map
Connects wiki documents to source paths. Created during the 2026-09-09 scan.
| Wiki Document | Source Paths | Notes |
| --- | --- | --- |
| [MOD-001 Bootstrap](../technical/modules/MOD-001-bootstrap-role.md) | `bootstrap.yml`, `roles/bootstrap/` | Composes docker + monitoring roles |
| [MOD-002 Docker](../technical/modules/MOD-002-docker-role.md) | `playbooks/docker.yml`, `roles/docker/` | Official Docker apt repo |
| [MOD-003 Monitoring](../technical/modules/MOD-003-monitoring-role.md) | `playbooks/monitoring.yml`, `roles/monitoring/`, `vault.yml` | Zabbix Agent 2, PSK, API registration |
| [MOD-004 OS Updates](../technical/modules/MOD-004-os-updates-role.md) | `playbooks/os-updates-deb.yml`, `roles/os-updates/` | Mirror switch, reboot, logging |
| [MOD-005 Healthcheck](../technical/modules/MOD-005-healthcheck-role.md) | `playbooks/os-updates-deb.yml`, `roles/healthcheck/` | Container quality gate |
| [MOD-006 Hawser](../technical/modules/MOD-006-hawser-role.md) | `playbooks/upgrade-hawser.yml`, `roles/hawser/` | Compose stack update |
| [MOD-007 Manage SSH Keys](../technical/modules/MOD-007-manage-ssh-keys-role.md) | `playbooks/hardening/manage-ssh-keys.yml`, `roles/manage-ssh-keys/` | No Debian guard (gap) |
| [TECH-DEPLOYMENT](../technical/deployment.md) | `execute.sh`, `docker/`, `ansible.cfg` | Runtime environment |
| [TECH-SECURITY](../technical/security.md) | `vault.yml`, `roles/*/defaults/`, `ansible.cfg`, `roles/monitoring/tasks/configure-psk.yml` | Secrets, SSH, PSK |
| [TECH-INTEGRATIONS-ZABBIX](../technical/integrations/zabbix.md) | `roles/monitoring/`, `inventory/group_vars/` | Zabbix + external services |
| [NFR-003](../requirements/non-functional/operational-policies.md#nfr-003) | `roles/os-updates/tasks/logging_*.yml`, `roles/healthcheck/tasks/main.yml` | Update log audit trail |
| [NFR-006](../requirements/non-functional/operational-policies.md#nfr-006) | `roles/os-updates/tasks/reboot.yml`, `roles/bootstrap/tasks/configure-sysctl.yml` | LXC skips |
| [ALERT-20260909-001](../alerts/ALERT-20260909-001.md) | `roles/bootstrap/defaults/main.yml`, `inventory/group_vars/external.yml`, `bootstrap.yml`, `vault.yml` | Plaintext admin hash - resolved (vaulted) |
| [ALERT-20260909-002](../alerts/ALERT-20260909-002.md) | `inventory/cloudlorean.yml`, `README.md`, `AGENTS.md`, `roles/*/README.md` | Rename committed, stale docs fixed |
@@ -0,0 +1,129 @@
version: 1
updated: '2026-09-09'
records:
REQ-001:
requirement: REQ-001
evidence:
- source: README.md
locator: "Playbooks table: 'bootstrap.yml | bootstrap | Vollständige Ersteinrichtung eines Debian-Hosts'"
type: doc
- source: roles/bootstrap/tasks/main.yml
locator: "import_tasks list + import_role docker/monitoring"
type: code
confidence: confirmed
REQ-002:
requirement: REQ-002
evidence:
- source: README.md
locator: "Playbooks table: 'playbooks/docker.yml | docker | Docker Engine installieren'"
type: doc
- source: roles/docker/defaults/main.yml
locator: "docker_mirror, docker_packages"
type: code
confidence: confirmed
REQ-003:
requirement: REQ-003
evidence:
- source: README.md
locator: "Playbooks table: 'playbooks/monitoring.yml | monitoring | Zabbix Agent 2 installieren & registrieren'"
type: doc
- source: roles/monitoring/tasks/register-host.yml
locator: "community.zabbix.zabbix_host registration"
type: code
confidence: confirmed
REQ-004:
requirement: REQ-004
evidence:
- source: README.md
locator: "Playbooks table: 'playbooks/os-updates-deb.yml | os-updates, healthcheck | Pakete aktualisieren + Healthcheck'"
type: doc
- source: playbooks/os-updates-deb.yml
locator: "include_role os-updates + healthcheck"
type: code
confidence: confirmed
REQ-005:
requirement: REQ-005
evidence:
- source: README.md
locator: "Playbooks table: 'playbooks/upgrade-hawser.yml | hawser | Hawser-Stack aktualisieren'"
type: doc
- source: roles/hawser/tasks/update-stack.yml
locator: "docker_compose_v2 pull: always"
type: code
confidence: confirmed
REQ-006:
requirement: REQ-006
evidence:
- source: README.md
locator: "Playbooks table: 'playbooks/hardening/manage-ssh-keys.yml | manage-ssh-keys | SSH-Schlüssel hartieren'"
type: doc
- source: roles/manage-ssh-keys/tasks/main.yml
locator: "validate/add/remove key subtasks"
type: code
confidence: confirmed
NFR-001:
requirement: NFR-001
evidence:
- source: README.md
locator: "Voraussetzungen: 'Ziel-Hosts: Debian (alle Playbooks prüfen os_family == \"Debian\")'"
type: doc
- source: bootstrap.yml
locator: "fail when os_family != Debian"
type: code
- source: playbooks/hardening/manage-ssh-keys.yml
locator: "no os_family guard (deviation)"
type: code
confidence: confirmed
NFR-002:
requirement: NFR-002
evidence:
- source: README.md
locator: "Secrets & Vault + Beitragen rule 3"
type: doc
- source: roles/bootstrap/defaults/main.yml
locator: "comment pointing to vault.yml (violation resolved, ALERT-20260909-001)"
type: code
- source: bootstrap.yml
locator: "vars_files: vault.yml (vaulted admin_password)"
type: code
confidence: confirmed
NFR-003:
requirement: NFR-003
evidence:
- source: README.md
locator: "Logging section: logs/<inventory>/<hostname>/update.log"
type: doc
- source: roles/os-updates/defaults/main.yml
locator: "os_update_log_file template"
type: code
confidence: confirmed
NFR-004:
requirement: NFR-004
evidence:
- source: README.md
locator: "Docker-Ausführungsumgebung section"
type: doc
- source: execute.sh
locator: "docker run with repo mount /ansible"
type: code
confidence: confirmed
NFR-005:
requirement: NFR-005
evidence:
- source: AGENTS.md
locator: "Dokumentationspflicht mapping table"
type: doc
- source: README.md
locator: "Beitragen rule 2"
type: doc
confidence: confirmed
NFR-006:
requirement: NFR-006
evidence:
- source: AGENTS.md
locator: "OS-Unterstützung: LXC sysctl/reboot skip"
type: doc
- source: roles/os-updates/tasks/reboot.yml
locator: "when: ansible_facts['virtualization_type'] != 'lxc'"
type: code
confidence: confirmed
@@ -0,0 +1,26 @@
# Requirement Traceability Map
Requirement records → implementing source paths → evidence. Created during
the 2026-09-09 scan; detailed evidence in
[requirement-evidence.yml](./requirement-evidence.yml).
| Requirement | Statement (short) | Implements / Verified By | Evidence |
| --- | --- | --- | --- |
| [REQ-001](../requirements/functional/host-lifecycle-operations.md#req-001) | Initial provisioning via bootstrap | `bootstrap.yml`, `roles/bootstrap/` | README playbook table |
| [REQ-002](../requirements/functional/host-lifecycle-operations.md#req-002) | Docker Engine install | `playbooks/docker.yml`, `roles/docker/` | README playbook table |
| [REQ-003](../requirements/functional/host-lifecycle-operations.md#req-003) | Zabbix Agent 2 install + register | `playbooks/monitoring.yml`, `roles/monitoring/` | README playbook table |
| [REQ-004](../requirements/functional/host-lifecycle-operations.md#req-004) | Package updates + healthcheck | `playbooks/os-updates-deb.yml`, `roles/os-updates/`, `roles/healthcheck/` | README playbook table |
| [REQ-005](../requirements/functional/host-lifecycle-operations.md#req-005) | Hawser stack update | `playbooks/upgrade-hawser.yml`, `roles/hawser/` | README playbook table |
| [REQ-006](../requirements/functional/host-lifecycle-operations.md#req-006) | SSH key hardening | `playbooks/hardening/manage-ssh-keys.yml`, `roles/manage-ssh-keys/` | README playbook table |
| [NFR-001](../requirements/non-functional/operational-policies.md#nfr-001) | Debian-only guard | `bootstrap.yml`, `playbooks/*.yml` (exception: manage-ssh-keys.yml) | README prerequisites |
| [NFR-002](../requirements/non-functional/operational-policies.md#nfr-002) | Secrets only in vault | `vault.yml`, `bootstrap.yml` + `playbooks/monitoring.yml` (`vars_files`) | README secrets section |
| [NFR-003](../requirements/non-functional/operational-policies.md#nfr-003) | Per-host update audit log | `roles/os-updates/tasks/logging_*.yml`, `roles/healthcheck/tasks/main.yml` | README logging section |
| [NFR-004](../requirements/non-functional/operational-policies.md#nfr-004) | Docker-based execution | `execute.sh`, `docker/Dockerfile`, `docker/requirements.yml` | README docker section |
| [NFR-005](../requirements/non-functional/operational-policies.md#nfr-005) | Documentation duty | `roles/*/README.md`, root `README.md` | README contributing, AGENTS.md |
| [NFR-006](../requirements/non-functional/operational-policies.md#nfr-006) | LXC-aware sysctl/reboot | `roles/os-updates/tasks/reboot.yml`, `roles/bootstrap/tasks/configure-sysctl.yml` | AGENTS.md OS support |
Gaps and deviations:
- NFR-001: `playbooks/hardening/manage-ssh-keys.yml` has no Debian guard.
- NFR-002: resolved 2026-09-09 - `admin_password` moved to vault.yml
(was ALERT-20260909-001).
+11 -1
View File
@@ -4,6 +4,16 @@ Richtlinien und Kontext für AI-Agenten (z. B. Mammouth Code, Claude, GPT),
die an diesem Ansible-Repository arbeiten. Diese Datei fasst Repository-spezifische
Konventionen zusammen, damit Änderungen konsistent und nachvollziehbar bleiben.
<!-- PROJECT-WIKI:BEGIN -->
## Project Wiki (Automatic Instructions)
- Before implementing, modifying, debugging, refactoring, testing, documenting, or planning code, read `.project-wiki/INDEX.md` and follow its routing to the smallest relevant set of wiki documents (automatic context preflight).
- After making source changes, update the affected `.project-wiki/` records (technical docs, traceability maps, section indexes, `REGISTRY.yml`, `STATUS.md`) as part of the same task.
- Use the wiki `sync` mode only for manual or externally changed code; agent-made changes are updated directly (automatic post-implementation wiki update).
- After every meaningful wiki edit, reconcile affected indexes, `REGISTRY.yml`, `STATUS.md`, traceability, and append an entry to `.project-wiki/logs/wiki-log-YYYY-MM.md`.
- Write all wiki content and generated instruction blocks in English; reply to the user in their chat language.
<!-- PROJECT-WIKI:END -->
## Repository-Übersicht
Zentrale Ansible-Sammlung für die Bereitstellung, Härtung, Aktualisierung und
@@ -156,7 +166,7 @@ Benötigte Collections (in `docker/requirements.yml`):
Default `trixie`. Nicht blind ändern – wird für Template-Ausfüllung der
`sources.list` verwendet.
- **`ssh_service_name`**: Auf manchen Hosts heißt der Service `ssh`, nicht
`sshd` (siehe `inventory/dmc12.yml`: `gitea`, `ipam`). Beim Hinzufügen
`sshd` (siehe `inventory/cloudlorean.yml`: `gitea`, `ipam`). Beim Hinzufügen
neuer Hosts prüfen.
- **PSK-Store**: `monitoring` speichert pro Host eine PSK unter
`.zabbix-psk/<hostname>.psk` (git-ignored). Bei Host-Umbenennung PSK
+28 -16
View File
@@ -52,7 +52,7 @@ gleichnamige Datei sowie ein Eintrag in `group_vars/`:
| Inventory | Datei | group_vars | Beschreibung |
|------------------|--------------------|------------------------|-------------------------------------------------|
| DMC12 (Umgebung) | `dmc12.yml` | `debian.yml` | Debian-Hosts & Proxmox-Knoten |
| Cloudlorean | `cloudlorean.yml` | `cloudlorean.yml`, `debian.yml` | Debian-Hosts & Proxmox-Knoten (u. a. `dmc12`) |
| Home | `home.yml` | `home.yml` | Heimisches Netzwerk (10.13.37.0/24) |
| External | `external.yml` | `external.yml` | Externe Hosts (IPv6) |
@@ -73,20 +73,20 @@ Spiegelserver und autorisierte SSH-Keys.
### Aufrufbeispiele
```bash
# Ersteinrichtung aller Hosts im DMC12-Inventory
ansible-playbook -i inventory/dmc12.yml bootstrap.yml
# Ersteinrichtung aller Hosts im Cloudlorean-Inventory
ansible-playbook -i inventory/cloudlorean.yml bootstrap.yml
# Nur Docker auf einem einzelnen Host installieren
ansible-playbook -i inventory/home.yml playbooks/docker.yml -l rp
# OS-Updates inkl. Healthcheck
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/os-updates-deb.yml
# Hawser aktualisieren
ansible-playbook -i inventory/dmc12.yml playbooks/upgrade-hawser.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/upgrade-hawser.yml
# SSH-Keys härtene
ansible-playbook -i inventory/dmc12.yml playbooks/hardening/manage-ssh-keys.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/hardening/manage-ssh-keys.yml
```
## Rollen
@@ -103,13 +103,14 @@ ansible-playbook -i inventory/dmc12.yml playbooks/hardening/manage-ssh-keys.yml
## Secrets & Vault
Sensible Werte (z. B. `monitoring_zabbix_api_password`, `admin_password`)
liegen verschlüsselt in `vault.yml`. Zum Entschlüsseln wird eine Vault-Passwort
benötigt, die in `.vault_pass` hinterlegt ist (git-ignored). Beim Aufruf muss
Ansible die Vault-Passwort-Datei kennen:
Sensible Werte (`monitoring_zabbix_api_password`, `admin_password`, Proxmox-Zugang)
liegen verschlüsselt in `vault.yml`. `playbooks/monitoring.yml` und `bootstrap.yml`
binden die Datei selbst per `vars_files` ein. Zum Entschlüsseln wird eine
Vault-Passwort benötigt, die in `.vault_pass` hinterlegt ist (git-ignored).
Beim Aufruf muss Ansible die Vault-Passwort-Datei kennen:
```bash
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_pass bootstrap.yml
ansible-playbook -i inventory/cloudlorean.yml --vault-password-file .vault_pass bootstrap.yml
```
> **Hinweis:** Die Datei `setenv.sh` enthält Zugangsdaten für Proxmox und ist
@@ -125,14 +126,25 @@ git-ignored und dient als lokales Audit-Trail.
## Konfiguration
`ansible.cfg` deaktiviert Host-Key-Checking und legt `./roles` als
Rollen-Pfad fest. SSH-Verbindungen verwenden
`StrictHostKeyChecking=no` sowie `/dev/null` als KnownHosts-Datei, was die
Ersteinrichtung neuer Hosts erleichtert – in produktiven Umgebungen
entsprechend restriktiver konfigurieren.
Rollen-Pfad fest. Für schnellere Ausführungen werden standardmäßig 20 parallele
Worker (`forks`), SSH-Pipelining und persistente SSH-Verbindungen
(`ControlPersist=60s`) verwendet. `gathering=smart` vermeidet die erneute
Faktenabfrage innerhalb eines Laufs, ohne einen persistenten Fakten-Cache mit
potenziell veralteten Hostdaten einzuführen. `internal_poll_interval` reduziert
die Wartezeit des Controllers zwischen Worker-Abfragen.
SSH-Verbindungen verwenden weiterhin `StrictHostKeyChecking=no` sowie `/dev/null`
als KnownHosts-Datei, was die Ersteinrichtung neuer Hosts erleichtert – in
produktiven Umgebungen entsprechend restriktiver konfigurieren. Bei sehr vielen
gleichzeitig verwalteten Hosts kann `forks` über `ANSIBLE_FORKS` oder einen
zusätzlichen Konfigurationswert an die Controller- und Netzwerkressourcen
angepasst werden. Fact-Caching und alternative Strategien wie `free` sind nicht
global aktiviert, da sie bei diesen Playbooks veraltete Fakten oder eine andere
Ausführungsreihenfolge verursachen können.
## Beitragen
1. Änderungen lokal testen – idealerweise über `./execute.sh` im Container.
2. Variablen in `defaults/main.yml` der jeweiligen Rolle pflegen und in der
Rollen-README dokumentieren.
3. Keine Secrets unverschlüsselt committen (Vault nutzen).
3. Keine Secrets unverschlüsselt committen (Vault nutzen).
+6 -1
View File
@@ -2,6 +2,11 @@
host_key_checking = False
roles_path = ./roles:/etc/ansible/roles
group_vars = ./group_vars
interpreter_python = auto_silent
forks = 20
gathering = smart
internal_poll_interval = 0.001
[ssh_connection]
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
pipelining = True
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s
+2
View File
@@ -1,6 +1,8 @@
- hosts: all
become: true
user: admin
vars_files:
- vault.yml
tasks:
- name: Verify if system is Debian
debug:
+3
View File
@@ -14,6 +14,9 @@ RUN apt update && apt install -y --no-install-recommends \
tzdata \
openssh-client \
iputils-ping \
vim \
less \
&& apt clean \
&& rm -rf /var/lib/apt/lists/*
RUN mkdir -p /etc/ssh/ssh_config.d \
+3 -1
View File
@@ -4,4 +4,6 @@ collections:
- name: community.general
version: 13.0.1
- name: community.docker
version: 5.2.0
version: 5.2.0
- name: community.zabbix
version: 4.2.0
-3
View File
@@ -3,7 +3,6 @@
defaultimage="ansible:deb13"
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
export ANSIBLE_CONFIG=./ansible.cfg
# Ermittle den nächsten freien Container-Namen
@@ -35,7 +34,6 @@ docker run --rm -dit \
--hostname "$container_name" \
--network "$network_name" \
-e ANSIBLE_HOST_KEY_CHECKING=False \
-e ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' \
-e ANSIBLE_CONFIG=./ansible.cfg \
-v "$(pwd):/ansible" \
-v ansible_ssh_keys:/root/.ssh \
@@ -59,4 +57,3 @@ echo "-----------------------------------"
docker attach "$container_name"
@@ -1,3 +1,8 @@
cloudlorean:
children:
debian:
proxmox:
debian:
hosts:
rp:
@@ -34,4 +39,4 @@ proxmox:
dmc12:
ansible_host: 192.168.212.10
pbs:
ansible_host: 192.168.212.11
ansible_host: 192.168.212.11
+5 -1
View File
@@ -1,3 +1,7 @@
external:
children:
debian:
debian:
hosts:
healthcheck:
@@ -7,4 +11,4 @@ debian:
teleport:
ansible_host: 2a01:4f8:1c19:c7d::1
podcast-linkstack:
ansible_host: 2a01:4f8:c17:de13::1
ansible_host: 2a01:4f8:c17:de13::1
+19
View File
@@ -0,0 +1,19 @@
monitoring_zabbix_passive_servers: ["192.168.212.1"]
# Zabbix server API (password lives in vault.yml as monitoring_zabbix_api_password)
monitoring_zabbix_api_url: "https://mon.cloudlorean.de/api_jsonrpc.php"
monitoring_zabbix_api_user: Admin
monitoring_zabbix_api_validate_certs: true
# Host registration defaults for the home inventory
monitoring_zabbix_host_groups: ["Linux servers", "Cloudlorean"]
monitoring_zabbix_templates: ["Linux by Zabbix agent"]
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent 2"]
# --- Zabbix Proxy (optional) -------------------------------------------------
# Leave empty to have agents talk to the Zabbix server directly.
# Per-site override example (e.g. inventory/group_vars/standort-a.yml):
# monitoring_zabbix_proxy: "fw-standort-a"
# monitoring_zabbix_proxy_address: "10.20.30.1"
monitoring_zabbix_proxy: "gatekeeper.cloudlorean.de"
monitoring_zabbix_proxy_address: "192.168.212.1"
+14 -2
View File
@@ -7,5 +7,17 @@ admin_authorized_keys:
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
comment: "Generic Ansible Key"
# Admin user password (hashed with SHA-512)
admin_password: "$6$NmIxM3ZbJDsbC1E6$BO8ag1ZyBqbhELjk0ppKV0CLnYXhHDp9oZc.jmkc62N9hjwbXihF1FmvsYgMKKINVcwaE73u2dRO8pnE6yEGH/"
# admin_password lives encrypted in vault.yml (loaded via vars_files in
# bootstrap.yml); no plaintext fallback per repository vault policy.
monitoring_zabbix_passive_servers: ["2a01:4f8:1c1e:62dd::1"]
# Zabbix server API (password lives in vault.yml as monitoring_zabbix_api_password)
monitoring_zabbix_api_url: "https://mon.cloudlorean.de/api_jsonrpc.php"
monitoring_zabbix_api_user: Admin
monitoring_zabbix_api_validate_certs: true
# Host registration defaults for the home inventory
monitoring_zabbix_host_groups: ["Linux servers", "Cloudlorean"]
monitoring_zabbix_templates: ["Linux by Zabbix agent"]
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent 2"]
+6 -7
View File
@@ -1,20 +1,19 @@
monitoring_zabbix_passive_servers: ["10.13.37.1"]
monitoring_zabbix_active_servers: ["10.13.37.1"]
# Zabbix server API (password lives in vault.yml as monitoring_zabbix_api_password)
monitoring_zabbix_api_url: "https://zabbix/api_jsonrpc.php"
monitoring_zabbix_api_url: "https://mon.cloudlorean.de/api_jsonrpc.php"
monitoring_zabbix_api_user: Admin
monitoring_zabbix_api_validate_certs: true
# Host registration defaults for the home inventory
monitoring_zabbix_host_groups: ["Linux servers"]
monitoring_zabbix_templates: ["Linux by Zabbix agent", "Zabbix agent2"]
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]
monitoring_zabbix_host_groups: ["Linux servers", "Meyer-Kempen"]
monitoring_zabbix_templates: ["Linux by Zabbix agent"]
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent 2"]
# --- Zabbix Proxy (optional) -------------------------------------------------
# Leave empty to have agents talk to the Zabbix server directly.
# Per-site override example (e.g. inventory/group_vars/standort-a.yml):
# monitoring_zabbix_proxy: "fw-standort-a"
# monitoring_zabbix_proxy_address: "10.20.30.1"
monitoring_zabbix_proxy: ""
monitoring_zabbix_proxy_address: ""
monitoring_zabbix_proxy: "gatekeeper.meyer-kempen.de"
monitoring_zabbix_proxy_address: "10.13.37.1"
+20 -16
View File
@@ -1,20 +1,24 @@
home:
children:
debian:
hosts:
rp:
ansible_host: 10.13.37.11
paperless:
ansible_host: 10.13.37.30
homeassistant:
ansible_host: 10.13.37.15
teleport-jumper:
ansible_host: 10.13.37.50
idris-dns:
ansible_host: 10.13.37.53
it-tools:
ansible_host: 10.13.37.16
proxmox:
hosts:
tardis:
ansible_host: 10.13.37.5
debian:
hosts:
rp:
ansible_host: 10.13.37.11
paperless:
ansible_host: 10.13.37.30
homeassistant:
ansible_host: 10.13.37.15
teleport-jumper:
ansible_host: 10.13.37.50
idris-dns:
ansible_host: 10.13.37.53
it-tools:
ansible_host: 10.13.37.16
proxmox:
hosts:
tardis:
ansible_host: 10.13.37.5
+2
View File
@@ -1,6 +1,8 @@
- hosts: all
user: admin
become: true
vars_files:
- ../vault.yml
tasks:
- name: Verify if system is Debian
debug:
+4 -4
View File
@@ -29,7 +29,7 @@ werden:
```
```bash
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_pass bootstrap.yml
ansible-playbook -i inventory/cloudlorean.yml --vault-password-file .vault_pass bootstrap.yml
```
## Funktionsweise
@@ -66,7 +66,7 @@ Handler neu gestartet.
| Variable | Typ | Default | Beschreibung |
|-------------------------|----------|-------------------|-----------------------------------------------------|
| `admin_authorized_keys` | list | siehe `defaults/` | Liste von `{ key, comment }`-Einträgen für `admin` |
| `admin_password` | string | siehe `defaults/` | SHA-512-Hash des Admin-Passworts |
| `admin_password` | string | – (Vault) | SHA-512-Hash des Admin-Passworts; liegt verschlüsselt in `vault.yml` und wird von `bootstrap.yml` per `vars_files` geladen |
### Steuer-Variablen (keine Defaults, optional setzen)
@@ -78,7 +78,7 @@ Handler neu gestartet.
`admin_authorized_keys` wird auch pro Inventory in `group_vars/external.yml`
überschrieben. Der Handler `Restart sshd` verwendet `ssh_service_name`, sofern
gesetzt (z. B. `ssh` für `gitea`/`ipam` in `inventory/dmc12.yml`).
gesetzt (z. B. `ssh` für `gitea`/`ipam` in `inventory/cloudlorean.yml`).
## Templates
@@ -102,7 +102,7 @@ gesetzt (z. B. `ssh` für `gitea`/`ipam` in `inventory/dmc12.yml`).
Teile, z. B.:
```bash
ansible-playbook bootstrap.yml -i inventory/dmc12.yml -t ssh
ansible-playbook bootstrap.yml -i inventory/cloudlorean.yml -t ssh
```
## Abhängigkeiten
+2 -2
View File
@@ -9,5 +9,5 @@ admin_authorized_keys:
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
comment: "Generic Ansible Key"
# Admin user password (hashed with SHA-512)
admin_password: "$6$NmIxM3ZbJDsbC1E6$BO8ag1ZyBqbhELjk0ppKV0CLnYXhHDp9oZc.jmkc62N9hjwbXihF1FmvsYgMKKINVcwaE73u2dRO8pnE6yEGH/"
# admin_password lives encrypted in vault.yml (loaded via vars_files in
# bootstrap.yml); no plaintext fallback per repository vault policy.
+5 -4
View File
@@ -29,7 +29,7 @@ Einbindung per `import_role`:
```
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/docker.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/docker.yml
```
## Funktionsweise
@@ -52,7 +52,7 @@ ansible-playbook -i inventory/dmc12.yml playbooks/docker.yml
| Variable | Typ | Default | Beschreibung |
|----------------------|---------|--------------------------------------|-------------------------------------------------------|
| `docker_mirror` | string | `https://download.docker.com/linux/debian` | Basis-URL des Docker-APT-Repositories |
| `os_version_codename`| string | `{{ ansible_lsb.codename }}` | Codename der Distribution (für `Suites:`) |
| `os_version_codename`| string | `{{ ansible_facts['distribution_release'] }}` | Codename der Distribution (für `Suites:`) |
| `docker_packages` | list | siehe unten | Liste der zu installierenden Docker-Pakete |
Default `docker_packages`:
@@ -67,7 +67,8 @@ docker_packages:
```
`os_version_codename` wird standardmäßig automatisch anhand von
`ansible_lsb.codename` ermittelt und kann bei Bedarf überschrieben werden.
`ansible_facts['distribution_release']` ermittelt und kann bei Bedarf
überschrieben werden.
## Templates
@@ -99,4 +100,4 @@ Die Rolle vergibt keine eigenen Tags. Bei Bedarf über das Playbook steuerbar.
- Der Handler `Start Docker` aktiviert und startet den Service, ohne bereits
laufende Container zu beeinflussen.
- Wird die Rolle innerhalb von `bootstrap` aufgerufen, übernimmt das Top-Level
Playbook das `become`/`user`-Handling.
Playbook das `become`/`user`-Handling.
+2 -2
View File
@@ -1,8 +1,8 @@
docker_mirror: https://download.docker.com/linux/debian
os_version_codename: "{{ ansible_lsb.codename }}"
os_version_codename: "{{ ansible_facts['distribution_release'] }}"
docker_packages:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
- docker-compose-plugin
+1 -1
View File
@@ -26,7 +26,7 @@ Template und zieht stets die neuesten Images (`pull: always`).
```
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/upgrade-hawser.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/upgrade-hawser.yml
```
## Funktionsweise
+1 -1
View File
@@ -28,7 +28,7 @@ Rolle eingebunden und wird in der Regel nicht separat aufgerufen:
```
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/os-updates-deb.yml
```
## Funktionsweise
+1 -1
View File
@@ -23,7 +23,7 @@ erwünschte ("Good") Keys hinzu und entfernt unerwünschte ("Bad") Keys aus der
```
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/hardening/manage-ssh-keys.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/hardening/manage-ssh-keys.yml
```
Good/Bad-Keys können per Inventory überschrieben oder über Umgebungsvariablen
+23 -14
View File
@@ -27,7 +27,7 @@ einschließlich Template-Verlinkung.
```
```bash
ansible-playbook -i inventory/dmc12.yml --vault-password-file .vault_password \
ansible-playbook -i inventory/cloudlorean.yml --vault-password-file .vault_password \
playbooks/monitoring.yml
```
@@ -50,14 +50,16 @@ Tag `monitoring`):
anlegen, `docker.conf` aus Template ausliefern. Falls nein: Plugin-Config
entfernen.
5. **`configure-psk.yml`** – stellt PSK-Store auf dem Controller sicher
(`<playbook_dir>/../.zabbix-psk`), generiert pro Host eine PSK mit
(im Repository unter `.zabbix-psk`), generiert pro Host eine PSK mit
`openssl rand -hex`, persistiert sie im Store und verteilt sie auf den
Zielhost (`/etc/zabbix/zabbix_agent2.psk`, Mode `0600`).
6. **`configure-agent.yml`** – schreibt `zabbix_agent2.conf` aus Template.
7. **`register-host.yml`** – registriert bzw. aktualisiert den Host über die
Zabbix-API (`community.zabbix.zabbix_host`). Verknüpft Standard-Templates
und ggf. Docker-Templates. Unterscheidet zwischen Proxy- und
Server-Modus (zwei Tasks, gegeneinander exklusiv). Delegiert an localhost.
Zabbix-API (`community.zabbix.zabbix_host` via `httpapi`-Connection).
Verknüpft Standard-Templates und ggf. Docker-Templates. Wählt
`monitored_by: proxy` bzw. `zabbix_server` anhand von
`monitoring_zabbix_proxy`.
Delegiert an localhost.
## Variablen
@@ -92,10 +94,10 @@ Tag `monitoring`):
|-----------------------------------------|--------|--------------------------------------|---------------------------------------------------------|
| `monitoring_zabbix_tls_connect` | string | `psk` | TLS-Modus für ausgehende Verbindungen |
| `monitoring_zabbix_tls_accept` | string | `psk` | TLS-Modus für eingehende Verbindungen |
| `monitoring_zabbix_psk_identity` | string | `{{ inventory_hostname }}` | PSK-Identity (hostname) |
| `monitoring_zabbix_psk_identity` | string | `{{ monitoring_zabbix_host_name }}` | PSK-Identity; muss mit der in Zabbix registrierten Identity übereinstimmen |
| `monitoring_zabbix_psk_file` | string | `/etc/zabbix/zabbix_agent2.psk` | Pfad zur PSK-Datei auf dem Zielhost |
| `monitoring_zabbix_psk_bits` | int | `256` | PSK-Länge in Bits (32 Byte → 64 Hex-Chars) |
| `monitoring_zabbix_psk_store` | string | `{{ playbook_dir }}/../.zabbix-psk` | PSK-Store-Verzeichnis auf dem Controller |
| `monitoring_zabbix_psk_store` | string | `{{ role_path }}/../../.zabbix-psk` | PSK-Store-Verzeichnis auf dem Controller |
| `monitoring_zabbix_psk_store_mode` | string | `0700` | Berechtigung des PSK-Stores |
### Zabbix Proxy (optional)
@@ -109,7 +111,7 @@ Tag `monitoring`):
| Variable | Typ | Default | Beschreibung |
|---------------------------------------------|--------|--------------------------------------|---------------------------------------------------------|
| `monitoring_zabbix_api_url` | string | `https://zabbix/api_jsonrpc.php` | API-URL |
| `monitoring_zabbix_api_url` | string | `https://zabbix/api_jsonrpc.php` | API-URL (wird via `urlsplit` in Host, Port, Pfad zerlegt) |
| `monitoring_zabbix_api_user` | string | `Admin` | API-Benutzer |
| `monitoring_zabbix_api_password` | string | (Vault) | API-Passwort – MUSS in `vault.yml` gesetzt werden |
| `monitoring_zabbix_api_validate_certs` | bool | `true` | TLS-Zertifikate prüfen |
@@ -151,7 +153,7 @@ Passive-Servers mit Proxy-Adresse, setzt `ServerActive` auf Proxy).
`monitoring` – alle Subtasks sind mit diesem Tag versehen:
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/monitoring.yml -t monitoring
ansible-playbook -i inventory/cloudlorean.yml playbooks/monitoring.yml -t monitoring
```
## Abhängigkeiten
@@ -163,14 +165,21 @@ ansible-playbook -i inventory/dmc12.yml playbooks/monitoring.yml -t monitoring
## Hinweise
- **PSK-Store**: Pro Host wird eine PSK unter
`<playbook_dir>/../.zabbix-psk/<hostname>.psk` (git-ignored) gespeichert.
`<Repository-Root>/.zabbix-psk/<hostname>.psk` (git-ignored) gespeichert.
Bei Host-Umbenennung PSK migrieren oder neu generieren – sonst stimmt die
Zabbix-Registrierung nicht.
- **PSK-Identity**: Die Agent-Konfiguration und die Zabbix-Hostkonfiguration
verwenden dieselbe Identity. Wenn `monitoring_zabbix_host_name` überschrieben
wird, wird die Identity standardmäßig automatisch daran angepasst.
- **API-Passwort** MUSS in `vault.yml` als `monitoring_zabbix_api_password`
gesetzt sein; die Validate-Tasks brechen sonst ab.
- **Docker-Plugin** wird nur konfiguriert, wenn der Socket existiert – sonst
wird eine eventuell vorhandene Plugin-Config entfernt (Idempotenz).
- Die Registrierung wird **delegiert an localhost** ausgeführt, da der
Controller den API-Zugang besitzt.
- Proxy- und Server-Modus schließen sich gegenseitig aus (zwei Tasks mit
entgegengesetzten `when`-Bedingungen).
- Die Registrierung nutzt die `httpapi`-Connection
(`ansible_network_os: community.zabbix.zabbix`, `ansible_connection: httpapi`)
und läuft direkt vom Controller aus – kein `delegate_to` nötig.
Die API-URL wird per `urlsplit` in Host, Port, SSL und Pfad zerlegt;
User/Passwort kommen als `ansible_user`/`ansible_password` in die
Task-Vars.
- Proxy- und Server-Modus werden über `monitored_by` gesteuert
(`proxy` bei gesetztem `monitoring_zabbix_proxy`, sonst `zabbix_server`).
+3 -3
View File
@@ -17,11 +17,11 @@ monitoring_zabbix_docker_endpoint: "unix://{{ monitoring_zabbix_docker_socket_pa
# --- TLS / PSK ----------------------------------------------------------------
monitoring_zabbix_tls_connect: psk # outgoing connections from agent: psk
monitoring_zabbix_tls_accept: psk # incoming connections to agent: psk
monitoring_zabbix_psk_identity: "{{ inventory_hostname }}"
monitoring_zabbix_psk_identity: "{{ monitoring_zabbix_host_name }}"
monitoring_zabbix_psk_file: /etc/zabbix/zabbix_agent2.psk
monitoring_zabbix_psk_bits: 256 # 32 bytes -> 64 hex chars
# Directory on the Ansible controller used to persist per-host PSKs across runs.
monitoring_zabbix_psk_store: "{{ playbook_dir }}/../.zabbix-psk"
monitoring_zabbix_psk_store: "{{ role_path }}/../../.zabbix-psk"
monitoring_zabbix_psk_store_mode: "0700"
# --- Zabbix Proxy (optional) --------------------------------------------------
@@ -45,4 +45,4 @@ monitoring_zabbix_host_inventory_mode: manual
# Templates linked to every host
monitoring_zabbix_templates: ["Linux by Zabbix agent", "Zabbix agent2"]
# Templates added when a Docker socket is present on the host
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]
monitoring_zabbix_docker_templates: ["Docker by Zabbix agent2"]
+19 -1
View File
@@ -12,6 +12,13 @@
become: false
run_once: false
- name: Show PSK store path
ansible.builtin.debug:
msg: "Persisting PSKs on the controller in {{ monitoring_zabbix_psk_store }}"
delegate_to: localhost
become: false
changed_when: false
- name: Check whether PSK already exists on controller
ansible.builtin.stat:
path: "{{ monitoring_zabbix_psk_store }}/{{ inventory_hostname }}.psk"
@@ -37,6 +44,17 @@
monitoring_zabbix_psk_store ~ '/' ~ inventory_hostname ~ '.psk')
| trim }}
- name: Validate PSK format
ansible.builtin.assert:
that:
- monitoring_zabbix_psk_value is match('^[0-9a-fA-F]+$')
- monitoring_zabbix_psk_value | length == (monitoring_zabbix_psk_bits / 4) | int
fail_msg: >-
The PSK must contain exactly {{ (monitoring_zabbix_psk_bits / 4) | int }}
hexadecimal characters.
delegate_to: localhost
become: false
- name: Ensure Zabbix agent runtime directory exists
ansible.builtin.file:
path: "{{ monitoring_zabbix_psk_file | dirname | default('/etc/zabbix') }}"
@@ -52,4 +70,4 @@
owner: "{{ monitoring_zabbix_agent_user }}"
group: "{{ monitoring_zabbix_agent_user }}"
mode: '0600'
notify: Restart Zabbix Agent
notify: Restart Zabbix Agent
+19 -35
View File
@@ -24,52 +24,36 @@
dns: "{{ inventory_hostname }}"
port: "{{ monitoring_zabbix_host_interface_port }}"
- name: Register or update host in Zabbix (monitored by proxy)
- name: Register or update host in Zabbix
community.zabbix.zabbix_host:
server_url: "{{ monitoring_zabbix_api_url }}"
login_user: "{{ monitoring_zabbix_api_user }}"
login_password: "{{ monitoring_zabbix_api_password }}"
validate_certs: "{{ monitoring_zabbix_api_validate_certs }}"
host_name: "{{ monitoring_zabbix_host_name }}"
visible_name: "{{ monitoring_zabbix_host_name }}"
host_groups: "{{ monitoring_zabbix_host_groups }}"
link_templates: "{{ monitoring_zabbix_link_templates }}"
interfaces: "{{ monitoring_zabbix_interfaces }}"
inventory_mode: "{{ monitoring_zabbix_host_inventory_mode }}"
monitored_by: proxy
proxy: "{{ monitoring_zabbix_proxy }}"
monitored_by: "{{ 'proxy' if monitoring_zabbix_proxy | length > 0 else 'zabbix_server' }}"
proxy: "{{ monitoring_zabbix_proxy | default(omit) }}"
tls_connect: 2
tls_accept: 2
tls_psk_identity: "{{ monitoring_zabbix_psk_identity }}"
tls_psk: "{{ monitoring_zabbix_psk_value }}"
status: enabled
state: present
delegate_to: localhost
vars:
ansible_network_os: community.zabbix.zabbix
ansible_connection: httpapi
ansible_host: "{{ (monitoring_zabbix_api_url | urlsplit).hostname }}"
ansible_httpapi_port: "{{ (monitoring_zabbix_api_url | urlsplit).port | default(443, true) }}"
ansible_httpapi_use_ssl: "{{ (monitoring_zabbix_api_url | urlsplit).scheme == 'https' }}"
ansible_httpapi_validate_certs: "{{ monitoring_zabbix_api_validate_certs }}"
ansible_zabbix_url_path: >-
{{
(monitoring_zabbix_api_url | urlsplit).path
| regex_replace('^/', '')
| regex_replace('/?api_jsonrpc\.php$', '')
}}
ansible_user: "{{ monitoring_zabbix_api_user }}"
ansible_password: "{{ monitoring_zabbix_api_password }}"
become: false
when:
- monitoring_zabbix_register_host | bool
- monitoring_zabbix_proxy | length > 0
- name: Register or update host in Zabbix (monitored by server)
community.zabbix.zabbix_host:
server_url: "{{ monitoring_zabbix_api_url }}"
login_user: "{{ monitoring_zabbix_api_user }}"
login_password: "{{ monitoring_zabbix_api_password }}"
validate_certs: "{{ monitoring_zabbix_api_validate_certs }}"
host_name: "{{ monitoring_zabbix_host_name }}"
visible_name: "{{ monitoring_zabbix_host_name }}"
host_groups: "{{ monitoring_zabbix_host_groups }}"
link_templates: "{{ monitoring_zabbix_link_templates }}"
interfaces: "{{ monitoring_zabbix_interfaces }}"
inventory_mode: "{{ monitoring_zabbix_host_inventory_mode }}"
tls_connect: 2
tls_accept: 2
tls_psk_identity: "{{ monitoring_zabbix_psk_identity }}"
tls_psk: "{{ monitoring_zabbix_psk_value }}"
status: enabled
state: present
delegate_to: localhost
become: false
when:
- monitoring_zabbix_register_host | bool
- monitoring_zabbix_proxy | length == 0
when: monitoring_zabbix_register_host | bool
+17 -7
View File
@@ -2,8 +2,9 @@
Aktualisiert alle installierten Pakete auf Debian-Hosts, optional mit
Spiegel-Wechsel (Mirror-Switch) und Codename-Anpassung. Die Rolle führt bei
Bedarf einen Reboot durch (nur bei neuem Kernel, nicht in LXC-Containern)
und schreibt ein detailliertes Update-Log auf den Ansible-Controller.
Bedarf einen Reboot durch (nur bei neuem Kernel, nicht in LXC-Containern oder
standardmäßig auf Proxmox-Hypervisoren) und schreibt ein detailliertes
Update-Log auf den Ansible-Controller.
> Siehe auch das Playbook `playbooks/os-updates-deb.yml` (in dem direkt im
> Anschluss die `healthcheck`-Rolle läuft) sowie die
@@ -26,7 +27,7 @@ und schreibt ein detailliertes Update-Log auf den Ansible-Controller.
```
```bash
ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
ansible-playbook -i inventory/cloudlorean.yml playbooks/os-updates-deb.yml
```
## Funktionsweise
@@ -51,9 +52,11 @@ ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
Pakete, zeichnet Start-Zeitpunkt auf.
- `apt upgrade: full` – vollständiges Upgrade aller Pakete. Benachrichtigt
Handler `apt cleanup` und `apt autoremove`.
- `reboot.yml` – entscheidet über Reboot-Vergleich von laufendem und
installiertem Kernel, rebootet asynchron, wartet auf Wiederkehr,
erfasst Downtime. Wird in LXC-Containern übersprungen.
- `reboot.yml` – entscheidet über Reboot-Vergleich von laufendem und
installiertem Kernel, rebootet asynchron, wartet auf Wiederkehr,
erfasst Downtime. Auf Hosts in der Inventory-Gruppe `proxmox` wird der
notwendige Reboot standardmäßig nur gemeldet und nicht ausgeführt.
Wird in LXC-Containern übersprungen.
- `logging_postflight.yml` – berechnet Dauer, schreibt Log-Eintrag mit
allen Fakten in `os_update_log_file` (delegiert an localhost).
@@ -62,6 +65,12 @@ ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
- Läuft ein älterer Kernel als installiert, gilt `reboot_required: true`.
- Der Reboot erfolgt mit `async: 1`, `poll: 0`, gefolgt von
`wait_for_connection` (Delay 10s, Timeout 600s).
- Auf Proxmox-Hypervisoren (`'proxmox' in group_names`) wird bei einem
notwendigen Reboot eine Meldung ausgegeben und `reboot_deferred: true` im
Log gesetzt. So kann der Hypervisor kontrolliert außerhalb dieses Laufs
neu gestartet werden.
- Mit `os_update_reboot_on_proxmox: true` kann der automatische Reboot für
einen Proxmox-Host explizit aktiviert werden.
- In LXC-Containern (`virtualization_type == "lxc"`) wird der gesamte
Reboot-Block übersprungen.
@@ -71,6 +80,7 @@ ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
|-----------------------------|--------|----------------------------------------------------------|-------------------------------------------------------------|
| `os_update_auto_upgrade` | bool | `true` | (Steuer-Vorbereitung) Auto-Upgrade erlauben |
| `os_also_update_mirror` | bool | `false` | Spiegel-Wechsel und Codename-Rewrite durchführen |
| `os_update_reboot_on_proxmox` | bool | `false` | Reboot auf Hosts der Inventory-Gruppe `proxmox` zulassen; standardmäßig wird nur gemeldet |
| `os_update_logging_enabled`| bool | `true` | Update-Logging aktivieren |
| `os_update_log_dir` | string | `/ansible/logs` | Basis-Verzeichnis für Logs |
| `os_update_log_inventory` | string | `{{ inventory_file \| basename \| splitext \| first }}` | Inventory-Name (abgeleitet) |
@@ -125,4 +135,4 @@ Die Rolle vergibt keine eigenen Tags.
- **LXC**: In Containern wird der Reboot-Block komplett übersprungen
(`virtualization_type != "lxc"`).
- **Idempotenz**: `apt upgrade: full` meldet `changed`, wenn Pakete
aktualisiert wurden; ohne anstehende Updates ist der Lauf "ok".
aktualisiert wurden; ohne anstehende Updates ist der Lauf "ok".
+2 -1
View File
@@ -1,6 +1,7 @@
# Standardwerte, die überschrieben werden können
os_update_auto_upgrade: true
os_also_update_mirror: false
os_update_reboot_on_proxmox: false
# Logging of OS update runs (preflight package count/list, updated packages, duration)
os_update_logging_enabled: true
@@ -16,4 +17,4 @@ os_update_debian_codenames:
# Only these suites are considered Debian codenames and will be rewritten in sources.list.d
- trixie
- bookworm
- bullseye
- bullseye
@@ -38,9 +38,10 @@
reboot_required: {{ os_update_reboot_required }}
reboot_reason: {{ os_update_reboot_reason }}
reboot_triggered: {{ os_update_reboot_triggered }}
reboot_deferred: {{ os_update_reboot_deferred }}
reboot_started: {{ os_update_reboot_start_iso }}
reboot_downtime_seconds: {{ os_update_reboot_downtime_seconds }}
kernel_before: {{ os_update_running_kernel.stdout | default('n/a') }}
kernel_after: {{ os_update_running_kernel_after }}
delegate_to: localhost
when: os_update_logging_enabled | bool
when: os_update_logging_enabled | bool
+20 -1
View File
@@ -34,10 +34,27 @@
- name: Default reboot timing facts
set_fact:
os_update_reboot_triggered: false
os_update_reboot_deferred: false
os_update_reboot_start_iso: "n/a"
os_update_reboot_downtime_seconds: 0
os_update_running_kernel_after: "{{ os_update_running_kernel.stdout | default('n/a') }}"
- name: Notify when reboot is deferred on Proxmox
ansible.builtin.debug:
msg: "Reboot required but deferred on Proxmox host {{ ansible_facts['hostname'] }}: {{ os_update_reboot_reason }}"
when:
- os_update_reboot_required | bool
- "'proxmox' in group_names"
- not os_update_reboot_on_proxmox | bool
- name: Record deferred reboot on Proxmox
ansible.builtin.set_fact:
os_update_reboot_deferred: true
when:
- os_update_reboot_required | bool
- "'proxmox' in group_names"
- not os_update_reboot_on_proxmox | bool
- block:
- name: Reboot - Record start time
command: date -Iseconds
@@ -80,4 +97,6 @@
os_update_reboot_triggered: true
os_update_reboot_start_iso: "{{ os_update_reboot_start_iso_raw.stdout }}"
os_update_running_kernel_after: "{{ os_update_running_kernel_after_raw.stdout }}"
when: os_update_reboot_required | bool
when:
- os_update_reboot_required | bool
- "'proxmox' not in group_names or os_update_reboot_on_proxmox | bool"
@@ -5,6 +5,7 @@
apt:
upgrade: full
update_cache: yes
install_recommends: true
register: os_update_upgrade_result
notify:
- apt cleanup
+19 -10
View File
@@ -1,11 +1,20 @@
$ANSIBLE_VAULT;1.1;AES256
31306438393238643764333164633738323833656131303331396336346461623633623531303563
3261353763303939633537356239633937633536336530340a353462653030306433613062323861
38313631613134646231346632653366346637316639343764313161303937656535323739636235
3933646232616635350a383165613538613264343264633466326266646463356463643565336238
31633237386565653635366164383962386338313739646466636564653338613635653636376665
65376631373166303438663565623061333133373630626137636266333865363433653666646135
34396630633265343036623436626439636534656438303265343537353661646335316665303664
61356135386138633433373466396530373839326664623562373066303039303235386139613065
39373864333638643862386232313437376631343133353966633130623834633764643838656361
6538623334323266313139326466326633643363313563333039
39383431633966343639323161393734386133646231653766326530633465336266643338323438
3862376636623232666265633861653331623134653936320a353064666435326134306666666534
65646138646436626438616630626530313831363464323936333166353966383961336334343963
3061393735316336300a386439383233643330613863363863363433373536666531663638663964
66386235643833343037326534636330373731343562393035643939393434366431393233623966
38616164373765326331316364623931306235333362626662643035666533633038313363643164
30623733613832343561383337653763313365383538393038376661336535386264353537616232
65363838326165303130316531623232373364376334336539626432626235396134373562386631
66616534663330633362663030346239663436353263353137646164333939343331616361323837
62306432636539326139386461326335613965373337616535623466356232636138316235373539
30323738363639636665346430323964386662353362393737353562353962316233613066303338
37343764643563303265316634636335353839623736633031633333643832313266386134303465
64363963616135303835613739383962366339646237353666363730633162333762333237313932
37636562636164313436356561643134303835613730303161666332396266333761363035373464
64366636396433346433623236643235393961356334653631336461363530376231356230336461
36306236363430613961653537376563326638636635306265346264306161333832343030393339
63393538366432306238666562373731373863383639623662633165373538303166663732343362
62353861353031333331326431643736313239313564313066336536346531653437393230386637
653261383537663566303663383762366135