This commit is contained in:
2026-07-12 08:44:40 +02:00
commit 55991dcb4e
21 changed files with 610 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
---
# Playbook do bezobsługowego uruchamiania z crona (patrz cron/run-autopilot.sh).
# Kolejność: aktualizacja pakietów -> sprzątanie/kondycja -> raport floty.
#
# Świadomie NIE zawiera:
# - playbook_security_baseline.yml (zmiany w sshd/unattended-upgrades — uruchamiać ręcznie)
# - restartu hostów (reboot jest tylko raportowany w fleet_report, decyzję
# o restarcie podejmuje operator ręcznie)
#
# Użycie: ansible-playbook -i patchmon_inventory.yml playbooks/playbook_autopilot.yml --limit "Update-now,localhost"
#
# WAŻNE: ",localhost" w --limit jest wymagane — playbook_fleet_report.yml ma
# drugą fazę na hosts: localhost (renderowanie raportu), a --limit bez "localhost"
# w wzorcu powoduje jej pominięcie ("skipping: no hosts matched").
- name: Aktualizacja pakietów
import_playbook: playbook_upgrade.yml
- name: Sprzątanie i kondycja systemu
import_playbook: playbook_cleanup.yml
- name: Raport stanu floty
import_playbook: playbook_fleet_report.yml

View File

@@ -0,0 +1,46 @@
---
# Rutynowe sprzątanie/kondycja systemu: apt autoremove/clean, czyszczenie journala,
# sprawdzenie zajętości dysku z progiem ostrzegawczym (domyślnie 85%, group_vars/all.yml).
- name: Sprzątanie i kondycja systemu
hosts: all
gather_facts: true
tasks:
- name: Usuń nieużywane pakiety (apt autoremove)
ansible.builtin.apt:
autoremove: yes
purge: yes
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Wyczyść lokalny cache pobranych pakietów (apt clean)
ansible.builtin.apt:
autoclean: yes
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Wyczyść dziennik systemowy starszy niż 7 dni (journalctl --vacuum-time)
ansible.builtin.command: journalctl --vacuum-time=7d
register: journal_vacuum
changed_when: "'Vacuuming done' in journal_vacuum.stdout and 'freed' in journal_vacuum.stdout"
when: ansible_service_mgr == "systemd"
- name: Odśwież fakty o zajętości dysku (po sprzątaniu)
ansible.builtin.setup:
filter: ansible_mounts
gather_timeout: 30
- name: Sprawdź zajętość dysku na partycji root
ansible.builtin.set_fact:
root_disk_percent_used: >-
{{ (( (mount.size_total - mount.size_available) / mount.size_total * 100) | round(0, 'ceil')) | int }}
vars:
mount: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | first }}"
when: ansible_mounts | selectattr('mount', 'equalto', '/') | list | length > 0
- name: OSTRZEŻENIE — zajętość dysku powyżej progu
ansible.builtin.debug:
msg: >-
WARN [{{ inventory_hostname }}]: dysk / zajęty w {{ root_disk_percent_used }}%
(próg: {{ disk_usage_warn_percent }}%)
when:
- root_disk_percent_used is defined
- root_disk_percent_used | int >= disk_usage_warn_percent | int

View File

@@ -0,0 +1,56 @@
---
# Czyszczenie nieużywanych obrazów Docker — tylko na hostach, na których Docker
# jest faktycznie zainstalowany (pozostałe hosty są bezpiecznie pomijane).
#
# Domyślnie usuwa wyłącznie obrazy "dangling" (bez tagu) — bezpieczne, nie rusza
# tagowanych obrazów, nawet jeśli akurat nie są używane przez żaden kontener.
#
# Aby usunąć WSZYSTKIE nieużywane obrazy (także tagowane, nieużywane przez żaden
# kontener) — więcej odzyskanego miejsca, ale bardziej agresywne — uruchom z:
# -e "docker_prune_all_images=true"
- name: Czyszczenie nieużywanych obrazów Docker
hosts: all
gather_facts: false
vars:
docker_prune_all_images: false
tasks:
- name: Sprawdź, czy docker jest zainstalowany
ansible.builtin.command: which docker
register: docker_check
changed_when: false
failed_when: false
- name: Pomiń — Docker nie jest zainstalowany na tym hoście
ansible.builtin.debug:
msg: "Docker nie jest zainstalowany na {{ inventory_hostname }} — pomijam."
when: docker_check.rc != 0
- name: Zajętość miejsca przez Dockera przed czyszczeniem
ansible.builtin.command: docker system df
register: docker_df_before
changed_when: false
when: docker_check.rc == 0
- name: Usuń nieużywane obrazy Docker (dangling)
ansible.builtin.command: docker image prune -f
register: prune_result
changed_when: "'Total reclaimed space: 0B' not in prune_result.stdout"
when:
- docker_check.rc == 0
- not docker_prune_all_images
- name: Usuń WSZYSTKIE nieużywane obrazy Docker (także tagowane)
ansible.builtin.command: docker image prune -a -f
register: prune_result_all
changed_when: "'Total reclaimed space: 0B' not in prune_result_all.stdout"
when:
- docker_check.rc == 0
- docker_prune_all_images
- name: Wynik czyszczenia obrazów
ansible.builtin.debug:
msg: >-
{{ (prune_result_all if docker_prune_all_images else prune_result).stdout_lines
| default(['brak danych']) }}
when: docker_check.rc == 0

View File

@@ -0,0 +1,66 @@
---
# Raport stanu floty (tylko odczyt, bez żadnych zmian na hostach):
# OS/wersja, uptime, zajętość dysku, liczba oczekujących aktualizacji
# oraz flaga reboot-required (decyzję o restarcie podejmuje operator ręcznie).
#
# WAŻNE: druga faza (renderowanie raportu) działa na hosts: localhost — jeśli
# używasz --limit, dopisz do niego ",localhost", inaczej ta faza zostanie pominięta,
# np.: --limit "Update-now,localhost"
- name: Zbierz stan floty
hosts: all
gather_facts: true
tasks:
- name: Sprawdź czy wymagany jest restart (reboot-required)
ansible.builtin.stat:
path: /var/run/reboot-required
register: reboot_required_stat
- name: Policz pakiety oczekujące na aktualizację
ansible.builtin.command: apt list --upgradable
register: upgradable_raw
changed_when: false
failed_when: false
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Sprawdź zajętość dysku na partycji root
ansible.builtin.set_fact:
root_disk_percent_used: >-
{{ (( (mount.size_total - mount.size_available) / mount.size_total * 100) | round(0, 'ceil')) | int }}
vars:
mount: "{{ ansible_mounts | selectattr('mount', 'equalto', '/') | first }}"
when: ansible_mounts | selectattr('mount', 'equalto', '/') | list | length > 0
- name: Zbuduj podsumowanie hosta
ansible.builtin.set_fact:
host_report:
os: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
uptime_days: "{{ (ansible_uptime_seconds / 86400) | round(1) }}"
disk_root_percent: "{{ root_disk_percent_used | default('n/a') }}"
upgradable_packages: >-
{{ (upgradable_raw.stdout_lines | default([]) | length - 1)
if (upgradable_raw is defined and upgradable_raw.stdout_lines is defined and upgradable_raw.stdout_lines | length > 0)
else 0 }}
reboot_required: "{{ reboot_required_stat.stat.exists }}"
- name: Wygeneruj raport floty
hosts: localhost
connection: local
gather_facts: true
tasks:
- name: Upewnij się, że katalog reports/ istnieje
ansible.builtin.file:
path: "{{ playbook_dir }}/../reports"
state: directory
mode: "0755"
- name: Renderuj raport floty
ansible.builtin.template:
src: "{{ playbook_dir }}/../templates/fleet_report.j2"
dest: "{{ playbook_dir }}/../reports/fleet_report_{{ ansible_date_time.iso8601_basic_short }}.txt"
mode: "0644"
- name: Ścieżka wygenerowanego raportu
ansible.builtin.debug:
msg: "Raport zapisany w reports/fleet_report_{{ ansible_date_time.iso8601_basic_short }}.txt"

View File

@@ -0,0 +1,64 @@
---
# Baza bezpieczeństwa: unattended-upgrades (tylko aktualizacje bezpieczeństwa,
# bez automatycznego restartu — patrz playbook_fleet_report.yml dla flagi reboot-required)
# oraz wyłączenie logowania hasłem po SSH.
- name: Baza bezpieczeństwa (unattended-upgrades + wyłączenie logowania hasłem)
hosts: all
gather_facts: true
tasks:
- name: Zainstaluj unattended-upgrades (Debian/Ubuntu)
ansible.builtin.apt:
name:
- unattended-upgrades
- apt-listchanges
state: present
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Skonfiguruj unattended-upgrades (tylko aktualizacje bezpieczeństwa, bez auto-reboot)
ansible.builtin.template:
src: ../templates/50unattended-upgrades.j2
dest: /etc/apt/apt.conf.d/50unattended-upgrades
owner: root
group: root
mode: "0644"
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Włącz okresowe aktualizacje APT (20auto-upgrades)
ansible.builtin.copy:
dest: /etc/apt/apt.conf.d/20auto-upgrades
owner: root
group: root
mode: "0644"
content: |
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Wyłącz logowanie hasłem (PasswordAuthentication no)
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '(?i)^\s*#?\s*PasswordAuthentication'
line: 'PasswordAuthentication no'
state: present
backup: yes
validate: '/usr/sbin/sshd -t -f %s'
notify: Restart SSH
- name: Ogranicz logowanie root do klucza (PermitRootLogin prohibit-password)
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '(?i)^\s*#?\s*PermitRootLogin'
line: 'PermitRootLogin prohibit-password'
state: present
backup: yes
validate: '/usr/sbin/sshd -t -f %s'
notify: Restart SSH
handlers:
- name: Restart SSH
ansible.builtin.service:
name: ssh
state: restarted

View File

@@ -0,0 +1,23 @@
---
- name: Konfiguracja SSH (blokada pustych haseł)
hosts: all
gather_facts: true
tasks:
- name: Zablokuj logowanie na puste hasła (PermitEmptyPasswords no)
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
# Szuka linii zaczynającej się od PermitEmptyPasswords (również zakomentowanej)
regexp: '(?i)^\s*#?\s*PermitEmptyPasswords'
line: 'PermitEmptyPasswords no'
state: present
backup: yes
# Sprawdza poprawność pliku przed zapisem, aby nie zepsuć SSH
validate: '/usr/sbin/sshd -t -f %s'
notify: Restart SSH
handlers:
- name: Restart SSH
ansible.builtin.service:
name: ssh
state: restarted

View File

@@ -0,0 +1,32 @@
---
# Zarządzanie kluczami publicznymi SSH konta logowania (root lub mgmt, w zależności
# od grupy PatchMon hosta) na całej flocie jednym uruchomieniem.
#
# Lista kluczy: admin_ssh_keys w group_vars/all.yml (uzupełnij przed użyciem).
#
# Domyślnie tylko DODAJE brakujące klucze (bezpieczne). Aby wymusić, żeby
# authorized_keys zawierał WYŁĄCZNIE klucze z admin_ssh_keys (usuwając inne),
# uruchom z: -e "ssh_keys_exclusive=true" — rób to świadomie, może odciąć dostęp.
- name: Zarządzanie kluczami SSH konta logowania
hosts: all
gather_facts: false
vars:
ssh_keys_exclusive: false
tasks:
- name: Sprawdź, czy admin_ssh_keys nie jest puste
ansible.builtin.assert:
that:
- admin_ssh_keys | length > 0
fail_msg: >-
admin_ssh_keys jest puste — uzupełnij listę kluczy w group_vars/all.yml
przed uruchomieniem tego playbooka.
run_once: true
delegate_to: localhost
- name: Zapewnij obecność kluczy publicznych w authorized_keys
ansible.posix.authorized_key:
user: "{{ ansible_user }}"
key: "{{ admin_ssh_keys | join('\n') }}"
state: present
exclusive: "{{ ssh_keys_exclusive }}"

View File

@@ -0,0 +1,16 @@
---
- name: Aktualizacja pakietów (Debian/Ubuntu)
hosts: all
gather_facts: true
tasks:
- name: Aktualizacja cache pakietów (Debian/Ubuntu)
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
when: ansible_os_family in ["Debian", "Ubuntu"]
- name: Aktualizacja wszystkich pakietów (Debian/Ubuntu)
ansible.builtin.apt:
upgrade: dist
when: ansible_os_family in ["Debian", "Ubuntu"]