# NODA2 Security Hardening Guide **MacBook Pro M4 Max — мінімальний безпечний пакет** **Дата:** 2026-02-27 --- ## 1. SSH — перехід з пароля на ключ (ED25519) ### Статус: ВИКОНАНО (2026-02-27) #### Що зроблено - Згенеровано ED25519 ключ: `~/.ssh/noda1_ed25519` - Public key доданий на NODA1 (`/root/.ssh/authorized_keys`) - Private key: `secrets/noda1_id_ed25519` (chmod 600) - `NODES_NODA1_SSH_PASSWORD` видалено з `.env` - `sofiia-console` читає ключ через `/run/secrets/noda1_ssh_key` (file mount) #### Як відновити (якщо ключ загублено) ```bash # Генерація нового ключа ssh-keygen -t ed25519 -C "sofiia-console@noda2" -f ./secrets/noda1_id_ed25519 -N "" chmod 600 ./secrets/noda1_id_ed25519 # Додати public key на NODA1 cat ./secrets/noda1_id_ed25519.pub | ssh root@144.76.224.179 "cat >> ~/.ssh/authorized_keys" # Перевірка ssh -i ./secrets/noda1_id_ed25519 root@144.76.224.179 "echo 'key auth works'" ``` #### Перевірка що пароль не використовується ```bash # Локально (repo) grep -r 'SSH_PASSWORD' . --include='*.yml' --include='*.yaml' --include='*.env' --include='*.py' 2>/dev/null | grep -v '.git\|venv\|__pycache__\|ops/\|docs/' # В запущеному контейнері docker inspect sofiia-console --format '{{range .Config.Env}}{{println .}}{{end}}' | grep SSH_PASSWORD # Очікуємо: 0 результатів ``` --- ## 2. Port Exposure — bind на 127.0.0.1 ### Статус: ВИКОНАНО (2026-02-27) | Порт | Сервіс | Bind | Причина | |------|--------|------|---------| | 9102 | dagi-router-node2 | 127.0.0.1 | тільки локальне використання | | 8890 | swapper-service-node2 | 127.0.0.1 | internal inference, не зовні | | 8002 | sofiia-console | 127.0.0.1 | web UI тільки локально | | 9300 | dagi-gateway-node2 | 0.0.0.0 | Telegram webhook потребує зовнішній доступ | | 4222 | dagi-nats-node2 | 0.0.0.0 | NATS leafnode від NODA1 | | 8222 | dagi-nats-node2 | 0.0.0.0 | NATS monitoring (обмежити якщо не потрібно) | #### Рекомендація: обмежити NATS HTTP monitoring Якщо 8222 не потрібен зовні: ```yaml # docker-compose.node2-sofiia.yml — dagi-nats: ports: - "0.0.0.0:4222:4222" # leafnode — потрібен зовні - "127.0.0.1:8222:8222" # monitoring — тільки локально ``` --- ## 3. macOS Application Firewall ### Перевірка поточних слухаючих портів ```bash lsof -iTCP -sTCP:LISTEN -P | grep -E '(LISTEN)' | awk '{print $9, $1}' | sort ``` ### Мінімальний macOS pf firewall (Application Firewall) Увімкнення через System Preferences → Security → Firewall: 1. Firewall → Turn On 2. Firewall Options → Block all incoming connections (крім Telegram і NATS) Або через pfctl (більш гнучко): ```bash # /etc/pf.conf (додати правила) # Дозволити тільки NATS (4222) і Telegram gateway (9300) зовні # Решту блокувати pass in on en0 proto tcp to any port 4222 # NATS leafnode pass in on en0 proto tcp to any port 9300 # Telegram gateway block in on en0 proto tcp to any port 8890 # swapper — тільки localhost block in on en0 proto tcp to any port 9102 # router — тільки localhost block in on en0 proto tcp to any port 8002 # sofiia-console — тільки localhost block in on en0 proto tcp to any port 8222 # nats monitoring — тільки localhost # Apply: sudo pfctl -f /etc/pf.conf -e ``` ### Швидка перевірка що порти не відкриті назовні ```bash # Ці команди мають повернути "refused" від зовнішньої машини: # router, swapper, sofiia-console nc -zv 9102 # має бути Connection refused nc -zv 8890 # має бути Connection refused nc -zv 8002 # має бути Connection refused # Ці мають бути доступні: nc -zv 4222 # NATS nc -zv 9300 # Gateway ``` --- ## 4. Secrets Directory `secrets/` — локальна директорія для чутливих файлів (НЕ в git): ``` secrets/ ├── noda1_id_ed25519 # SSH private key → NODA1 (chmod 600) └── README.md # опис (ок в git) ``` Правила: - `secrets/noda1_id_ed25519` і `secrets/*.key` — в `.gitignore` - Всі файли `chmod 600` - НЕ зберігати паролі в env docker-compose — тільки через file mount --- ## 5. Checklist фінальний - [x] SSH пароль видалено з `.env` - [x] SSH key-based auth налаштований і перевірений - [x] `secrets/noda1_id_ed25519` в `.gitignore` - [x] Router (9102) bind на 127.0.0.1 - [x] Swapper (8890) bind на 127.0.0.1 - [x] Sofiia-console (8002) bind на 127.0.0.1 - [ ] NATS monitoring (8222) обмежити до 127.0.0.1 (optional) - [ ] macOS Firewall увімкнений - [ ] pf rules додані для зовнішніх портів