Docs/docs/10-security.md
2026-03-24 11:35:03 +05:00

336 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 10. Безопасность
## Обзор
В этом разделе собраны текущие проблемы безопасности инфраструктуры и план их устранения. Документ основан на результатах аудита, проведённого в марте 2026 года.
> **Последнее обновление**: 24 марта 2026
> **Применено на хостах**: `torrent` (192.168.1.211)
> **В процессе**: применение на остальных хостах
---
## Текущее состояние
| Область | Статус | Комментарий |
|---------|--------|-------------|
| SSH (парольная аутентификация) | ✅ | Отключена на всех хостах |
| SSH (вход root) | ✅ | Запрещён (`PermitRootLogin no`) на `torrent`, применяется на остальных |
| Пользователь `zailon` | ✅ | Создан с правами `sudo`, SSH-ключи настроены |
| SSH-ключи | ✅ | Управляются централизованно через Ansible |
| Samba (протокол) | ✅ | Обновлён до `SMB2` на `media` |
| Samba (шифрование) | 🟡 | `smb encrypt = desired` (пока не `required` из-за совместимости) |
| UFW / фаервол | 🔴 | Отключён на всех LXC и ВМ |
| Хранение паролей в Ansible | ✅ | Все секреты перенесены в `vault.yml` и зашифрованы |
| Заголовки безопасности в NPM | 🔴 | Отсутствуют для большинства прокси |
| Docker-образы | 🟡 | Используется тег `latest` на части сервисов |
| Обновления систем | 🟡 | Требуют периодического применения |
| Мониторинг | ✅ | Node Exporter, Promtail, VictoriaMetrics настроены |
| Резервное копирование | 🔴 | Не настроено (будет описано в разделе 11) |
---
## ✅ Решённые проблемы
### 1. Вход root по SSH — ИСПРАВЛЕНО
- **Описание**: На всех хостах разрешён вход под пользователем `root` через SSH. При компрометации ключа злоумышленник получает полный контроль над системой.
- **Что сделано**:
- Создан пользователь `zailon` с правами `sudo`
- Настроены SSH-ключи из `ssh_public_keys`
- В `/etc/ssh/sshd_config` установлено `PermitRootLogin no`
- Применено через Ansible на хосте `torrent`
- **Проверка**:
```bash
# Проверка подключения под zailon
ssh zailon@192.168.1.211 # ✅ Работает
# Проверка запрета root
ssh root@192.168.1.211 # ❌ Permission denied (publickey)
# Проверка конфигурации SSH
grep PermitRootLogin /etc/ssh/sshd_config
# Ожидаемый вывод: PermitRootLogin no
```
- **Статус**: ✅ Применено на `torrent`, готовится применение на остальных хостах
### 2. Пароли в открытом виде в Ansible — ИСПРАВЛЕНО
- **Описание**: В файле `group_vars/all.yml` присутствовали пароли в открытом виде.
- **Что сделано**:
- Все секреты перенесены в `group_vars/vault.yml`
- Файл зашифрован через `ansible-vault encrypt vault.yml`
- В `all.yml` остались только публичные переменные
- **Список зашифрованных переменных**:
```yaml
# vault.yml (зашифрован)
vault_zailon_password: "..." # Пароль администратора
vault_grafana_admin_password: "..." # Grafana
vault_gitlab_root_password: "..." # GitLab
vault_bitwarden_admin_token: "..." # Bitwarden
vault_bitwarden_smtp_password: "..." # Bitwarden SMTP
vault_mealie_db_password: "..." # Mealie DB
vault_flibusta_db_password: "..." # Flibusta DB
vault_immich_db_password: "..." # Immich DB
vault_mumble_server_password: "..." # Mumble
vault_mumble_superuser_password: "..." # Mumble superuser
vault_matrix_postgres_password: "..." # Matrix/Synapse
vault_matrix_synapse_secret: "..." # Matrix secrets
vault_matrix_macaroon_secret: "..."
vault_matrix_form_secret: "..."
vault_matrix_admin_password: "..."
vault_snikket_admin_password: "..." # Snikket XMPP
vault_snikket_invite_token: "..."
vault_smb_olimp_password: "..." # SMB shares
vault_samba_password_qb: "..."
vault_pve_exporter_token: "..." # Proxmox exporter
```
- **Запуск playbook с vault**:
```bash
# Интерактивный ввод пароля
ansible-playbook -i inventories/hosts olimp-deploy.yml --ask-vault-pass
# Или через файл с паролем
echo "your_vault_password" > ~/.vault_pass
chmod 600 ~/.vault_pass
ansible-playbook -i inventories/hosts olimp-deploy.yml --vault-password-file ~/.vault_pass
```
- **Статус**: ✅ Завершено
### 3. Samba использует SMB1 — ИСПРАВЛЕНО
- **Описание**: На хосте `media` в конфигурации Samba был установлен `server min protocol = NT1` (SMB1), что уязвимо к атакам типа EternalBlue.
- **Что сделано**:
- В `/etc/samba/smb.conf` на хосте `media` изменено:
```ini
[global]
server min protocol = smb2 # было: NT1
smb encrypt = desired # оставлено для совместимости с клиентами
```
- Проверена работа клиентов (Windows, Android, Docker)
- **Статус**: ✅ Завершено на `media`
---
## 🔴 Критические проблемы (требуют внимания)
### 1. Отсутствие фаервола на всех LXC
- **Описание**: UFW отключён на всех LXC-контейнерах. Сервисы доступны из всей локальной сети без ограничений.
- **Решение**: Включить UFW на каждом хосте с минимально необходимыми правилами:
```yaml
# Пример роли ufw_setup/tasks/main.yml
- name: Enable UFW with default deny
ufw:
state: enabled
policy: deny
direction: incoming
become: yes
- name: Allow SSH from trusted subnets
ufw:
rule: allow
port: 22
proto: tcp
from: "{{ item }}"
loop:
- "192.168.1.0/24" # LAN
- "192.168.45.0/24" # OpenVPN
become: yes
- name: Allow Samba from trusted subnets
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
from: "{{ from_item }}"
loop:
- 139
- 445
loop_control:
loop_var: port
vars:
from_item: "192.168.1.0/24"
become: yes
- name: Allow HTTP/HTTPS for NPM
ufw:
rule: allow
port: "{{ item }}"
proto: tcp
loop:
- 80
- 443
become: yes
```
- **План**: Создать роль `ufw_setup` и применить ко всем хостам
- **Срок**: В течение недели
### 2. Отсутствие заголовков безопасности в NPM
- **Описание**: Для публичных прокси не настроены заголовки безопасности: HSTS, X-Content-Type-Options, X-Frame-Options.
- **Решение**: Через веб-интерфейс NPM → Proxy Hosts → Edit → Advanced → Custom locations добавить:
```nginx
# Security headers
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;
```
- **Применить ко всем публичным доменам**: `*.zailon.ru`
- **Срок**: В течение недели
### 3. Резервное копирование не настроено
- **Описание**: Нет автоматического бэкапа конфигураций, баз данных и пользовательских данных.
- **Решение**: Описано в разделе [11. Резервное копирование](11-backup.md)
- **Срок**: В течение 2 недель
---
## 🟠 Проблемы высокого приоритета
### 1. Использование Docker-образов с тегом `latest`
- **Описание**: Образы обновляются неконтролируемо, что может привести к несовместимости.
- **Решение**: Зафиксировать версии в `docker-compose.yml`:
```yaml
# Было:
services:
npm:
image: jc21/nginx-proxy-manager:latest
# Стало:
services:
npm:
image: jc21/nginx-proxy-manager:2.12.3 # Зафиксированная версия
```
- **План**: Пройтись по всем `docker-compose.yml` и зафиксировать версии
- **Срок**: В течение месяца
### 2. Необновлённые системы
- **Описание**: На хостах накапливаются обновления пакетов.
- **Решение**:
- Регулярно запускать `apt update && apt upgrade` через Ansible (уже реализовано в роли `base_setup`)
- Настроить `unattended-upgrades` для автоматических обновлений безопасности
```yaml
# Пример задачи для unattended-upgrades
- name: Install unattended-upgrades
apt:
name: unattended-upgrades
state: present
become: yes
- name: Configure unattended-upgrades
copy:
content: |
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}";
"${distro_id}:${distro_codename}-security";
};
Unattended-Upgrade::Automatic-Reboot "false";
dest: /etc/apt/apt.conf.d/50unattended-upgrades
owner: root
mode: '0644'
become: yes
```
- **Статус**: 🟡 В процессе
---
## 🟡 Проблемы среднего приоритета
### 1. Шифрование Samba: `desired` вместо `required`
- **Описание**: `smb encrypt = desired` допускает незашифрованные соединения.
- **Решение**: После тестирования всех клиентов в VPN изменить на `required`:
```ini
[global]
smb encrypt = required
```
- **Статус**: 🟡 Отложено до полной проверки совместимости
### 2. Отсутствие алертов на логи в Grafana
- **Описание**: Нет правил для оповещения при ошибках в логах.
- **Решение**: Настроить правила в Grafana → Alerting на основе Loki:
```logql
# Пример: алерт на ошибки в логах SSH
{job="promtail", filename="/var/log/auth.log"} |= "Failed password" | rate() > 5
# Пример: алерт на ошибки в логах NPM
{job="promtail", container="nginx-proxy-manager"} |= "error" | level="error"
```
- **Статус**: 🟡 В планах
### 3. cAdvisor не включён на всех хостах
- **Описание**: Метрики Docker-контейнеров собираются не везде.
- **Решение**: Раскомментировать роль `cadvisor` в `olimp-deploy.yml` при необходимости.
- **Статус**: 🟡 По мере необходимости
---
## 🟢 Рекомендации по улучшению
| Задача | Описание | Приоритет |
|--------|----------|-----------|
| Автоматические обновления | Настроить `unattended-upgrades` на всех хостах | 🟢 |
| Сегментация сети | Выделить VLAN для IoT и гостевой сети | 🟢 |
| Мониторинг роутера | Сбор SNMP-метрик с TP-Link | 🟢 |
| Двухфакторная аутентификация | Включить 2FA в Grafana, GitLab, Bitwarden | 🟢 |
| Регулярный аудит | Запускать Lynis/OpenVAS раз в 3 месяца | 🟢 |
---
## 📋 План действий
| Задача | Приоритет | Срок | Статус |
|--------|-----------|------|--------|
| Применить настройку SSH (root+zailon) на всех хостах | 🔴 | 1 день | 🔄 В процессе |
| Включить UFW на всех хостах | 🔴 | 1 неделя | ⏳ Ожидает |
| Добавить заголовки безопасности в NPM | 🔴 | 1 неделя | ⏳ Ожидает |
| Настроить резервное копирование | 🔴 | 2 недели | ⏳ Ожидает |
| Зафиксировать версии Docker-образов | 🟠 | 1 месяц | ⏳ Ожидает |
| Настроить unattended-upgrades | 🟢 | 1 месяц | ⏳ Ожидает |
| Настроить алерты на логи | 🟡 | По необходимости | ⏳ Ожидает |
---
## 🔐 Чек-лист применения изменений
Перед запуском playbook на всех хостах:
```bash
# 1. Проверка прав на SSH-ключ Ansible
chmod 600 /root/.ssh/id_rsa
# 2. Проверка vault
ansible-vault view vault.yml --ask-vault-pass | grep zailon
# 3. Dry-run на одном хосте
ansible-playbook -i inventories/hosts olimp-deploy.yml -l torrent --check --diff --ask-vault-pass
# 4. Применение на одном хосте
ansible-playbook -i inventories/hosts olimp-deploy.yml -l torrent --ask-vault-pass
# 5. Тест подключения под zailon (в НОВОМ окне!)
ssh zailon@192.168.1.211
# 6. Если всё ок — применяем на всех
ansible-playbook -i inventories/hosts olimp-deploy.yml --ask-vault-pass
```
> ⚠️ **Важно**: Не закрывайте текущую SSH-сессию `root`, пока не проверите вход под `zailon` в отдельном окне!
---
**Связанные разделы**:
- [05. Samba файловые шары](05-samba.md)
- [07. Проксирование и SSL (NPM)](07-proxy-ssl.md)
- [08. Мониторинг и логирование](08-monitoring.md)
- [09. Управление конфигурацией (Ansible)](09-ansible.md)
- [11. Резервное копирование](11-backup.md)