diff --git a/CHANGELOG.md b/CHANGELOG.md index 076157e..e823205 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,30 @@ # Changelog -## 2025-08-03 +## 2025-08-03 (v2.0) + +### Dodano + +- **Modularność Skryptu**: Wprowadzono obsługę komend (`install`, `deploy_traefik`, `deploy_monitoring`, `uninstall`), co pozwala na uruchamianie tylko wybranych części skryptu. +- **Idempotentność**: Skrypt sprawdza stan systemu (np. czy użytkownik istnieje) przed wykonaniem akcji, co pozwala na jego bezpieczne wielokrotne uruchamianie. +- **Weryfikacja Systemu**: Skrypt weryfikuje, czy jest uruchamiany na kompatybilnej dystrybucji (Debian/Ubuntu). +- **Ulepszone Logowanie**: Wszystkie operacje są logowane do pliku `/var/log/autoscript.log`. +- **Funkcja `uninstall`**: Dodano możliwość bezpiecznego odinstalowania wszystkich komponentów wdrożonych przez skrypt. +- **Szablony Konfiguracji**: Konfiguracje usług (Traefik, Prometheus) zostały przeniesione do zewnętrznych plików w folderze `templates/`. +- **Opcjonalne Moduły** (konfigurowalne w `autoscript.conf`): + - **Fail2ban**: Dodatkowa warstwa ochrony przed atakami brute-force. + - **PostgreSQL**: Możliwość wdrożenia bazy danych. + - **Loki**: Centralne zbieranie logów z kontenerów Docker. + - **Restic Backups**: Integracja z systemem kopii zapasowych (wymaga ręcznej konfiguracji po stronie dostawcy chmury). + +### Zmieniono + +- **Struktura Projektu**: Dodano folder `templates` na pliki konfiguracyjne. +- **Plik Konfiguracyjny**: `autoscript.conf.example` został rozbudowany o nowe opcje dla modułów opcjonalnych. +- **Dokumentacja**: `README.md` zostało całkowicie przepisane, aby odzwierciedlać nową, modularną strukturę i wszystkie nowe funkcje. + +--- + +## 2025-08-03 (v1.1) ### Dodano @@ -11,4 +35,4 @@ - **Refaktoryzacja Konfiguracji**: Całkowicie zmieniono sposób konfiguracji skryptu. Zamiast polegać na zmiennych środowiskowych, skrypt wczytuje teraz wszystkie ustawienia z dedykowanego pliku `autoscript.conf`. To upraszcza zarządzanie i zmniejsza ryzyko błędu. - **Skrypt `start.sh`**: Zaktualizowano logikę skryptu, aby wczytywał konfigurację z pliku `autoscript.conf` i sprawdzał jego obecność przed uruchomieniem. -- **Dokumentacja `README.md`**: gruntownie zaktualizowano dokumentację, aby odzwierciedlała nowy proces konfiguracji oparty na pliku. Instrukcje są teraz prostsze i bardziej przejrzyste. +- **Dokumentacja `README.md`**: gruntownie zaktualizowano dokumentację, aby odzwierciedlała nowy proces konfiguracji oparty na pliku. Instrukcje są teraz prostsze i bardziej przejrzyste. \ No newline at end of file diff --git a/README.md b/README.md index af3c465..e5b7d42 100644 --- a/README.md +++ b/README.md @@ -1,129 +1,81 @@ -# AutoScript - Zautomatyzowana Konfiguracja Serwera +# AutoScript v2 - Zautomatyzowana Konfiguracja i Zarządzanie Serwerem ## 1. Przegląd -Ten projekt zawiera kompleksowy skrypt `start.sh`, który automatyzuje proces konfiguracji i zabezpieczania nowego serwera opartego na systemie Debian (lub jego pochodnych, jak Ubuntu). Skrypt instaluje niezbędne oprogramowanie, wzmacnia zabezpieczenia systemu (hardening) i wdraża środowisko aplikacyjne oparte na kontenerach Docker. - -Jest to idealne rozwiązanie do szybkiego przygotowania serwera deweloperskiego lub produkcyjnego, z gotowym do użycia reverse proxy (Traefik) oraz pełnym stosem monitoringu (Prometheus, Grafana). +AutoScript to potężne narzędzie do automatyzacji pełnego cyklu życia serwera opartego o system Debian/Ubuntu. Skrypt przekształca "surowy" serwer w gotowe do pracy, zabezpieczone i monitorowane środowisko produkcyjne. Dzięki modularnej budowie, możesz używać go zarówno do wstępnej konfiguracji, jak i do późniejszego zarządzania poszczególnymi komponentami. ## 2. Główne Funkcje -- **Automatyzacja:** Uruchom jeden skrypt, aby w pełni przygotować serwer. -- **Zabezpieczenia (Hardening):** - - Konfiguracja firewalla `UFW`. - - Wzmocnienie zabezpieczeń SSH (zmiana portu, blokada logowania roota, autoryzacja kluczem). - - Tworzenie dedykowanego użytkownika `admin` z uprawnieniami `sudo` i weryfikacją dwuetapową (TOTP). - - Instalacja i konfiguracja `CrowdSec` (system zapobiegania włamaniom). - - Wdrożenie podstawowych zabezpieczeń jądra systemu. -- **Środowisko Docker:** - - Instalacja i konfiguracja Docker Engine z najlepszymi praktykami (m.in. `userns-remap`). - - Wdrożenie `Traefik` jako reverse proxy z automatycznym generowaniem certyfikatów SSL/TLS od Let's Encrypt (przy użyciu Cloudflare DNS). -- **Monitoring i Alerty:** - - Wdrożenie `Prometheus` do zbierania metryk. - - Wdrożenie `Grafana` do wizualizacji danych z gotową konfiguracją. - - Wdrożenie `Alertmanager` do wysyłania powiadomień o anomaliach (e-mailem). - - Wdrożenie eksporterów metryk (`node-exporter`, `cAdvisor`, `blackbox-exporter`). -- **Zarządzanie Sekretami:** - - Bezpieczne zarządzanie hasłami i kluczami API przy użyciu `sops` i `age`, bez przechowywania ich w formie jawnego tekstu. +- **Modularność**: Uruchamiaj tylko te części skryptu, których potrzebujesz (`install`, `deploy_monitoring`, `uninstall` itp.). +- **Automatyzacja i Idempotentność**: Skrypt można bezpiecznie uruchamiać wielokrotnie - zawsze doprowadzi system do pożądanego stanu. +- **Hardening (Wzmacnianie Zabezpieczeń)**: Kompleksowe zabezpieczenie serwera, w tym firewall, niestandardowy port SSH, blokada roota, uwierzytelnianie kluczem, `CrowdSec` i opcjonalnie `Fail2ban`. +- **Środowisko Docker**: Wdrożenie Dockera z Traefikiem jako reverse proxy i automatycznymi certyfikatami SSL. +- **Monitoring i Alerty**: Pełny stos monitoringu (Prometheus, Grafana, Alertmanager) z prekonfigurowanymi regułami. +- **Zarządzanie Sekretami**: Bezpieczne przechowywanie haseł i kluczy API dzięki `sops`. +- **Funkcje Opcjonalne**: Możliwość łatwego doinstalowania bazy danych PostgreSQL, systemu logów Loki czy kopii zapasowych Restic. +- **Czysta Deinstalacja**: Możliwość wycofania wszystkich zmian za pomocą jednej komendy. -## 3. Wymagania Wstępne - -Zanim uruchomisz skrypt, upewnij się, że posiadasz: - -1. **Nowy serwer** z systemem operacyjnym Debian lub Ubuntu. -2. **Dostęp do konta `root`** na tym serwerze. -3. **Domenę internetową** zarządzaną przez **Cloudflare**. -4. **Klucz API Cloudflare** z uprawnieniami do edycji strefy DNS (`DNS:Edit`). -5. **Publiczny klucz SSH** (np. zawartość pliku `~/.ssh/id_ed25519.pub`). - -## 4. Konfiguracja - -Konfiguracja skryptu odbywa się w całości poprzez plik `autoscript.conf`. - -1. **Utwórz plik konfiguracyjny:** - Skopiuj szablon `autoscript.conf.example` do nowego pliku o nazwie `autoscript.conf`. - ```bash - cp autoscript.conf.example autoscript.conf - ``` - -2. **Wypełnij plik `autoscript.conf`:** - Otwórz plik `autoscript.conf` w edytorze tekstu i uzupełnij wszystkie zmienne zgodnie z komentarzami. Szczególną uwagę zwróć na sekcje `WYMAGANE`. - - - `PUBLIC_KEY`: Twój publiczny klucz SSH. - - `CF_DNS_API_TOKEN`: Twój token API od Cloudflare. - - `PRIMARY_DOMAIN`: Twoja główna domena. - - `ADMIN_EMAIL`: Twój adres e-mail. - - ...i inne ustawienia, takie jak dane do serwera SMTP czy wersje oprogramowania. - -## 5. Użycie - -1. Sklonuj to repozytorium na swój serwer. -2. Przejdź do folderu projektu: `cd autoscript`. -3. Utwórz i wypełnij plik konfiguracyjny `autoscript.conf` (zgodnie z punktem 4). -4. Uruchom skrypt z uprawnieniami `root`. - ```bash - sudo ./start.sh - ``` -5. Skrypt automatycznie wczyta konfigurację z pliku i rozpocznie instalację. - -## 6. Co robić po zakończeniu skryptu? - -Po pomyślnym wykonaniu skryptu, twoje środowisko jest gotowe, ale musisz wiedzieć o kilku ważnych zmianach: - -1. **Nowy Port SSH:** Port SSH został zmieniony na losowy numer z zakresu 10000-65535. **Znajdziesz go w pliku `/root/ssh_port.txt`**. - ```bash - # Zaloguj się na serwerze jako root i wykonaj: - cat /root/ssh_port.txt - ``` -2. **Logowanie na serwer:** - - Logowanie na konto `root` jest **zablokowane**. - - Możesz zalogować się tylko jako użytkownik `admin` przy użyciu podanego klucza SSH i nowego portu. - ```bash - ssh admin@ -p - ``` -3. **Konfiguracja Weryfikacji Dwuetapowej (TOTP):** - - Przy pierwszej próbie użycia `sudo` przez użytkownika `admin` (np. `sudo ls /root`), zostaniesz poproszony o skonfigurowanie TOTP. - - W terminalu wyświetli się **kod QR**. Zeskanuj go aplikacją do uwierzytelniania (np. Google Authenticator, Authy). - - Zapisz wyświetlone kody zapasowe w bezpiecznym miejscu! -4. **Dostęp do Usług:** - Wdrożone usługi będą dostępne pod subdomenami Twojej `PRIMARY_DOMAIN`: - - **Prometheus:** `https://prometheus.twojadomena.pl` - - **Grafana:** `https://grafana.twojadomena.pl` - - **Alertmanager:** `https://alertmanager.twojadomena.pl` - - **Traefik Dashboard:** Domyślnie nie jest publicznie dostępny. Aby go udostępnić, musiałbyś dodać odpowiednią regułę routingu w plikach konfiguracyjnych Traefik. - -5. **Hasła i Sekrety:** - - Hasło administratora Grafany jest generowane automatycznie. - - Wszystkie sekrety są zaszyfrowane w folderze `/opt/services/` przy użyciu `sops`. Aby je odczytać lub edytować, musisz użyć `sops` bezpośrednio na serwerze, np.: - ```bash - # To polecenie odszyfruje i wyświetli plik w edytorze - sudo sops /opt/services/monitoring/secrets/monitoring.env.sops - ``` - -## 7. Szczegółowy Opis Działania Skryptu - -Skrypt `start.sh` składa się z szeregu funkcji, które są wywoływane po kolei. - -- `ensure_root`: Sprawdza, czy skrypt jest uruchamiany z uprawnieniami `root`. -- `install_node_and_gemini`: Instaluje Node.js oraz Gemini CLI. -- `install_base_tools`: Instaluje podstawowe pakiety systemowe, takie jak `ufw` (firewall), `jq` (przetwarzanie JSON), `sops` (zarządzanie sekretami), `age` (szyfrowanie), `aide` (monitorowanie integralności plików) oraz `CrowdSec` (ochrona przed atakami). -- `bootstrap_sops`: Inicjalizuje konfigurację `sops` z kluczem `age`, który będzie używany do szyfrowania wszystkich sekretów. -- `create_admin_user`: Tworzy nowego użytkownika `admin`, dodaje go do grupy `sudo`, konfiguruje logowanie za pomocą klucza SSH i wymusza użycie weryfikacji dwuetapowej (TOTP) przy użyciu `sudo`. -- `harden_ssh`: Zabezpiecza serwer SSH: generuje nowe klucze hosta, blokuje logowanie na konto `root` i za pomocą hasła, zmienia domyślny port na losowy i ogranicza dostęp tylko do autoryzowanych grup. -- `configure_firewall`: Konfiguruje zaporę sieciową `UFW`, otwierając tylko niezbędne porty (nowy port SSH, HTTP, HTTPS, poczta, etc.) i blokując resztę. Dodaje również reguły chroniące kontenery Docker. -- `system_baseline`: Wprowadza zmiany w konfiguracji jądra systemowego w celu poprawy bezpieczeństwa i wydajności. Konfiguruje trwałe logi `journald` oraz automatyczne aktualizacje (`unattended-upgrades`). -- `install_docker`: Instaluje silnik Docker oraz wtyczkę `docker-compose`. Konfiguruje go zgodnie z zaleceniami bezpieczeństwa, m.in. włączając izolację przestrzeni nazw użytkowników (`userns-remap`). -- `prepare_secrets`: Przygotowuje wszystkie potrzebne sekrety (token Cloudflare, hasło do Grafany, hasło do SMTP) i szyfruje je za pomocą `sops`, aby nie były przechowywane na dysku jako jawny tekst. -- `deploy_traefik`: Wdraża kontener z Traefikiem. Konfiguruje go do obsługi ruchu HTTP/HTTPS, automatycznego przekierowywania na HTTPS oraz zamawiania certyfikatów SSL od Let's Encrypt. -- `deploy_monitoring`: Wdraża pełny stos monitoringu, w tym: - - **Prometheus:** do zbierania danych. - - **Grafana:** do ich wizualizacji. - - **Alertmanager:** do wysyłania alertów. - - **Exportery:** `node-exporter` (metryki systemu), `cAdvisor` (metryki kontenerów), `blackbox-exporter` (monitorowanie dostępności stron). - -## 8. Plik `.gitattributes` +## 3. Struktura Projektu ``` -* text=auto +autoscript/ +├── templates/ # Szablony plików konfiguracyjnych +│ ├── monitoring/ +│ └── traefik/ +├── autoscript.conf.example # Przykład pliku konfiguracyjnego +├── CHANGELOG.md # Dziennik zmian +├── README.md # Ta dokumentacja +└── start.sh # Główny skrypt wykonawczy ``` -Ta linia w pliku `.gitattributes` jest ważna dla spójności projektu. Nakazuje ona systemowi Git automatyczne zarządzanie znakami końca linii w plikach tekstowych. Dzięki temu unikniesz problemów, jeśli będziesz pracować nad projektem na różnych systemach operacyjnych (np. Windows i Linux), które używają różnych standardów dla końca linii. \ No newline at end of file + +## 4. Użycie + +### Krok 1: Konfiguracja + +1. Sklonuj repozytorium na serwer: `git clone ...` +2. Przejdź do folderu: `cd autoscript` +3. Stwórz plik konfiguracyjny z szablonu: `cp autoscript.conf.example autoscript.conf` +4. Otwórz `autoscript.conf` i **dokładnie wypełnij wszystkie zmienne**, zwłaszcza te w sekcji `WYMAGANE`. + +### Krok 2: Uruchomienie Skryptu + +Skryptem zarządza się za pomocą komend. Wszystkie komendy należy wykonywać z uprawnieniami `root` (np. `sudo ./start.sh `). + +**Główne Komendy:** + +- `sudo ./start.sh install` + **Pełna, pierwsza instalacja.** Wykonuje wszystkie niezbędne kroki: instaluje pakiety, konfiguruje zabezpieczenia, wdraża Dockera, Traefika i stos monitoringu. Uruchom tę komendę na nowym serwerze. + +- `sudo ./start.sh uninstall` + **Pełna deinstalacja.** Zatrzymuje i usuwa wszystkie usługi, kontenery, wolumeny, a także odinstalowuje pakiety i wycofuje zmiany konfiguracyjne. **Używaj z ostrożnością!** + +**Komendy do Zarządzania Modułami:** + +Możesz zarządzać poszczególnymi częściami systemu niezależnie. + +- `sudo ./start.sh deploy_traefik` +- `sudo ./start.sh deploy_monitoring` +- `sudo ./start.sh deploy_database` (jeśli włączone w konfigu) + +**Komendy Pomocnicze:** + +- `sudo ./start.sh reboot` - Bezpieczny restart serwera. +- `sudo ./start.sh update` - Aktualizacja pakietów systemowych. + +## 5. Opis Modułów Opcjonalnych + +Możesz włączyć je w pliku `autoscript.conf`. + +- **Fail2ban**: Dodatkowa ochrona, która analizuje logi i blokuje adresy IP wykazujące złośliwą aktywność (np. próby logowania brute-force). +- **PostgreSQL**: Wdraża kontener z popularną bazą danych. Hasło jest zarządzane przez `sops`. +- **Loki**: System do agregacji logów z Twoich kontenerów. Umożliwia ich wygodne przeszukiwanie w Grafanie. +- **Restic Backup**: Instaluje i konfiguruje `restic` do tworzenia regularnych, szyfrowanych kopii zapasowych do chmury (np. AWS S3, Backblaze B2). **Wymaga dodatkowej konfiguracji po stronie dostawcy chmury!** + +## 6. Co robić po instalacji? + +Po zakończeniu komendy `install`: + +1. **Nowy Port SSH:** Został zmieniony na losowy. Znajdziesz go w pliku `/root/ssh_port.txt`. +2. **Logowanie**: Logowanie na `root` jest zablokowane. Użyj użytkownika `admin` z Twoim kluczem SSH i nowym portem: `ssh admin@ -p `. +3. **TOTP (2FA)**: Przy pierwszym użyciu `sudo` zostaniesz poproszony o skonfigurowanie aplikacji do uwierzytelniania (np. Google Authenticator). +4. **Dostęp do usług**: Usługi będą dostępne pod subdomenami Twojej domeny (np. `https://grafana.twojadomena.pl`). diff --git a/autoscript.conf.example b/autoscript.conf.example index cf55b84..f7bf77e 100644 --- a/autoscript.conf.example +++ b/autoscript.conf.example @@ -1,5 +1,5 @@ # =================================================================== -# Konfiguracja AutoScript +# Konfiguracja AutoScript v2 # =================================================================== # # Instrukcja: @@ -40,22 +40,10 @@ TIMEZONE='Europe/Warsaw' # ------------------------------------------------------------------- # USTAWIENIA POWIADOMIEŃ (SMTP) # ------------------------------------------------------------------- -# Ta sekcja konfiguruje serwer e-mail do wysyłania alertów z monitoringu. -# Adres hosta i port serwera SMTP. -# Przykład: ALERT_SMTP_HOST='smtp.example.com:587' ALERT_SMTP_HOST='mail.drap.ovh:587' - -# Nazwa użytkownika do logowania SMTP. -# Przykład: ALERT_SMTP_USER='alerts@example.com' ALERT_SMTP_USER='alerts@drap.ovh' - -# Hasło do logowania SMTP. -# Jeśli pozostawisz puste, zostanie wygenerowane losowe i zapisane bezpiecznie w sops. -ALERT_SMTP_PASS='' - -# Adres e-mail, z którego będą wysyłane alerty (pole 'From'). -# Przykład: ALERT_SMTP_FROM='server-alerts@example.com' +ALERT_SMTP_PASS='' # Pozostaw puste, aby wygenerować losowe ALERT_SMTP_FROM='alerts@drap.ovh' # ------------------------------------------------------------------- @@ -66,11 +54,53 @@ ALERT_SMTP_FROM='alerts@drap.ovh' # Jeśli pozostawisz puste, zostanie wygenerowane losowe i zapisane bezpiecznie w sops. GRAFANA_ADMIN_PASSWORD='' +# ------------------------------------------------------------------- +# MODUŁY OPCJONALNE (włącz/wyłącz za pomocą true/false) +# ------------------------------------------------------------------- + +# Czy instalować i konfigurować Fail2ban jako dodatkową warstwę ochrony? +INSTALL_FAIL2BAN=true + +# Czy wdrażać bazę danych PostgreSQL? +INSTALL_DATABASE=false + +# Czy wdrażać Loki do centralnego zbierania logów z kontenerów? +INSTALL_LOKI=false + +# Czy konfigurować system kopii zapasowych Restic? +# UWAGA: Wymaga ręcznego uzupełnienia danych repozytorium! +INSTALL_BACKUP=false + +# ------------------------------------------------------------------- +# KONFIGURACJA BAZY DANYCH (jeśli INSTALL_DATABASE=true) +# ------------------------------------------------------------------- + +# Hasło dla użytkownika 'postgres'. Zostanie zapisane w sops. +# Jeśli pozostawisz puste, zostanie wygenerowane losowe. +POSTGRES_PASSWORD='' + +# ------------------------------------------------------------------- +# KONFIGURACJA KOPII ZAPASOWYCH (jeśli INSTALL_BACKUP=true) +# ------------------------------------------------------------------- + +# Pełna ścieżka do repozytorium Restic (np. s3:s3.amazonaws.com/my-bucket) +BACKUP_REPO='' + +# Hasło do repozytorium Restic. Zostanie zapisane w sops. +BACKUP_PASSWORD='' + +# Dane dostępowe do Twojego dostawcy chmury (np. AWS S3) +# Zostaną zapisane w sops. +AWS_ACCESS_KEY_ID='' +AWS_SECRET_ACCESS_KEY='' + +# Harmonogram tworzenia kopii zapasowych (format cron) +# Poniższy przykład oznacza "codziennie o 3:30 w nocy" +BACKUP_CRON_SCHEDULE='30 3 * * *' + # ------------------------------------------------------------------- # WERSJE OBRAZÓW DOCKER # ------------------------------------------------------------------- -# Dobrą praktyką jest używanie konkretnych wersji oprogramowania dla stabilności. -# Używaj 'latest' z rozwagą. TRAEFIK_VER='v3.0' PROMETHEUS_VER='latest' @@ -79,3 +109,6 @@ CADVISOR_VER='latest' BLACKBOX_VER='latest' GRAFANA_VER='latest' ALERTMANAGER_VER='latest' +POSTGRES_VER='16' +LOKI_VER='latest' +PROMTAIL_VER='latest' \ No newline at end of file diff --git a/templates/monitoring/alertmanager.yml b/templates/monitoring/alertmanager.yml new file mode 100644 index 0000000..375db6a --- /dev/null +++ b/templates/monitoring/alertmanager.yml @@ -0,0 +1,17 @@ +global: + smtp_smarthost: '$ALERT_SMTP_HOST' + smtp_from: '$ALERT_SMTP_FROM' + smtp_auth_username: '$ALERT_SMTP_USER' + smtp_auth_password_file: '/etc/alertmanager/secrets/smtp_pass' +route: + group_by: ['alertname'] + group_wait: 10s + group_interval: 10s + repeat_interval: 1h + receiver: 'email' +receivers: +- name: 'email' + email_configs: + - to: '$ADMIN_EMAIL' + subject: 'Alert: {{ "{{" }} .GroupLabels.alertname {{ "}}" }}' + send_resolved: true diff --git a/templates/monitoring/alerts.yml b/templates/monitoring/alerts.yml new file mode 100644 index 0000000..9437ec0 --- /dev/null +++ b/templates/monitoring/alerts.yml @@ -0,0 +1,30 @@ +groups: +- name: general.rules + rules: + - alert: InstanceDown + expr: up == 0 + for: 2m + labels: { severity: critical } + annotations: + summary: "Instance {{ $labels.instance }} down" + description: "{{ $labels.instance }} of job {{ $labels.job }} down >2m" + - alert: HighCPUUsage + expr: 100 - (avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))*100) > 80 + for: 5m + labels: { severity: warning } + annotations: { summary: "High CPU {{ $labels.instance }}" } + - alert: HighMemoryUsage + expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes)/node_memory_MemTotal_bytes*100 > 90 + for: 5m + labels: { severity: warning } + annotations: { summary: "High memory {{ $labels.instance }}" } + - alert: DiskSpaceLow + expr: (node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}/node_filesystem_size_bytes) < 0.1 + for: 10m + labels: { severity: warning } + annotations: { summary: "Low disk {{ $labels.instance }}" } + - alert: CertificateExpiration + expr: probe_ssl_earliest_cert_expiry - time() < 604800 + for: 0m + labels: { severity: warning } + annotations: { summary: "Cert expires soon {{ $labels.instance }}" } diff --git a/templates/monitoring/blackbox.yml b/templates/monitoring/blackbox.yml new file mode 100644 index 0000000..7c15ee0 --- /dev/null +++ b/templates/monitoring/blackbox.yml @@ -0,0 +1,10 @@ +modules: + http_2xx: + prober: http + timeout: 5s + http: + valid_http_versions: ["HTTP/1.1","HTTP/2.0"] + valid_status_codes: [200,301,302] + method: GET + follow_redirects: true + tls_config: { insecure_skip_verify: false } diff --git a/templates/monitoring/docker-compose.yml b/templates/monitoring/docker-compose.yml new file mode 100644 index 0000000..9854b43 --- /dev/null +++ b/templates/monitoring/docker-compose.yml @@ -0,0 +1,140 @@ +networks: + monitoring: + traefik_proxy: + external: true +services: + prometheus: + image: prom/prometheus:${PROMETHEUS_VER} + container_name: prometheus + restart: unless-stopped + networks: [monitoring, traefik_proxy] + volumes: + - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro + - ./prometheus/rules:/etc/prometheus/rules:ro + - prometheus_data:/prometheus + command: + - --config.file=/etc/prometheus/prometheus.yml + - --storage.tsdb.path=/prometheus + - --storage.tsdb.retention.time=30d + - --web.enable-lifecycle + - --web.external-url=https://prometheus.${PRIMARY_DOMAIN} + security_opt: [no-new-privileges:true] + read_only: true + tmpfs: ["/tmp:size=64m"] + cap_drop: [ALL] + healthcheck: + test: ["CMD","wget","-qO-","http://localhost:9090/-/healthy"] + interval: 30s + timeout: 3s + retries: 5 + labels: + - traefik.enable=true + - traefik.http.routers.prom.rule=Host(`prometheus.${PRIMARY_DOMAIN}`) + - traefik.http.routers.prom.entrypoints=websecure + - traefik.http.routers.prom.tls.certresolver=le-dns + - traefik.http.routers.prom.middlewares=security-headers@file + + node-exporter: + image: prom/node-exporter:${NODE_EXPORTER_VER} + container_name: node-exporter + restart: unless-stopped + networks: [monitoring] + pid: host + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + command: + - --path.procfs=/host/proc + - --path.rootfs=/rootfs + - --path.sysfs=/host/sys + - --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) + security_opt: [no-new-privileges:true] + read_only: true + cap_drop: [ALL] + + cadvisor: + image: gcr.io/cadvisor/cadvisor:${CADVISOR_VER} + container_name: cadvisor + restart: unless-stopped + networks: [monitoring] + volumes: + - /:/rootfs:ro + - /var/run:/var/run:rw + - /sys:/sys:ro + - /var/lib/docker:/var/lib/docker:ro + privileged: true + devices: ["/dev/kmsg:/dev/kmsg"] + + blackbox-exporter: + image: prom/blackbox-exporter:${BLACKBOX_VER} + container_name: blackbox-exporter + restart: unless-stopped + networks: [monitoring] + volumes: + - ./blackbox/blackbox.yml:/etc/blackbox_exporter/config.yml:ro + security_opt: [no-new-privileges:true] + read_only: true + tmpfs: ["/tmp:size=64m"] + cap_drop: [ALL] + + alertmanager: + image: prom/alertmanager:${ALERTMANAGER_VER} + container_name: alertmanager + restart: unless-stopped + networks: [monitoring, traefik_proxy] + volumes: + - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro + - alertmanager_data:/alertmanager + - ${ALERT_SMTP_PASS_PATH}:/etc/alertmanager/secrets/smtp_pass:ro + command: + - --config.file=/etc/alertmanager/alertmanager.yml + - --storage.path=/alertmanager + - --web.external-url=https://alertmanager.${PRIMARY_DOMAIN} + security_opt: [no-new-privileges:true] + read_only: true + tmpfs: ["/tmp:size=64m"] + cap_drop: [ALL] + healthcheck: + test: ["CMD","wget","-qO-","http://localhost:9093/-/healthy"] + interval: 30s + timeout: 3s + retries: 5 + labels: + - traefik.enable=true + - traefik.http.routers.alert.rule=Host(`alertmanager.${PRIMARY_DOMAIN}`) + - traefik.http.routers.alert.entrypoints=websecure + - traefik.http.routers.alert.tls.certresolver=le-dns + - traefik.http.routers.alert.middlewares=security-headers@file + + grafana: + image: grafana/grafana:${GRAFANA_VER} + container_name: grafana + user: "472" + restart: unless-stopped + networks: [monitoring, traefik_proxy] + volumes: + - grafana_data:/var/lib/grafana + - ./grafana/provisioning:/etc/grafana/provisioning:ro + environment: + GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD} + GF_USERS_ALLOW_SIGN_UP: "false" + GF_SERVER_ROOT_URL: https://grafana.${PRIMARY_DOMAIN} + security_opt: [no-new-privileges:true] + cap_drop: [ALL] + healthcheck: + test: ["CMD","wget","-qO-","http://localhost:3000/api/health"] + interval: 30s + timeout: 3s + retries: 5 + labels: + - traefik.enable=true + - traefik.http.routers.grafana.rule=Host(`grafana.${PRIMARY_DOMAIN}`) + - traefik.http.routers.grafana.entrypoints=websecure + - traefik.http.routers.grafana.tls.certresolver=le-dns + - traefik.http.routers.grafana.middlewares=security-headers@file + +volumes: + prometheus_data: + grafana_data: + alertmanager_data: diff --git a/templates/monitoring/prometheus-datasource.yml b/templates/monitoring/prometheus-datasource.yml new file mode 100644 index 0000000..2d43399 --- /dev/null +++ b/templates/monitoring/prometheus-datasource.yml @@ -0,0 +1,8 @@ +apiVersion: 1 +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + editable: false diff --git a/templates/monitoring/prometheus.yml b/templates/monitoring/prometheus.yml new file mode 100644 index 0000000..611fcff --- /dev/null +++ b/templates/monitoring/prometheus.yml @@ -0,0 +1,35 @@ +global: + scrape_interval: 15s + evaluation_interval: 15s +rule_files: + - "/etc/prometheus/rules/*.yml" +alerting: + alertmanagers: + - static_configs: [{ targets: ['alertmanager:9093'] }] +scrape_configs: + - job_name: prometheus + static_configs: [{ targets: ['localhost:9090'] }] + - job_name: node-exporter + static_configs: [{ targets: ['node-exporter:9100'] }] + - job_name: cadvisor + static_configs: [{ targets: ['cadvisor:8080'] }] + - job_name: traefik + static_configs: [{ targets: ['traefik:8080'] }] + - job_name: blackbox + metrics_path: /probe + params: { module: [http_2xx] } + static_configs: + - targets: + - https://forum.yeswas.pl + - https://social.ovh + - https://rss.social.ovh + - https://pawelorzech.pl + - https://dash.orzech.me + - https://run.orzech.me + relabel_configs: + - source_labels: [__address__] + target_label: __param_target + - source_labels: [__param_target] + target_label: instance + - target_label: __address__ + replacement: blackbox-exporter:9115 diff --git a/templates/traefik/docker-compose.yml b/templates/traefik/docker-compose.yml new file mode 100644 index 0000000..5131407 --- /dev/null +++ b/templates/traefik/docker-compose.yml @@ -0,0 +1,27 @@ +services: + traefik: + image: traefik:${TRAEFIK_VER} + container_name: traefik + restart: unless-stopped + networks: [traefik_proxy] + ports: ["80:80","443:443"] + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./config/traefik.yml:/etc/traefik/traefik.yml:ro + - ./dynamic:/etc/traefik/dynamic:ro + - ./data/acme.json:/acme/acme.json + environment: + CF_DNS_API_TOKEN: ${CF_DNS_API_TOKEN} + security_opt: [no-new-privileges:true] + read_only: true + tmpfs: ["/tmp:size=64m"] + cap_drop: [ALL] + cap_add: [NET_BIND_SERVICE] + healthcheck: + test: ["CMD","wget","--no-verbose","--tries=1","--spider","http://localhost:8080/ping"] + interval: 30s + timeout: 3s + retries: 5 +networks: + traefik_proxy: + external: true diff --git a/templates/traefik/middlewares.yml b/templates/traefik/middlewares.yml new file mode 100644 index 0000000..933d1b3 --- /dev/null +++ b/templates/traefik/middlewares.yml @@ -0,0 +1,14 @@ +http: + middlewares: + security-headers: + headers: + stsSeconds: 63072000 + stsIncludeSubdomains: true + stsPreload: true + contentTypeNosniff: true + referrerPolicy: "strict-origin-when-cross-origin" + frameDeny: true + browserXssFilter: true + gzip: { compress: {} } + rate-limit: + rateLimit: { burst: 100, average: 50 } diff --git a/templates/traefik/tls.yml b/templates/traefik/tls.yml new file mode 100644 index 0000000..ca6764f --- /dev/null +++ b/templates/traefik/tls.yml @@ -0,0 +1,5 @@ +tls: + options: + default: + minVersion: VersionTLS12 + sniStrict: true diff --git a/templates/traefik/traefik.yml b/templates/traefik/traefik.yml new file mode 100644 index 0000000..6a275cc --- /dev/null +++ b/templates/traefik/traefik.yml @@ -0,0 +1,22 @@ +api: { dashboard: true } +ping: {} +entryPoints: + web: + address: ":80" + http: { redirections: { entryPoint: { to: websecure, scheme: https } } } + websecure: + address: ":443" +providers: + file: { directory: "/etc/traefik/dynamic", watch: true } + docker: + exposedByDefault: false + network: traefik_proxy +certificatesResolvers: + le-dns: + acme: + email: ${ADMIN_EMAIL} + storage: /acme/acme.json + dnsChallenge: { provider: cloudflare, delayBeforeCheck: 0 } +metrics: { prometheus: { addEntryPointsLabels: true, addServicesLabels: true } } +log: { level: INFO, format: json } +accessLog: { format: json }