Ansible automation for the fleet — system hardening, configuration management, operator-host tooling — aligned with EU and Austrian regulatory requirements.
Companions:
infra (OpenTofu provisioning),
runbooks (ad-hoc operator
scripts).
| Framework | Coverage |
|---|---|
| NIS2 Directive (EU 2022/2555) | Art 20–23: risk management, incident handling, reporting |
| NISG 2026 (Austrian transposition) | National NIS2 implementation; effective 2026-10-01 |
| Cyber Resilience Act (EU 2024/2847) | Annex I: secure-by-design, minimal attack surface |
| GDPR (EU 2016/679) / Austrian DSG | Art 5, 25, 32: data protection by design |
| ISO/IEC 27001:2022 | Annex A controls (A.5–A.8) |
Controls and policies live in
docs/compliance-controls.yml and map
to the regulatory frameworks above.
- Target OS: Ubuntu 24.04 LTS (Noble) and Ubuntu 26.04 LTS (Resolute, kernel 7.0). No official CIS 26.04 benchmark exists yet, so the 26.04 baseline is "CIS 24.04 + kernel-7.0/KSPP delta" (ADR-004).
- Ansible ≥ 2.18 (
community.general13.x requiresansible-core≥ 2.18) - Python ≥ 3.10
ansible-galaxy install -r requirements.yml# Dry-run
ansible-playbook -i inventories/<env>/hosts playbooks/site-common.yml --check --diff
# Apply
ansible-playbook -i inventories/<env>/hosts playbooks/site-common.yml
# Compliance-tagged roles only
ansible-playbook -i inventories/<env>/hosts playbooks/site-common.yml --tags compliance
# Specific roles
ansible-playbook -i inventories/<env>/hosts playbooks/site-common.yml --tags ssh,firewall,auditListed in playbooks/site-common.yml application order; the three roles
below the rule ship in their own playbooks. Full regulatory detail per
control lives in docs/compliance-controls.yml.
| Role | Purpose | Key compliance references |
|---|---|---|
common |
Base packages, timezone, sysctl, kernel/FS hardening, log retention | CTL-002, CTL-003, POL-004, NIS2 Art 21.2(a)(e), GDPR Art 25/32, CRA Annex I |
apparmor |
Ensure the AppArmor MAC LSM is enabled and profiles enforced | POL-001 |
kernel_lockdown |
Audit the kernel lockdown LSM level; opt-in enforcement, module/kexec restrictions | POL-004 |
usbguard |
Audit the USB attack surface; opt-in default-deny device allowlisting | POL-001 |
users |
User accounts, sudo, password policy, account lockout | CTL-001, POL-001, POL-003, NIS2 Art 21.2(i), GDPR Art 32 |
ntp |
chrony time sync (Austrian/EU NTP pools, NTS) |
CTL-003, POL-002, POL-003, ISO 27001 A.8.17 |
dns |
DNS resolver hardening via systemd-resolved (DNSSEC/DoT) |
POL-003 |
ssh_hardening |
SSH server hardening, legal banner, BSI-aligned crypto | CTL-001, POL-001, POL-003, NIS2 Art 21.2(h)(i) |
ufw |
UFW firewall, default-deny, IPv6, rate limiting | POL-001, NIS2 Art 21.2(e), GDPR Art 32 |
nftables_egress |
Default-deny outbound (egress) filtering with an allow-list | POL-001 |
fail2ban |
Intrusion prevention with recidive jail |
POL-002, NIS2 Art 21.2(b) |
aide |
File integrity monitoring | CTL-002, POL-002, POL-003, NIS2 Art 21.2(a), GDPR Art 32 |
rkhunter |
Rootkit detection (known-rootkit signatures, file-property integrity, suspicious-file scans; noisy host-state probes disabled — see role README) | POL-002, NIS2 Art 21.2(a)(b), GDPR Art 32, ISO 27001 A.8.7 |
auditd |
System audit logging (CIS + NIS2/GDPR rules) | CTL-002, CTL-003, POL-004, POL-005, GDPR Art 5(2), NIS2 Art 21.2(a) |
log_forwarding |
Central log forwarding via rsyslog (TLS) + audisp-remote |
CTL-002, CTL-003, POL-002, POL-003, NIS2 Art 21.2(a), GDPR Art 5(2) |
vector |
Log shipper (journald → SIEM) — opt-in (vector_enabled) |
CTL-002, CTL-003, POL-003 |
rsyslog_hardening |
Harden the local rsyslog daemon (create-modes, privilege drop, reception audit) | CTL-003 |
wazuh_agent |
Wazuh HIDS/FIM agent enrolment — opt-in (wazuh_agent_enabled) |
CTL-002, POL-002 |
systemd_hardening |
Per-service systemd sandboxing + systemd-analyze security audit |
POL-004 |
sre_toolchain |
SRE/Platform/Security toolchain installer (kind, flux, trivy, sops, cosign, opa, k6, …) for operator hosts | NIS2 Art 21.2(a)(e), CRA Annex I, ISO 27001 A.8.30, POL-002, CTL-002 |
ollama |
Local LLM inference runtime (Ollama) — on-prem data sovereignty | POL-004 |
redfish |
Aspirational out-of-band (BMC) management via Redfish | POL-001 |
The first nineteen roles form the fleet hardening baseline applied by
playbooks/site-common.yml (vector and wazuh_agent stay opt-in — each
needs a SIEM / manager endpoint, so the default baseline run is unaffected).
The last three ship in dedicated playbooks: sre_toolchain targets operator
hosts only (workstations, admin/bastion VMs, CI runners) via
playbooks/sre-toolchain.yml; ollama via playbooks/local-inference.yml;
redfish via playbooks/redfish-oob.yml.
inventories/<env>/ # production, staging, development (each with own group_vars, host_vars)
playbooks/ # site-common, sre-toolchain, local-inference, redfish-oob
roles/ # Custom roles (see table above)
group_vars/all.yml # Global group variables
docs/ # Compliance controls catalog + ADRs
scripts/ # Local helpers (compliance-controls validator)
Files and templates live inside each role
(roles/<role>/files/, roles/<role>/templates/) — not at the
repository root, per the
official Ansible sample setup.
Each role produces configuration artifacts that serve as compliance evidence:
- Audit logs (
/var/log/audit/) — CIS + NIS2/GDPR rules, immutable - AIDE reports (
/var/log/aide/) — daily file-integrity checks - rkhunter reports (
/var/log/rkhunter.log) — daily rootkit scans - Auth logs — retained per
common_log_retention.security_audit(365 days default) - SSH banner — legal monitoring notice (GDPR Art 5(2))
- Sysctl hardening — kernel security parameters per CRA Annex I
Log retention tiers (CTL-002 evidence retention; see
docs/compliance-controls.yml):
| Tier | Days |
|---|---|
governance |
3650 (10 years) |
incidents |
1825 (5 years) |
dr_tests |
1825 (5 years) |
ci |
1095 (3 years) |
security_audit |
365 (1 year) |
operational |
90 |
Periodic full-tree validation against known-good sources (CIS Ubuntu
Benchmark, BSI TR-02102-4, upstream OpenSSH / chrony / auditd /
pam_faillock / pam_pwquality manuals, Ansible production-profile
lint rules). Each pass produces an ADR under docs/:
| ADR | Date | Topic |
|---|---|---|
| ADR-001 | 2026-05-24 | Code validation baseline — index, findings, accepted design tensions, doc-parity policy |
| ADR-002 | 2026-05-30 | sre_toolchain supply-chain hardening — strict checksum default, optional cosign signatures, optional tag pinning, evidence manifest |
| ADR-003 | 2026-05-30 | Runtime-correctness fixes (auditd restart, role order, fail2ban/rsyslog) and CIS baseline extension; pam_faillock via pam-config profiles |
| ADR-004 | 2026-05-30 | Ubuntu 24.04 + 26.04 (kernel 7.0) dual-support; interim "CIS 24.04 + KSPP/kernel-7.0 delta" benchmark stance; kernel-7.0 sysctl review |
| ADR-005 | 2026-05-31 | Out-of-band (BMC) management via Redfish — Proposed/aspirational (no BMC hardware in the fleet yet); the redfish role + playbooks/redfish-oob.yml |
| ADR-006 | 2026-05-31 | AI-in-CI advisory compliance review via local inference — Proposed/dormant until a local endpoint is configured; scripts/ai-compliance-review.py |
| ADR-007 | 2026-05-31 | Compliance posture export as the fleet → MCP bridge — Accepted; scripts/export-compliance-posture.py emits versioned posture JSON |
Static analysis is enforced on every push and pull request by
.github/workflows/ci.yml:
# Reproduce locally
make install # ansible-core, ansible-lint, yamllint, pre-commit, galaxy deps
make check # lint + syntax-check + validate-compliancemake check runs:
| Check | Tool | Purpose |
|---|---|---|
yamllint |
yamllint + project overrides (.yamllint) |
YAML hygiene |
ansible-lint |
production profile (FQCN, no-changed-when enforced) |
Ansible conformance |
ansible-playbook --syntax-check |
per playbook | Playbook syntax |
scripts/validate-compliance-controls.py |
local Python check | docs/compliance-controls.yml schema and role cross-references |
pre-commit run --all-files |
pre-commit | EditorConfig, EOF, trailing whitespace, private-key detection, hygiene |
ADR-001's current baseline records 0 failure(s), 0 warning(s) under
ansible-lint production and yamllint with project overrides.
| File | Purpose |
|---|---|
CLAUDE.md |
Conventions, FQCN policy, variable precedence |
CONTRIBUTING.md |
Workflow, compliance-controls obligation |
CHANGELOG.md |
Keep a Changelog 1.1.0; cite CTL-/POL- IDs |
LIMITATIONS.md |
Known scope boundaries (L1–L7) |
Makefile |
make help for local targets |
docs/compliance-controls.yml |
Audit-facing CTL-/POL- catalog |
.github/SECURITY.md |
Vulnerability reporting |
.github/PULL_REQUEST_TEMPLATE.md |
PR checklist |
.github/CODEOWNERS |
Review assignment |
LICENSE / NOTICE |
Apache 2.0 |