Das Ansible-Playbook für jeden neuen Server
Werbung
Ich habe bereits über meine Checkliste geschrieben, die ich bei jedem neuen Server abarbeite: ein Non-Root-User, Key-Only-SSH, eine restriktive Firewall (Default Deny), Fail2ban und automatische Sicherheitsupdates. Das alles manuell zu erledigen, dauert keine Stunde. Es ist wirklich nicht schwer.
Aber "keine Stunde, manuell, für jeden Server" summiert sich verdammt schnell, sobald man mehr als drei Server verwaltet. Und genau bei manuellen Schritten schleichen sich die kleinen Unstimmigkeiten ein. Der eine Server bekommt MaxAuthTries 3 gesetzt, der andere nicht – einfach, weil derjenige, der den Server an dem Tag eingerichtet hat, es eilig hatte.
Die Lösung ist simpel: Man gießt die Checkliste in ein Playbook. Gleiche Schritte, gleiche Reihenfolge, jedes Mal. Und es ist idempotent: Führt man es auf einem bereits konfigurierten Server erneut aus, ändert sich absolut nichts.
Das Playbook
---
- name: Baseline hardening for a new server
hosts: new_servers
become: true
vars:
admin_user: deploy
ssh_public_key: "{{ lookup('file', '~/.ssh/id_ed25519.pub') }}"
tasks:
- name: Create admin user
user:
name: "{{ admin_user }}"
groups: sudo
shell: /bin/bash
create_home: true
- name: Add SSH key for admin user
authorized_key:
user: "{{ admin_user }}"
key: "{{ ssh_public_key }}"
- name: Harden SSH config (overrides cloud-init defaults)
copy:
dest: /etc/ssh/sshd_config.d/99-hardening.conf
content: |
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
mode: '0644'
notify: restart sshd
- name: Install UFW and Fail2ban
apt:
name: [ufw, fail2ban]
state: present
update_cache: true
- name: Configure UFW defaults
ufw:
direction: "{{ item.direction }}"
policy: "{{ item.policy }}"
loop:
- { direction: incoming, policy: deny }
- { direction: outgoing, policy: allow }
- name: Allow required ports
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop: ['22', '80', '443']
- name: Enable UFW
ufw:
state: enabled
- name: Enable Fail2ban
systemd:
name: fail2ban
enabled: true
state: started
- name: Install unattended-upgrades
apt:
name: unattended-upgrades
state: present
handlers:
- name: restart sshd
systemd:
name: ssh
state: restarted
Die Ausführung
Sobald ein neuer Server online ist, wird er dem Inventory hinzugefügt und das Playbook läuft exakt gegen diesen einen Host:
ansible-playbook -i inventory.ini baseline.yml -l new-server-01 -u root
Der allererste Lauf muss als root erfolgen – das ist auf einem frischen Server der einzig existierende Benutzer. Sobald das Playbook durchgelaufen ist, ist der Root-Login deaktiviert. Ab diesem Moment ist der User deploy der Einsprungpunkt:
ansible-playbook -i inventory.ini baseline.yml -l new-server-01 -u deploy
Der erste Lauf übernimmt die ganze Arbeit: Er erstellt den Benutzer, riegelt SSH ab und richtet die Firewall ein. Der Handler startet sshd nur dann neu, wenn sich die Config auch wirklich geändert hat. Jeder weitere Lauf ist im Grunde nur noch eine Nulloperation (No-Op), die mir bestätigt, dass die Konfiguration nicht abgedriftet ist.
Interaktiv ausprobieren: Mit dem Ansible Baseline Generator auf dieser Website kann dieses Playbook über ein UI konfiguriert werden. Man legt den Admin-Nutzernamen und den SSH-Port fest, wählt die gewünschten Module aus und kopiert dann einfach den exakten YAML-Output.
Warum Idempotenz das eigentliche Ziel ist
Der wahre Mehrwert liegt nicht in der gesparten Zeit am ersten Tag. Die Befehle manuell einzutippen, ist nicht so langsam. Der Wert zeigt sich sechs Monate später: Wenn ich mir nicht sicher bin, ob ein Server das volle Hardening-Programm bekommen hat oder ob er während eines Incidents in Hektik hochgezogen wurde, lasse ich das Playbook einfach noch einmal laufen.
Wenn alles passt, meldet Ansible null Änderungen und ich hake die Sache ab. Wenn etwas fehlt, wird es auf der Stelle repariert. Ich muss mich nicht mehr daran erinnern, welcher der fünf manuellen Schritte damals vielleicht übersprungen wurde.
Dieses Playbook ist absichtlich so kompakt gehalten. Es installiert keine Application-Stacks und konfiguriert keine projektspezifischen Dienste. Es ist das absolute Fundament, auf dem jeder Server stehen muss, bevor irgendetwas anderes hinzukommt. Indem man es von anwendungsspezifischen Playbooks trennt, bleibt es stabil. Und eine Baseline, die sich kaum verändert, ist eine, der man blind vertrauen kann.
Werbung