# Ansible — Syntax & Variablen-Handout Kompakte Referenz zu YAML-Syntax, Ad-hoc-Befehlen, Jinja2, Facts, Variablen-Auflösung, Ansible Vault, FQCN und ansible.cfg. --- ## 1. YAML-Grundsyntax | Element | Syntax | Beispiel | |--------------------|-----------------|--------------------------| | Schlüssel-Wert | `key: wert` | `name: webserver` | | Liste | `- eintrag` | `- nginx` | | Verschachtelung | Einrückung | 2 Leerzeichen (KEINE Tabs) | | Kommentar | `# text` | `# Dies ist ein Kommentar` | | Zeichenkette | mit/ohne Quotes | `name: "Mein Server"` | Einrückung mit 2 Leerzeichen (niemals Tabs!): ```yaml user: name: admin shell: /bin/bash groups: - sudo - docker ``` --- ## 2. Ad-hoc-Befehle (ohne Playbook) ```bash ansible -m -a "" ``` Beispiele: ```bash # Erreichbarkeit testen ansible all -m ping # Facts anzeigen ansible webserver -m setup # Paket installieren (mit become/-b für Root-Rechte) ansible webserver -b -m apt -a "name=nginx state=present" # Dienst neu starten (mit become/-b) ansible webserver -b -m service -a "name=nginx state=restarted" ``` Wichtige Optionen: | Option | Bedeutung | |--------|----------------------| | `-m` | Modul wählen | | `-a` | Argumente übergeben | | `-i` | Inventory angeben | | `-b` | become (sudo) | | `-u` | Benutzer | **Lokal gegen localhost:** `localhost` ist kein echter Host im Netzwerk. Um direkt auf dem eigenen Rechner zu laufen (ohne SSH), nutzt man im Playbook: ```yaml - hosts: localhost # Hostname: localhost connection: local # Connection-Typ: local (nicht "localhost"!) gather_facts: true become: true # sudo für z.B. Paket-Installation ``` > `hosts: localhost` (Host) und `connection: local` (Typ) sind zwei verschiedene > Angaben — `localhost` ist der Hostname, `local` der Connection-Typ. --- ## 3. Jinja2 — Variablen auflösen Ansible nutzt die Template-Engine **Jinja2**. Variablen werden in doppelte geschweifte Klammern gesetzt: ```yaml # Wert einsetzen message: "Hallo {{ benutzer }}" path: "/home/{{ benutzer }}/.config" # Verschachtelte Variablen db_host: "{{ hostvars['db'].ansible_host }}" ``` ### Filter ```yaml name: "{{ name | upper }}" # -> GROSSSCHREIBUNG port: "{{ port | default(80) }}" # Fallback, wenn Variable leer anzahl: "{{ liste | length }}" # Anzahl der Elemente ip: "{{ ansible_host | ipaddr }}" # IP-Adresse validieren ``` ### Template-Dateien (.j2) Dateien mit Endung `.j2` werden vom Modul `template` gerendert: ```jinja # nginx.conf.j2 server { listen {{ nginx_port }}; server_name {{ domain }}; root {{ web_root }}; } ``` --- ## 4. Gather Facts (Systeminformationen) Ansible sammelt automatisch **Facts** (Systeminformationen) über jeden Host — über das Modul `setup`, standardmäßig `gather_facts: true`. > **Aktuelle Schreibweise:** Facts werden über das Dictionary > `ansible_facts` gelesen — **ohne** `ansible_`-Präfix: > `ansible_facts['distribution']` statt `ansible_distribution`. Die alten > `ansible_*`-Top-Level-Variablen sind veraltet (Deprecated) und werden > standardmäßig nicht mehr injiziert. Häufige Facts: | Fact | Bedeutung | |-----------------------------------|-------------------------------| | `ansible_facts['os_family']` | OS-Familie (Debian, RedHat) | | `ansible_facts['distribution']` | z.B. Ubuntu, CentOS, Debian | | `ansible_facts['distribution_version']` | Version (z.B. 22.04) | | `ansible_facts['hostname']` | Hostname des Systems | | `ansible_facts['default_ipv4']['address']` | IP-Adresse | | `ansible_facts['architecture']` | CPU-Architektur (x86_64) | | `ansible_facts['memtotal_mb']` | RAM in MB | | `ansible_facts['processor_vcpus']`| Anzahl CPU-Kerne | Zugriff im Playbook: ```yaml - name: OS anzeigen ansible.builtin.debug: msg: "{{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}" ``` Eigene Facts (Custom Facts) setzen: ```bash # Datei anlegen (INI-Format): # /etc/ansible/facts.d/app.fact # Inhalt: # [app] # version=1.2.3 # Abruf (der Name des .fact-Files wird zum Unter-Key): # {{ ansible_facts['ansible_local']['app']['version'] }} ``` Facts deaktivieren (Performance): ```yaml gather_facts: false ``` --- ## 5. Wo Variablen definiert werden | Quelle | Datei / Ort | Beispiel | |------------|------------------------------------|---------------------------------| | Inventory | `host_vars/`, `group_vars/` | `group_vars/webserver.yml` | | Playbook | `vars:` / `vars_files:` | `vars: { port: 8080 }` | | Rolle | `roles//vars/` + `defaults/`| `vars/main.yml` | | Facts | automatisch gesammelt | `ansible_facts['os_family']` | | Laufzeit | `register` / `set_fact` | `register: result` | | CLI | Extra-Variablen | `-e "port=8080"` | --- ## 6. Ansible Vault — Secrets verschlüsseln Ansible Vault verschlüsselt sensible Daten (Passwörter, API-Keys, ganze Dateien) mit **AES-256**. Der Schlüssel ist dein Vault-Passwort. Jede verschlüsselte Datei erkennt man an der ersten Zeile: `$ANSIBLE_VAULT;1.1;AES256`. ### Fall A: Eine einzelne Variable verschlüsseln ```bash ansible-vault encrypt_string 'S3kret!' --name db_password ``` Ausgabe — diesen Block einfach in `group_vars/all.yml` (o.ä.) einfügen: ```yaml db_password: !vault | $ANSIBLE_VAULT;1.1;AES256 366230636531633162386130623530653637353436623539... ...weiche Chiffre-Zeilen... ``` Die Datei bleibt sonst Klartext; Ansible erkennt den `!vault`-Block und löst die Variable beim Lauf automatisch auf — Nutzung wie jede andere Variable: ```yaml - name: DB-Zugang testen ansible.builtin.debug: msg: "Passwort: {{ db_password }}" ``` ### Fall B: Eine ganze Datei verschlüsseln ```bash ansible-vault create secrets.yml # neue verschlüsselte Datei anlegen ansible-vault encrypt secrets.yml # bestehende Datei verschlüsseln ansible-vault view secrets.yml # Inhalt ansehen (entschlüsselt anzeigen) ansible-vault edit secrets.yml # im Editor bearbeiten (bleibt verschlüsselt) ansible-vault decrypt secrets.yml # wieder entschlüsseln ``` `secrets.yml` enthält danach nur noch Chiffre-Text. Als Inventory-Variable eingebunden (z.B. `group_vars/all.yml` = Vault-Datei) stehen alle Werte daraus als ganz normale Variablen zur Verfügung. ### Playbook ausführen ```bash ansible-playbook site.yml --ask-vault-pass # Passwort interaktiv ansible-playbook site.yml --vault-password-file ~/.vault_pass ``` Alternativ in `ansible.cfg`: `[defaults] vault_password_file = ~/.vault_pass` > **Git-Praxis:** Verschlüsselte Dateien dürfen ins Repo. Das Vault-Passwort > (bzw. die Passwort-Datei) NIEMALS committen — z.B. über `.gitignore` schützen. ## 7. Variablen-Präzedenz (Auflösungs-Reihenfolge) Ist dieselbe Variable an mehreren Stellen definiert, gewinnt die mit der **höchsten** Priorität (oben = gewinnt): 1. **Extra-Variablen** (CLI `-e`) — gewinnen immer 2. **Task-/Block-Variablen** (`vars:` direkt an der Aufgabe) 3. **set_fact / register** (Werte aus der Laufzeit) 4. **Rollen-Variablen** (`roles/.../vars/main.yml`) 5. **Playbook-Variablen** (`vars:` im Play) 6. **host_vars / group_vars** (aus dem Inventory) 7. **Rollen-Defaults** (`roles/.../defaults/main.yml`) — verlieren > **Faustregel:** Je spezifischer die Quelle, desto höher die Priorität. --- ## 8. Module & FQCN FQCN = **Fully Qualified Collection Name** — `namespace.collection.modul`. ```yaml ansible.builtin.apt: name: nginx state: present ``` | FQCN | Zweck | |-----------------------------------|---------------------------| | `ansible.builtin.copy` | Datei kopieren | | `ansible.builtin.apt` | Paket installieren (Debian) | | `ansible.builtin.service` | Dienst verwalten | | `ansible.builtin.template` | `.j2`-Template rendern | | `ansible.posix.firewalld` | Firewall konfigurieren | | `community.general.git_config` | Git-Einstellungen | --- ## 9. ansible.cfg — Konfiguration INI-Datei, die Ansible global steuert. Ansible nutzt die **erste** gefundene Datei (kein Zusammenführen): 1. `ANSIBLE_CONFIG` — Umgebungsvariable (expliziter Pfad) 2. `./ansible.cfg` — aktuelles Verzeichnis (Projekt) 3. `~/.ansible.cfg` — Home-Verzeichnis (Benutzer) 4. `/etc/ansible/ansible.cfg` — systemweit (Fallback) Wichtige Werte: | Sektion | Schlüssel | Bedeutung | |---------------------------|--------------------|------------------------------------| | `[defaults]` | `inventory` | Pfad zur Inventory-Datei | | | `remote_user` | Standard-SSH-Benutzer | | | `forks` | parallele Prozesse (Default 5) | | | `host_key_checking`| SSH-Key-Prüfung (True/False) | | | `gather_facts` | Facts automatisch sammeln | | | `roles_path` | Suchpfad für Rollen | | `[privilege_escalation]` | `become` | sudo aktivieren | | | `become_method` | sudo / su | | | `become_user` | Ziel-Benutzer (Default root) | | `[ssh_connection]` | `pipelining` | Performance-Optimierung | | | `ssh_args` | zusätzliche SSH-Argumente | Beispiel: ```ini [defaults] inventory = ./inventory.yml remote_user = admin forks = 20 host_key_checking = False gather_facts = True roles_path = ./roles [privilege_escalation] become = True become_method = sudo [ssh_connection] pipelining = True ``` --- ## 10. Vollständiges Beispiel **Playbook** (`deploy.yml`): ```yaml - name: Webserver ausrollen hosts: webserver become: true vars: nginx_port: 8080 # überschreibt den Rollen-Default roles: - webserver ``` **Rollen-Defaults** (`roles/webserver/defaults/main.yml`) — niedrigste Priorität: ```yaml nginx_port: 80 domain: example.com ``` **Rollen-Tasks** (`roles/webserver/tasks/main.yml`): ```yaml - name: nginx installieren ansible.builtin.apt: name: nginx state: present - name: Konfiguration rendern ansible.builtin.template: src: nginx.conf.j2 dest: /etc/nginx/nginx.conf ```