# 🛡️ Security Hardening Plan — DAARION & MicroDAO **Версія:** 1.0.0 **Дата:** 2026-01-10 **Статус:** В процесі впровадження --- ## 📋 Зміст 1. [Аналіз інцидентів](#аналіз-інцидентів) 2. [Рівень 1: Image Security](#рівень-1-image-security) 3. [Рівень 2: Container Runtime Security](#рівень-2-container-runtime-security) 4. [Рівень 3: Host Security](#рівень-3-host-security) 5. [Рівень 4: Network Security](#рівень-4-network-security) 6. [Рівень 5: Monitoring & Detection](#рівень-5-monitoring--detection) 7. [Рівень 6: Incident Response](#рівень-6-incident-response) 8. [Чеклист впровадження](#чеклист-впровадження) --- ## 📊 Аналіз інцидентів ### Що пішло не так: | Інцидент | Вектор атаки | Чому не виявили раніше | |----------|--------------|------------------------| | #1 | Вразливий `daarion-web` образ | Не сканували образи | | #2 | `restart: unless-stopped` | Не видалили image, тільки container | | #3 | Compromised postgres image | Довіряли Docker Hub без перевірки | | #4 | Host persistence (perfctl) | Не перевіряли host на malware | ### Ключові уроки: 1. 🔴 **Не довіряти жодному образу** — навіть official 2. 🟡 **Сканувати ВСЕ** — images, containers, host 3. 🟢 **Моніторити в реальному часі** — CPU, network, processes 4. 🔵 **Мати план відновлення** — швидкий rebuild з нуля --- ## 🔒 Рівень 1: Image Security ### 1.1 Image Scanning (Trivy) ```bash # Встановлення Trivy curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin # Сканування перед pull trivy image --severity HIGH,CRITICAL postgres:16-alpine # Автоматичне сканування в CI/CD trivy image --exit-code 1 --severity CRITICAL $IMAGE_NAME ``` ### 1.2 Image Pinning by SHA256 **❌ НІКОЛИ:** ```yaml image: postgres:16-alpine # Тег може змінитись! ``` **✅ ЗАВЖДИ:** ```yaml image: postgres@sha256:abc123... # Фіксований digest ``` ### 1.3 Allowlist Registry ```yaml # /etc/docker/daemon.json { "allowed-registries": [ "docker.io/library", "ghcr.io/daarion-dao" ] } ``` ### 1.4 Custom Base Images Створити власні базові образи з мінімальним attack surface: ```dockerfile # Dockerfile.postgres-secure FROM postgres:16-alpine@sha256:verified_digest # Remove unnecessary packages RUN apk del --purge wget curl busybox-extras # Add security scanning COPY --from=aquasec/trivy:latest /usr/local/bin/trivy /usr/local/bin/trivy # Non-root user USER postgres # Read-only filesystem # (set in docker-compose) ``` --- ## 🐳 Рівень 2: Container Runtime Security ### 2.1 Security Options ```yaml # docker-compose.yml services: postgres: image: postgres@sha256:verified_digest # ⚠️ НІКОЛИ auto-restart для нових сервісів restart: "no" # Змінити на "unless-stopped" ТІЛЬКИ після верифікації # Security options security_opt: - no-new-privileges:true - seccomp:seccomp-profile.json # Read-only root filesystem read_only: true # Temporary directories tmpfs: - /tmp:noexec,nosuid,nodev,size=100m - /var/run/postgresql:noexec,nosuid,nodev # Resource limits deploy: resources: limits: cpus: '2' memory: 2G reservations: cpus: '0.5' memory: 512M # Drop all capabilities, add only needed cap_drop: - ALL cap_add: - CHOWN - SETUID - SETGID # No privileged mode privileged: false # User namespace userns_mode: "host" ``` ### 2.2 Seccomp Profile ```json // seccomp-profile.json { "defaultAction": "SCCOMP_ACT_ERRNO", "syscalls": [ { "names": ["accept", "bind", "clone", "close", "connect", ...], "action": "SCCOMP_ACT_ALLOW" } ] } ``` ### 2.3 AppArmor Profile ```bash # /etc/apparmor.d/docker-postgres profile docker-postgres flags=(attach_disconnected) { # Deny network raw access deny network raw, # Deny ptrace deny ptrace, # Allow only postgres paths /var/lib/postgresql/** rw, /var/run/postgresql/** rw, # Deny /tmp execution deny /tmp/** x, } ``` --- ## 🖥️ Рівень 3: Host Security ### 3.1 Hardening Script ```bash #!/bin/bash # /opt/scripts/harden-host.sh set -e echo "🔒 Hardening NODE1..." # 1. Update system apt update && apt upgrade -y # 2. Install security tools apt install -y \ fail2ban \ ufw \ auditd \ rkhunter \ chkrootkit \ lynis \ aide # 3. Configure fail2ban cat > /etc/fail2ban/jail.local << 'EOF' [sshd] enabled = true port = ssh filter = sshd logpath = /var/log/auth.log maxretry = 3 bantime = 3600 findtime = 600 [docker-abuse] enabled = true filter = docker-abuse logpath = /var/log/docker.log maxretry = 5 bantime = 86400 EOF # 4. Configure UFW ufw default deny incoming ufw default deny outgoing # ⚠️ Strict egress! ufw allow 22/tcp # SSH ufw allow 80/tcp # HTTP ufw allow 443/tcp # HTTPS ufw allow out 53/udp # DNS ufw allow out 443/tcp # HTTPS out (for updates) ufw allow out 80/tcp # HTTP out (for updates) # Block internal networks ufw deny out to 10.0.0.0/8 ufw deny out to 172.16.0.0/12 ufw deny out to 192.168.0.0/16 ufw enable # 5. Kernel hardening cat >> /etc/sysctl.conf << 'EOF' # Disable IP forwarding net.ipv4.ip_forward = 0 # Disable ICMP redirects net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 # Enable SYN cookies net.ipv4.tcp_syncookies = 1 # Disable source routing net.ipv4.conf.all.accept_source_route = 0 # Log martians net.ipv4.conf.all.log_martians = 1 EOF sysctl -p # 6. Audit rules cat > /etc/audit/rules.d/docker.rules << 'EOF' # Monitor Docker daemon -w /usr/bin/docker -p rwxa -k docker -w /var/lib/docker -p rwxa -k docker -w /etc/docker -p rwxa -k docker # Monitor /tmp for executables -w /tmp -p x -k tmp_exec # Monitor network connections -a exit,always -F arch=b64 -S connect -k network EOF service auditd restart # 7. Initialize AIDE (file integrity) aideinit mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db echo "✅ Hardening complete!" ``` ### 3.2 Automated Security Checks ```bash #!/bin/bash # /opt/scripts/security-check.sh # Run via cron every hour LOG="/var/log/security-check.log" ALERT_EMAIL="admin@daarion.city" echo "$(date) - Starting security check" >> $LOG # 1. Check for suspicious processes SUSPICIOUS=$(ps aux | grep -E "(xmrig|kdevtmp|kinsing|perfctl|httpd.*tmp)" | grep -v grep) if [ -n "$SUSPICIOUS" ]; then echo "🚨 ALERT: Suspicious process found!" >> $LOG echo "$SUSPICIOUS" >> $LOG # Kill and alert pkill -9 -f "xmrig|kdevtmp|kinsing|perfctl" echo "$SUSPICIOUS" | mail -s "🚨 NODE1 ALERT: Suspicious process" $ALERT_EMAIL fi # 2. Check /tmp for executables TMP_EXEC=$(find /tmp -type f -executable 2>/dev/null) if [ -n "$TMP_EXEC" ]; then echo "🚨 ALERT: Executable in /tmp!" >> $LOG echo "$TMP_EXEC" >> $LOG rm -f $TMP_EXEC echo "$TMP_EXEC" | mail -s "🚨 NODE1 ALERT: Executable in /tmp" $ALERT_EMAIL fi # 3. Check CPU load LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d',' -f1 | tr -d ' ') if (( $(echo "$LOAD > 5" | bc -l) )); then echo "⚠️ WARNING: High CPU load: $LOAD" >> $LOG TOP_PROCS=$(ps aux --sort=-%cpu | head -5) echo "$TOP_PROCS" | mail -s "⚠️ NODE1 WARNING: High CPU load" $ALERT_EMAIL fi # 4. Check for rootkits rkhunter --check --skip-keypress --quiet RKHUNTER_STATUS=$? if [ $RKHUNTER_STATUS -ne 0 ]; then echo "🚨 ALERT: Rootkit detected!" >> $LOG rkhunter --check --skip-keypress | mail -s "🚨 NODE1 ALERT: Rootkit detected" $ALERT_EMAIL fi # 5. Check file integrity aide --check > /tmp/aide_check.txt 2>&1 if grep -q "changed" /tmp/aide_check.txt; then echo "⚠️ WARNING: File integrity changed" >> $LOG cat /tmp/aide_check.txt | mail -s "⚠️ NODE1 WARNING: File integrity" $ALERT_EMAIL fi # 6. Check Docker containers UNKNOWN_CONTAINERS=$(docker ps --format '{{.Names}}' | grep -v -E "(dagi-|postgres|redis|neo4j|qdrant|grafana|prometheus)") if [ -n "$UNKNOWN_CONTAINERS" ]; then echo "🚨 ALERT: Unknown containers running!" >> $LOG echo "$UNKNOWN_CONTAINERS" >> $LOG fi echo "$(date) - Security check complete" >> $LOG ``` ### 3.3 Cron Setup ```bash # /etc/cron.d/security # Security checks 0 * * * * root /opt/scripts/security-check.sh */15 * * * * root /opt/scripts/monitor-docker.sh # Daily scans 0 3 * * * root rkhunter --update && rkhunter --check --skip-keypress 0 4 * * * root chkrootkit > /var/log/chkrootkit.log 0 5 * * * root lynis audit system --quiet # Weekly 0 2 * * 0 root aide --check > /var/log/aide-weekly.log ``` --- ## 🌐 Рівень 4: Network Security ### 4.1 Docker Network Isolation ```yaml # docker-compose.yml networks: frontend: driver: bridge internal: false # Can access internet backend: driver: bridge internal: true # No internet access! database: driver: bridge internal: true # No internet access! services: nginx: networks: - frontend router: networks: - frontend - backend postgres: networks: - database # Only database network! ``` ### 4.2 Egress Filtering ```bash #!/bin/bash # /opt/scripts/setup-egress-firewall.sh # Default deny outgoing iptables -P OUTPUT DROP # Allow established connections iptables -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow loopback iptables -A OUTPUT -o lo -j ACCEPT # Allow DNS iptables -A OUTPUT -p udp --dport 53 -j ACCEPT # Allow HTTPS (for updates, API calls) iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT # Allow HTTP (for Let's Encrypt) iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT # Allow NTP iptables -A OUTPUT -p udp --dport 123 -j ACCEPT # Block internal networks (Hetzner) iptables -A OUTPUT -d 10.0.0.0/8 -j DROP iptables -A OUTPUT -d 172.16.0.0/12 -j DROP # Log dropped packets iptables -A OUTPUT -j LOG --log-prefix "DROPPED_EGRESS: " # Save iptables-save > /etc/iptables/rules.v4 ``` ### 4.3 Mining Pool Blocking ```bash # /etc/hosts.deny additions # Block known mining pools 0.0.0.0 pool.minexmr.com 0.0.0.0 xmr.pool.minergate.com 0.0.0.0 xmrpool.eu 0.0.0.0 pool.supportxmr.com 0.0.0.0 xmr-eu1.nanopool.org 0.0.0.0 xmr-eu2.nanopool.org 0.0.0.0 xmr.2miners.com 0.0.0.0 pool.hashvault.pro ``` --- ## 📊 Рівень 5: Monitoring & Detection ### 5.1 Real-time Process Monitoring ```python #!/usr/bin/env python3 # /opt/scripts/process-monitor.py import psutil import time import subprocess import smtplib from email.mime.text import MIMEText SUSPICIOUS_NAMES = [ 'xmrig', 'kdevtmp', 'kinsing', 'perfctl', 'httpd', 'softirq', 'vrarhpb', 'cpioshuf', 'ipcalc', 'mysql' ] ALERT_EMAIL = "admin@daarion.city" CPU_THRESHOLD = 80 # Alert if process uses >80% CPU def send_alert(subject, body): """Send email alert""" # Implement email sending print(f"ALERT: {subject}\n{body}") def check_processes(): """Check for suspicious processes""" for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'cmdline']): try: name = proc.info['name'].lower() cmdline = ' '.join(proc.info['cmdline'] or []).lower() cpu = proc.info['cpu_percent'] # Check suspicious names for suspicious in SUSPICIOUS_NAMES: if suspicious in name or suspicious in cmdline: send_alert( f"🚨 Suspicious process: {name}", f"PID: {proc.info['pid']}\nCPU: {cpu}%\nCmd: {cmdline}" ) # Kill it proc.kill() return # Check high CPU if cpu > CPU_THRESHOLD: send_alert( f"⚠️ High CPU process: {name}", f"PID: {proc.info['pid']}\nCPU: {cpu}%" ) except (psutil.NoSuchProcess, psutil.AccessDenied): pass def check_network(): """Check for suspicious network connections""" connections = psutil.net_connections() for conn in connections: if conn.status == 'ESTABLISHED': # Check for mining pool ports if conn.raddr and conn.raddr.port in [3333, 4444, 5555, 8080, 8888]: send_alert( f"🚨 Suspicious connection to port {conn.raddr.port}", f"Remote: {conn.raddr}\nPID: {conn.pid}" ) if __name__ == "__main__": while True: check_processes() check_network() time.sleep(10) # Check every 10 seconds ``` ### 5.2 Docker Event Monitoring ```bash #!/bin/bash # /opt/scripts/monitor-docker.sh # Monitor Docker events in real-time docker events --filter 'type=container' --format '{{.Time}} {{.Action}} {{.Actor.Attributes.name}}' | while read event; do echo "$event" >> /var/log/docker-events.log # Alert on suspicious events if echo "$event" | grep -qE "(start|create)"; then CONTAINER=$(echo "$event" | awk '{print $3}') # Check if container is in allowlist if ! grep -q "$CONTAINER" /opt/config/allowed-containers.txt; then echo "🚨 Unknown container started: $CONTAINER" | mail -s "NODE1 ALERT" admin@daarion.city fi fi done ``` ### 5.3 Prometheus Alerts ```yaml # /opt/prometheus/alerts.yml groups: - name: security rules: - alert: HighCPUUsage expr: node_cpu_seconds_total{mode="idle"} < 20 for: 5m labels: severity: warning annotations: summary: "High CPU usage detected" - alert: SuspiciousProcess expr: process_cpu_seconds_total{process=~"xmrig|kdevtmp|perfctl"} > 0 for: 1m labels: severity: critical annotations: summary: "Suspicious process detected" - alert: UnauthorizedContainer expr: container_last_seen{name!~"dagi-.*|postgres|redis|neo4j"} > 0 for: 1m labels: severity: critical annotations: summary: "Unauthorized container running" ``` --- ## 🚨 Рівень 6: Incident Response ### 6.1 Automated Response Script ```bash #!/bin/bash # /opt/scripts/incident-response.sh # Автоматична реакція на інцидент set -e LOG="/var/log/incident-response.log" BACKUP_DIR="/opt/backups/incident-$(date +%Y%m%d_%H%M%S)" echo "$(date) - INCIDENT RESPONSE STARTED" >> $LOG # 1. Зберегти стан для форензики mkdir -p $BACKUP_DIR ps aux > $BACKUP_DIR/processes.txt netstat -tulpn > $BACKUP_DIR/network.txt docker ps -a > $BACKUP_DIR/containers.txt docker images > $BACKUP_DIR/images.txt iptables -L -n > $BACKUP_DIR/iptables.txt cat /etc/crontab > $BACKUP_DIR/crontab.txt ls -la /tmp > $BACKUP_DIR/tmp.txt # 2. Kill suspicious processes pkill -9 -f "xmrig|kdevtmp|kinsing|perfctl|httpd.*tmp" # 3. Stop all non-essential containers docker stop $(docker ps -q --filter "name!=dagi-router" --filter "name!=dagi-gateway") # 4. Block all outgoing traffic except SSH iptables -P OUTPUT DROP iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT iptables -A OUTPUT -m state --state ESTABLISHED -j ACCEPT # 5. Clean /tmp find /tmp -type f -executable -delete rm -rf /tmp/.perf.c /tmp/httpd /tmp/mysql # 6. Alert echo "INCIDENT RESPONSE COMPLETED at $(date)" | mail -s "🚨 NODE1 INCIDENT" admin@daarion.city echo "$(date) - INCIDENT RESPONSE COMPLETED" >> $LOG echo "Backup saved to: $BACKUP_DIR" >> $LOG ``` ### 6.2 Recovery Playbook ```markdown ## 🔄 Recovery Playbook ### Крок 1: Ізоляція (0-5 хвилин) 1. Запустити incident-response.sh 2. Відключити від мережі (якщо критично) 3. Зберегти докази ### Крок 2: Аналіз (5-30 хвилин) 1. Переглянути логи: /var/log/security-check.log 2. Перевірити processes.txt 3. Ідентифікувати вектор атаки ### Крок 3: Очищення (30-60 хвилин) 1. Видалити compromised containers + images 2. Очистити persistence mechanisms 3. Перевірити cron, systemd, /etc/ld.so.preload ### Крок 4: Відновлення (1-2 години) 1. Rebuild з чистих images 2. Restore з backup (якщо потрібно) 3. Перевірити функціональність ### Крок 5: Post-mortem (24 години) 1. Документувати інцидент 2. Оновити захист 3. Ротувати секрети ``` --- ## ✅ Чеклист впровадження ### Негайно (сьогодні): - [ ] Встановити Trivy на NODE1 - [ ] Створити security-check.sh - [ ] Налаштувати cron для перевірок - [ ] Оновити docker-compose.yml з security options - [ ] Налаштувати egress firewall ### Цього тижня: - [ ] Впровадити image pinning by SHA - [ ] Налаштувати fail2ban - [ ] Встановити rkhunter, chkrootkit - [ ] Налаштувати auditd - [ ] Створити process-monitor.py ### Цього місяця: - [ ] Впровадити network isolation - [ ] Налаштувати Prometheus alerts - [ ] Створити custom secure base images - [ ] Документувати всі процедури - [ ] Провести security audit --- ## 📚 Додаткові ресурси - [Docker Security Best Practices](https://docs.docker.com/engine/security/) - [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker) - [Trivy Documentation](https://aquasecurity.github.io/trivy/) - [Falco Runtime Security](https://falco.org/) - [OWASP Container Security](https://owasp.org/www-project-container-security/) --- **Автор:** Ivan Tytar & AI Assistant **Останнє оновлення:** 2026-01-10