- Created SECURITY-HARDENING-PLAN.md with 6 security levels - Added setup-node1-security.sh for automated hardening - Added scan-image.sh for pre-deployment image scanning - Created docker-compose.secure.yml template - Includes: Trivy, fail2ban, UFW, auditd, rkhunter, chkrootkit - Network isolation, egress filtering, process monitoring - Incident response procedures and recovery playbook
18 KiB
18 KiB
🛡️ Security Hardening Plan — DAARION & MicroDAO
Версія: 1.0.0
Дата: 2026-01-10
Статус: В процесі впровадження
📋 Зміст
- Аналіз інцидентів
- Рівень 1: Image Security
- Рівень 2: Container Runtime Security
- Рівень 3: Host Security
- Рівень 4: Network Security
- Рівень 5: Monitoring & Detection
- Рівень 6: Incident Response
- Чеклист впровадження
📊 Аналіз інцидентів
Що пішло не так:
| Інцидент | Вектор атаки | Чому не виявили раніше |
|---|---|---|
| #1 | Вразливий daarion-web образ |
Не сканували образи |
| #2 | restart: unless-stopped |
Не видалили image, тільки container |
| #3 | Compromised postgres image | Довіряли Docker Hub без перевірки |
| #4 | Host persistence (perfctl) | Не перевіряли host на malware |
Ключові уроки:
- 🔴 Не довіряти жодному образу — навіть official
- 🟡 Сканувати ВСЕ — images, containers, host
- 🟢 Моніторити в реальному часі — CPU, network, processes
- 🔵 Мати план відновлення — швидкий rebuild з нуля
🔒 Рівень 1: Image Security
1.1 Image Scanning (Trivy)
# Встановлення 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
❌ НІКОЛИ:
image: postgres:16-alpine # Тег може змінитись!
✅ ЗАВЖДИ:
image: postgres@sha256:abc123... # Фіксований digest
1.3 Allowlist Registry
# /etc/docker/daemon.json
{
"allowed-registries": [
"docker.io/library",
"ghcr.io/daarion-dao"
]
}
1.4 Custom Base Images
Створити власні базові образи з мінімальним attack surface:
# 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
# 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
// seccomp-profile.json
{
"defaultAction": "SCCOMP_ACT_ERRNO",
"syscalls": [
{
"names": ["accept", "bind", "clone", "close", "connect", ...],
"action": "SCCOMP_ACT_ALLOW"
}
]
}
2.3 AppArmor Profile
# /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
#!/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
#!/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
# /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
# 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
#!/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
# /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
#!/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
#!/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
# /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
#!/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
## 🔄 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
- CIS Docker Benchmark
- Trivy Documentation
- Falco Runtime Security
- OWASP Container Security
Автор: Ivan Tytar & AI Assistant
Останнє оновлення: 2026-01-10