Аудит перед запуском в прод. Найдены и исправлены critical и medium issues: Critical (fixed): - File permissions 644 → 600/640 для id_ed25519, БД, config.yaml - Нет logrotate (диск 2GB зальётся) → /etc/logrotate.d/rustdesk - Нет авто-бэкапа → daily cron 03:00 в /root/rustdesk-backups/ Medium (fixed): - Brute-force на /api/admin/login → NPM rate-limit 5r/m Medium (deferred): - NC share без пароля (NC сейчас down — отдельный task) - Security headers не наследуются в location / (NPM template limitation) Документация: - decisions/2026-04-30-rustdesk-pre-prod-audit.md — полный отчёт - projects/dttb/rustdesk-runbook.md — операционный runbook (recovery, troubleshooting, onboarding, updates) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
10 KiB
date, type, tags
| date | type | tags | ||||
|---|---|---|---|---|---|---|
| 2026-04-30 | audit |
|
RustDesk pre-production audit + fixes
Контекст
Перед запуском RustDesk-сервера в продакшн (для удалённого доступа клиентских организаций + личного использования) — системный аудит security, reliability, operations. Findings + примененные fixes.
Findings & fixes
🔴 Critical (исправлено)
1. Права на критичные файлы 644 → 600/640
Что было: все sensitive файлы на LXC 116 были world-readable (-rw-r--r--):
/var/lib/rustdesk-server/id_ed25519(приватный ключ сервера)/var/lib/rustdesk-server/id_ed25519.pub/var/lib/rustdesk-server/db_v2.sqlite3*(hbbs БД с peers UUID)/var/lib/rustdesk-api/data/rustdeskapi.db(хеши паролей юзеров, токены сессий)/var/lib/rustdesk-api/conf/config.yaml(содержит JWT secret иkey)
Риск: при компрометации любого non-root юзера на LXC 116 → leak приватного ключа сервера → весь парк клиентов перестаёт быть приватным; возможность подделки JWT и login as admin.
Fix (2026-04-30):
chmod 600 /var/lib/rustdesk-server/id_ed25519*
chmod 640 /var/lib/rustdesk-server/db_v2.sqlite3*
chmod 640 /var/lib/rustdesk-api/data/rustdeskapi.db
chmod 640 /var/lib/rustdesk-api/conf/config.yaml
2. Нет logrotate для rustdesk-логов на 2GB-диске
Что было: /var/log/rustdesk-server/hbbs.log ~260KB и rosт каждый день. На 2GB-диске LXC 116 (где уже 55% used) логи зальют диск за пару месяцев → сервер ляжет.
Fix (2026-04-30): /etc/logrotate.d/rustdesk:
/var/log/rustdesk-server/*.log /var/log/rustdesk-server/*.error
/var/log/rustdesk-api/*.log /var/log/rustdesk-api/*.error {
daily
rotate 14
compress
delaycompress
notifempty
missingok
copytruncate
su root root
}
3. Нет авто-бэкапа БД и ключей
Что было: одна вручную сделанная копия /root/rustdesk-backup-20260428-1134/. Если завтра LVM упадёт — теряем весь стейт (peers, users, ключи).
Fix (2026-04-30): cron daily 03:00 → /usr/local/bin/rustdesk-backup.sh:
- tar.gz в
/root/rustdesk-backups/rustdesk-YYYYMMDD.tar.gz - ключи + обе БД + config.yaml + systemd overrides
- retention 30 дней (find -mtime +30 -delete)
- chmod 600 на каждый tarball
TODO: доставить копии бэкапа на ArtLeon (off-site) через NetBird/rsync.
🟡 Medium (исправлено)
4. Нет rate-limit на login → brute-force admin password
Что было: https://remot.dttb.ru/api/admin/login принимал безlimit запросы. С учётом стандартного pw 1qaz!QAZ — кто-то с словарём найдёт его за час.
Fix (2026-04-30): в NPM /data/compose/2/data/nginx/custom/http.conf:
limit_req_zone $binary_remote_addr zone=adminlogin:10m rate=5r/m;
limit_req_zone $binary_remote_addr zone=apilogin:10m rate=10r/m;
В Proxy Host 14 advanced_config:
location = /api/admin/login {
limit_req zone=adminlogin burst=3 nodelay;
proxy_pass http://10.0.0.244:21114;
...
}
location = /api/login {
limit_req zone=apilogin burst=5 nodelay;
proxy_pass http://10.0.0.244:21114;
...
}
Verified: после 4 быстрых попыток — 503 от NPM. На уровне rustdesk-api также ban-threshold: 5 забанит user-account на ~1 час.
Грабли при настройке: limit_req_zone нельзя класть в server-контекст — только http. Первая попытка положить в advanced_config привела к удалению NPM proxy_host/14.conf и обвалу remot.dttb.ru. Восстановилось через disable/enable + переноса zone в http.conf.
🟡 Medium (отложено)
5. NC public-link без пароля + содержит RustDesk2.toml с key
Что было: https://dttb.ru/s/wPm8oaiFEyz7Ywx без пароля и без expiration. ZIP внутри содержит key=R0lA4r77.... Любой нашедший ссылку может зарегистрировать peer'а на нашем сервере.
Status: Nextcloud-AIO сейчас лежит (502 from NPM upstream), новую share создать не получается. Спавнен отдельный task на восстановление NC. После — пересоздать share с паролем + 30 дней expiration.
Митigation в текущем виде: MUST_LOGIN=Y отбивает входящие connections к незалогиненным peers. Кто-то регистрируется как peer — heartbeat-флуд возможен, но connections не пройдут.
6. Security headers не наследуются в location /
Что было: HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy не появляются в response от https://remot.dttb.ru/_admin/.
Корневая причина: NPM в template для Proxy Host генерит location / со встроенным add_header X-Served-By (через include proxy.conf). По правилу nginx — если в location есть хоть один add_header, наследование от server-block отключается. Мои add_header в advanced_config (server-level) не применяются к location /.
Fix-варианты (выбран wait):
- (a) Patch NPM template
/etc/nginx/conf.d/include/proxy.confчтобы добавить headers — теряется при container recreate - (b) Использовать
more_set_headers(модуль ngx_headers_more) — нужно проверить что он есть в openresty - (c) Override
location /в advanced_config с явными add_header — конфликт с NPM-сгенерированным location / - (d) Принять как cosmetic — TLS 1.2/1.3 + LE cert + rate-limit обеспечивают основную защиту; HSTS на server-level записан в nginx.conf (не на response).
Status: отложено как cosmetic. Если будем делать (b) или (a) — отдельной задачей.
🟢 Low / Informational
| Item | Status |
|---|---|
Server header раскрывает openresty |
Accept (мелкий fingerprinting, не критично) |
show-swagger: 1 в API |
Accept (Олег использует для разработки) |
| TLS 1.2 + 1.3, intermediate ciphers | ✅ optimal |
| LE cert valid until 28 June 2026 | ✅ auto-renew |
| Block Common Exploits (NPM) | ✅ enabled на host 14 |
block_exploits: true, caching_enabled: false |
✅ verified |
register: false в API |
✅ закрытая система |
ban-threshold: 5, captcha-threshold: 3 |
✅ enabled |
MUST_LOGIN=Y |
✅ enforced (видно в hbbs.log) |
| RustDesk peers версии | 1.4.6 (latest stable) |
| Disk LXC 116 free | 826 MB / 2 GB (55% used) — monitoring |
| RAM LXC 116 used | 105M / 512M — большой запас |
| NPM compose ports 21115-21119 | ✅ exposed после 2026-04-29 update |
Что осталось сделать (production todo)
Перед массовым deploy
- Восстановить Nextcloud (отдельный task)
- Создать share-link с паролем + expiration после восстановления NC
- Создать минимум 2 группы в
/_admin/(напримерНИИКН,Клиенты-Internal) - Настроить Configuration Strategy в админке lejianwen — push настроек существующим клиентам автоматически
- Off-site бэкап
/root/rustdesk-backups/*.tar.gzна ArtLeon через rsync over NetBird (cron weekly)
Полезное (не блокирует prod)
more_set_headersфикс security headers- fail2ban на NPM access logs (поверх rate-limit) — extra слой против distributed brute-force
- Monitoring: alert на падение rustdesk сервиса (через watchyourlan/zabbix/uptime-kuma)
- Auto-login клиента в API через service-token (упрощает onboarding)
rustdesk-utils2.x для single-filerustdesk-licensed-*.exedeployment
Долгосрочное
- Через 1-2 месяца — миграция в Docker
lejianwen/rustdesk-server-s6(Вариант A3) - HA-схема на втором экземпляре (НИИКН Proxmox) с общей MySQL
- MCP-обёртка поверх Swagger API для управления из Claude Code
Верификация
# Permissions OK
ssh root@10.0.0.250 "pct exec 116 -- ls -la /var/lib/rustdesk-server/id_ed25519"
# → -rw------- 1 root root 88 Oct 10 2025
# Logrotate OK
ssh root@10.0.0.250 "pct exec 116 -- logrotate -d /etc/logrotate.d/rustdesk"
# → "considering log /var/log/rustdesk-..."
# Auto-backup ran
ssh root@10.0.0.250 "pct exec 116 -- ls -la /root/rustdesk-backups/"
# → rustdesk-20260430.tar.gz
# Rate-limit работает
for i in {1..6}; do
curl -ks -o /dev/null -w "%{http_code} " -X POST https://remot.dttb.ru/api/admin/login \
-H "Content-Type: application/json" -d '{"username":"x","password":"y"}'
done
# → 200 200 200 200 503 503
# Сервер отвечает
curl -ksI https://remot.dttb.ru/_admin/ | head -1
# → HTTP/2 200
Связанные
- ../projects/dttb/rustdesk-runbook — операционный runbook (создан этим audit'ом)
- 2026-04-28-rustdesk-lejianwen-pro-migration — миграция с OSS
- 2026-04-29-rustdesk-client-deployment-package — пакет установки клиентов
- ../projects/dttb/rustdesk — справочник