- 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
196 lines
5.1 KiB
YAML
196 lines
5.1 KiB
YAML
# ============================================================
|
||
# docker-compose.secure.yml — Secure Docker Compose Template
|
||
# ============================================================
|
||
# Використовуйте цей шаблон як базу для всіх сервісів
|
||
# ============================================================
|
||
|
||
version: '3.8'
|
||
|
||
# Ізольовані мережі
|
||
networks:
|
||
frontend:
|
||
driver: bridge
|
||
# Доступ до інтернету (для nginx, gateway)
|
||
backend:
|
||
driver: bridge
|
||
internal: true # БЕЗ доступу до інтернету!
|
||
database:
|
||
driver: bridge
|
||
internal: true # БЕЗ доступу до інтернету!
|
||
|
||
services:
|
||
# ============================================================
|
||
# ПРИКЛАД: Безпечний PostgreSQL
|
||
# ============================================================
|
||
postgres:
|
||
# ✅ Завжди використовуйте digest, не тег!
|
||
image: postgres@sha256:ЗАМІНІТЬ_НА_ПЕРЕВІРЕНИЙ_DIGEST
|
||
container_name: dagi-postgres
|
||
|
||
# ⚠️ НІКОЛИ auto-restart для нових сервісів!
|
||
# Змініть на "unless-stopped" ТІЛЬКИ після верифікації
|
||
restart: "no"
|
||
|
||
# 🔒 Security options
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
|
||
# 📁 Read-only root filesystem
|
||
read_only: true
|
||
|
||
# 📂 Тимчасові директорії (noexec!)
|
||
tmpfs:
|
||
- /tmp:noexec,nosuid,nodev,size=100m
|
||
- /var/run/postgresql:noexec,nosuid,nodev,size=10m
|
||
|
||
# 💾 Volumes (тільки необхідні)
|
||
volumes:
|
||
- postgres_data:/var/lib/postgresql/data
|
||
|
||
# 🔧 Resource limits
|
||
deploy:
|
||
resources:
|
||
limits:
|
||
cpus: '2'
|
||
memory: 2G
|
||
reservations:
|
||
cpus: '0.5'
|
||
memory: 512M
|
||
|
||
# 🔓 Capabilities (мінімум!)
|
||
cap_drop:
|
||
- ALL
|
||
cap_add:
|
||
- CHOWN
|
||
- SETUID
|
||
- SETGID
|
||
- DAC_OVERRIDE
|
||
|
||
# ❌ No privileged mode!
|
||
privileged: false
|
||
|
||
# 🌐 Network (тільки database!)
|
||
networks:
|
||
- database
|
||
|
||
# 🔐 Environment
|
||
environment:
|
||
POSTGRES_USER: ${POSTGRES_USER}
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||
POSTGRES_DB: ${POSTGRES_DB}
|
||
|
||
# 🏥 Healthcheck
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
start_period: 30s
|
||
|
||
# ============================================================
|
||
# ПРИКЛАД: Безпечний Redis
|
||
# ============================================================
|
||
redis:
|
||
image: redis@sha256:ЗАМІНІТЬ_НА_ПЕРЕВІРЕНИЙ_DIGEST
|
||
container_name: dagi-redis
|
||
restart: "no"
|
||
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
|
||
read_only: true
|
||
|
||
tmpfs:
|
||
- /tmp:noexec,nosuid,nodev,size=50m
|
||
|
||
volumes:
|
||
- redis_data:/data
|
||
|
||
deploy:
|
||
resources:
|
||
limits:
|
||
cpus: '1'
|
||
memory: 512M
|
||
|
||
cap_drop:
|
||
- ALL
|
||
|
||
privileged: false
|
||
|
||
networks:
|
||
- database
|
||
|
||
healthcheck:
|
||
test: ["CMD", "redis-cli", "ping"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
|
||
# ============================================================
|
||
# ПРИКЛАД: Безпечний Router (з доступом до мережі)
|
||
# ============================================================
|
||
router:
|
||
image: ghcr.io/daarion-dao/dagi-router@sha256:ЗАМІНІТЬ
|
||
container_name: dagi-router
|
||
restart: "no"
|
||
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
|
||
# Router потребує запис для логів
|
||
read_only: false
|
||
|
||
tmpfs:
|
||
- /tmp:noexec,nosuid,nodev,size=100m
|
||
|
||
deploy:
|
||
resources:
|
||
limits:
|
||
cpus: '2'
|
||
memory: 1G
|
||
|
||
cap_drop:
|
||
- ALL
|
||
cap_add:
|
||
- NET_BIND_SERVICE
|
||
|
||
privileged: false
|
||
|
||
# Router має доступ до frontend і backend
|
||
networks:
|
||
- frontend
|
||
- backend
|
||
|
||
ports:
|
||
- "9102:9102"
|
||
|
||
healthcheck:
|
||
test: ["CMD", "curl", "-f", "http://localhost:9102/health"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
|
||
# ============================================================
|
||
# Volumes
|
||
# ============================================================
|
||
volumes:
|
||
postgres_data:
|
||
driver: local
|
||
redis_data:
|
||
driver: local
|
||
|
||
# ============================================================
|
||
# SECURITY CHECKLIST:
|
||
# ============================================================
|
||
# [ ] Всі images pinned by SHA256 digest
|
||
# [ ] restart: "no" для нових сервісів
|
||
# [ ] security_opt: no-new-privileges
|
||
# [ ] read_only: true де можливо
|
||
# [ ] tmpfs з noexec для /tmp
|
||
# [ ] Resource limits встановлені
|
||
# [ ] cap_drop: ALL + тільки необхідні cap_add
|
||
# [ ] privileged: false
|
||
# [ ] Мережі ізольовані (internal: true для backend/database)
|
||
# [ ] Healthcheck налаштований
|
||
# ============================================================
|