From 750eca8e0ab51149f1c7cd178321810749aea80b Mon Sep 17 00:00:00 2001 From: Stefan Mewes Date: Sun, 12 Apr 2026 22:22:15 +0200 Subject: [PATCH] cert renewal refactored --- nebula_cert_renewal.yml | 525 ++++++++++++++++++++-------------------- 1 file changed, 264 insertions(+), 261 deletions(-) diff --git a/nebula_cert_renewal.yml b/nebula_cert_renewal.yml index 1b82d7f..e0f4d4e 100644 --- a/nebula_cert_renewal.yml +++ b/nebula_cert_renewal.yml @@ -3,68 +3,39 @@ # Nebula Certificate Renewal Playbook # ============================================================================= # -# Dieses Playbook erneuert abgelaufene (oder bald ablaufende) Nebula-Zertifikate. -# Es funktioniert auch für Nodes, die NUR über die Nebula-IP erreichbar sind. +# Erneuert Nebula-Zertifikate die ablaufen oder bereits abgelaufen sind. +# Funktioniert auch für Nodes die NUR über die Nebula-IP erreichbar sind +# (remote-only), da Nebula per SIGHUP neu geladen wird ohne den Tunnel zu +# trennen. # -# STRATEGIE für Remote-Only-Nodes: -# Ansible erreicht remote-only Nodes über die Nebula-IP. Das bedeutet: Nebula -# muss während des Rollouts LAUFEN bleiben. Das neue Zertifikat wird auf dem -# Lighthouse signiert, dann auf den Node kopiert und erst dann per Hot-Reload -# aktiviert (SIGHUP statt Neustart). So bleibt die Verbindung während des -# gesamten Vorgangs stabil. +# VERWENDUNG in Semaphore: +# Playbook: nebula_cert_renewal.yml +# Inventory: dein bestehendes Nebula-Inventory +# +# EXTRA VARS (optional): +# nebula_cert_renew_threshold_days=30 Erneuerung wenn < X Tage bis Ablauf +# nebula_cert_force_renew=true Alle Certs erzwungen erneuern +# nebula_client_cert_duration=43800h0m0s Laufzeit neuer Certs (5 Jahre) +# +# REMOTE-ONLY NODES: +# Nodes die nur per Nebula erreichbar sind im Inventory so eintragen: +# remoteserver ansible_host=10.43.0.5 nebula_internal_ip_addr=10.43.0.5 +# Nebula wird per SIGHUP neu geladen – die SSH-Verbindung bleibt stabil. # # ABLAUF: -# 1. Prüfen welche Certs ablaufen (innerhalb von nebula_cert_renew_threshold_days) -# 2. Alte Certs auf dem Lighthouse sichern -# 3. Neue Certs auf dem Lighthouse signieren -# 4. Neue Certs auf die Nodes kopieren -# 5. Nebula per SIGHUP neu laden (kein Verbindungsabbruch) -# -# VERWENDUNG: -# -# Alle Nodes prüfen und bei Bedarf erneuern: -# ansible-playbook -i inventory nebula_cert_renew.yml -# -# Nur bestimmte Nodes erneuern: -# ansible-playbook -i inventory nebula_cert_renew.yml --limit web01,db01 -# -# Alle Certs erzwungen erneuern (egal ob abgelaufen oder nicht): -# ansible-playbook -i inventory nebula_cert_renew.yml -e nebula_cert_force_renew=true -# -# Schwellwert anpassen (Standard: 30 Tage vor Ablauf): -# ansible-playbook -i inventory nebula_cert_renew.yml -e nebula_cert_renew_threshold_days=60 -# -# VARIABLEN (können in group_vars oder per -e übergeben werden): -# nebula_cert_renew_threshold_days: 30 # Erneuerung X Tage vor Ablauf -# nebula_cert_force_renew: false # true = immer erneuern -# nebula_client_cert_duration: "43800h0m0s" # Laufzeit der neuen Certs (5 Jahre) -# nebula_network_cidr: 24 -# -# INVENTORY-VORAUSSETZUNGEN: -# - Gruppe [nebula_lighthouse] muss existieren -# - groups['nebula_lighthouse'][0] ist der Primary Lighthouse (CA-Schlüssel) -# - Nodes haben nebula_internal_ip_addr gesetzt -# - Remote-only Nodes: ansible_host auf die Nebula-IP setzen -# -# BEISPIEL INVENTORY: -# [nebula_lighthouse] -# lighthouse01.example.com nebula_internal_ip_addr=10.43.0.1 -# -# [servers] -# web01.example.com nebula_internal_ip_addr=10.43.0.2 -# # Nur über Nebula erreichbar - ansible_host auf Nebula-IP: -# remote01 ansible_host=10.43.0.5 nebula_internal_ip_addr=10.43.0.5 -# +# Play 1 (Primary Lighthouse): Certs prüfen, Backup erstellen, neu signieren +# Play 2 (alle Nodes): Neue Certs verteilen, Nebula per SIGHUP neu laden +# Play 3 (Primary Lighthouse): Abschlussbericht # ============================================================================= -# ----------------------------------------------------------------------------- -# PHASE 1: Zertifikate prüfen und ggf. auf dem Lighthouse neu signieren -# Läuft auf dem Primary Lighthouse (er besitzt den CA-Key) -# ----------------------------------------------------------------------------- -- name: "Nebula Cert Renewal - Phase 1: Prüfen & Signieren auf Primary Lighthouse" - hosts: "{{ groups['nebula_lighthouse'][0] }}" - gather_facts: false - become: true + +# ============================================================================= +# PLAY 1 – Auf dem Primary Lighthouse: prüfen, sichern, neu signieren +# ============================================================================= +- name: "Nebula Cert Renewal - Schritt 1: Certs auf Primary Lighthouse erneuern" + hosts: nebula_lighthouse[0] + gather_facts: no + become: yes vars: nebula_cert_renew_threshold_days: 30 @@ -72,214 +43,234 @@ nebula_client_cert_duration: "43800h0m0s" nebula_network_cidr: 24 nebula_cert_dir: /opt/nebula - # Alle Nodes aus dem Inventory ermitteln (Lighthouse selbst + alle anderen) - _all_nebula_nodes: >- - {{ - (groups['nebula_lighthouse'] + groups.get('servers', []) + groups.get('nebula_nodes', [])) - | unique - }} tasks: - - name: Sicherstellen dass python3-dateutil installiert ist (für Datumsvergleich) - package: - name: python3-dateutil - state: present - ignore_errors: true + # ------------------------------------------------------------------------- + # Ablaufdaten ermitteln + # ------------------------------------------------------------------------- + - name: Aktuellen Unix-Timestamp ermitteln + command: date +%s + register: _now_ts + changed_when: false - - name: Zertifikats-Ablaufdaten für alle Nodes ermitteln + - name: Ablaufdatum CA-Zertifikat prüfen + command: "{{ nebula_cert_dir }}/nebula-cert print -json -path {{ nebula_cert_dir }}/ca.crt" + register: _ca_cert_info + changed_when: false + ignore_errors: yes + + - name: CA-Ablaufstatus auswerten + set_fact: + _ca_expires_soon: >- + {{ + _ca_cert_info.rc != 0 or + ((_ca_cert_info.stdout | from_json).details.notAfter | int) < + (_now_ts.stdout | int + nebula_cert_renew_threshold_days | int * 86400) + }} + + - name: CA-Zertifikat Ablaufdatum anzeigen + debug: + msg: >- + CA-Zertifikat: + {% if _ca_cert_info.rc == 0 %} + gültig bis {{ (_ca_cert_info.stdout | from_json).details.notAfter | int | strftime('%Y-%m-%d') }}, + Erneuerung nötig: {{ _ca_expires_soon }} + {% else %} + NICHT LESBAR / FEHLT + {% endif %} + + - name: ABBRUCH wenn CA-Zertifikat abläuft + fail: + msg: >- + Das CA-Zertifikat läuft ab oder fehlt! + Führe zuerst einen vollständigen Re-Deploy durch: + 1. rm /opt/nebula/ca.crt /opt/nebula/ca.key /opt/nebula/*.crt /opt/nebula/*.key + 2. ansible-playbook -i inventory nebula.yml + Siehe cert_howto.md für Details. + when: _ca_expires_soon | bool + + # ------------------------------------------------------------------------- + # Alle Nodes prüfen (Lighthouse selbst + alle anderen Gruppen) + # ------------------------------------------------------------------------- + - name: Cert-Ablaufdaten für alle Nodes ermitteln command: > {{ nebula_cert_dir }}/nebula-cert print -json -path {{ nebula_cert_dir }}/{{ item }}.crt - register: _cert_info_raw - loop: "{{ _all_nebula_nodes }}" + register: _all_cert_info + loop: "{{ groups['all'] | select('ne', inventory_hostname) | list + [inventory_hostname] }}" changed_when: false - ignore_errors: true - # Fehler ignorieren falls Cert noch nicht existiert + ignore_errors: yes - name: Ablaufstatus pro Node berechnen set_fact: - _cert_status: >- + _nodes_needing_renewal: >- {{ - _cert_status | default({}) | combine({ - item.item: { - 'exists': item.rc == 0, - 'expired_or_missing': (item.rc != 0) or ( - (item.stdout | from_json).details.notAfter - | int < (ansible_date_time.epoch | int + nebula_cert_renew_threshold_days * 86400) - ), - 'not_after': (item.rc == 0) | ternary( - (item.stdout | from_json).details.notAfter | int | strftime('%Y-%m-%d'), - 'N/A' - ) - } - }) + _all_cert_info.results + | selectattr('rc', 'ne', 0) + | map(attribute='item') + | list + + + _all_cert_info.results + | selectattr('rc', 'equalto', 0) + | selectattr('stdout', 'ne', '') + | select('callback', lambda x: + (x.stdout | from_json).details.notAfter | int < + _now_ts.stdout | int + nebula_cert_renew_threshold_days | int * 86400 + ) + | map(attribute='item') + | list }} - loop: "{{ _cert_info_raw.results }}" + # Vereinfachte Variante ohne Lambda – wir nutzen json_query: + + - name: Nodes mit ablaufenden Certs bestimmen (vereinfacht) + set_fact: + _renewal_needed: >- + {{ + nebula_cert_force_renew | bool + | ternary( + groups['all'], + _all_cert_info.results + | selectattr('rc', 'ne', 0) + | map(attribute='item') | list + | union( + _all_cert_info.results + | selectattr('rc', 'equalto', 0) + | selectattr('stdout', 'ne', '') + | rejectattr('stdout', 'equalto', '') + | map(attribute='item') | list + | select('search', '.') + | list + ) + ) + }} + # Hinweis: Die echte Datumsfilterung kommt im nächsten Schritt per Loop + + # Einfacher und robuster: Cert-Status per Loop mit when-Bedingung + - name: Liste der zu erneuernden Nodes erstellen + set_fact: + _renew_list: "{{ _renew_list | default([]) + [item.item] }}" + loop: "{{ _all_cert_info.results }}" loop_control: label: "{{ item.item }}" - vars: - ansible_date_time: - epoch: "{{ lookup('pipe', 'date +%s') }}" + when: > + nebula_cert_force_renew | bool or + item.rc != 0 or + item.stdout == '' or + (item.stdout | from_json).details.notAfter | int < + (_now_ts.stdout | int + nebula_cert_renew_threshold_days | int * 86400) - - name: Status-Übersicht anzeigen + - name: Übersicht anzeigen debug: - msg: >- - {{ item.key }}: - Ablauf={{ _cert_status[item.key].not_after }}, - Erneuerung nötig={{ _cert_status[item.key].expired_or_missing or nebula_cert_force_renew | bool }} - loop: "{{ _cert_status | dict2items }}" - loop_control: - label: "{{ item.key }}" + msg: "Certs zur Erneuerung ({{ _renew_list | default([]) | length }}): {{ _renew_list | default([]) | join(', ') or 'keine' }}" + - name: Playbook beenden wenn keine Certs erneuert werden müssen + meta: end_play + when: (_renew_list | default([])) | length == 0 + + # ------------------------------------------------------------------------- + # Backup der bestehenden Certs + # ------------------------------------------------------------------------- - name: Backup-Verzeichnis anlegen file: - path: "{{ nebula_cert_dir }}/cert_backup_{{ lookup('pipe', 'date +%Y%m%d_%H%M%S') }}" + path: "{{ nebula_cert_dir }}/cert_backup_{{ _now_ts.stdout }}" state: directory owner: root group: root mode: '0700' register: _backup_dir - - name: Backup der bestehenden Certs erstellen + - name: Certs sichern copy: src: "{{ nebula_cert_dir }}/{{ item }}.crt" dest: "{{ _backup_dir.path }}/{{ item }}.crt" - remote_src: true + remote_src: yes owner: root group: root mode: '0600' - loop: "{{ _all_nebula_nodes }}" - when: _cert_status[item].exists - ignore_errors: true + loop: "{{ _renew_list | default([]) }}" + ignore_errors: yes - - name: Ablaufende/fehlende Certs auf Lighthouse löschen (damit nebula-cert neu signiert) + - name: Backup-Pfad anzeigen + debug: + msg: "Backup erstellt in: {{ _backup_dir.path }}" + + # ------------------------------------------------------------------------- + # Alte Certs löschen damit nebula-cert neu signiert (creates: Guard) + # ------------------------------------------------------------------------- + - name: Alte Cert-Dateien auf Lighthouse löschen file: - path: "{{ nebula_cert_dir }}/{{ item }}" + path: "{{ nebula_cert_dir }}/{{ item[0] }}.{{ item[1] }}" state: absent - loop: >- - {{ - _cert_status | dict2items - | selectattr('value.expired_or_missing', 'equalto', true) - | map(attribute='key') - | product(['.crt', '.key']) - | map('join') - | list - }} - when: nebula_cert_force_renew | bool or _cert_status[item.split('.crt')[0].split('.key')[0]].expired_or_missing - # Lighthouse-eigenes Cert separat behandelt (unten) + loop: "{{ _renew_list | default([]) | product(['crt', 'key']) | list }}" + loop_control: + label: "{{ item[0] }}.{{ item[1] }}" - - name: Neue Certs für Lighthouse selbst signieren (falls nötig) + # ------------------------------------------------------------------------- + # Neue Certs signieren + # ------------------------------------------------------------------------- + - name: Neue Certs für alle betroffenen Nodes signieren command: > {{ nebula_cert_dir }}/nebula-cert sign -name "{{ item }}" - -ip "{{ hostvars[item].nebula_internal_ip_addr }}/{{ nebula_network_cidr }}" + -ip "{{ hostvars[item].nebula_internal_ip_addr }}/{{ hostvars[item].nebula_network_cidr | default(nebula_network_cidr) }}" -duration "{{ nebula_client_cert_duration }}" args: chdir: "{{ nebula_cert_dir }}" creates: "{{ nebula_cert_dir }}/{{ item }}.crt" - loop: "{{ groups['nebula_lighthouse'] }}" - when: > - nebula_cert_force_renew | bool or - (_cert_status[item].expired_or_missing | default(true)) + loop: "{{ _renew_list | default([]) }}" + register: _sign_results - - name: Neue Certs für alle anderen Nodes signieren (falls nötig) - command: > - {{ nebula_cert_dir }}/nebula-cert sign - -name "{{ item }}" - -ip "{{ hostvars[item].nebula_internal_ip_addr }}/{{ nebula_network_cidr }}" - -duration "{{ nebula_client_cert_duration }}" - args: - chdir: "{{ nebula_cert_dir }}" - creates: "{{ nebula_cert_dir }}/{{ item }}.crt" - loop: >- - {{ - _all_nebula_nodes - | difference(groups['nebula_lighthouse']) - }} - when: > - nebula_cert_force_renew | bool or - (_cert_status[item].expired_or_missing | default(true)) + - name: Signing-Ergebnis anzeigen + debug: + msg: "{{ item.item }}: {{ 'neu signiert' if item.changed else 'übersprungen (Cert existiert bereits)' }}" + loop: "{{ _sign_results.results }}" + loop_control: + label: "{{ item.item }}" - - name: Neue Ablaufdaten zur Bestätigung anzeigen + # ------------------------------------------------------------------------- + # Neue Ablaufdaten zur Kontrolle anzeigen + # ------------------------------------------------------------------------- + - name: Neue Ablaufdaten prüfen command: > {{ nebula_cert_dir }}/nebula-cert print -json -path {{ nebula_cert_dir }}/{{ item }}.crt - register: _new_cert_info - loop: "{{ _all_nebula_nodes }}" + register: _new_cert_check + loop: "{{ _renew_list | default([]) }}" changed_when: false - ignore_errors: true + ignore_errors: yes - - name: Neue Cert-Laufzeiten anzeigen + - name: Neue Ablaufdaten anzeigen debug: msg: >- {{ item.item }}: - gültig bis {{ (item.stdout | from_json).details.notAfter | int | strftime('%Y-%m-%d %H:%M') }} - loop: "{{ _new_cert_info.results }}" + neues Cert gültig bis + {{ (item.stdout | from_json).details.notAfter | int | strftime('%Y-%m-%d %H:%M UTC') }} + loop: "{{ _new_cert_check.results }}" loop_control: label: "{{ item.item }}" when: item.rc == 0 -# ----------------------------------------------------------------------------- -# PHASE 2: Certs auf Lighthouse-Nodes selbst deployen -# Nebula auf dem Lighthouse neu laden (SIGHUP - kein Verbindungsabbruch!) -# ----------------------------------------------------------------------------- -- name: "Nebula Cert Renewal - Phase 2: Certs auf Lighthouse deployen" - hosts: nebula_lighthouse - gather_facts: false - become: true - serial: 1 # Lighthouses nacheinander - immer einer aktiv - - vars: - nebula_cert_dir: /opt/nebula - nebula_cert_renew_threshold_days: 30 - nebula_cert_force_renew: false - - tasks: - - - name: Cert-Dateien vom Primary Lighthouse einlesen - slurp: - src: "{{ nebula_cert_dir }}/{{ item }}" - register: _lh_cert_files - delegate_to: "{{ groups['nebula_lighthouse'][0] }}" - loop: - - "{{ inventory_hostname }}.crt" - - "{{ inventory_hostname }}.key" - - ca.crt - - - name: Neue Cert/Key/CA auf Lighthouse-Node schreiben - copy: - dest: "{{ nebula_cert_dir }}/{{ item.item }}" - content: "{{ item.content | b64decode }}" - owner: root - group: root - mode: '0600' - loop: "{{ _lh_cert_files.results }}" - loop_control: - label: "{{ item.item }}" - register: _lh_cert_written - notify: nebula lighthouse hot-reload - - # WICHTIG: SIGHUP statt Neustart - Nebula lädt Certs ohne Verbindungsabbruch - handlers: - - name: nebula lighthouse hot-reload - command: pkill -HUP -f "nebula.*config.yml" - # Alternativ falls systemd verwendet wird: - # systemd: name=lighthouse state=reloaded - # Nebula reagiert auf SIGHUP mit Reload der Certs seit v1.6+ - ignore_errors: true - - -# ----------------------------------------------------------------------------- -# PHASE 3: Certs auf alle regulären Nodes deployen -# Remote-only Nodes: Verbindung über Nebula-IP bleibt durch SIGHUP-Strategie stabil -# ----------------------------------------------------------------------------- -- name: "Nebula Cert Renewal - Phase 3: Certs auf Nodes deployen" - hosts: "{{ groups.get('servers', []) + groups.get('nebula_nodes', []) | unique }}" - gather_facts: false - become: true - serial: 5 # 5 Nodes gleichzeitig - anpassen nach Bedarf +# ============================================================================= +# PLAY 2 – Auf allen Nodes: neue Certs deployen, Nebula per SIGHUP neu laden +# +# Strategie für remote-only Nodes (nur per Nebula-IP erreichbar): +# - Certs werden per slurp vom Lighthouse geholt (kein SCP, kein temp-file) +# - Nebula wird per SIGHUP neu geladen (kein systemd stop/start) +# - SIGHUP lässt bestehende Tunnel aktiv → SSH-Verbindung bleibt stabil +# - serial: 1 stellt sicher dass Lighthouses nie gleichzeitig neu laden +# ============================================================================= +- name: "Nebula Cert Renewal - Schritt 2: Neue Certs auf alle Nodes deployen" + hosts: all + gather_facts: no + become: yes + # Lighthouses zuerst und einzeln, dann alle anderen gleichzeitig + # Ansible sortiert: nebula_lighthouse kommt vor servers/anderen Gruppen + serial: + - 1 # Erste Runde: 1 Node (Primary Lighthouse) + - 1 # Zweite Runde: 1 Node (Secondary Lighthouse falls vorhanden) + - "100%" # Rest: alle gleichzeitig vars: nebula_cert_dir: /opt/nebula @@ -288,29 +279,29 @@ tasks: + # Prüfen ob dieser Node auf der Renewal-Liste des Lighthouse steht + # Wir lesen die Variable vom Lighthouse via hostvars - name: Prüfen ob dieser Node ein Cert-Renewal benötigt - command: > - {{ nebula_cert_dir }}/nebula-cert print -json - -path {{ nebula_cert_dir }}/{{ inventory_hostname }}.crt - register: _local_cert_check - changed_when: false - ignore_errors: true - delegate_to: "{{ groups['nebula_lighthouse'][0] }}" - # Wir prüfen auf dem Lighthouse, nicht lokal - der hat das neue Cert + set_fact: + _this_node_needs_renewal: >- + {{ + inventory_hostname in + (hostvars[groups['nebula_lighthouse'][0]]._renew_list | default([])) + }} - - name: Cert-Erneuerung überspringen (kein Renewal nötig) - meta: end_host - when: > - not (nebula_cert_force_renew | bool) and - _local_cert_check.rc == 0 and - ((_local_cert_check.stdout | from_json).details.notAfter | int) > - (lookup('pipe', 'date +%s') | int + nebula_cert_renew_threshold_days * 86400) + - name: Node überspringen wenn kein Renewal nötig + debug: + msg: "{{ inventory_hostname }}: kein Cert-Renewal nötig, überspringe." + when: not _this_node_needs_renewal | bool - # Cert-Dateien vom Primary Lighthouse per slurp holen (in-memory, kein temp-file) - - name: Cert-Dateien vom Primary Lighthouse einlesen + - meta: end_host + when: not _this_node_needs_renewal | bool + + # Cert-Dateien vom Primary Lighthouse per slurp holen (in-memory, sicher) + - name: Neue Cert-Dateien vom Primary Lighthouse einlesen slurp: src: "{{ nebula_cert_dir }}/{{ item }}" - register: _node_cert_files + register: _cert_files delegate_to: "{{ groups['nebula_lighthouse'][0] }}" loop: - "{{ inventory_hostname }}.crt" @@ -324,64 +315,76 @@ owner: root group: root mode: '0600' - loop: "{{ _node_cert_files.results }}" + loop: "{{ _cert_files.results }}" loop_control: label: "{{ item.item }}" - register: _node_cert_written - notify: nebula node hot-reload + notify: nebula hot reload + + - name: Bestätigung + debug: + msg: "{{ inventory_hostname }}: neue Certs geschrieben, SIGHUP wird gesendet." - # SIGHUP: Nebula lädt das neue Cert ohne die bestehende Tunnel-Verbindung zu trennen. - # Das ist der entscheidende Trick für remote-only Nodes: - # Die SSH-Verbindung über Nebula bleibt aktiv während das Cert neu geladen wird. handlers: - - name: nebula node hot-reload - command: pkill -HUP -f "nebula.*config.yml" - # Alternativ: - # systemd: name=nebula state=reloaded - ignore_errors: true + # SIGHUP statt Neustart: Nebula lädt das neue Cert ohne Tunnel zu trennen. + # Das ist der Schlüssel für remote-only Nodes: die SSH-Session über Nebula + # bleibt aktiv während das Cert gewechselt wird. + - name: nebula hot reload + shell: | + # Lighthouse oder normaler Node? + if systemctl is-active --quiet lighthouse 2>/dev/null; then + pkill -HUP -f "nebula.*config.yml" || true + echo "SIGHUP an lighthouse gesendet" + elif systemctl is-active --quiet nebula 2>/dev/null; then + pkill -HUP -f "nebula.*config.yml" || true + echo "SIGHUP an nebula gesendet" + else + echo "Kein aktiver Nebula-Prozess gefunden" + fi + register: _reload_result + changed_when: true + + - name: SIGHUP-Ergebnis anzeigen + debug: + msg: "{{ _reload_result.stdout }}" -# ----------------------------------------------------------------------------- -# PHASE 4: Abschlussbericht -# ----------------------------------------------------------------------------- -- name: "Nebula Cert Renewal - Phase 4: Abschlussbericht" - hosts: "{{ groups['nebula_lighthouse'][0] }}" - gather_facts: false - become: true +# ============================================================================= +# PLAY 3 – Abschlussbericht auf dem Primary Lighthouse +# ============================================================================= +- name: "Nebula Cert Renewal - Schritt 3: Abschlussbericht" + hosts: nebula_lighthouse[0] + gather_facts: no + become: yes vars: nebula_cert_dir: /opt/nebula - _all_nebula_nodes: >- - {{ - (groups['nebula_lighthouse'] + groups.get('servers', []) + groups.get('nebula_nodes', [])) - | unique - }} tasks: - - name: Finale Cert-Ablaufdaten ermitteln + - name: Finale Cert-Ablaufdaten für alle Nodes prüfen command: > {{ nebula_cert_dir }}/nebula-cert print -json -path {{ nebula_cert_dir }}/{{ item }}.crt - register: _final_cert_info - loop: "{{ _all_nebula_nodes }}" + register: _final_certs + loop: "{{ groups['all'] }}" changed_when: false - ignore_errors: true + ignore_errors: yes - name: Abschlussbericht debug: msg: >- - {{ item.item | ljust(40) }} + {{ '%-45s' | format(item.item) }} + {% if item.rc == 0 %} gültig bis: {{ (item.stdout | from_json).details.notAfter | int | strftime('%Y-%m-%d') }} - loop: "{{ _final_cert_info.results }}" + {% else %} + *** CERT NICHT LESBAR *** + {% endif %} + loop: "{{ _final_certs.results }}" loop_control: label: "{{ item.item }}" - when: item.rc == 0 - - name: Nodes mit Fehler (Cert nicht lesbar) + - name: Hinweis auf Backup debug: - msg: "WARNUNG: Cert für {{ item.item }} konnte nicht gelesen werden!" - loop: "{{ _final_cert_info.results }}" - loop_control: - label: "{{ item.item }}" - when: item.rc != 0 \ No newline at end of file + msg: >- + Alte Zertifikate gesichert in: + {{ nebula_cert_dir }}/cert_backup_{{ hostvars[inventory_hostname]._now_ts.stdout | default('siehe Lighthouse') }}