Compare commits
2
Commits
master
..
5febb427e6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5febb427e6 | ||
|
|
45ccd6a25f |
@@ -1,13 +0,0 @@
|
|||||||
# 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 -->
|
|
||||||
+1
-4
@@ -1,8 +1,5 @@
|
|||||||
hosts
|
hosts
|
||||||
proxmox.*
|
proxmox.*
|
||||||
.vscode
|
.vscode
|
||||||
|
inventory
|
||||||
.vault_pass
|
.vault_pass
|
||||||
logs
|
|
||||||
.zabbix-psk
|
|
||||||
setenv.sh
|
|
||||||
.agents
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
# 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-10-11
|
|
||||||
|
|
||||||
## 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)
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,373 +0,0 @@
|
|||||||
version: 1
|
|
||||||
updated: '2026-10-11'
|
|
||||||
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 (Runtime Environment)
|
|
||||||
path: technical/deployment.md
|
|
||||||
status: active
|
|
||||||
tags:
|
|
||||||
- technical
|
|
||||||
- deployment
|
|
||||||
- docker
|
|
||||||
related:
|
|
||||||
- TECH-ARCHITECTURE
|
|
||||||
source_paths:
|
|
||||||
- execute.sh
|
|
||||||
- docker/Dockerfile
|
|
||||||
- docker/requirements.yml
|
|
||||||
- docker/ansible-functs.sh
|
|
||||||
- ansible.cfg
|
|
||||||
- README.md
|
|
||||||
confidence: confirmed
|
|
||||||
- id: TECH-SECURITY
|
|
||||||
type: technical
|
|
||||||
title: Security
|
|
||||||
path: technical/security.md
|
|
||||||
status: active
|
|
||||||
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
|
|
||||||
- execute.sh
|
|
||||||
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
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
# Project Status
|
|
||||||
|
|
||||||
Last updated: 2026-10-11
|
|
||||||
|
|
||||||
## 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
|
|
||||||
|
|
||||||
- Updated 2026-10-11: Docker launcher uses the caller's local SSH directory
|
|
||||||
read-only (`SSH_KEY_DIR`, default `$HOME/.ssh`); runtime behavior and usage
|
|
||||||
are documented in [deployment](./technical/deployment.md) and `README.md`.
|
|
||||||
- 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).
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
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.
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
---
|
|
||||||
id: ALERT-20260909-001
|
|
||||||
type: alert
|
|
||||||
status: resolved
|
|
||||||
severity: high
|
|
||||||
title: Plaintext admin password hash committed outside vault
|
|
||||||
created: 2026-09-09
|
|
||||||
updated: 2026-09-09
|
|
||||||
resolved: 2026-09-09
|
|
||||||
tags: [alert, security, secrets]
|
|
||||||
related: [NFR-002, OQ-006, TECH-SECURITY]
|
|
||||||
source_paths:
|
|
||||||
- roles/bootstrap/defaults/main.yml
|
|
||||||
- inventory/group_vars/external.yml
|
|
||||||
- README.md
|
|
||||||
confidence: confirmed
|
|
||||||
---
|
|
||||||
|
|
||||||
# ALERT-20260909-001 - Plaintext admin password hash committed outside vault
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
The SHA-512 hash of the admin password (`admin_password`) is committed in
|
|
||||||
plaintext in `roles/bootstrap/defaults/main.yml` and
|
|
||||||
`inventory/group_vars/external.yml`, while the root README states that
|
|
||||||
`admin_password` lives encrypted in `vault.yml`. The documented secret
|
|
||||||
policy (AGENTS.md, README "Beitragen") forbids plaintext secrets in
|
|
||||||
`defaults/` or `group_vars/`. The same hash is reused across both locations.
|
|
||||||
|
|
||||||
## Why It Matters
|
|
||||||
|
|
||||||
- A committed password hash allows offline guessing of the shared admin
|
|
||||||
password; reusing one hash across hosts amplifies the impact.
|
|
||||||
- It contradicts the project's own documented vault policy and misleads
|
|
||||||
contributors (README claims the value is vaulted).
|
|
||||||
|
|
||||||
## Evidence
|
|
||||||
|
|
||||||
- `roles/bootstrap/defaults/main.yml` lines 12-13 (`admin_password` hash)
|
|
||||||
- `inventory/group_vars/external.yml` lines 10-11 (same hash)
|
|
||||||
- `README.md` "Secrets & Vault" section claims `admin_password` is in
|
|
||||||
`vault.yml`
|
|
||||||
- AGENTS.md "Secrets": no plaintext secrets in `defaults/`/`group_vars/`
|
|
||||||
|
|
||||||
## Suggested Resolution
|
|
||||||
|
|
||||||
Move `admin_password` to `vault.yml` in both locations; keep no plaintext
|
|
||||||
fallback in role defaults. If a default is truly needed for bootstrap,
|
|
||||||
document it explicitly as an accepted risk and set a unique hash per site.
|
|
||||||
Verify whether `vault.yml` already overrides it (OQ-006).
|
|
||||||
|
|
||||||
## Resolution
|
|
||||||
|
|
||||||
Resolved 2026-09-09. OQ-006 was verified first: decrypting `vault.yml`
|
|
||||||
confirmed it did **not** define `admin_password` (no override existed), so the
|
|
||||||
committed hash was a policy violation, not an intended fallback. Fix applied:
|
|
||||||
|
|
||||||
- `admin_password` (SHA-512 hash) moved into encrypted `vault.yml`.
|
|
||||||
- Plaintext hash removed from `roles/bootstrap/defaults/main.yml` and
|
|
||||||
`inventory/group_vars/external.yml` (comment now points to `vault.yml`).
|
|
||||||
- `bootstrap.yml` loads `vault.yml` via `vars_files` (same pattern as
|
|
||||||
`playbooks/monitoring.yml`), so the bootstrap role still resolves the
|
|
||||||
variable for every inventory.
|
|
||||||
- Documentation updated: root `README.md` "Secrets & Vault" and
|
|
||||||
`roles/bootstrap/README.md` (variable now documented as vault-sourced).
|
|
||||||
- NFR-002 acceptance notes and evidence updated accordingly.
|
|
||||||
|
|
||||||
Remaining recommendation (hardening, not blocking): the same hash is still
|
|
||||||
shared across sites; rotating to a unique hash per site would remove the
|
|
||||||
single shared credential.
|
|
||||||
|
|
||||||
## Resolution Evidence
|
|
||||||
|
|
||||||
- `ansible-vault view vault.yml` (decrypted during resolution) now lists
|
|
||||||
`admin_password` among `PROXMOX_USER_NAME`, `PROXMOX_USER_PASS`,
|
|
||||||
`monitoring_zabbix_api_password`.
|
|
||||||
- Repository-wide search for the former hash string (salt fragment) returns
|
|
||||||
no matches - the hash exists only inside the encrypted vault file.
|
|
||||||
- `ansible-playbook --syntax-check bootstrap.yml` passes (with
|
|
||||||
`--vault-password-file .vault_pass`).
|
|
||||||
- Resolved within coherent change-set commit `30f3e9a` (2026-09-09).
|
|
||||||
- `rg -n "admin_password"` shows the variable now only in `vault.yml`
|
|
||||||
(encrypted) and consumed at `roles/bootstrap/tasks/create-admin-user.yml:9`.
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
---
|
|
||||||
id: ALERT-20260909-002
|
|
||||||
type: alert
|
|
||||||
status: resolved
|
|
||||||
severity: medium
|
|
||||||
title: Uncommitted dmc12-to-cloudlorean rename and stale documentation
|
|
||||||
created: 2026-09-09
|
|
||||||
updated: 2026-09-09
|
|
||||||
resolved: 2026-09-09
|
|
||||||
tags: [alert, consistency, git]
|
|
||||||
related: [OQ-003, SCAN-20260909, TECH-CODEBASE-MAP]
|
|
||||||
source_paths:
|
|
||||||
- inventory/dmc12.yml
|
|
||||||
- inventory/cloudlorean.yml
|
|
||||||
- inventory/group_vars/cloudlorean.yml
|
|
||||||
- README.md
|
|
||||||
- AGENTS.md
|
|
||||||
confidence: confirmed
|
|
||||||
---
|
|
||||||
|
|
||||||
# ALERT-20260909-002 - Uncommitted dmc12-to-cloudlorean rename and stale documentation
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
The working tree carries a large uncommitted change set (23 modified files,
|
|
||||||
203 insertions / 148 deletions) including the deletion of
|
|
||||||
`inventory/dmc12.yml` and the addition of untracked
|
|
||||||
`inventory/cloudlorean.yml` + `inventory/group_vars/cloudlorean.yml`
|
|
||||||
(git log confirms no rename commit). `README.md` (inventory table, call
|
|
||||||
examples) and `AGENTS.md` (fallstricke) still reference `inventory/dmc12.yml`
|
|
||||||
and `group_vars/dmc12.yml`, which no longer exist.
|
|
||||||
|
|
||||||
## Why It Matters
|
|
||||||
|
|
||||||
- Documentation, examples, and agent instructions point to a non-existent
|
|
||||||
inventory; commands copied from README fail.
|
|
||||||
- The rename plus modifications exist only in the working tree; losing or
|
|
||||||
partially committing them would leave the repo internally inconsistent.
|
|
||||||
- Git history will not record a rename (delete + untracked add), which
|
|
||||||
complicates tracing inventory history.
|
|
||||||
|
|
||||||
## Evidence
|
|
||||||
|
|
||||||
- `git status --short`: `D inventory/dmc12.yml`, `?? inventory/cloudlorean.yml`,
|
|
||||||
`?? inventory/group_vars/cloudlorean.yml`, plus modified roles/ansible.cfg/
|
|
||||||
execute.sh/README/AGENTS
|
|
||||||
- `git log --follow -- inventory/dmc12.yml`: only add commit `d2e8ce4`
|
|
||||||
- `README.md` inventory table lists `dmc12.yml` / `group_vars/dmc12.yml`
|
|
||||||
- `logs/cloudlorean/dmc12/` and `.zabbix-psk/dmc12.psk` exist for host
|
|
||||||
`dmc12` under the new site name
|
|
||||||
|
|
||||||
## Suggested Resolution
|
|
||||||
|
|
||||||
1. Update `README.md` and `AGENTS.md` to the `cloudlorean` inventory.
|
|
||||||
2. Review and commit the rename together with the modified files as one
|
|
||||||
coherent change (owner decision).
|
|
||||||
|
|
||||||
## Resolution
|
|
||||||
|
|
||||||
Resolved 2026-09-09 (owner decision confirmed during the session):
|
|
||||||
|
|
||||||
1. Documentation updated to the `cloudlorean` inventory:
|
|
||||||
- `README.md` - inventory table (Cloudlorean row:
|
|
||||||
`cloudlorean.yml` / `group_vars/cloudlorean.yml` + `debian.yml`),
|
|
||||||
all call examples, "Secrets & Vault" example command.
|
|
||||||
- `AGENTS.md` - "Häufige Fallstricke": `ssh_service_name` reference now
|
|
||||||
points to `inventory/cloudlorean.yml` (`gitea`, `ipam`).
|
|
||||||
- Role READMEs (bootstrap, monitoring, docker, os-updates, healthcheck,
|
|
||||||
manage-ssh-keys, hawser): all `inventory/dmc12.yml` call examples
|
|
||||||
replaced with `inventory/cloudlorean.yml`.
|
|
||||||
2. The rename and the full working-tree change set (23 modified files,
|
|
||||||
untracked `inventory/cloudlorean.yml` + `inventory/group_vars/
|
|
||||||
cloudlorean.yml`, plus this resolution's documentation/vault fixes) were
|
|
||||||
committed together as one coherent change, as suggested.
|
|
||||||
|
|
||||||
## Resolution Evidence
|
|
||||||
|
|
||||||
- `rg -n "dmc12\.yml"` across `README.md`, `AGENTS.md`, and `roles/`
|
|
||||||
returns no matches.
|
|
||||||
- `git status --short` is clean after the commit `30f3e9a` ("rename dmc12
|
|
||||||
inventory to cloudlorean and vault admin_password", 2026-09-09); the
|
|
||||||
change set - including the inventory rename and this resolution - is
|
|
||||||
recorded as one commit.
|
|
||||||
- README inventory table lists Cloudlorean with `group_vars/cloudlorean.yml`
|
|
||||||
and `debian.yml`, matching `inventory/` contents.
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Project Changelog
|
|
||||||
|
|
||||||
No project changes have been captured yet.
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Maintenance
|
|
||||||
|
|
||||||
This section stores semantic lint and wiki health reports.
|
|
||||||
|
|
||||||
## Latest Report
|
|
||||||
|
|
||||||
- None yet.
|
|
||||||
|
|
||||||
## Schema Migration Reports
|
|
||||||
|
|
||||||
- None yet.
|
|
||||||
|
|
||||||
## Reports
|
|
||||||
|
|
||||||
- None yet.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
---
|
|
||||||
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`.
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
---
|
|
||||||
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`.
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version: 1
|
|
||||||
updated: '2026-09-09'
|
|
||||||
sources: []
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# 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) - image build, launcher, read-only local SSH keys
|
|
||||||
- [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).
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
---
|
|
||||||
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).
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
---
|
|
||||||
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).
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
---
|
|
||||||
id: TECH-DEPLOYMENT
|
|
||||||
type: technical
|
|
||||||
status: active
|
|
||||||
title: Deployment (Runtime Environment)
|
|
||||||
created: '2026-09-09'
|
|
||||||
updated: '2026-10-11'
|
|
||||||
tags:
|
|
||||||
- technical
|
|
||||||
- deployment
|
|
||||||
- docker
|
|
||||||
related:
|
|
||||||
- TECH-ARCHITECTURE
|
|
||||||
source_paths:
|
|
||||||
- execute.sh
|
|
||||||
- docker/Dockerfile
|
|
||||||
- docker/requirements.yml
|
|
||||||
- docker/ansible-functs.sh
|
|
||||||
- ansible.cfg
|
|
||||||
- README.md
|
|
||||||
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. Resolve `SSH_KEY_DIR` (default `$HOME/.ssh`) and reject a missing or
|
|
||||||
unreadable directory before invoking Docker. Relative paths are resolved
|
|
||||||
against the current working directory.
|
|
||||||
2. Pick next free container name `ansible-<n>`.
|
|
||||||
3. Ensure IPv6-enabled bridge network `ansible-dualstack` (fails fast with
|
|
||||||
a clear message if the network exists without IPv6).
|
|
||||||
4. Run the container detached: repo mounted at `/ansible` (workdir), local
|
|
||||||
SSH directory bind-mounted read-only at `/root/.ssh`, env
|
|
||||||
`ANSIBLE_HOST_KEY_CHECKING=False`, `ANSIBLE_CONFIG=./ansible.cfg`.
|
|
||||||
Abort if `docker run` fails.
|
|
||||||
5. Print name/IPv4/IPv6/OS, then `docker attach` for interactive use.
|
|
||||||
|
|
||||||
The launcher preserves the local SSH configuration and permissions. Standard
|
|
||||||
key names are discovered by OpenSSH; other filenames require `IdentityFile`
|
|
||||||
or Ansible's `--private-key /root/.ssh/<filename>`. Host-specific absolute
|
|
||||||
paths in SSH configuration must also exist inside the container. Encrypted
|
|
||||||
keys can be loaded into an agent started inside the container with
|
|
||||||
`eval "$(ssh-agent -s)"` followed by `ssh-add /root/.ssh/<filename>`.
|
|
||||||
|
|
||||||
## 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`.
|
|
||||||
- Build from the repository root with `docker build -t ansible:deb13 docker/`.
|
|
||||||
- SSH keys are supplied at runtime, not embedded in the image.
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
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).
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
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`.
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
---
|
|
||||||
id: TECH-SECURITY
|
|
||||||
type: technical
|
|
||||||
status: active
|
|
||||||
title: Security
|
|
||||||
created: '2026-09-09'
|
|
||||||
updated: '2026-10-11'
|
|
||||||
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
|
|
||||||
- execute.sh
|
|
||||||
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
|
|
||||||
|
|
||||||
- Runtime key access: `execute.sh` bind-mounts the caller's `$HOME/.ssh`
|
|
||||||
(or `SSH_KEY_DIR`) read-only at `/root/.ssh`. It does not rewrite the host
|
|
||||||
SSH configuration or permissions. Private keys are not baked into the image.
|
|
||||||
- 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).
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
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`).
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
---
|
|
||||||
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.
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
---
|
|
||||||
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 |
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<a id="req-001"></a>
|
|
||||||
|
|
||||||
## REQ-001 - Requirement Title
|
|
||||||
|
|
||||||
Status: active
|
|
||||||
Tags: []
|
|
||||||
Related: []
|
|
||||||
Confidence: confirmed
|
|
||||||
|
|
||||||
### Statement
|
|
||||||
|
|
||||||
TBD
|
|
||||||
|
|
||||||
### Rationale
|
|
||||||
|
|
||||||
TBD
|
|
||||||
|
|
||||||
### Acceptance Notes
|
|
||||||
|
|
||||||
TBD
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# 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.
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version: 1
|
|
||||||
updated: YYYY-MM-DD
|
|
||||||
sources: []
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
---
|
|
||||||
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
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# 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).
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# Change Impact Map
|
|
||||||
|
|
||||||
No change impact traceability has been captured yet.
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# 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`, `README.md` | Runtime environment; local SSH directory mounted read-only via `SSH_KEY_DIR` |
|
|
||||||
| [TECH-SECURITY](../technical/security.md) | `vault.yml`, `roles/*/defaults/`, `ansible.cfg`, `execute.sh`, `roles/monitoring/tasks/configure-psk.yml` | Secrets, SSH, PSK; runtime-only local key access |
|
|
||||||
| [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 |
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# 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).
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
# AGENTS.md
|
|
||||||
|
|
||||||
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
|
|
||||||
Überwachung von Debian-Hosts.
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── ansible.cfg # Globale Ansible-Konfiguration
|
|
||||||
├── bootstrap.yml # Top-Level-Playbook für die Ersteinrichtung
|
|
||||||
├── execute.sh # Startet die Docker-Ausführungsumgebung
|
|
||||||
├── setenv.sh # Umgebungsvariablen für Proxmox (git-ignored)
|
|
||||||
├── vault.yml # Ansible-Vault-verschlüsselte Secrets
|
|
||||||
├── .vault_pass # Vault-Passwort (git-ignored)
|
|
||||||
├── docker/ # Dockerfile & Requirements für die Laufzeit-Umgebung
|
|
||||||
├── inventory/ # Inventories mit group_vars
|
|
||||||
├── logs/ # Update-Logs (git-ignored)
|
|
||||||
├── playbooks/ # Playbooks, die die Rollen einbinden
|
|
||||||
└── roles/ # Wiederverwendbare Ansible-Rollen
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollen
|
|
||||||
|
|
||||||
| Rolle | Kurzbeschreibung |
|
|
||||||
|---------------------|-----------------------------------------------------------------------------|
|
|
||||||
| `bootstrap` | Ersteinrichtung: Pakete, Admin-User, SSH, MOTD, sysctl, Docker, Monitoring |
|
|
||||||
| `docker` | Installation der Docker Engine über das offizielle Repository |
|
|
||||||
| `hawser` | Aktualisierung des Hawser Docker-Compose-Stacks |
|
|
||||||
| `healthcheck` | Quality-Gate: prüft laufende Container nach Updates |
|
|
||||||
| `manage-ssh-keys` | Verwaltung erwünschter/unerwünschter SSH-Keys (Hardening) |
|
|
||||||
| `monitoring` | Zabbix Agent 2: Installation, TLS-PSK, Docker-Plugin, API-Registrierung |
|
|
||||||
| `os-updates` | Debian-Paketaktualisierung mit Spiegel-Wechsel, Reboot & Logging |
|
|
||||||
|
|
||||||
Jede Rolle besitzt eine eigene `README.md` unter `roles/<name>/README.md`,
|
|
||||||
die Anforderungen, Variablen, Templates, Handler, Tags und Nutzung
|
|
||||||
dokumentiert. Die globale `README.md` im Repo-Root verweist auf diese
|
|
||||||
Rollen-READMEs und beschreibt Inventories, Playbooks und die
|
|
||||||
Docker-Ausführungsumgebung.
|
|
||||||
|
|
||||||
## WICHTIG: Dokumentationspflicht bei Änderungen
|
|
||||||
|
|
||||||
> **Jede neue Funktion, jeder neue Parameter und jede neue Variable MUSS
|
|
||||||
> dokumentiert werden.** Keine undokumentierten Änderungen committen.
|
|
||||||
|
|
||||||
### Wann welche README aktualisiert werden muss
|
|
||||||
|
|
||||||
| Art der Änderung | Zu aktualisierende Datei(en) |
|
|
||||||
|-----------------------------------------------------------|-------------------------------------------------------|
|
|
||||||
| Neue Variable in `defaults/main.yml` einer Rolle | `roles/<rolle>/README.md` (Abschnitt "Variablen") |
|
|
||||||
| Neue Task-Datei / neuer Subtask in einer Rolle | `roles/<rolle>/README.md` (Abschnitte "Funktionsweise" / "Tasks") |
|
|
||||||
| Neues Template oder Handler | `roles/<rolle>/README.md` (Abschnitt "Templates" / "Handler") |
|
|
||||||
| Neuer Tag | `roles/<rolle>/README.md` (Abschnitt "Tags") |
|
|
||||||
| Neues Playbook oder wesentliche Änderung an bestehendem | Globale `README.md` (Tabelle "Playbooks") |
|
|
||||||
| Neue Rolle | Globale `README.md` (Tabellen "Inhalt" & "Rollen") + `roles/<neu>/README.md` erstellen |
|
|
||||||
| Neues Inventory oder group_vars | Globale `README.md` (Abschnitt "Inventories") |
|
|
||||||
| Änderung an `ansible.cfg`, `execute.sh` oder `docker/` | Globale `README.md` |
|
|
||||||
| Änderung an Secrets / Vault-Handhabung | Globale `README.md` (Abschnitt "Secrets & Vault") |
|
|
||||||
|
|
||||||
### Konventionen für Rollen-READMEs
|
|
||||||
|
|
||||||
Jede `roles/<name>/README.md` soll mindestens folgende Abschnitte enthalten:
|
|
||||||
|
|
||||||
1. **Titel & Kurzbeschreibung** – was macht die Rolle, Verweis auf Repo-README
|
|
||||||
2. **Voraussetzungen** – OS, Collections, Zugriff
|
|
||||||
3. **Einbindung** – Beispiel-Playbook oder Aufruf
|
|
||||||
4. **Funktionsweise** – Reihenfolge der Tasks, was passiert
|
|
||||||
5. **Variablen** – Tabelle mit Name, Typ, Default, Beschreibung
|
|
||||||
- Trennen zwischen Variablen mit Defaults (`defaults/main.yml`) und
|
|
||||||
Steuer-Variablen ohne Defaults
|
|
||||||
6. **Templates** – Template-Datei → Ziel-Pfad
|
|
||||||
7. **Handler** – Handler-Name → Auslöser
|
|
||||||
8. **Tags** – verfügbare Tags und Beispiel
|
|
||||||
9. **Abhängigkeiten** – andere Rollen oder Collections
|
|
||||||
10. **Hinweise** – Besonderheiten, Plattform-Einschränkungen
|
|
||||||
|
|
||||||
### Konventionen für die globale README
|
|
||||||
|
|
||||||
- Tabellen für Playbooks, Inventories und Rollen aktuell halten
|
|
||||||
- Neue Rollen-READMEs in der Rollen-Tabelle verlinken
|
|
||||||
- Aufrufbeispiele bei neuen Playbooks ergänzen
|
|
||||||
|
|
||||||
## Technische Konventionen
|
|
||||||
|
|
||||||
### Sprache & Stil
|
|
||||||
|
|
||||||
- **Dokumentation** (`README.md`, Kommentare in Templates): Deutsch
|
|
||||||
- **Code**: Englisch (Variablennamen, Task-Names, Module)
|
|
||||||
- **Keine** Kommentare in Task-Dateien, außer wenn der User es ausdrücklich
|
|
||||||
wünscht (siehe System-Regeln). Inline-Doku über die READMEs laufen.
|
|
||||||
|
|
||||||
### Ansible-Stil
|
|
||||||
|
|
||||||
- Module grundsätzlich mit FQCN verwenden (`ansible.builtin.apt`,
|
|
||||||
`ansible.builtin.template`, …), ausgenommen ältere Tasks, die
|
|
||||||
kurze Namen nutzen – bei neuen Tasks FQCN verwenden.
|
|
||||||
- Variablen-Defaults immer in `defaults/main.yml`, nie hart in Tasks.
|
|
||||||
- Variablen pro Inventory in `inventory/group_vars/<gruppe>.yml` überschreiben.
|
|
||||||
- Templates nutzen `# {{ ansible_managed }}` als Header.
|
|
||||||
- Tasks sind in Subtask-Dateien (`tasks/<name>.yml`) ausgelagert, wenn eine
|
|
||||||
Rolle mehr als eine logische Einheit hat. `tasks/main.yml` enthält nur
|
|
||||||
`import_tasks`/`include_tasks` und `import_role`.
|
|
||||||
|
|
||||||
### Secrets
|
|
||||||
|
|
||||||
- Sensible Werte (Passwörter, API-Keys) gehören in `vault.yml` (verschlüsselt).
|
|
||||||
- `.vault_pass`, `setenv.sh`, `logs/`, `.zabbix-psk` sind git-ignored und
|
|
||||||
dürfen **niemals** committet werden.
|
|
||||||
- Klartext-Secrets in `defaults/` oder `group_vars/` vermeiden; stattdessen
|
|
||||||
Vault-Referenz verwenden.
|
|
||||||
|
|
||||||
### OS-Unterstützung
|
|
||||||
|
|
||||||
- Alle Playbooks prüfen `ansible_facts['os_family'] == "Debian"` und brechen
|
|
||||||
bei Nicht-Debian ab. Neue Playbooks müssen diesen Check enthalten.
|
|
||||||
- LXC-Container: Tasks, die `sysctl` oder `reboot` betreffen, müssen
|
|
||||||
`virtualization_type != "lxc"` prüfen und übersprungen werden.
|
|
||||||
|
|
||||||
### Tags
|
|
||||||
|
|
||||||
- Verwendete Tags pro Rolle in der jeweiligen README dokumentieren.
|
|
||||||
- Gängige Tags: `ssh`, `motd`, `bashrc`, `sysctl`, `monitoring`.
|
|
||||||
|
|
||||||
### Collections
|
|
||||||
|
|
||||||
Benötigte Collections (in `docker/requirements.yml`):
|
|
||||||
|
|
||||||
- `ansible.posix`
|
|
||||||
- `community.general`
|
|
||||||
- `community.docker`
|
|
||||||
- `community.zabbix` (nur in der `monitoring`-Rolle verwendet – ggf. ergänzen)
|
|
||||||
|
|
||||||
### Docker-Ausführungsumgebung
|
|
||||||
|
|
||||||
- `docker/Dockerfile` baut ein `debian:trixie-slim`-Image mit `ansible-core`.
|
|
||||||
- `execute.sh` startet einen interaktiven Container, der das Repo nach
|
|
||||||
`/ansible` mountet und SSH-Keys unter `/root/.ssh` bereithält.
|
|
||||||
- Bei Änderung der Collections muss `docker/requirements.yml` aktualisiert und
|
|
||||||
ein Image-Rebuild durchgeführt werden.
|
|
||||||
|
|
||||||
## Testing & Verifikation
|
|
||||||
|
|
||||||
1. Änderungen im Docker-Container testen: `./execute.sh`
|
|
||||||
2. Lint prüfen, falls verfügbar: `ansible-lint` (nicht im Repo vorausgesetzt,
|
|
||||||
aber empfohlen).
|
|
||||||
3. Playbook Dry-Run: `--check` verwenden, wo sinnvoll.
|
|
||||||
4. Nach Änderungen an einer Rolle die zugehörige `README.md` aktualisieren.
|
|
||||||
|
|
||||||
## Häufige Fallstricke
|
|
||||||
|
|
||||||
- **`os_update_version_codename`** in `inventory/group_vars/debian.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/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
|
|
||||||
migrieren oder neu generieren – sonst stimmt die Zabbix-Registrierung nicht.
|
|
||||||
- **Logs**: `os-updates` und `healthcheck` schreiben Logs nach
|
|
||||||
`logs/<inventory>/<hostname>/update.log` (auf dem Controller, delegiert).
|
|
||||||
Verzeichnis ist git-ignored.
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
# Ansible Playbooks
|
|
||||||
|
|
||||||
Zentrale Ansible-Sammlung für die Bereitstellung, Härtung, Aktualisierung und
|
|
||||||
Überwachung von Debian-Hosts. Das Repository enthält eigenständige Rollen,
|
|
||||||
zugehörige Playbooks, mehrere Inventories sowie eine Docker-basierte
|
|
||||||
Ausführungsumgebung, sodass Playbooks direkt aus einem Container heraus
|
|
||||||
gestartet werden können.
|
|
||||||
|
|
||||||
## Inhaltsübersicht
|
|
||||||
|
|
||||||
```
|
|
||||||
.
|
|
||||||
├── ansible.cfg # Globale Ansible-Konfiguration
|
|
||||||
├── bootstrap.yml # Top-Level-Playbook für die Ersteinrichtung
|
|
||||||
├── execute.sh # Startet die Docker-Ausführungsumgebung
|
|
||||||
├── setenv.sh # Umgebungsvariablen für Proxmox (nicht im Repo)
|
|
||||||
├── vault.yml # Ansible-Vault-verschlüsselte Secrets
|
|
||||||
├── docker/ # Dockerfile & Requirements für die Laufzeit-Umgebung
|
|
||||||
├── inventory/ # Inventories mit group_vars
|
|
||||||
├── logs/ # Update-Logs (git-ignored)
|
|
||||||
├── playbooks/ # Playbooks, die die Rollen einbinden
|
|
||||||
└── roles/ # Wiederverwendbare Ansible-Rollen
|
|
||||||
```
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- **Ansible** >= 2.20 (im Docker-Image bereits enthalten)
|
|
||||||
- **Ziel-Hosts**: Debian (alle Playbooks prüfen `os_family == "Debian"`)
|
|
||||||
- **Ansible-Collections**: `ansible.posix`, `community.general`,
|
|
||||||
`community.docker`, `community.zabbix` (siehe `docker/requirements.yml`)
|
|
||||||
- **Zugang**: SSH-Zugang als Benutzer `admin` mit hinterlegtem Public Key
|
|
||||||
|
|
||||||
### Docker-Ausführungsumgebung
|
|
||||||
|
|
||||||
Damit Playbooks nicht lokal installiert werden müssen, liefert das Repository
|
|
||||||
ein fertiges Docker-Image. Das Image lässt sich vom Repository-Verzeichnis aus
|
|
||||||
bauen:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker build -t ansible:deb13 docker/
|
|
||||||
```
|
|
||||||
|
|
||||||
`execute.sh` erstellt ein IPv6-fähiges Bridge-Netzwerk, startet einen interaktiven
|
|
||||||
Container und mountet das Repository nach `/ansible`. Das lokale SSH-Verzeichnis
|
|
||||||
`~/.ssh` des aufrufenden Benutzers wird schreibgeschützt nach `/root/.ssh`
|
|
||||||
eingebunden. Damit verwendet SSH im Container deine lokalen Standard-Keys
|
|
||||||
(z. B. `id_ed25519` oder `id_rsa`) und eine vorhandene SSH-Konfiguration:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./execute.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Ein anderes lokales Schlüsselverzeichnis kann über `SSH_KEY_DIR` angegeben
|
|
||||||
werden (Standard: `$HOME/.ssh`). Das Verzeichnis muss vorhanden und lesbar sein:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
SSH_KEY_DIR=/pfad/zu/ssh ./execute.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
Bei einem abweichenden Key-Dateinamen gibst du im Container beispielsweise
|
|
||||||
`--private-key /root/.ssh/mein_key` beim Ansible-Aufruf an. Pfade in deiner
|
|
||||||
SSH-Konfiguration müssen im Container erreichbar sein, z. B.
|
|
||||||
`IdentityFile ~/.ssh/mein_key`. Für passwortgeschützte Keys kannst du im
|
|
||||||
Container einen SSH-Agent starten und den Key laden:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
eval "$(ssh-agent -s)"
|
|
||||||
ssh-add /root/.ssh/id_ed25519
|
|
||||||
```
|
|
||||||
|
|
||||||
Im Container stehen Aliase wie `ap` (ansible-playbook), `ag` (ansible-galaxy)
|
|
||||||
und `av` (ansible-vault) zur Verfügung. Das Image wird über
|
|
||||||
`docker/Dockerfile` gebaut, die benötigten Collections werden beim Build
|
|
||||||
automatisch installiert.
|
|
||||||
|
|
||||||
## Inventories
|
|
||||||
|
|
||||||
Alle Inventories liegen unter `inventory/`. Pro Inventory existiert eine
|
|
||||||
gleichnamige Datei sowie ein Eintrag in `group_vars/`:
|
|
||||||
|
|
||||||
| Inventory | Datei | group_vars | Beschreibung |
|
|
||||||
|------------------|--------------------|------------------------|-------------------------------------------------|
|
|
||||||
| 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) |
|
|
||||||
|
|
||||||
Die `group_vars` definieren standortspezifische Werte wie Zabbix-Server,
|
|
||||||
Spiegelserver und autorisierte SSH-Keys.
|
|
||||||
|
|
||||||
## Playbooks
|
|
||||||
|
|
||||||
| Playbook | Rolle(n) | Zweck |
|
|
||||||
|---------------------------------------|-----------------------------------|--------------------------------------------------------|
|
|
||||||
| `bootstrap.yml` | bootstrap | Vollständige Ersteinrichtung eines Debian-Hosts |
|
|
||||||
| `playbooks/docker.yml` | docker | Docker Engine installieren |
|
|
||||||
| `playbooks/monitoring.yml` | monitoring | Zabbix Agent 2 installieren & registrieren |
|
|
||||||
| `playbooks/os-updates-deb.yml` | os-updates, healthcheck | Pakete aktualisieren + Healthcheck |
|
|
||||||
| `playbooks/upgrade-hawser.yml` | hawser | Hawser-Stack aktualisieren |
|
|
||||||
| `playbooks/hardening/manage-ssh-keys.yml` | manage-ssh-keys | SSH-Schlüssel hartieren |
|
|
||||||
|
|
||||||
### Aufrufbeispiele
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 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/cloudlorean.yml playbooks/os-updates-deb.yml
|
|
||||||
|
|
||||||
# Hawser aktualisieren
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/upgrade-hawser.yml
|
|
||||||
|
|
||||||
# SSH-Keys härtene
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/hardening/manage-ssh-keys.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Rollen
|
|
||||||
|
|
||||||
| Rolle | Kurzbeschreibung | Dokumentation |
|
|
||||||
|---------------------|-----------------------------------------------------------------------------|-------------------------------------|
|
|
||||||
| `bootstrap` | Ersteinrichtung: Pakete, Admin-User, SSH, MOTD, sysctl, Docker, Monitoring | [roles/bootstrap/README.md](roles/bootstrap/README.md) |
|
|
||||||
| `docker` | Installation der Docker Engine über das offizielle Repository | [roles/docker/README.md](roles/docker/README.md) |
|
|
||||||
| `hawser` | Aktualisierung des Hawser Docker-Compose-Stacks | [roles/hawser/README.md](roles/hawser/README.md) |
|
|
||||||
| `healthcheck` | Quality-Gate: prüft laufende Container nach Updates | [roles/healthcheck/README.md](roles/healthcheck/README.md) |
|
|
||||||
| `manage-ssh-keys` | Verwaltung erwünschter/unerwünschter SSH-Keys (Hardening) | [roles/manage-ssh-keys/README.md](roles/manage-ssh-keys/README.md) |
|
|
||||||
| `monitoring` | Zabbix Agent 2: Installation, TLS-PSK, Docker-Plugin, API-Registrierung | [roles/monitoring/README.md](roles/monitoring/README.md) |
|
|
||||||
| `os-updates` | Debian-Paketaktualisierung mit Spiegel-Wechsel, Reboot & Logging | [roles/os-updates/README.md](roles/os-updates/README.md) |
|
|
||||||
|
|
||||||
## Secrets & Vault
|
|
||||||
|
|
||||||
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/cloudlorean.yml --vault-password-file .vault_pass bootstrap.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Hinweis:** Die Datei `setenv.sh` enthält Zugangsdaten für Proxmox und ist
|
|
||||||
> bewusst nicht für eine Veröffentlichung vorgesehen. `.vault_pass` und
|
|
||||||
> `setenv.sh` stehen in `.gitignore`.
|
|
||||||
|
|
||||||
## Logging
|
|
||||||
|
|
||||||
Die Rollen `os-updates` und `healthcheck` schreiben pro Host ein Update-Log
|
|
||||||
unter `logs/<inventory>/<hostname>/update.log`. Das Verzeichnis `logs/` ist
|
|
||||||
git-ignored und dient als lokales Audit-Trail.
|
|
||||||
|
|
||||||
## Konfiguration
|
|
||||||
|
|
||||||
`ansible.cfg` deaktiviert Host-Key-Checking und legt `./roles` als
|
|
||||||
Rollen-Pfad fest. Für schnellere Ausführungen werden standardmäßig 20 parallele
|
|
||||||
Worker (`forks`), SSH-Pipelining und persistente SSH-Verbindungen
|
|
||||||
(`ControlPersist=60s`) verwendet. `gathering=smart` vermeidet die erneute
|
|
||||||
Faktenabfrage innerhalb eines Laufs, ohne einen persistenten Fakten-Cache mit
|
|
||||||
potenziell veralteten Hostdaten einzuführen. `internal_poll_interval` reduziert
|
|
||||||
die Wartezeit des Controllers zwischen Worker-Abfragen.
|
|
||||||
|
|
||||||
SSH-Verbindungen verwenden weiterhin `StrictHostKeyChecking=no` sowie `/dev/null`
|
|
||||||
als KnownHosts-Datei, was die Ersteinrichtung neuer Hosts erleichtert – in
|
|
||||||
produktiven Umgebungen entsprechend restriktiver konfigurieren. Bei sehr vielen
|
|
||||||
gleichzeitig verwalteten Hosts kann `forks` über `ANSIBLE_FORKS` oder einen
|
|
||||||
zusätzlichen Konfigurationswert an die Controller- und Netzwerkressourcen
|
|
||||||
angepasst werden. Fact-Caching und alternative Strategien wie `free` sind nicht
|
|
||||||
global aktiviert, da sie bei diesen Playbooks veraltete Fakten oder eine andere
|
|
||||||
Ausführungsreihenfolge verursachen können.
|
|
||||||
|
|
||||||
## Beitragen
|
|
||||||
|
|
||||||
1. Änderungen lokal testen – idealerweise über `./execute.sh` im Container.
|
|
||||||
2. Variablen in `defaults/main.yml` der jeweiligen Rolle pflegen und in der
|
|
||||||
Rollen-README dokumentieren.
|
|
||||||
3. Keine Secrets unverschlüsselt committen (Vault nutzen).
|
|
||||||
+1
-6
@@ -2,11 +2,6 @@
|
|||||||
host_key_checking = False
|
host_key_checking = False
|
||||||
roles_path = ./roles:/etc/ansible/roles
|
roles_path = ./roles:/etc/ansible/roles
|
||||||
group_vars = ./group_vars
|
group_vars = ./group_vars
|
||||||
interpreter_python = auto_silent
|
|
||||||
forks = 20
|
|
||||||
gathering = smart
|
|
||||||
internal_poll_interval = 0.001
|
|
||||||
|
|
||||||
[ssh_connection]
|
[ssh_connection]
|
||||||
pipelining = True
|
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
|
||||||
ssh_args = -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ControlMaster=auto -o ControlPersist=60s
|
|
||||||
+1
-3
@@ -1,8 +1,6 @@
|
|||||||
- hosts: all
|
- hosts: all
|
||||||
become: true
|
become: true
|
||||||
user: root
|
user: admin
|
||||||
vars_files:
|
|
||||||
- vault.yml
|
|
||||||
tasks:
|
tasks:
|
||||||
- name: Verify if system is Debian
|
- name: Verify if system is Debian
|
||||||
debug:
|
debug:
|
||||||
|
|||||||
+2
-9
@@ -1,7 +1,7 @@
|
|||||||
FROM debian:trixie-slim
|
FROM debian:trixie-slim
|
||||||
ARG DEBIAN_FRONTEND=noninteractive
|
ARG DEBIAN_FRONTEND=noninteractive
|
||||||
ENV TZ=Europe/Berlin
|
ENV TZ=Europe/Berlin
|
||||||
ENV ANSIBLE_VERSION=2.20.6
|
ENV ANSIBLE_MAJOR_VERSION=2.18
|
||||||
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
ENV PIP_BREAK_SYSTEM_PACKAGES=1
|
||||||
|
|
||||||
RUN apt update && apt install -y --no-install-recommends \
|
RUN apt update && apt install -y --no-install-recommends \
|
||||||
@@ -13,26 +13,19 @@ RUN apt update && apt install -y --no-install-recommends \
|
|||||||
python3-pip \
|
python3-pip \
|
||||||
tzdata \
|
tzdata \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
iputils-ping \
|
|
||||||
vim \
|
|
||||||
less \
|
|
||||||
&& apt clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN mkdir -p /etc/ssh/ssh_config.d \
|
RUN mkdir -p /etc/ssh/ssh_config.d \
|
||||||
&& printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /etc/ssh/ssh_config.d/99-no-hostkey-check.conf
|
&& printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /etc/ssh/ssh_config.d/99-no-hostkey-check.conf
|
||||||
|
|
||||||
RUN pip3 install --no-cache-dir --upgrade \
|
RUN pip3 install --no-cache-dir --upgrade \
|
||||||
ansible-core~=${ANSIBLE_VERSION}
|
ansible-core~=${ANSIBLE_MAJOR_VERSION}
|
||||||
|
|
||||||
RUN mkdir -p /root/.bashrc.d
|
RUN mkdir -p /root/.bashrc.d
|
||||||
COPY ansible-functs.sh /root/.bashrc.d/ansible-functs.sh
|
COPY ansible-functs.sh /root/.bashrc.d/ansible-functs.sh
|
||||||
RUN chmod +x /root/.bashrc.d/ansible-functs.sh \
|
RUN chmod +x /root/.bashrc.d/ansible-functs.sh \
|
||||||
&& printf '\n[ -f /root/.bashrc.d/ansible-functs.sh ] && . /root/.bashrc.d/ansible-functs.sh\n' >> /root/.bashrc
|
&& printf '\n[ -f /root/.bashrc.d/ansible-functs.sh ] && . /root/.bashrc.d/ansible-functs.sh\n' >> /root/.bashrc
|
||||||
|
|
||||||
COPY requirements.yml /ansible/requirements.yml
|
|
||||||
RUN ansible-galaxy collection install -r /ansible/requirements.yml
|
|
||||||
|
|
||||||
WORKDIR /ansible
|
WORKDIR /ansible
|
||||||
|
|
||||||
CMD ["ansible-playbook", "--version"]
|
CMD ["ansible-playbook", "--version"]
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
collections:
|
|
||||||
- name: ansible.posix
|
|
||||||
version: 2.2.0
|
|
||||||
- name: community.general
|
|
||||||
version: 13.0.1
|
|
||||||
- name: community.docker
|
|
||||||
version: 5.2.0
|
|
||||||
- name: community.zabbix
|
|
||||||
version: 4.2.0
|
|
||||||
Executable → Regular
+9
-15
@@ -1,20 +1,9 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
defaultimage="ansible:deb13"
|
defaultimage="ansible:deb13"
|
||||||
ssh_key_dir="${SSH_KEY_DIR:-$HOME/.ssh}"
|
|
||||||
|
|
||||||
if [ ! -d "$ssh_key_dir" ] || [ ! -r "$ssh_key_dir" ]; then
|
|
||||||
echo "Lokales SSH-Verzeichnis '$ssh_key_dir' fehlt oder ist nicht lesbar." >&2
|
|
||||||
echo "Setze SSH_KEY_DIR auf das Verzeichnis mit deinem SSH-Key." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
case "$ssh_key_dir" in
|
|
||||||
/*) ;;
|
|
||||||
*) ssh_key_dir="$(pwd)/$ssh_key_dir" ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
export ANSIBLE_HOST_KEY_CHECKING=False
|
export ANSIBLE_HOST_KEY_CHECKING=False
|
||||||
|
export ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'
|
||||||
export ANSIBLE_CONFIG=./ansible.cfg
|
export ANSIBLE_CONFIG=./ansible.cfg
|
||||||
|
|
||||||
# Ermittle den nächsten freien Container-Namen
|
# Ermittle den nächsten freien Container-Namen
|
||||||
@@ -46,12 +35,15 @@ docker run --rm -dit \
|
|||||||
--hostname "$container_name" \
|
--hostname "$container_name" \
|
||||||
--network "$network_name" \
|
--network "$network_name" \
|
||||||
-e ANSIBLE_HOST_KEY_CHECKING=False \
|
-e ANSIBLE_HOST_KEY_CHECKING=False \
|
||||||
|
-e ANSIBLE_SSH_ARGS='-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' \
|
||||||
-e ANSIBLE_CONFIG=./ansible.cfg \
|
-e ANSIBLE_CONFIG=./ansible.cfg \
|
||||||
-v "$(pwd):/ansible" \
|
-v "$(pwd):/ansible" \
|
||||||
-v "$ssh_key_dir:/root/.ssh:ro" \
|
-v ansible_ssh_keys:/root/.ssh \
|
||||||
-w /ansible \
|
-w /ansible \
|
||||||
"$defaultimage" \
|
$defaultimage \
|
||||||
"/bin/bash" || exit "$?"
|
"/bin/bash"
|
||||||
|
|
||||||
|
docker exec "$container_name" sh -lc "mkdir -p /root/.ssh && chmod 700 /root/.ssh && printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config && chmod 600 /root/.ssh/config"
|
||||||
|
|
||||||
container_ipv4=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{.IPAddress}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
container_ipv4=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .IPAddress}}{{.IPAddress}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
||||||
container_ipv6=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .GlobalIPv6Address}}{{.GlobalIPv6Address}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
container_ipv6=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{if .GlobalIPv6Address}}{{.GlobalIPv6Address}}{{end}}{{end}}' "$container_name" 2>/dev/null)
|
||||||
@@ -66,3 +58,5 @@ echo "-----------------------------------"
|
|||||||
|
|
||||||
docker attach "$container_name"
|
docker attach "$container_name"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
cloudlorean:
|
|
||||||
children:
|
|
||||||
debian:
|
|
||||||
proxmox:
|
|
||||||
|
|
||||||
debian:
|
|
||||||
hosts:
|
|
||||||
rp:
|
|
||||||
ansible_host: 192.168.212.50
|
|
||||||
bitwarden:
|
|
||||||
ansible_host: 192.168.212.20
|
|
||||||
pdf:
|
|
||||||
ansible_host: 192.168.212.65
|
|
||||||
mailcow:
|
|
||||||
ansible_host: 192.168.212.70
|
|
||||||
plex:
|
|
||||||
ansible_host: 192.168.212.62
|
|
||||||
cloud:
|
|
||||||
ansible_host: 192.168.212.60
|
|
||||||
romm:
|
|
||||||
ansible_host: 192.168.212.64
|
|
||||||
gitea:
|
|
||||||
ansible_host: 192.168.212.30
|
|
||||||
ssh_service_name: ssh
|
|
||||||
ipam:
|
|
||||||
ansible_host: 192.168.212.56
|
|
||||||
ssh_service_name: ssh
|
|
||||||
teamspeck6:
|
|
||||||
ansible_host: 192.168.212.75
|
|
||||||
wiki:
|
|
||||||
ansible_host: 192.168.212.55
|
|
||||||
patchmon:
|
|
||||||
ansible_host: 192.168.212.80
|
|
||||||
einstein-dns:
|
|
||||||
ansible_host: 192.168.212.53
|
|
||||||
weddigram-devel:
|
|
||||||
ansible_host: 192.168.212.201
|
|
||||||
|
|
||||||
proxmox:
|
|
||||||
hosts:
|
|
||||||
dmc12:
|
|
||||||
ansible_host: 192.168.212.10
|
|
||||||
pbs:
|
|
||||||
ansible_host: 192.168.212.11
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
external:
|
|
||||||
children:
|
|
||||||
debian:
|
|
||||||
|
|
||||||
debian:
|
|
||||||
hosts:
|
|
||||||
healthcheck:
|
|
||||||
ansible_host: 2a01:4f8:1c1e:62dd::1
|
|
||||||
netbird:
|
|
||||||
ansible_host: 2a01:4f8:1c1c:8c8::1
|
|
||||||
teleport:
|
|
||||||
ansible_host: 2a01:4f8:1c19:c7d::1
|
|
||||||
podcast-linkstack:
|
|
||||||
ansible_host: 2a01:4f8:c17:de13::1
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
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"
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
# Standardwerte, die überschrieben werden können
|
|
||||||
os_update_auto_upgrade: true
|
|
||||||
os_also_update_mirror: false
|
|
||||||
os_update_mirrors:
|
|
||||||
# Role needs two mirros to use for the sources.list.j2 Template
|
|
||||||
- "http://deb.debian.org/debian" # Enter a main mirror here (not security)
|
|
||||||
- "http://security.debian.org/debian-security" # Enter a security mirror here
|
|
||||||
os_update_version_codename: "trixie" # KEEP UNTOUCHED!! | Used for jinja2 Template fill in as it determines the current codename of system where ansible is run on
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
---
|
|
||||||
# SSH authorized keys for admin user
|
|
||||||
# Format: key and optional comment
|
|
||||||
admin_authorized_keys:
|
|
||||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIL/XwF0Na+YH7lRqGtwEcyIMVGTQZetNDrC9sZ8ofjC5 niklas@Linkman-PC"
|
|
||||||
comment: "Niklas - Linkman-PC"
|
|
||||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
|
||||||
comment: "Generic Ansible Key"
|
|
||||||
|
|
||||||
# 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,19 +0,0 @@
|
|||||||
monitoring_zabbix_passive_servers: ["10.13.37.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", "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: "gatekeeper.meyer-kempen.de"
|
|
||||||
monitoring_zabbix_proxy_address: "10.13.37.1"
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
home:
|
|
||||||
children:
|
|
||||||
debian:
|
|
||||||
proxmox:
|
|
||||||
|
|
||||||
|
|
||||||
debian:
|
|
||||||
hosts:
|
|
||||||
rp:
|
|
||||||
ansible_host: 10.13.37.11
|
|
||||||
paperless:
|
|
||||||
ansible_host: 10.13.37.30
|
|
||||||
homeassistant:
|
|
||||||
ansible_host: 10.13.37.15
|
|
||||||
teleport-jumper:
|
|
||||||
ansible_host: 10.13.37.50
|
|
||||||
idris-dns:
|
|
||||||
ansible_host: 10.13.37.53
|
|
||||||
it-tools:
|
|
||||||
ansible_host: 10.13.37.16
|
|
||||||
proxmox:
|
|
||||||
hosts:
|
|
||||||
tardis:
|
|
||||||
ansible_host: 10.13.37.5
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
- hosts: all
|
|
||||||
user: admin
|
|
||||||
become: true
|
|
||||||
vars_files:
|
|
||||||
- ../vault.yml
|
|
||||||
tasks:
|
|
||||||
- name: Verify if system is Debian
|
|
||||||
debug:
|
|
||||||
msg: "This playbook is running on a Debian system."
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
|
|
||||||
- name: Stop playbook if system is not Debian
|
|
||||||
fail:
|
|
||||||
msg: "This playbook only supports Debian."
|
|
||||||
when: ansible_facts['os_family'] != "Debian"
|
|
||||||
|
|
||||||
- name: Include monitoring role
|
|
||||||
import_role:
|
|
||||||
name: monitoring
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
@@ -16,8 +16,3 @@
|
|||||||
include_role:
|
include_role:
|
||||||
name: os-updates
|
name: os-updates
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
when: ansible_facts['os_family'] == "Debian"
|
||||||
|
|
||||||
- name: Include healthcheck role (post-update quality gate)
|
|
||||||
include_role:
|
|
||||||
name: healthcheck
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
- hosts: all
|
|
||||||
user: admin
|
|
||||||
become: true
|
|
||||||
tasks:
|
|
||||||
- name: Verify if system is Debian
|
|
||||||
debug:
|
|
||||||
msg: "This playbook is running on a Debian system."
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
|
|
||||||
- name: Stop playbook if system is not Debian
|
|
||||||
fail:
|
|
||||||
msg: "This playbook only supports Debian."
|
|
||||||
when: ansible_facts['os_family'] != "Debian"
|
|
||||||
|
|
||||||
- name: Include hawser role
|
|
||||||
import_role:
|
|
||||||
name: hawser
|
|
||||||
when: ansible_facts['os_family'] == "Debian"
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
# Rolle `bootstrap`
|
|
||||||
|
|
||||||
Ersteinrichtung (Provisioning) eines frischen Debian-Hosts. Die Rolle legt den
|
|
||||||
Admin-User an, installiert Basispakete, härtet die SSH-Konfiguration, verteilt
|
|
||||||
autorisierte SSH-Keys, konfiguriert Tastaturlayout, MOTD, Bash-Aliase und
|
|
||||||
sysctl, und bindet optional die Rollen `docker` und `monitoring` ein.
|
|
||||||
|
|
||||||
> Siehe auch das Top-Level-Playbook `bootstrap.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- SSH-Zugang als Benutzer, der `become` darf (Playbook nutzt `user: admin`)
|
|
||||||
- `ansible.posix` Collection (für `sysctl`-Modul)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle wird normalerweise über das Top-Level-Playbook `bootstrap.yml`
|
|
||||||
aufgerufen, kann aber auch direkt per `include_role`/`import_role` eingebunden
|
|
||||||
werden:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: bootstrap
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml --vault-password-file .vault_pass bootstrap.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` reiht die Subtasks nacheinander aus und bindet am Ende
|
|
||||||
bedarfsabhängig die Rollen `docker` und `monitoring` ein:
|
|
||||||
|
|
||||||
1. `install-basicpackages.yml` – Basispakete installieren
|
|
||||||
2. `create-admin-user.yml` – Admin-User anlegen + sudoers
|
|
||||||
3. `set-motd.yml` – MOTD via fastfetch (`tags: motd`)
|
|
||||||
4. `set-keyboardlayout.yml` – QWERTZ-Layout
|
|
||||||
5. `install-openssh.yml` – OpenSSH Server/Client (`tags: ssh`)
|
|
||||||
6. `configure-ssh.yml` – sshd_config härtbar (`tags: ssh`)
|
|
||||||
7. `add-ssh-keys.yml` – authorized_keys verteilen (`tags: ssh`)
|
|
||||||
8. `setup-bashrc.yml` – nützliche Aliase (`tags: bashrc`)
|
|
||||||
9. `configure-sysctl.yml` – vm.swappiness = 10 (`tags: sysctl`)
|
|
||||||
10. `import_role: docker` (sofern nicht `skip_docker`)
|
|
||||||
11. `import_role: monitoring` (sofern nicht `skip_monitoring`)
|
|
||||||
|
|
||||||
### Installierte Basispakete
|
|
||||||
|
|
||||||
`fastfetch`, `htop`, `curl`, `wget`, `git`, `sudo`, `console-setup`,
|
|
||||||
`qemu-guest-agent`, `cron`, `net-tools`, `tcpdump`, `locales-all`.
|
|
||||||
|
|
||||||
### SSH-Härtung
|
|
||||||
|
|
||||||
Die Vorlage `templates/sshd.conf.j2` deaktiviert Root-Login und
|
|
||||||
Passwort-Authentifizierung, erlaubt ausschließlich Publickey-Auth und setzt
|
|
||||||
restriktive Forwarding-/Logging-Optionen. Nach Änderung wird der sshd via
|
|
||||||
Handler neu gestartet.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-------------------------|----------|-------------------|-----------------------------------------------------|
|
|
||||||
| `admin_authorized_keys` | list | siehe `defaults/` | Liste von `{ key, comment }`-Einträgen für `admin` |
|
|
||||||
| `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)
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|--------------------|--------|---------|-----------------------------------------------------------|
|
|
||||||
| `skip_docker` | bool | `false` | Wenn `true`, wird die `docker`-Rolle übersprungen |
|
|
||||||
| `skip_monitoring` | bool | `false` | Wenn `true`, wird die `monitoring`-Rolle übersprungen |
|
|
||||||
| `ssh_service_name` | string | `sshd` | Name des SSH-Service (überschrieben bspw. für `ssh`) |
|
|
||||||
|
|
||||||
`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/cloudlorean.yml`).
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|------------------------|------------------------------------------------|
|
|
||||||
| `sshd.conf.j2` | `/etc/ssh/sshd_config` (validiert via `sshd -T`) |
|
|
||||||
| `authorized_keys.j2` | `/home/admin/.ssh/authorized_keys` |
|
|
||||||
| `sudoers-admin.j2` | `/etc/sudoers.d/10-admin` (validiert via `visudo -cf`) |
|
|
||||||
| `keyboard.j2` | `/etc/default/keyboard` |
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser |
|
|
||||||
|-------------------------|-------------------------------------------|
|
|
||||||
| `Restart sshd` | Änderung an `sshd_config` |
|
|
||||||
| `Reload keyboard layout`| Änderung an `/etc/default/keyboard` |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
`motd`, `ssh`, `bashrc`, `sysctl` – ermöglichen das gezielte Re-Apply einzelner
|
|
||||||
Teile, z. B.:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook bootstrap.yml -i inventory/cloudlorean.yml -t ssh
|
|
||||||
```
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- `docker` (optional, via `import_role`)
|
|
||||||
- `monitoring` (optional, via `import_role`)
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- `configure-sysctl.yml` wird auf LXC-Containern übersprungen
|
|
||||||
(`virtualization_type != "lxc"`).
|
|
||||||
- `setup-bashrc.yml` legt Aliase für alle regulären User inkl. root an.
|
|
||||||
- `install-openssh.yml` entfernt ggf. das Meta-Paket `ssh` vor der
|
|
||||||
Installation von `openssh-server`/`openssh-client`.
|
|
||||||
@@ -9,5 +9,5 @@ admin_authorized_keys:
|
|||||||
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
- key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIA+EvtGavPlXfv7b00jSYsXX2+IEsqFWupEs6Rzf5z9q root@ansible"
|
||||||
comment: "Generic Ansible Key"
|
comment: "Generic Ansible Key"
|
||||||
|
|
||||||
# admin_password lives encrypted in vault.yml (loaded via vars_files in
|
# Admin user password (hashed with SHA-512)
|
||||||
# bootstrap.yml); no plaintext fallback per repository vault policy.
|
admin_password: "$6$NmIxM3ZbJDsbC1E6$BO8ag1ZyBqbhELjk0ppKV0CLnYXhHDp9oZc.jmkc62N9hjwbXihF1FmvsYgMKKINVcwaE73u2dRO8pnE6yEGH/"
|
||||||
|
|||||||
@@ -3,9 +3,7 @@
|
|||||||
service:
|
service:
|
||||||
name: "{{ ssh_service_name | default('sshd') }}"
|
name: "{{ ssh_service_name | default('sshd') }}"
|
||||||
state: restarted
|
state: restarted
|
||||||
remote_user: admin
|
|
||||||
|
|
||||||
- name: Reload keyboard layout
|
- name: Reload keyboard layout
|
||||||
shell: setupcon
|
shell: setupcon
|
||||||
ignore_errors: yes
|
ignore_errors: yes
|
||||||
remote_user: admin
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Configure swappiness to reduce swap usage
|
|
||||||
become: yes
|
|
||||||
ansible.posix.sysctl:
|
|
||||||
name: vm.swappiness
|
|
||||||
value: 10
|
|
||||||
state: present
|
|
||||||
reload: yes
|
|
||||||
when: ansible_facts['virtualization_type'] != "lxc"
|
|
||||||
@@ -19,14 +19,3 @@
|
|||||||
|
|
||||||
- import_tasks: setup-bashrc.yml
|
- import_tasks: setup-bashrc.yml
|
||||||
tags: bashrc
|
tags: bashrc
|
||||||
|
|
||||||
- import_tasks: configure-sysctl.yml
|
|
||||||
tags: sysctl
|
|
||||||
|
|
||||||
- import_role:
|
|
||||||
name: docker
|
|
||||||
when: not skip_docker | default(false)
|
|
||||||
|
|
||||||
- import_role:
|
|
||||||
name: monitoring
|
|
||||||
when: not skip_monitoring | default(false)
|
|
||||||
@@ -3,10 +3,7 @@
|
|||||||
content: |
|
content: |
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Managed by Ansible - Do not edit manually
|
# Managed by Ansible - Do not edit manually
|
||||||
if [[ -z "${FASTFETCH_MOTD_SHOWN:-}" && -z "${SUDO_USER:-}" ]]; then
|
fastfetch -s os:kernel:uptime:packages:shell:disk:cpu:memory:localip:colors
|
||||||
fastfetch -s os:kernel:uptime:packages:shell:disk:cpu:memory:localip:colors
|
|
||||||
export FASTFETCH_MOTD_SHOWN=1
|
|
||||||
fi
|
|
||||||
dest: /etc/profile.d/motd.sh
|
dest: /etc/profile.d/motd.sh
|
||||||
owner: root
|
owner: root
|
||||||
group: root
|
group: root
|
||||||
|
|||||||
@@ -1,103 +0,0 @@
|
|||||||
# Rolle `docker`
|
|
||||||
|
|
||||||
Installiert die Docker Engine über das offizielle Docker-Repository für Debian.
|
|
||||||
Die Rolle fügt den Docker-GPG-Key hinzu, richtet eine APT-Quelle im deb822-Format
|
|
||||||
ein und installiert alle benötigten Pakete (Engine, CLI, containerd, Buildx- und
|
|
||||||
Compose-Plugin).
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/docker.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Internetzugang zum Docker-Repository (`download.docker.com`)
|
|
||||||
- Benutzer mit `become`-Rechten
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle wird typischerweise über das Playbook `playbooks/docker.yml` oder
|
|
||||||
automatisch durch die `bootstrap`-Rolle (`import_role`) aufgerufen. Direkte
|
|
||||||
Einbindung per `import_role`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: docker
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/docker.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` inkludiert die eigentliche Installations-Logik aus
|
|
||||||
`tasks/install-docker.yml`:
|
|
||||||
|
|
||||||
1. **apt-Cache aktualisieren** – `cache_valid_time: 3600`
|
|
||||||
2. **Voraussetzungen installieren** – `ca-certificates`, `curl`
|
|
||||||
3. **Keyring-Verzeichnis anlegen** – `/etc/apt/keyrings` (Mode `0755`)
|
|
||||||
4. **Docker GPG-Key herunterladen** – nach `/etc/apt/keyrings/docker.asc`
|
|
||||||
5. **APT-Quelle einrichten** – Template `sources.list.j2` nach
|
|
||||||
`/etc/apt/sources.list.d/docker.sources` (deb822-Format)
|
|
||||||
6. **apt-Cache aktualisieren** – nach Repository-Hinzufügung
|
|
||||||
7. **Docker-Pakete installieren** – `docker_packages` (benachrichtigt Handler
|
|
||||||
`Start Docker`)
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|----------------------|---------|--------------------------------------|-------------------------------------------------------|
|
|
||||||
| `docker_mirror` | string | `https://download.docker.com/linux/debian` | Basis-URL des Docker-APT-Repositories |
|
|
||||||
| `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`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
docker_packages:
|
|
||||||
- docker-ce
|
|
||||||
- docker-ce-cli
|
|
||||||
- containerd.io
|
|
||||||
- docker-buildx-plugin
|
|
||||||
- docker-compose-plugin
|
|
||||||
```
|
|
||||||
|
|
||||||
`os_version_codename` wird standardmäßig automatisch anhand von
|
|
||||||
`ansible_facts['distribution_release']` ermittelt und kann bei Bedarf
|
|
||||||
überschrieben werden.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|-------------------|-------------------------------------------------|
|
|
||||||
| `sources.list.j2` | `/etc/apt/sources.list.d/docker.sources` (deb822) |
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser |
|
|
||||||
|------------------|-----------------------------------------------------|
|
|
||||||
| `Start Docker` | Installation/Aktualisierung der Docker-Pakete |
|
|
||||||
| `Restart Docker` | (reserviert) systemd-Neustart |
|
|
||||||
| `Reload Docker` | (reserviert) systemd-Reload |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags. Bei Bedarf über das Playbook steuerbar.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die APT-Quelle liegt im **deb822-Format** vor, was ab Debian 12+ empfohlen
|
|
||||||
wird. Das签ierte-Keyfile liegt unter `/etc/apt/keyrings/docker.asc`.
|
|
||||||
- Der Handler `Start Docker` aktiviert und startet den Service, ohne bereits
|
|
||||||
laufende Container zu beeinflussen.
|
|
||||||
- Wird die Rolle innerhalb von `bootstrap` aufgerufen, übernimmt das Top-Level
|
|
||||||
Playbook das `become`/`user`-Handling.
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
docker_mirror: https://download.docker.com/linux/debian
|
docker_mirror: https://download.docker.com/linux/debian
|
||||||
os_version_codename: "{{ ansible_facts['distribution_release'] }}"
|
os_version_codename: "{{ ansible_lsb.codename }}"
|
||||||
docker_packages:
|
docker_packages:
|
||||||
- docker-ce
|
- docker-ce
|
||||||
- docker-ce-cli
|
- docker-ce-cli
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
# Rolle `hawser`
|
|
||||||
|
|
||||||
Aktualisiert den [Hawser](https://ghcr.io/finsys/hawser) Docker-Compose-Stack
|
|
||||||
auf den Ziel-Hosts. Hawser ist ein Docker-Management-Agent, der das Docker-
|
|
||||||
Socket nach außen freigibt. Die Rolle deployt die Compose-Datei aus einem
|
|
||||||
Template und zieht stets die neuesten Images (`pull: always`).
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/upgrade-hawser.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host mit installierter Docker Engine (Rolle `docker`)
|
|
||||||
- Bereits vorhandene Hawser-Installation
|
|
||||||
(`/opt/hawser/docker-compose.yml` muss existieren)
|
|
||||||
- `community.docker` Collection
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: hawser
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/upgrade-hawser.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` importiert `tasks/update-stack.yml`:
|
|
||||||
|
|
||||||
1. **Docker-Host-Info sammeln** – prüft, ob Docker erreichbar ist
|
|
||||||
(`community.docker.docker_host_info`). Bei Fehler werden nachfolgende
|
|
||||||
Tasks übersprungen.
|
|
||||||
2. **Compose-Datei prüfen** – `stat` auf `<hawser_compose_dir>/docker-compose.yml`.
|
|
||||||
Fehlt die Datei, wird kein Update durchgeführt (Bestandsschutz).
|
|
||||||
3. **Compose-Datei ausliefern** – Template `docker-compose.yml.j2` wird nur
|
|
||||||
geschrieben, wenn Docker erreichbar UND bereits eine Compose-Datei
|
|
||||||
vorhanden ist.
|
|
||||||
4. **Stack aktualisieren** – `community.docker.docker_compose_v2` mit
|
|
||||||
`pull: always` und `state: present` zieht die neuesten Images und
|
|
||||||
erneuert die Container.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|--------------------------------|--------|----------------|-----------------------------------------------------------|
|
|
||||||
| `hawser_project_name` | string | `hawser` | Name des Docker-Compose-Projekts |
|
|
||||||
| `hawser_compose_dir` | string | `/opt/hawser` | Verzeichnis der Compose-Datei auf dem Zielhost |
|
|
||||||
| `hawser_port` | string | `2376` | Freigegebener Port des Hawser-Agents (Host-Port) |
|
|
||||||
| `hawser_stacks_volume` | string | `hawser_stacks`| Name des externen Docker-Volumes für Stack-Dateien |
|
|
||||||
| `hawser_allow_insecure_no_auth`| bool | `true` | `ALLOW_INSECURE_NO_AUTH` – Standard-Mode ohne Token |
|
|
||||||
|
|
||||||
> **Achtung:** `hawser_allow_insecure_no_auth: true` erlaubt den Betrieb ohne
|
|
||||||
> Token-Authentifizierung auch auf Nicht-Loopback-Adressen. Nur setzen, wenn
|
|
||||||
> das Netzwerk durch andere Maßnahmen (Firewall, VPN) abgesichert ist.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
| Template | Ziel |
|
|
||||||
|------------------------|--------------------------------------------|
|
|
||||||
| `docker-compose.yml.j2`| `<hawser_compose_dir>/docker-compose.yml` |
|
|
||||||
|
|
||||||
Das Template konfiguriert den Hawser-Container mit Socket-Mount, externem
|
|
||||||
Volume, Port-Mapping, Environment-Variablen, `image: ghcr.io/finsys/hawser:latest`
|
|
||||||
und `restart: always`.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
Keine Handler erforderlich – `docker compose up -d` ersetzt laufende Container
|
|
||||||
eigenständig.
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- `community.docker` Collection (`docker_host_info`, `docker_compose_v2`)
|
|
||||||
- Vorherige Installation der `docker`-Rolle
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die Rolle **erzeugt keine Neuinstallation** – die Compose-Datei wird nur
|
|
||||||
geschrieben, wenn bereits eine existiert. So wird verhindert, dass Hawser
|
|
||||||
versehentlich auf Hosts ausgebracht wird, auf denen es nicht vorgesehen ist.
|
|
||||||
- Das externe Volume `hawser_stacks` muss vor dem ersten Start manuell
|
|
||||||
erstellt werden (`docker volume create hawser_stacks`).
|
|
||||||
- `pull: always` sorgt für aktuelle Images, erfordert aber Internetzugang
|
|
||||||
zum ghcr.io-Registry.
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
# Name des Docker Compose Projekts
|
|
||||||
hawser_project_name: hawser
|
|
||||||
|
|
||||||
# Verzeichnis, in dem die Compose-Datei auf den Zielsystemen liegt
|
|
||||||
hawser_compose_dir: /opt/hawser
|
|
||||||
|
|
||||||
# Freigegebener Port des Hawser-Agents
|
|
||||||
hawser_port: "2376"
|
|
||||||
|
|
||||||
# Name des externen Docker Volumes für die Stack-Dateien
|
|
||||||
hawser_stacks_volume: hawser_stacks
|
|
||||||
|
|
||||||
# ALLOW_INSECURE_NO_AUTH=true erlaubt Standard-Mode ohne Token auf nicht-loopback Adressen.
|
|
||||||
# Nur setzen, wenn das Netzwerk durch andere Maßnahmen abgesichert ist.
|
|
||||||
hawser_allow_insecure_no_auth: true
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
---
|
|
||||||
# Keine Handler erforderlich – docker compose up -d ersetzt laufende Container eigenständig
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
- name: Update Hawser Docker stack
|
|
||||||
ansible.builtin.import_tasks: update-stack.yml
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
- name: Gather Docker host information
|
|
||||||
community.docker.docker_host_info:
|
|
||||||
register: hawser_docker_info
|
|
||||||
ignore_errors: true
|
|
||||||
|
|
||||||
- name: Check if Hawser compose file is present
|
|
||||||
ansible.builtin.stat:
|
|
||||||
path: "{{ hawser_compose_dir }}/docker-compose.yml"
|
|
||||||
register: hawser_compose_file
|
|
||||||
when: hawser_docker_info is not failed
|
|
||||||
|
|
||||||
- name: Deploy Hawser compose file from template
|
|
||||||
ansible.builtin.template:
|
|
||||||
src: docker-compose.yml.j2
|
|
||||||
dest: "{{ hawser_compose_dir }}/docker-compose.yml"
|
|
||||||
owner: root
|
|
||||||
group: root
|
|
||||||
mode: "0640"
|
|
||||||
when:
|
|
||||||
- hawser_docker_info is not failed
|
|
||||||
- hawser_compose_file.stat.exists
|
|
||||||
|
|
||||||
- name: Pull latest images and recreate Hawser stack
|
|
||||||
community.docker.docker_compose_v2:
|
|
||||||
project_src: "{{ hawser_compose_dir }}"
|
|
||||||
project_name: "{{ hawser_project_name }}"
|
|
||||||
state: present
|
|
||||||
pull: always
|
|
||||||
when:
|
|
||||||
- hawser_docker_info is not failed
|
|
||||||
- hawser_compose_file.stat.exists
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
services:
|
|
||||||
hawser:
|
|
||||||
container_name: hawser
|
|
||||||
volumes:
|
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
|
||||||
- {{ hawser_stacks_volume }}:/data/stacks
|
|
||||||
ports:
|
|
||||||
- "{{ hawser_port }}:2376"
|
|
||||||
environment:
|
|
||||||
- ALLOW_INSECURE_NO_AUTH={{ hawser_allow_insecure_no_auth | string | lower }}
|
|
||||||
image: ghcr.io/finsys/hawser:latest
|
|
||||||
restart: always
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
{{ hawser_stacks_volume }}:
|
|
||||||
external: true
|
|
||||||
name: {{ hawser_stacks_volume }}
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# Rolle `healthcheck`
|
|
||||||
|
|
||||||
Post-Update Quality-Gate. Die Rolle prüft nach einem OS-Update, ob alle
|
|
||||||
Docker-Container wieder laufen, und protokolliert das Ergebnis im selben
|
|
||||||
Update-Log, das auch von der `os-updates`-Rolle verwendet wird.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/os-updates-deb.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- Optional installiertes Docker (wird automatisch erkannt)
|
|
||||||
- Idealerweise vorheriger Lauf der `os-updates`-Rolle (für gemeinsames Log)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
Die Rolle ist fest in `playbooks/os-updates-deb.yml` nach der `os-updates`-
|
|
||||||
Rolle eingebunden und wird in der Regel nicht separat aufgerufen:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
become: true
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: os-updates
|
|
||||||
- role: healthcheck
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/os-updates-deb.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` führt nacheinander folgende Schritte aus:
|
|
||||||
|
|
||||||
1. **Docker-Binary erkennen** – `which docker` (fehlertolerant)
|
|
||||||
2. **Docker-Präsenz festhalten** – Fakt `healthcheck_docker_installed`
|
|
||||||
3. **Alle Container auflisten** – `docker ps -a --format {{.Names}}`
|
|
||||||
4. **Laufende Container auflisten** – `docker ps --filter status=running`
|
|
||||||
5. **Container-Health bewerten** – Differenz aus allen und laufenden
|
|
||||||
Containern ergibt `healthcheck_non_running_containers`
|
|
||||||
6. **Gesamtergebnis bestimmen** – `healthcheck_all_running`,
|
|
||||||
`healthcheck_passed`
|
|
||||||
7. **Default-Ergebnis ohne Docker** – falls Docker nicht installiert ist,
|
|
||||||
gilt der Healthcheck als bestanden (`passed: true`, 0 Container)
|
|
||||||
8. **Log-Verzeichnis sicherstellen** – delegiert an localhost
|
|
||||||
9. **Quality-Gate in Update-Log schreiben** – `blockinfile` mit Marker
|
|
||||||
`# {mark} ANSIBLE-HEALTHCHECK`, Abschnitt `quality_gate:`
|
|
||||||
10. **Fehlschlagen bei ungesunden Containern** – nur wenn
|
|
||||||
`healthcheck_fail_on_unhealthy` gesetzt ist
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|------------------------------|-------|------------------------------------------------------------------|-----------------------------------------------|
|
|
||||||
| `healthcheck_logging_enabled`| bool | `{{ os_update_logging_enabled \| default(true) }}` | Logging aktivieren |
|
|
||||||
| `healthcheck_log_dir` | string| `{{ os_update_log_dir \| default('/ansible/logs') }}` | Basis-Verzeichnis für Logs |
|
|
||||||
| `healthcheck_log_inventory` | string| `{{ inventory_file \| basename \| splitext \| first }}` | Inventory-Name (abgeleitet) |
|
|
||||||
| `healthcheck_log_file` | string| `<log_dir>/<inventory>/<hostname>/update.log` | Pfad zur Update-Log-Datei |
|
|
||||||
| `healthcheck_fail_on_unhealthy`| bool| `false` | Playbook fehlschlagen lassen, wenn Container nicht laufen |
|
|
||||||
|
|
||||||
Die Variablen leiten sich standardmäßig aus den Werten der `os-updates`-Rolle
|
|
||||||
ab, sodass beide Rollen in dasselbe Log schreiben.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
Keine Templates.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
Keine Handler.
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
- Empfohlener Partner: `os-updates`-Rolle (für gemeinsames Log-Format).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Wird Docker nicht gefunden, gilt der Healthcheck als bestanden – nützlich
|
|
||||||
für Hosts, die keine Container betreiben.
|
|
||||||
- Das Log wird **delegiert auf localhost** geschrieben (auf dem Ansible-
|
|
||||||
Controller), nicht auf dem Zielhost. Das Verzeichnis `logs/` ist
|
|
||||||
git-ignored.
|
|
||||||
- Die `quality_gate`-Sektion im Log ist an denselben Eintrag gekoppelt wie
|
|
||||||
der `os-updates`-Preflight, sodass ein Update-Lauf inkl. Healthcheck
|
|
||||||
nachvollziehbar dokumentiert ist.
|
|
||||||
- `healthcheck_fail_on_unhealthy: false` (Default) bricht das Playbook nicht
|
|
||||||
ab – bewusst gewählt, damit nach Updates nicht versehentlich ganze
|
|
||||||
Host-Gruppen blockiert werden. Für kritische Hosts individuell setzen.
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
# Post-update health check (quality gate) defaults.
|
|
||||||
# The role verifies that every Docker container is running after an OS update
|
|
||||||
# and records the result in the same update log used by the os-updates role.
|
|
||||||
|
|
||||||
healthcheck_logging_enabled: "{{ os_update_logging_enabled | default(true) }}"
|
|
||||||
healthcheck_log_dir: "{{ os_update_log_dir | default('/ansible/logs') }}"
|
|
||||||
healthcheck_log_inventory: "{{ inventory_file | basename | splitext | first }}"
|
|
||||||
healthcheck_log_file: "{{ healthcheck_log_dir }}/{{ healthcheck_log_inventory }}/{{ ansible_facts['hostname'] }}/update.log"
|
|
||||||
|
|
||||||
# When true, the role fails the playbook if any container is not running.
|
|
||||||
healthcheck_fail_on_unhealthy: false
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
# Post-update health check (quality gate).
|
|
||||||
# Detects whether Docker is installed and, if so, verifies that every
|
|
||||||
# container is in the running state. Results are appended to the update
|
|
||||||
# log as a "quality_gate" section, tied to the current update run via the
|
|
||||||
# os-updates preflight start timestamp.
|
|
||||||
|
|
||||||
- name: Healthcheck - Detect Docker binary
|
|
||||||
ansible.builtin.command: which docker
|
|
||||||
register: healthcheck_docker_bin
|
|
||||||
changed_when: false
|
|
||||||
failed_when: false
|
|
||||||
|
|
||||||
- name: Healthcheck - Record Docker presence
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_docker_installed: "{{ healthcheck_docker_bin.rc == 0 }}"
|
|
||||||
|
|
||||||
- name: Healthcheck - List all container names
|
|
||||||
ansible.builtin.command: "docker ps -a --format {{ '{{' }}.Names{{ '}}' }}"
|
|
||||||
register: healthcheck_all_containers
|
|
||||||
changed_when: false
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - List running container names
|
|
||||||
ansible.builtin.command: "docker ps --filter status=running --format {{ '{{' }}.Names{{ '}}' }}"
|
|
||||||
register: healthcheck_running_containers
|
|
||||||
changed_when: false
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Evaluate container health
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_total_containers: "{{ healthcheck_all_containers.stdout_lines | length }}"
|
|
||||||
healthcheck_running_count: "{{ healthcheck_running_containers.stdout_lines | length }}"
|
|
||||||
healthcheck_non_running_containers: "{{ (healthcheck_all_containers.stdout_lines | difference(healthcheck_running_containers.stdout_lines)) | list }}"
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Determine overall result
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_all_running: "{{ (healthcheck_non_running_containers | length) == 0 }}"
|
|
||||||
healthcheck_passed: "{{ (healthcheck_non_running_containers | length) == 0 }}"
|
|
||||||
when: healthcheck_docker_installed | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Default result when Docker is not installed
|
|
||||||
ansible.builtin.set_fact:
|
|
||||||
healthcheck_total_containers: 0
|
|
||||||
healthcheck_running_count: 0
|
|
||||||
healthcheck_non_running_containers: []
|
|
||||||
healthcheck_all_running: true
|
|
||||||
healthcheck_passed: true
|
|
||||||
when: not (healthcheck_docker_installed | bool)
|
|
||||||
|
|
||||||
- name: Healthcheck - Ensure log directory exists
|
|
||||||
ansible.builtin.file:
|
|
||||||
path: "{{ healthcheck_log_file | dirname }}"
|
|
||||||
state: directory
|
|
||||||
delegate_to: localhost
|
|
||||||
when: healthcheck_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Write quality gate section to update log
|
|
||||||
ansible.builtin.blockinfile:
|
|
||||||
path: "{{ healthcheck_log_file }}"
|
|
||||||
create: yes
|
|
||||||
marker: "# {mark} ANSIBLE-HEALTHCHECK"
|
|
||||||
block: |
|
|
||||||
quality_gate:
|
|
||||||
docker_installed: {{ healthcheck_docker_installed }}
|
|
||||||
total_containers: {{ healthcheck_total_containers }}
|
|
||||||
running_containers: {{ healthcheck_running_count }}
|
|
||||||
all_running: {{ healthcheck_all_running }}
|
|
||||||
non_running_containers:
|
|
||||||
{% for c in healthcheck_non_running_containers %}
|
|
||||||
- {{ c }}
|
|
||||||
{% endfor %}
|
|
||||||
healthcheck_passed: {{ healthcheck_passed }}
|
|
||||||
delegate_to: localhost
|
|
||||||
when: healthcheck_logging_enabled | bool
|
|
||||||
|
|
||||||
- name: Healthcheck - Fail when containers are unhealthy (quality gate)
|
|
||||||
ansible.builtin.fail:
|
|
||||||
msg: >-
|
|
||||||
Quality gate failed: the following containers are not running:
|
|
||||||
{{ healthcheck_non_running_containers | join(', ') }}
|
|
||||||
when:
|
|
||||||
- healthcheck_fail_on_unhealthy | bool
|
|
||||||
- healthcheck_docker_installed | bool
|
|
||||||
- not (healthcheck_all_running | bool)
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
# Rolle `manage-ssh-keys`
|
|
||||||
|
|
||||||
Hardening-Rolle zur Verwaltung autorisierter SSH-Schlüssel. Sie fügt
|
|
||||||
erwünschte ("Good") Keys hinzu und entfernt unerwünschte ("Bad") Keys aus der
|
|
||||||
`authorized_keys`-Datei des Zielbenutzers.
|
|
||||||
|
|
||||||
> Siehe auch das Playbook `playbooks/hardening/manage-ssh-keys.yml` sowie die
|
|
||||||
> [Repo-README](../../README.md).
|
|
||||||
|
|
||||||
## Voraussetzungen
|
|
||||||
|
|
||||||
- Debian-Ziel-Host
|
|
||||||
- SSH-Zugang als Zielbenutzer (Default: `admin`)
|
|
||||||
- `lineinfile`-/`blockinfile`-Module (Bordmittel)
|
|
||||||
|
|
||||||
## Einbindung
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
- hosts: all
|
|
||||||
user: admin
|
|
||||||
roles:
|
|
||||||
- role: manage-ssh-keys
|
|
||||||
```
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ansible-playbook -i inventory/cloudlorean.yml playbooks/hardening/manage-ssh-keys.yml
|
|
||||||
```
|
|
||||||
|
|
||||||
Good/Bad-Keys können per Inventory überschrieben oder über Umgebungsvariablen
|
|
||||||
übergeben werden (siehe auskommentiertes Beispiel im Playbook):
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# vars:
|
|
||||||
# good_keys: "{{ lookup('env', 'good_keys') | from_json }}"
|
|
||||||
# bad_keys: "{{ lookup('env', 'bad_keys') | from_json }}"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Funktionsweise
|
|
||||||
|
|
||||||
`tasks/main.yml` steuert den modularen Ablauf:
|
|
||||||
|
|
||||||
1. **`validate-authorized-keys.yml`** – stellt das `.ssh`-Verzeichnis des
|
|
||||||
eingeloggten Users sicher (Mode `0700`).
|
|
||||||
2. **`add-goodkeys.yml`** – fügt jeden Key aus `good_keys` per `lineinfile`
|
|
||||||
zur `authorized_keys` hinzu (idempotent). Benachrichtigt Handler
|
|
||||||
`Cleanup Comments` und `Add Comment`.
|
|
||||||
3. **`remove-badkeys.yml`** – entfernt jeden Key aus `bad_keys` per
|
|
||||||
`lineinfile` (state: absent). Benachrichtigt ebenfalls die Handler.
|
|
||||||
|
|
||||||
Die Handler bereinigen alle Kommentarzeilen (`^#.*$`) und fügen einen
|
|
||||||
eindeutigen "Modified by Ansible"-Block mit Datum/Uhrzeit ein.
|
|
||||||
|
|
||||||
## Variablen
|
|
||||||
|
|
||||||
| Variable | Typ | Default | Beschreibung |
|
|
||||||
|-----------------------|---------|----------------|------------------------------------------------------|
|
|
||||||
| `ssh_user` | string | `admin` | (Referenz) Zielbenutzer – Aktionen laufen als dieser User |
|
|
||||||
| `good_keys` | list | siehe `defaults/` | Liste erwünschter SSH-Keys (vollständige Key-Zeilen) |
|
|
||||||
| `bad_keys` | list | siehe `defaults/` | Liste unerwünschter SSH-Keys (vollständige Key-Zeilen) |
|
|
||||||
|
|
||||||
### Steuer-Variablen (keine Defaults)
|
|
||||||
|
|
||||||
| Variable | Typ | Beschreibung |
|
|
||||||
|-----------------------|--------|-----------------------------------------------------------|
|
|
||||||
| `authorized_keys_file`| string | Pfad zur `authorized_keys`-Datei (muss gesetzt sein) |
|
|
||||||
|
|
||||||
> `authorized_keys_file` wird im Playbook bzw. Inventory gesetzt und muss
|
|
||||||
> auf die Datei des Zielusers verweisen (z. B.
|
|
||||||
> `/home/admin/.ssh/authorized_keys`).
|
|
||||||
|
|
||||||
Default `good_keys` enthält die Admin-Keys (Niklas, Dennis, Generic Ansible).
|
|
||||||
Default `bad_keys` enthält einen veralteten RSA-Key als Beispiel.
|
|
||||||
|
|
||||||
## Templates
|
|
||||||
|
|
||||||
Keine Templates.
|
|
||||||
|
|
||||||
## Handler
|
|
||||||
|
|
||||||
| Handler | Auslöser | Beschreibung |
|
|
||||||
|-------------------|-------------------------------------------|----------------------------------------------------------|
|
|
||||||
| `Cleanup Comments`| Good/Bad-Key-Änderung | Entfernt alle Kommentarzeilen (`^#.*$`) aus der Datei |
|
|
||||||
| `Add Comment` | Good/Bad-Key-Änderung | Fügt "Modified by Ansible on <Datum> at <Uhrzeit>" ein |
|
|
||||||
|
|
||||||
## Tags
|
|
||||||
|
|
||||||
Die Rolle vergibt keine eigenen Tags.
|
|
||||||
|
|
||||||
## Abhängigkeiten
|
|
||||||
|
|
||||||
- Keine weiteren Rollen.
|
|
||||||
- Collections: `ansible.builtin` (Bordmittel).
|
|
||||||
|
|
||||||
## Hinweise
|
|
||||||
|
|
||||||
- Die Rolle ist **idempotent**: mehrfaches Ausführen führt zu keinem
|
|
||||||
geänderten Zustand, wenn Keys bereits vorhanden/abwesend sind.
|
|
||||||
- Good/Bad-Keys sind **vollständige Key-Zeilen** inkl. Typ, Key und
|
|
||||||
Kommentar (z. B. `ssh-ed25519 AAAA... user@host`). Der Vergleich erfolgt
|
|
||||||
zeilenbasiert.
|
|
||||||
- Handler laufen erst am Ende des Playbook-Laufs – bei mehreren Key-Änderungen
|
|
||||||
wird die Datei nur einmal bereinigt.
|
|
||||||
- Vorsicht bei der Definition von `bad_keys`: zu weit gefasste Patterns
|
|
||||||
könnten legitime Keys entfernen. Immer die exakte Key-Zeile angeben.
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user