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
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
# 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:
|
||||
|
||||
```bash
|
||||
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.**
|
||||
Reference in New Issue
Block a user