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
This commit is contained in:
@@ -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 -->
|
||||
@@ -5,3 +5,4 @@ proxmox.*
|
||||
logs
|
||||
.zabbix-psk
|
||||
setenv.sh
|
||||
.agents
|
||||
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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).
|
||||
@@ -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,82 @@
|
||||
---
|
||||
id: ALERT-20260909-001
|
||||
type: alert
|
||||
status: resolved
|
||||
severity: high
|
||||
title: Plaintext admin password hash committed outside vault
|
||||
created: 2026-09-09
|
||||
updated: 2026-09-09
|
||||
resolved: 2026-09-09
|
||||
tags: [alert, security, secrets]
|
||||
related: [NFR-002, OQ-006, TECH-SECURITY]
|
||||
source_paths:
|
||||
- roles/bootstrap/defaults/main.yml
|
||||
- inventory/group_vars/external.yml
|
||||
- README.md
|
||||
confidence: confirmed
|
||||
---
|
||||
|
||||
# ALERT-20260909-001 - Plaintext admin password hash committed outside vault
|
||||
|
||||
## Summary
|
||||
|
||||
The SHA-512 hash of the admin password (`admin_password`) is committed in
|
||||
plaintext in `roles/bootstrap/defaults/main.yml` and
|
||||
`inventory/group_vars/external.yml`, while the root README states that
|
||||
`admin_password` lives encrypted in `vault.yml`. The documented secret
|
||||
policy (AGENTS.md, README "Beitragen") forbids plaintext secrets in
|
||||
`defaults/` or `group_vars/`. The same hash is reused across both locations.
|
||||
|
||||
## Why It Matters
|
||||
|
||||
- A committed password hash allows offline guessing of the shared admin
|
||||
password; reusing one hash across hosts amplifies the impact.
|
||||
- It contradicts the project's own documented vault policy and misleads
|
||||
contributors (README claims the value is vaulted).
|
||||
|
||||
## Evidence
|
||||
|
||||
- `roles/bootstrap/defaults/main.yml` lines 12-13 (`admin_password` hash)
|
||||
- `inventory/group_vars/external.yml` lines 10-11 (same hash)
|
||||
- `README.md` "Secrets & Vault" section claims `admin_password` is in
|
||||
`vault.yml`
|
||||
- AGENTS.md "Secrets": no plaintext secrets in `defaults/`/`group_vars/`
|
||||
|
||||
## Suggested Resolution
|
||||
|
||||
Move `admin_password` to `vault.yml` in both locations; keep no plaintext
|
||||
fallback in role defaults. If a default is truly needed for bootstrap,
|
||||
document it explicitly as an accepted risk and set a unique hash per site.
|
||||
Verify whether `vault.yml` already overrides it (OQ-006).
|
||||
|
||||
## Resolution
|
||||
|
||||
Resolved 2026-09-09. OQ-006 was verified first: decrypting `vault.yml`
|
||||
confirmed it did **not** define `admin_password` (no override existed), so the
|
||||
committed hash was a policy violation, not an intended fallback. Fix applied:
|
||||
|
||||
- `admin_password` (SHA-512 hash) moved into encrypted `vault.yml`.
|
||||
- Plaintext hash removed from `roles/bootstrap/defaults/main.yml` and
|
||||
`inventory/group_vars/external.yml` (comment now points to `vault.yml`).
|
||||
- `bootstrap.yml` loads `vault.yml` via `vars_files` (same pattern as
|
||||
`playbooks/monitoring.yml`), so the bootstrap role still resolves the
|
||||
variable for every inventory.
|
||||
- Documentation updated: root `README.md` "Secrets & Vault" and
|
||||
`roles/bootstrap/README.md` (variable now documented as vault-sourced).
|
||||
- NFR-002 acceptance notes and evidence updated accordingly.
|
||||
|
||||
Remaining recommendation (hardening, not blocking): the same hash is still
|
||||
shared across sites; rotating to a unique hash per site would remove the
|
||||
single shared credential.
|
||||
|
||||
## Resolution Evidence
|
||||
|
||||
- `ansible-vault view vault.yml` (decrypted during resolution) now lists
|
||||
`admin_password` among `PROXMOX_USER_NAME`, `PROXMOX_USER_PASS`,
|
||||
`monitoring_zabbix_api_password`.
|
||||
- Repository-wide search for the former hash string (salt fragment) returns
|
||||
no matches - the hash exists only inside the encrypted vault file.
|
||||
- `ansible-playbook --syntax-check bootstrap.yml` passes (with
|
||||
`--vault-password-file .vault_pass`).
|
||||
- `rg -n "admin_password"` shows the variable now only in `vault.yml`
|
||||
(encrypted) and consumed at `roles/bootstrap/tasks/create-admin-user.yml:9`.
|
||||
@@ -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` shows a clean tree after the commit (no deleted
|
||||
`inventory/dmc12.yml` and no untracked `inventory/cloudlorean.yml`
|
||||
remaining); `git log` records the coherent change set including the
|
||||
inventory rename.
|
||||
- README inventory table lists Cloudlorean with `group_vars/cloudlorean.yml`
|
||||
and `debian.yml`, matching `inventory/` contents.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Project Changelog
|
||||
|
||||
No project changes have been captured yet.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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,15 @@
|
||||
# Maintenance
|
||||
|
||||
This section stores semantic lint and wiki health reports.
|
||||
|
||||
## Latest Report
|
||||
|
||||
- None yet.
|
||||
|
||||
## Schema Migration Reports
|
||||
|
||||
- None yet.
|
||||
|
||||
## Reports
|
||||
|
||||
- None yet.
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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: []
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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).
|
||||
@@ -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`.
|
||||
@@ -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).
|
||||
@@ -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`).
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 |
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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: []
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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).
|
||||
@@ -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
|
||||
|
||||
@@ -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,10 +126,21 @@ 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
|
||||
|
||||
|
||||
+6
-1
@@ -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
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
- hosts: all
|
||||
become: true
|
||||
user: admin
|
||||
vars_files:
|
||||
- vault.yml
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -5,3 +5,5 @@ collections:
|
||||
version: 13.0.1
|
||||
- name: community.docker
|
||||
version: 5.2.0
|
||||
- name: community.zabbix
|
||||
version: 4.2.0
|
||||
@@ -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:
|
||||
@@ -1,3 +1,7 @@
|
||||
external:
|
||||
children:
|
||||
debian:
|
||||
|
||||
debian:
|
||||
hosts:
|
||||
healthcheck:
|
||||
|
||||
@@ -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"
|
||||
@@ -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"]
|
||||
@@ -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"
|
||||
+5
-1
@@ -1,6 +1,10 @@
|
||||
home:
|
||||
children:
|
||||
debian:
|
||||
proxmox:
|
||||
|
||||
|
||||
debian:
|
||||
hosts:
|
||||
rp:
|
||||
ansible_host: 10.13.37.11
|
||||
@@ -14,7 +18,7 @@ home:
|
||||
ansible_host: 10.13.37.53
|
||||
it-tools:
|
||||
ansible_host: 10.13.37.16
|
||||
proxmox:
|
||||
proxmox:
|
||||
hosts:
|
||||
tardis:
|
||||
ansible_host: 10.13.37.5
|
||||
@@ -1,6 +1,8 @@
|
||||
- hosts: all
|
||||
user: admin
|
||||
become: true
|
||||
vars_files:
|
||||
- ../vault.yml
|
||||
tasks:
|
||||
- name: Verify if system is Debian
|
||||
debug:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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`).
|
||||
|
||||
@@ -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) --------------------------------------------------
|
||||
|
||||
@@ -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') }}"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -53,7 +54,9 @@ ansible-playbook -i inventory/dmc12.yml playbooks/os-updates-deb.yml
|
||||
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.
|
||||
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) |
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
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') }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user