diff --git a/.project-wiki/INDEX.md b/.project-wiki/INDEX.md index e0f1a6e..8afa601 100644 --- a/.project-wiki/INDEX.md +++ b/.project-wiki/INDEX.md @@ -2,7 +2,7 @@ This wiki stores the project knowledge base for requirements, changes, technical documentation, implementation state, and traceability. Use this file as the routing entrypoint; open only the linked files needed for the current task. -Last updated: 2026-09-09 +Last updated: 2026-10-11 ## Current State diff --git a/.project-wiki/REGISTRY.yml b/.project-wiki/REGISTRY.yml index 0b86d3d..22ae085 100644 --- a/.project-wiki/REGISTRY.yml +++ b/.project-wiki/REGISTRY.yml @@ -1,5 +1,5 @@ version: 1 -updated: '2026-09-09' +updated: '2026-10-11' documents: - id: GLOSSARY type: note @@ -162,7 +162,7 @@ documents: confidence: confirmed - id: TECH-DEPLOYMENT type: technical - title: Deployment + title: Deployment (Runtime Environment) path: technical/deployment.md status: active tags: @@ -173,7 +173,11 @@ documents: - TECH-ARCHITECTURE source_paths: - execute.sh - - docker/ + - docker/Dockerfile + - docker/requirements.yml + - docker/ansible-functs.sh + - ansible.cfg + - README.md confidence: confirmed - id: TECH-SECURITY type: technical @@ -185,11 +189,16 @@ documents: - 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 diff --git a/.project-wiki/STATUS.md b/.project-wiki/STATUS.md index 1bd1ba7..9f614e2 100644 --- a/.project-wiki/STATUS.md +++ b/.project-wiki/STATUS.md @@ -1,6 +1,6 @@ # Project Status -Last updated: 2026-09-09 +Last updated: 2026-10-11 ## Scaffold State @@ -11,6 +11,9 @@ Last updated: 2026-09-09 ## 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 diff --git a/.project-wiki/technical/INDEX.md b/.project-wiki/technical/INDEX.md index c0979c6..658405f 100644 --- a/.project-wiki/technical/INDEX.md +++ b/.project-wiki/technical/INDEX.md @@ -11,7 +11,7 @@ This section records implemented or observed code behavior and technical structu - [Architecture](./architecture.md) - [Codebase map](./codebase-map.md) - [Testing](./testing.md) -- [Deployment](./deployment.md) +- [Deployment](./deployment.md) - image build, launcher, read-only local SSH keys - [Security](./security.md) ## Modules diff --git a/.project-wiki/technical/deployment.md b/.project-wiki/technical/deployment.md index 9a7cd9a..018cc85 100644 --- a/.project-wiki/technical/deployment.md +++ b/.project-wiki/technical/deployment.md @@ -4,7 +4,7 @@ type: technical status: active title: Deployment (Runtime Environment) created: '2026-09-09' -updated: '2026-09-09' +updated: '2026-10-11' tags: - technical - deployment @@ -17,6 +17,7 @@ source_paths: - docker/requirements.yml - docker/ansible-functs.sh - ansible.cfg +- README.md confidence: confirmed --- @@ -38,14 +39,24 @@ confidence: confirmed ## Launch Flow (execute.sh) -1. Pick next free container name `ansible-`. -2. Ensure IPv6-enabled bridge network `ansible-dualstack` (fails fast with +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-`. +3. Ensure IPv6-enabled bridge network `ansible-dualstack` (fails fast with a clear message if the network exists without IPv6). -3. Run the container detached: repo mounted at `/ansible` (workdir), SSH - keys from the `ansible_ssh_keys` volume into `/root/.ssh`, env +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`. -4. Write a per-container SSH client config, print name/IPv4/IPv6/OS, then - `docker attach` for interactive use. + 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/`. 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/`. ## Controller-Side Artifacts @@ -57,3 +68,5 @@ confidence: confirmed - 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. diff --git a/.project-wiki/technical/security.md b/.project-wiki/technical/security.md index 91dc708..4bf450c 100644 --- a/.project-wiki/technical/security.md +++ b/.project-wiki/technical/security.md @@ -4,7 +4,7 @@ type: technical status: active title: Security created: '2026-09-09' -updated: '2026-09-09' +updated: '2026-10-11' tags: - technical - security @@ -19,6 +19,7 @@ source_paths: - roles/monitoring/tasks/configure-psk.yml - roles/bootstrap/defaults/main.yml - ansible.cfg +- execute.sh confidence: confirmed --- @@ -39,6 +40,9 @@ confidence: confirmed ## 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 diff --git a/.project-wiki/traceability/code-map.md b/.project-wiki/traceability/code-map.md index e85304d..b2bc1b6 100644 --- a/.project-wiki/traceability/code-map.md +++ b/.project-wiki/traceability/code-map.md @@ -11,8 +11,8 @@ Connects wiki documents to source paths. Created during the 2026-09-09 scan. | [MOD-005 Healthcheck](../technical/modules/MOD-005-healthcheck-role.md) | `playbooks/os-updates-deb.yml`, `roles/healthcheck/` | Container quality gate | | [MOD-006 Hawser](../technical/modules/MOD-006-hawser-role.md) | `playbooks/upgrade-hawser.yml`, `roles/hawser/` | Compose stack update | | [MOD-007 Manage SSH Keys](../technical/modules/MOD-007-manage-ssh-keys-role.md) | `playbooks/hardening/manage-ssh-keys.yml`, `roles/manage-ssh-keys/` | No Debian guard (gap) | -| [TECH-DEPLOYMENT](../technical/deployment.md) | `execute.sh`, `docker/`, `ansible.cfg` | Runtime environment | -| [TECH-SECURITY](../technical/security.md) | `vault.yml`, `roles/*/defaults/`, `ansible.cfg`, `roles/monitoring/tasks/configure-psk.yml` | Secrets, SSH, PSK | +| [TECH-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 | diff --git a/README.md b/README.md index a770b5c..5f787ee 100644 --- a/README.md +++ b/README.md @@ -33,13 +33,41 @@ gestartet werden können. ### Docker-Ausführungsumgebung Damit Playbooks nicht lokal installiert werden müssen, liefert das Repository -ein fertiges Docker-Image. `execute.sh` erstellt ein IPv6-fähiges Bridge-Netzwerk, -startet einen interaktiven Container und mountet das Repository nach `/ansible`: +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 diff --git a/bootstrap.yml b/bootstrap.yml index 1a53f21..f46501a 100644 --- a/bootstrap.yml +++ b/bootstrap.yml @@ -1,6 +1,6 @@ - hosts: all become: true - user: admin + user: root vars_files: - vault.yml tasks: diff --git a/execute.sh b/execute.sh index f882995..01286b4 100755 --- a/execute.sh +++ b/execute.sh @@ -1,6 +1,18 @@ #!/bin/bash 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_CONFIG=./ansible.cfg @@ -36,12 +48,10 @@ docker run --rm -dit \ -e ANSIBLE_HOST_KEY_CHECKING=False \ -e ANSIBLE_CONFIG=./ansible.cfg \ -v "$(pwd):/ansible" \ - -v ansible_ssh_keys:/root/.ssh \ + -v "$ssh_key_dir:/root/.ssh:ro" \ -w /ansible \ - $defaultimage \ - "/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" + "$defaultimage" \ + "/bin/bash" || exit "$?" 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) @@ -56,4 +66,3 @@ echo "-----------------------------------" docker attach "$container_name" - diff --git a/inventory/cloudlorean.yml b/inventory/cloudlorean.yml index 2323fc5..79fb2a2 100644 --- a/inventory/cloudlorean.yml +++ b/inventory/cloudlorean.yml @@ -33,6 +33,8 @@ debian: ansible_host: 192.168.212.80 einstein-dns: ansible_host: 192.168.212.53 + weddigram-devel: + ansible_host: 192.168.212.201 proxmox: hosts: