Warum eine Linux-Baseline sinnvoll ist

Eine Linux-Baseline ist kein vollständiges Hardening und kein Ersatz für CIS, OpenSCAP oder ein Security-Profil. Sie ist die wiederholbare Grundkonfiguration, die jeder verwaltete Server bekommen soll: Basispakete, Dienste, Zeitbasis, SSH-Grundregeln, Login-Hinweise und ein nachvollziehbarer Abnahmelauf.

Der Beitrag baut auf der vorherigen Ansible-Struktur auf. Inventory, group_vars, host_vars und Vault bleiben gleich; neu ist eine konkrete Rolle, die gegen SLES, Fedora, Rocky, Alma, Debian oder Ubuntu angepasst werden kann.

Zielbild der Rolle

  • Distributionsübergreifende Aufgaben bleiben generisch.

  • Paketlisten, Servicenamen und Ausnahmen liegen in Variablen.

  • Konfigurationsdateien werden mit validate geprüft, bevor sie aktiv werden.

  • Handler starten oder laden Dienste nur neu, wenn sich wirklich etwas geändert hat.

  • Check Mode und Diff Mode zeigen vorab, was passieren würde.

Rollenstruktur

roles/linux_baseline/
defaults/main.yaml
tasks/main.yaml
handlers/main.yaml
templates/issue.j2
templates/sshd_config.d/forgeone-baseline.conf.j2

Defaults: bewusst klein starten

Die Defaults sollten sicher, aber nicht überladen sein. Alles, was pro Distribution oder Kunde abweicht, kann später in group_vars oder host_vars überschrieben werden.

yaml
# roles/linux_baseline/defaults/main.yaml
linux_baseline_packages:
- curl
- vim
- chrony
linux_baseline_services:
- chronyd
linux_baseline_manage_issue: true
linux_baseline_manage_sshd_dropin: true
linux_baseline_ssh_password_authentication: false
linux_baseline_ssh_permit_root_login: false

Distributionen sauber abbilden

Ein häufiger Fehler ist, Paket- und Servicenamen direkt in Tasks zu verdrahten. Besser ist eine Variable pro Plattformfamilie. Die Rolle bleibt dadurch lesbar und kann später in mehreren Umgebungen verwendet werden.

yaml
# inventories/lab/group_vars/suse.yaml
linux_baseline_services:
- chronyd
# inventories/lab/group_vars/debian.yaml
linux_baseline_services:
- chrony

Tasks: Pakete, Dienste und Templates

yaml
# roles/linux_baseline/tasks/main.yaml
- name: Install baseline packages
ansible.builtin.package:
name: "{{ linux_baseline_packages }}"
state: present
- name: Ensure baseline services are enabled and started
ansible.builtin.service:
name: "{{ item }}"
enabled: true
state: started
loop: "{{ linux_baseline_services }}"
- name: Render login banner
ansible.builtin.template:
src: issue.j2
dest: /etc/issue
owner: root
group: root
mode: '0644'
when: linux_baseline_manage_issue
- name: Install sshd baseline drop-in
ansible.builtin.template:
src: sshd_config.d/forgeone-baseline.conf.j2
dest: /etc/ssh/sshd_config.d/99-forgeone-baseline.conf
owner: root
group: root
mode: '0644'
validate: /usr/sbin/sshd -t -f %s
notify: Reload sshd
when: linux_baseline_manage_sshd_dropin

Template: SSH bewusst als Drop-in

Wo möglich, sollte die Rolle nicht die komplette sshd_config ersetzen. Ein Drop-in reduziert das Risiko, lokale Vorgaben zu überschreiben. Wichtig bleibt die Validierung mit sshd -t, bevor der Handler den Dienst neu lädt.

jinja2
# roles/linux_baseline/templates/sshd_config.d/forgeone-baseline.conf.j2
PasswordAuthentication {{ 'yes' if linux_baseline_ssh_password_authentication else 'no' }}
PermitRootLogin {{ 'yes' if linux_baseline_ssh_permit_root_login else 'no' }}

Handler: nur reagieren, wenn sich etwas geändert hat

yaml
# roles/linux_baseline/handlers/main.yaml
- name: Reload sshd
ansible.builtin.service:
name: sshd
state: reloaded

Playbook für die Baseline

yaml
# playbooks/linux-baseline.yaml
- name: Apply Linux baseline
hosts: linux
become: true
gather_facts: true
roles:
- role: linux_baseline

Abnahmelauf

Vor dem echten Lauf sollte die Baseline erst trocken geprüft werden. Danach folgt ein echter Lauf und anschließend ein zweiter Check-Lauf, um unerwartete Änderungen sichtbar zu machen.

bash
ansible-inventory -i inventories/lab/hosts.yaml --graph
ansible-playbook -i inventories/lab/hosts.yaml playbooks/linux-baseline.yaml --syntax-check
ansible-playbook -i inventories/lab/hosts.yaml playbooks/linux-baseline.yaml --check --diff
ansible-playbook -i inventories/lab/hosts.yaml playbooks/linux-baseline.yaml
ansible-playbook -i inventories/lab/hosts.yaml playbooks/linux-baseline.yaml --check --diff

Prüftabelle

Grenzen der Baseline

Diese Rolle ist eine Betriebsbasis. Sie ersetzt kein vollständiges Security-Hardening, keine Schwachstellenbehandlung und keine Compliance-Abnahme. Für CIS, OpenSCAP oder kundenspezifische Härtung sollten eigene Rollen, Profile und Abnahmeprotokolle entstehen.

Was als Nächstes kommt

Der nächste sinnvolle Schritt ist kontrolliertes Patch- und Reboot-Management mit Ansible: Updates vorbereiten, Zielgruppen begrenzen, Reboot-Bedarf erkennen, Wartungsfenster einhalten und nach dem Neustart Dienste prüfen.