Files
infra/docs/SECURITY.md
T
kacperor 6ed7a7f4d2 Init repo infra + poprawki runbooka bootstrap i HANDOFF
- Krok 9 (tmux): tee -> tee -a (nie nadpisuj configu), dodano
  focus-events on, poprawiono nazwę sesji na "bootstrap"
- Krok 10: struktura katalogów odzwierciedla stan faktyczny
  (/srv i /srv/infra już istnieją, brakuje apps i data)
- Krok 12: Claude Code oznaczony jako wykonany 20-08-2026,
  instalator natywny bez Node.js
- Nowy Krok 14: audyt po bootstrapie (SSH, ufw, fail2ban,
  unattended-upgrades, swap, Docker, porty, klucze)
- HANDOFF.md: poprawiona numeracja sekcji 6
2026-08-20 15:53:51 +00:00

5.9 KiB

SECURITY.md — bezpieczeństwo serwera

Zasada porządkująca: serwer jest tak bezpieczny, jak jego najsłabsza wystawiona usługa. Utwardzony SSH nie ma znaczenia, jeśli obok stoi panel administracyjny bez hasła.


1. Warstwy

Warstwa Czym chronimy Gdzie skonfigurowane
Dostęp do maszyny SSH tylko na klucz, root wyłączony /etc/ssh/sshd_config.d/99-hardening.conf
Sieć ufw: deny incoming, allow 22/80/443 ufw status verbose
Automatyczne ataki fail2ban na sshd /etc/fail2ban/jail.local
Aktualizacje unattended-upgrades (security) /etc/apt/apt.conf.d/50unattended-upgrades
Izolacja aplikacji osobne sieci Dockera, brak publikowanych portów compose każdego stacka
Transport TLS z Let's Encrypt na wszystkim Traefik
Sekrety pliki .env, chmod 600, poza repo obok każdego stacka

2. SSH

Docelowa konfiguracja:

PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AllowUsers ubuntu
X11Forwarding no
MaxAuthTries 3

Reguła bezwzględna przy każdej zmianie w sshd: otwierasz drugą sesję SSH i sprawdzasz, że logowanie działa, zanim zamkniesz pierwszą. Błąd w sshd_config przy zamkniętej sesji oznacza odzyskiwanie dostępu przez konsolę KVM w panelu OVH.

Port zostawiamy na 22. Przenoszenie na 2222 to kosmetyka — odsiewa hałas w logach, ale nie zatrzymuje nikogo, kto celuje w konkretną maszynę. fail2ban robi tu realną robotę.

Klucze

  • osobny klucz na każde urządzenie, ed25519, z komentarzem identyfikującym sprzęt
  • klucz prywatny nigdy nie trafia na serwer ani do repo
  • rejestr kluczy: SERVER.md, sekcja 4
  • przy zgubieniu urządzenia: usuwasz jego linię z ~/.ssh/authorized_keys, koniec

iOS: Termius lub Blink. Wchodzisz przez tmux attach -t claude do tej samej sesji, którą zostawiłeś na Macu.


3. Sekrety

Zasada Dlaczego
.env obok stacka, chmod 600, właściciel ubuntu inni użytkownicy systemu nie odczytają
.env w .gitignore, w repo tylko .env.example sekret w historii gita zostaje tam na zawsze
Hasła generowane, nie wymyślane — openssl rand -base64 32 brak ponownego użycia
Osobny sekret na usługę wyciek jednego nie kompromituje reszty

Jeśli sekret przypadkiem trafi do repo: nie wystarczy commit usuwający go. Trzeba go unieważnić i wygenerować nowy — historia gita pamięta, a jeśli poszła na mirror GitHuba, to jest już poza Twoją kontrolą.


4. Usługi administracyjne

Panel Traefika, bazy danych, narzędzia debugowe — nie wystawiamy publicznie. Dostęp przez tunel SSH:

ssh -L 8080:127.0.0.1:8080 ubuntu@dfkk.cloud
# potem localhost:8080 w przeglądarce

Jeśli coś musi być publiczne (np. status.dfkk.cloud, żeby działało z telefonu), to za basic auth w Traefiku, z hasłem z generatora.

Gitea: rejestracja nowych użytkowników wyłączona natychmiast po instalacji. Otwarta rejestracja na publicznej instancji to zaproszenie dla botów, które w kilka dni zamienią ją w hosting spamu.


5. Aktualizacje

Co Jak Kiedy
Poprawki bezpieczeństwa Ubuntu unattended-upgrades, automatycznie codziennie
Reszta pakietów systemu ręcznie, apt upgrade miesięczny przegląd
Obrazy Dockera ręcznie, podniesienie tagu wersji w compose miesięczny przegląd
Restart po aktualizacji kernela ręcznie, po snapshocie gdy /var/run/reboot-required

Automatyczny restart po aktualizacji jest wyłączony. Nie chcemy, żeby maszyna sama się przeładowała w środku pracy albo w trakcie działania czegoś produkcyjnego.

Obrazy pinujemy do konkretnych wersji. latest oznacza, że najbliższy docker compose pull może podmienić działającą aplikację na wersję z breaking changes — bez ostrzeżenia.


6. Co monitorujemy

Sygnał Próg Reakcja
Zajętość dysku 75% sprzątanie wg 40-utrzymanie.md
Usługa nie odpowiada 2 nieudane sprawdzenia alert mailem
Certyfikat wygasa < 14 dni sprawdzić DNS-01 i klucze OVH
Nietypowe wpisy w logach SSH przegląd przy miesięcznym audycie

Alerty idą na k.kruszka@hotmail.com przez zewnętrzny SMTP. Serwera pocztowego tu nie stawiamy — OVH blokuje port 25.


7. Podejrzenie włamania

Kolejność ma znaczenie. Nie restartuj i nie „posprzątaj" najpierw — zniszczysz ślady i stracisz możliwość ustalenia, czym weszli.

  1. Odetnij ruch: ufw default deny incoming i zatrzymaj wystawione kontenery
  2. Zrób snapshot OVH — to Twój materiał dowodowy
  3. Zbierz: last, journalctl -u ssh, docker ps -a, crontab -l dla wszystkich użytkowników, ls -la /tmp /var/tmp, nietypowe procesy i połączenia (ss -tulpn)
  4. Unieważnij wszystko: klucze SSH, tokeny API OVH, token GitHub, hasła w .env
  5. Oceń zakres — jeśli atakujący miał roota, maszyna jest spalona. Postawienie od zera z repo infra + backup danych jest szybsze i pewniejsze niż czyszczenie. Dlatego repo infra musi być kompletne.
  6. Dopiero potem: odbudowa, i wpis do SERVER.md co się stało

8. Braki, które trzeba domknąć

Uczciwa lista rzeczy, których jeszcze nie ma. Przeglądać przy miesięcznym audycie.

  • Backup off-site (restic). Snapshot OVH to rollback, nie backup — jeden slot, ręczny, nadpisywany, w tej samej infrastrukturze. Do domknięcia zanim na serwerze pojawią się pierwsze prawdziwe dane.
  • Test odtworzenia z backupu. Backup, którego nie odtworzyłeś, nie istnieje.
  • Mirror repo infra na GitHub. Bez tego awaria serwera zabiera kod, historię i konfigurację potrzebną do odtworzenia serwera — naraz.
  • 2FA na koncie OVH. Panel OVH może zrobić z maszyną wszystko, łącznie z reinstalacją. Jest w praktyce ważniejszy niż dostęp SSH.
  • 2FA na koncie GitHub.