344 lines
16 KiB
Markdown
344 lines
16 KiB
Markdown
# 10. Безопасность
|
||
|
||
## Обзор
|
||
|
||
В этом разделе собраны текущие проблемы безопасности инфраструктуры и план их устранения. Документ основан на результатах аудита, проведённого в марте 2026 года.
|
||
|
||
> **Последнее обновление**: 1 апреля 2026
|
||
> **Применено на хостах**: `torrent` (192.168.1.211), `Olimp` (Proxmox VE)
|
||
> **В процессе**: применение на остальных хостах
|
||
|
||
---
|
||
|
||
## Текущее состояние
|
||
|
||
| Область | Статус | Комментарий |
|
||
|---------|--------|-------------|
|
||
| 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 настроены |
|
||
| Резервное копирование | ✅ | **Proxmox Backup Server настроен и протестирован** |
|
||
|
||
---
|
||
|
||
## ✅ Решённые проблемы
|
||
|
||
### 1. Вход root по SSH — ИСПРАВЛЕНО
|
||
|
||
- **Описание**: На всех хостах разрешён вход под пользователем `root` через SSH. При компрометации ключа злоумышленник получает полный контроль над системой.
|
||
- **Что сделано**:
|
||
- Создан пользователь `zailon` с правами `sudo`
|
||
- Настроены SSH-ключи из `ssh_public_keys`
|
||
- В `/etc/ssh/sshd_config` установлено `PermitRootLogin no`
|
||
- Применено через Ansible на хосте `torrent`
|
||
- **Проверка**:
|
||
```bash
|
||
ssh zailon@192.168.1.211
|
||
ssh root@192.168.1.211
|
||
grep PermitRootLogin /etc/ssh/sshd_config
|
||
```
|
||
- **Статус**: ✅ Применено на всех хостах
|
||
|
||
### 2. Пароли в открытом виде в Ansible — ИСПРАВЛЕНО
|
||
|
||
- **Описание**: В файле `group_vars/all.yml` присутствовали пароли в открытом виде.
|
||
- **Что сделано**:
|
||
- Все секреты перенесены в `group_vars/vault.yml`
|
||
- Файл зашифрован через `ansible-vault encrypt vault.yml`
|
||
- В `all.yml` остались только публичные переменные
|
||
- **Список зашифрованных переменных**:
|
||
```yaml
|
||
vault_zailon_password: "..."
|
||
vault_grafana_admin_password: "..."
|
||
vault_gitlab_root_password: "..."
|
||
vault_bitwarden_admin_token: "..."
|
||
vault_bitwarden_smtp_password: "..."
|
||
vault_mealie_db_password: "..."
|
||
vault_flibusta_db_password: "..."
|
||
vault_immich_db_password: "..."
|
||
vault_mumble_server_password: "..."
|
||
vault_mumble_superuser_password: "..."
|
||
vault_matrix_postgres_password: "..."
|
||
vault_matrix_synapse_secret: "..."
|
||
vault_matrix_macaroon_secret: "..."
|
||
vault_matrix_form_secret: "..."
|
||
vault_matrix_admin_password: "..."
|
||
vault_snikket_admin_password: "..."
|
||
vault_snikket_invite_token: "..."
|
||
vault_smb_olimp_password: "..."
|
||
vault_samba_password_qb: "..."
|
||
vault_pve_exporter_token: "..."
|
||
```
|
||
- **Запуск 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
|
||
smb encrypt = desired
|
||
```
|
||
- Проверена работа клиентов (Windows, Android, Docker)
|
||
- **Статус**: ✅ Завершено на `media` `games`
|
||
|
||
### 4. Резервное копирование не было настроено — ИСПРАВЛЕНО
|
||
|
||
- **Описание**: Отсутствовала автоматическая система резервного копирования конфигураций, баз данных и пользовательских данных.
|
||
- **Что сделано** (апрель 2026):
|
||
- **Установлен Proxmox Backup Server** (PBS) в LXC контейнере (CT 220)
|
||
- **Создано хранилище** на ZFS dataset `rpool/pbs-backups` (187 GB, SSD mirror)
|
||
- **Настроено хранилище** `ssd-backups` с дедупликацией и компрессией ZSTD
|
||
- **PBS подключён** к Proxmox VE как `pbs-ssd`
|
||
- **Настроены бэкапы** для критичных систем:
|
||
- LXC контейнеры: 201-211 (gateway, data, media, photo, talk, games, manage, git, ansible, torrent)
|
||
- VM: 205 (Nextcloud), 213 (VPN)
|
||
- **Расписание**: ежедневно в 02:30 и 22:30
|
||
- **Retention политика**: Keep Last 7, Keep Daily 7, Keep Weekly 2
|
||
- **Режим**: Snapshot (без остановки сервисов)
|
||
- **Исключены** большие диски (16TB RAID6 массив)
|
||
- **Восстановление протестировано**: CT 201 → CT 216 (успешно)
|
||
- **Архитектура**:
|
||
```
|
||
Proxmox VE Host (Olimp)
|
||
├─ ZFS Pool: rpool (2x240GB SSD mirror)
|
||
│ └─ Dataset: rpool/pbs-backups (187 GB)
|
||
│ └─ Mounted to: /rpool/pbs-backups
|
||
│
|
||
└─ LXC Container (CT 220) - Proxmox Backup Server
|
||
└─ Mount: /mnt/backups → /rpool/pbs-backups
|
||
└─ Datastore: ssd-backups
|
||
```
|
||
- **Команды управления**:
|
||
```bash
|
||
zfs list rpool/pbs-backups
|
||
zpool list rpool
|
||
pct exec 220 -- proxmox-backup-client datastore stats ssd-backups
|
||
```
|
||
- **Восстановление**:
|
||
```bash
|
||
pct restore <new-vmid> pbs-ssd:backup/ct/<ctid>/<backup-time>
|
||
qm restore <new-vmid> pbs-ssd:backup/vm/<vmid>/<backup-time>
|
||
```
|
||
- **Статус**: ✅ Работает, требует мониторинга места
|
||
- **Примечание**: PBS развёрнут на том же хосте что и Proxmox VE (временное решение до появления отдельного сервера). Рекомендуется настроить репликацию на внешний носитель или облако.
|
||
|
||
---
|
||
|
||
## 🔴 Критические проблемы (требуют внимания)
|
||
|
||
### 1. Отсутствие фаервола на всех LXC
|
||
|
||
- **Описание**: UFW отключён на всех LXC-контейнерах. Сервисы доступны из всей локальной сети без ограничений.
|
||
- **Решение**: Включить UFW на каждом хосте с минимально необходимыми правилами:
|
||
```yaml
|
||
- 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"
|
||
- "192.168.45.0/24"
|
||
become: yes
|
||
|
||
- name: Allow Samba from trusted subnets
|
||
ufw:
|
||
rule: allow
|
||
port: "{{ item }}"
|
||
proto: tcp
|
||
from: "192.168.1.0/24"
|
||
loop:
|
||
- 139
|
||
- 445
|
||
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
|
||
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`
|
||
- **Срок**: В течение недели
|
||
|
||
---
|
||
|
||
## 🟠 Проблемы высокого приоритета
|
||
|
||
### 1. Использование Docker-образов с тегом `latest`
|
||
|
||
- **Описание**: Образы обновляются неконтролируемо, что может привести к несовместимости.
|
||
- **Решение**: Зафиксировать версии в `docker-compose.yml`:
|
||
```yaml
|
||
services:
|
||
npm:
|
||
image: jc21/nginx-proxy-manager:2.12.3
|
||
```
|
||
- **План**: Пройтись по всем `docker-compose.yml` и зафиксировать версии
|
||
- **Срок**: В течение месяца
|
||
|
||
### 2. Необновлённые системы
|
||
|
||
- **Описание**: На хостах накапливаются обновления пакетов.
|
||
- **Решение**:
|
||
- Регулярно запускать `apt update && apt upgrade` через Ansible
|
||
- Настроить `unattended-upgrades` для автоматических обновлений безопасности
|
||
```yaml
|
||
- 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
|
||
become: yes
|
||
```
|
||
- **Статус**: 🟡 В процессе
|
||
|
||
---
|
||
|
||
## 🟡 Проблемы среднего приоритета
|
||
|
||
### 1. Шифрование Samba: `desired` вместо `required`
|
||
|
||
- **Описание**: `smb encrypt = desired` допускает незашифрованные соединения.
|
||
- **Решение**: После тестирования всех клиентов в VPN изменить на `required`:
|
||
```ini
|
||
[global]
|
||
smb encrypt = required
|
||
```
|
||
- **Статус**: 🟡 Отложено до полной проверки совместимости
|
||
|
||
### 2. Отсутствие алертов на логи в Grafana
|
||
|
||
- **Описание**: Нет правил для оповещения при ошибках в логах.
|
||
- **Решение**: Настроить правила в Grafana → Alerting на основе Loki:
|
||
```logql
|
||
{job="promtail", filename="/var/log/auth.log"} |= "Failed password" | rate() > 5
|
||
{job="promtail", container="nginx-proxy-manager"} |= "error"
|
||
```
|
||
- **Статус**: 🟡 В планах
|
||
|
||
### 3. cAdvisor не включён на всех хостах
|
||
|
||
- **Описание**: Метрики Docker-контейнеров собираются не везде.
|
||
- **Решение**: Раскомментировать роль `cadvisor` в `olimp-deploy.yml` при необходимости.
|
||
- **Статус**: 🟡 По мере необходимости
|
||
|
||
---
|
||
|
||
## 🟢 Рекомендации по улучшению
|
||
|
||
| Задача | Описание | Приоритет |
|
||
|--------|----------|-----------|
|
||
| Автоматические обновления | Настроить `unattended-upgrades` на всех хостах | 🟢 |
|
||
| Сегментация сети | Выделить VLAN для IoT и гостевой сети | 🟢 |
|
||
| Мониторинг роутера | Сбор SNMP-метрик с TP-Link | 🟢 |
|
||
| Двухфакторная аутентификация | Включить 2FA в Grafana, GitLab, Bitwarden | 🟢 |
|
||
| Регулярный аудит | Запускать Lynis/OpenVAS раз в 3 месяца | 🟢 |
|
||
| Оффсайт-бэкапы | Настроить репликацию PBS в облако (Backblaze B2/Wasabi) | 🟢 |
|
||
|
||
---
|
||
|
||
## 📋 План действий
|
||
|
||
| Задача | Приоритет | Срок | Статус |
|
||
|--------|-----------|------|--------|
|
||
| Применить настройку SSH (root+zailon) на всех хостах | 🔴 | 1 день | 🔄 В процессе |
|
||
| Включить UFW на всех хостах | 🔴 | 1 неделя | ⏳ Ожидает |
|
||
| Добавить заголовки безопасности в NPM | 🔴 | 1 неделя | ⏳ Ожидает |
|
||
| Зафиксировать версии Docker-образов | 🟠 | 1 месяц | ⏳ Ожидает |
|
||
| Настроить unattended-upgrades | 🟢 | 1 месяц | ⏳ Ожидает |
|
||
| Настроить алерты на логи | 🟡 | По необходимости | ⏳ Ожидает |
|
||
| Настроить репликацию PBS (оффсайт) | 🟢 | 2 месяца | ⏳ Ожидает |
|
||
|
||
---
|
||
|
||
## 🔐 Чек-лист применения изменений
|
||
|
||
Перед запуском playbook на всех хостах:
|
||
|
||
```bash
|
||
chmod 600 /root/.ssh/id_rsa
|
||
ansible-vault view vault.yml --ask-vault-pass | grep zailon
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml -l torrent --check --diff --ask-vault-pass
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml -l torrent --ask-vault-pass
|
||
ssh zailon@192.168.1.211
|
||
ansible-playbook -i inventories/hosts olimp-deploy.yml --ask-vault-pass
|
||
```
|
||
|
||
> ⚠️ **Важно**: Не закрывайте текущую SSH-сессию `root`, пока не проверите вход под `zailon` в отдельном окне!
|
||
|
||
---
|
||
|
||
## 📊 Мониторинг безопасности
|
||
|
||
```bash
|
||
zfs list rpool/pbs-backups
|
||
zpool list rpool
|
||
pct exec 220 -- proxmox-backup-client datastore stats ssd-backups
|
||
pct exec 220 -- df -h /mnt/backups
|
||
```
|
||
|
||
---
|
||
|
||
**Связанные разделы**:
|
||
- [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) |