📚 docs(security): Add comprehensive Security chapter
## New Security Documentation Structure
/security/
├── README.md # Security overview & contacts
├── forensics-checklist.md # Incident investigation guide
├── persistence-scan.sh # Quick persistence detector
├── runtime-detector.sh # Mining/suspicious process detector
└── hardening/
├── docker.md # Docker security baseline
├── kubernetes.md # K8s policies (future reference)
└── cloud.md # Hetzner-specific hardening
## Key Components
### Forensics Checklist
- Process analysis commands
- Persistence mechanism detection
- Network connection analysis
- File system inspection
- Authentication audit
- Decision matrix for threat response
### Scripts
- persistence-scan.sh: Cron, systemd, executables, SSH keys
- runtime-detector.sh: Mining process detection with --kill option
### Hardening Guides
- Docker: Secure compose template, Dockerfile best practices
- Kubernetes: NetworkPolicy, PodSecurityStandard, Falco rules
- Cloud: Egress firewall, SSH hardening, fail2ban, monitoring
## Post-Incident Documentation
Based on lessons learned from Incidents #1 and #2 (Jan 2026)
Co-authored-by: Cursor Agent <agent@cursor.sh>
This commit is contained in:
310
security/hardening/cloud.md
Normal file
310
security/hardening/cloud.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# ☁️ Cloud Security Hardening — Hetzner
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Provider:** Hetzner Dedicated (GEX44)
|
||||
**Server:** NODE1 (144.76.224.179)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Критичні налаштування
|
||||
|
||||
### 1. Egress Firewall (№1 Priority)
|
||||
|
||||
**Блокування внутрішніх мереж Hetzner:**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /root/firewall-egress.sh
|
||||
|
||||
# Block Hetzner internal networks (prevent scanning)
|
||||
iptables -I OUTPUT -d 10.0.0.0/8 -j DROP
|
||||
iptables -I OUTPUT -d 172.16.0.0/12 -j DROP
|
||||
iptables -I OUTPUT -d 192.168.0.0/16 -j DROP
|
||||
|
||||
# Allow necessary internal traffic
|
||||
iptables -I OUTPUT -d 10.0.0.0/8 -p tcp --dport 443 -j ACCEPT
|
||||
iptables -I OUTPUT -d 10.0.0.0/8 -p tcp --dport 80 -j ACCEPT
|
||||
|
||||
# Log blocked attempts
|
||||
iptables -I OUTPUT -d 10.0.0.0/8 -j LOG --log-prefix "BLOCKED_INTERNAL: "
|
||||
|
||||
# Block known mining pool ports
|
||||
MINING_PORTS="3333 5555 7777 14433 45700 45560 14444 9999"
|
||||
for port in $MINING_PORTS; do
|
||||
iptables -A OUTPUT -p tcp --dport $port -j DROP
|
||||
iptables -A OUTPUT -p tcp --dport $port -j LOG --log-prefix "BLOCKED_MINING: "
|
||||
done
|
||||
|
||||
# Save rules
|
||||
iptables-save > /etc/iptables/rules.v4
|
||||
```
|
||||
|
||||
### 2. SSH Hardening
|
||||
|
||||
```bash
|
||||
# /etc/ssh/sshd_config
|
||||
|
||||
# Disable root login with password
|
||||
PermitRootLogin prohibit-password
|
||||
|
||||
# Use only SSH keys
|
||||
PasswordAuthentication no
|
||||
PubkeyAuthentication yes
|
||||
|
||||
# Limit authentication attempts
|
||||
MaxAuthTries 3
|
||||
MaxSessions 5
|
||||
|
||||
# Idle timeout
|
||||
ClientAliveInterval 300
|
||||
ClientAliveCountMax 2
|
||||
|
||||
# Disable unused features
|
||||
X11Forwarding no
|
||||
AllowAgentForwarding no
|
||||
AllowTcpForwarding no
|
||||
|
||||
# Allow only specific users
|
||||
AllowUsers root
|
||||
|
||||
# Use strong ciphers
|
||||
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
|
||||
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
|
||||
```
|
||||
|
||||
### 3. Fail2ban Configuration
|
||||
|
||||
```ini
|
||||
# /etc/fail2ban/jail.local
|
||||
|
||||
[DEFAULT]
|
||||
bantime = 3600
|
||||
findtime = 600
|
||||
maxretry = 3
|
||||
|
||||
[sshd]
|
||||
enabled = true
|
||||
port = ssh
|
||||
filter = sshd
|
||||
logpath = /var/log/auth.log
|
||||
maxretry = 3
|
||||
bantime = 86400
|
||||
|
||||
[docker-abuse]
|
||||
enabled = true
|
||||
filter = docker-abuse
|
||||
logpath = /var/log/syslog
|
||||
maxretry = 5
|
||||
bantime = 3600
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Network Security
|
||||
|
||||
### UFW Configuration
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /root/setup-ufw.sh
|
||||
|
||||
# Reset UFW
|
||||
ufw --force reset
|
||||
|
||||
# Default policies
|
||||
ufw default deny incoming
|
||||
ufw default deny outgoing
|
||||
|
||||
# Allow SSH (from specific IPs if possible)
|
||||
ufw allow in 22/tcp
|
||||
|
||||
# Allow HTTP/HTTPS
|
||||
ufw allow in 80/tcp
|
||||
ufw allow in 443/tcp
|
||||
|
||||
# Allow outbound DNS
|
||||
ufw allow out 53/tcp
|
||||
ufw allow out 53/udp
|
||||
|
||||
# Allow outbound HTTP/HTTPS
|
||||
ufw allow out 80/tcp
|
||||
ufw allow out 443/tcp
|
||||
|
||||
# Allow outbound to Docker registry
|
||||
ufw allow out to any port 443 proto tcp
|
||||
|
||||
# Block mining pools (additional layer)
|
||||
# Add rules from firewall-egress.sh
|
||||
|
||||
# Enable UFW
|
||||
ufw --force enable
|
||||
```
|
||||
|
||||
### Port Exposure Rules
|
||||
|
||||
| Port | Service | Binding | Notes |
|
||||
|------|---------|---------|-------|
|
||||
| 22 | SSH | 0.0.0.0 | With fail2ban |
|
||||
| 80 | Nginx | 0.0.0.0 | Redirect to 443 |
|
||||
| 443 | Nginx | 0.0.0.0 | HTTPS only |
|
||||
| 3000 | daarion-web | 127.0.0.1 | Via Nginx |
|
||||
| 9102 | Router | 127.0.0.1 | Internal |
|
||||
| 9300 | Gateway | 127.0.0.1 | Via Nginx |
|
||||
| * | Other services | 127.0.0.1 | Never public |
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring
|
||||
|
||||
### System Monitoring Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /root/security-monitor.sh
|
||||
# Run via cron every 5 minutes
|
||||
|
||||
LOG_FILE="/var/log/security-monitor.log"
|
||||
ALERT_THRESHOLD_CPU=80
|
||||
ALERT_THRESHOLD_LOAD=10
|
||||
|
||||
timestamp() {
|
||||
date '+%Y-%m-%d %H:%M:%S'
|
||||
}
|
||||
|
||||
# Check load average
|
||||
LOAD=$(cat /proc/loadavg | awk '{print $1}')
|
||||
LOAD_INT=${LOAD%.*}
|
||||
|
||||
if [ "$LOAD_INT" -gt "$ALERT_THRESHOLD_LOAD" ]; then
|
||||
echo "[$(timestamp)] ALERT: High load average: $LOAD" >> $LOG_FILE
|
||||
# Send alert (implement your notification)
|
||||
fi
|
||||
|
||||
# Check for mining processes
|
||||
MINING=$(ps aux | grep -iE "xmrig|catcal|softirq|vrarhpb|miner" | grep -v grep)
|
||||
if [ -n "$MINING" ]; then
|
||||
echo "[$(timestamp)] CRITICAL: Mining process detected!" >> $LOG_FILE
|
||||
echo "$MINING" >> $LOG_FILE
|
||||
# Kill the process
|
||||
echo "$MINING" | awk '{print $2}' | xargs -r kill -9
|
||||
fi
|
||||
|
||||
# Check outbound connections to mining ports
|
||||
MINING_CONN=$(ss -antp | grep -E ":(3333|5555|7777|14433)")
|
||||
if [ -n "$MINING_CONN" ]; then
|
||||
echo "[$(timestamp)] CRITICAL: Mining pool connection!" >> $LOG_FILE
|
||||
echo "$MINING_CONN" >> $LOG_FILE
|
||||
fi
|
||||
|
||||
# Check Docker containers CPU
|
||||
docker stats --no-stream --format "{{.Name}}: {{.CPUPerc}}" | while read line; do
|
||||
CPU=$(echo "$line" | grep -oE '[0-9]+' | head -1)
|
||||
if [ -n "$CPU" ] && [ "$CPU" -gt "$ALERT_THRESHOLD_CPU" ]; then
|
||||
echo "[$(timestamp)] WARNING: High CPU container: $line" >> $LOG_FILE
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Cron Setup
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/security-monitor
|
||||
|
||||
# Run security monitor every 5 minutes
|
||||
*/5 * * * * root /root/security-monitor.sh
|
||||
|
||||
# Run persistence scan daily
|
||||
0 3 * * * root /opt/microdao-daarion/security/persistence-scan.sh >> /var/log/persistence-scan.log 2>&1
|
||||
|
||||
# Log rotation
|
||||
0 0 * * * root find /var/log -name "*.log" -mtime +30 -delete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Incident Response (Hetzner)
|
||||
|
||||
### При отриманні Abuse Report:
|
||||
|
||||
1. **Негайно:**
|
||||
```bash
|
||||
# Заблокувати весь вихідний трафік
|
||||
iptables -I OUTPUT -j DROP
|
||||
|
||||
# Зберегти стан для аналізу
|
||||
ps auxf > /root/incident/ps_$(date +%s).txt
|
||||
ss -antp > /root/incident/ss_$(date +%s).txt
|
||||
docker ps -a > /root/incident/docker_$(date +%s).txt
|
||||
```
|
||||
|
||||
2. **Знайти джерело:**
|
||||
```bash
|
||||
# Запустити forensics
|
||||
/opt/microdao-daarion/security/persistence-scan.sh
|
||||
/opt/microdao-daarion/security/runtime-detector.sh
|
||||
```
|
||||
|
||||
3. **Усунути загрозу:**
|
||||
```bash
|
||||
# Kill процеси
|
||||
killall -9 <process_name>
|
||||
|
||||
# Видалити контейнер ТА образ
|
||||
docker stop <container>
|
||||
docker rm <container>
|
||||
docker rmi <image> # КРИТИЧНО!
|
||||
```
|
||||
|
||||
4. **Відповісти Hetzner:**
|
||||
- URL: https://statement-abuse.hetzner.com/statements/?token=<token>
|
||||
- Описати причину та вжиті заходи
|
||||
- Зареєструвати retry test
|
||||
|
||||
5. **Задокументувати:**
|
||||
- Оновити INFRASTRUCTURE.md
|
||||
- Створити incident report
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Secrets Management
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# /opt/microdao-daarion/.env
|
||||
|
||||
# NEVER commit to git!
|
||||
# Use .env.example as template
|
||||
|
||||
# Generate secure passwords
|
||||
openssl rand -base64 32
|
||||
|
||||
# Store secrets securely
|
||||
chmod 600 .env
|
||||
chown root:root .env
|
||||
```
|
||||
|
||||
### SSH Keys
|
||||
|
||||
```bash
|
||||
# Generate strong SSH key
|
||||
ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519
|
||||
|
||||
# Rotate keys periodically
|
||||
# Keep backup of old keys until rotation complete
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Hetzner Security Checklist
|
||||
|
||||
- [ ] Egress firewall blocking internal networks
|
||||
- [ ] Mining pool ports blocked
|
||||
- [ ] SSH hardened (key-only, fail2ban)
|
||||
- [ ] UFW configured (deny by default)
|
||||
- [ ] All services bound to 127.0.0.1 except Nginx
|
||||
- [ ] Security monitoring cron active
|
||||
- [ ] Log rotation configured
|
||||
- [ ] .env file secured (chmod 600)
|
||||
- [ ] Rescue mode access documented
|
||||
- [ ] Hetzner Robot access secured
|
||||
310
security/hardening/docker.md
Normal file
310
security/hardening/docker.md
Normal file
@@ -0,0 +1,310 @@
|
||||
# 🐳 Docker Security Hardening — DAARION
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Принцип:** Майнінг можливий тільки там, де дозволений **outbound + CPU без контролю**
|
||||
|
||||
---
|
||||
|
||||
## 📋 Security Checklist
|
||||
|
||||
### Must-Have (Обов'язково)
|
||||
|
||||
| Налаштування | docker-compose | Пояснення |
|
||||
|--------------|----------------|-----------|
|
||||
| Read-only filesystem | `read_only: true` | Запобігає запису malware |
|
||||
| Drop capabilities | `cap_drop: [ALL]` | Мінімальні привілеї |
|
||||
| No new privileges | `security_opt: [no-new-privileges:true]` | Блокує privilege escalation |
|
||||
| CPU limit | `cpus: '1.0'` | Обмежує crypto mining |
|
||||
| Memory limit | `memory: 512M` | Запобігає DoS |
|
||||
| Non-root user | `user: "1001:1001"` | Не root в контейнері |
|
||||
| No privileged | `privileged: false` | Завжди! |
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Secure docker-compose Template
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
secure-service:
|
||||
image: your-image:tag
|
||||
container_name: secure-service
|
||||
|
||||
# ============================================
|
||||
# SECURITY HARDENING
|
||||
# ============================================
|
||||
|
||||
# 1. Restart policy (use "no" until verified)
|
||||
restart: "no" # Change to "unless-stopped" after verification
|
||||
|
||||
# 2. Network binding (localhost only for internal services)
|
||||
ports:
|
||||
- "127.0.0.1:8080:8080"
|
||||
|
||||
# 3. Read-only root filesystem
|
||||
read_only: true
|
||||
|
||||
# 4. Temporary filesystems (for apps that need write)
|
||||
tmpfs:
|
||||
- /tmp:size=64M,mode=1777
|
||||
- /app/cache:size=128M,mode=1777
|
||||
|
||||
# 5. Drop ALL capabilities
|
||||
cap_drop:
|
||||
- ALL
|
||||
|
||||
# 6. Add only what's needed (rarely needed)
|
||||
# cap_add:
|
||||
# - NET_BIND_SERVICE # Only if port < 1024
|
||||
|
||||
# 7. Security options
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# 8. Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 128M
|
||||
|
||||
# 9. Process limits
|
||||
pids_limit: 100
|
||||
|
||||
# 10. Disable privileged mode
|
||||
privileged: false
|
||||
|
||||
# 11. Non-root user
|
||||
user: "1001:1001"
|
||||
|
||||
# 12. Health check
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
|
||||
# 13. Logging limits
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# 14. Labels for audit
|
||||
labels:
|
||||
- "security.hardened=true"
|
||||
- "security.reviewed=2026-01-09"
|
||||
|
||||
networks:
|
||||
default:
|
||||
driver: bridge
|
||||
driver_opts:
|
||||
com.docker.network.bridge.enable_icc: "false" # Disable inter-container communication
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Secure Dockerfile Template
|
||||
|
||||
```dockerfile
|
||||
# ============================================
|
||||
# Stage 1: Builder
|
||||
# ============================================
|
||||
FROM node:20-alpine AS builder
|
||||
WORKDIR /app
|
||||
|
||||
# Copy only package files first (cache optimization)
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production --ignore-scripts
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# ============================================
|
||||
# Stage 2: Production (minimal)
|
||||
# ============================================
|
||||
FROM node:20-alpine AS production
|
||||
|
||||
# Security: Create non-root user
|
||||
RUN addgroup -g 1001 -S appgroup && \
|
||||
adduser -u 1001 -S appuser -G appgroup
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Security: Remove unnecessary tools
|
||||
RUN apk del --purge wget curl busybox-extras && \
|
||||
rm -rf /var/cache/apk/* /tmp/* /var/tmp/*
|
||||
|
||||
# Copy from builder
|
||||
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
|
||||
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
|
||||
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
|
||||
|
||||
# Security: Restrictive permissions
|
||||
RUN chmod -R 500 /app && \
|
||||
chmod 400 /app/package.json
|
||||
|
||||
# Switch to non-root
|
||||
USER appuser
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
|
||||
CMD node -e "require('http').get('http://localhost:8080/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["node", "dist/server.js"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚫 Anti-Patterns (НЕ робіть)
|
||||
|
||||
```yaml
|
||||
# ❌ NEVER DO THIS:
|
||||
|
||||
services:
|
||||
insecure:
|
||||
privileged: true # ❌ Full host access
|
||||
|
||||
ports:
|
||||
- "8080:8080" # ❌ Binds to 0.0.0.0 (public)
|
||||
|
||||
volumes:
|
||||
- /:/host # ❌ Full host filesystem
|
||||
- /var/run/docker.sock:/var/run/docker.sock # ❌ Docker escape
|
||||
|
||||
cap_add:
|
||||
- SYS_ADMIN # ❌ Too powerful
|
||||
- NET_ADMIN # ❌ Network manipulation
|
||||
|
||||
restart: unless-stopped # ❌ Without verification
|
||||
|
||||
# No resource limits # ❌ Crypto mining possible
|
||||
# No read_only # ❌ Malware can persist
|
||||
# No user specification # ❌ Runs as root
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Security Scanning
|
||||
|
||||
### Pre-deployment scan
|
||||
|
||||
```bash
|
||||
# Install Trivy
|
||||
brew install trivy # macOS
|
||||
apt install trivy # Ubuntu
|
||||
|
||||
# Scan image for vulnerabilities
|
||||
trivy image --severity HIGH,CRITICAL your-image:tag
|
||||
|
||||
# Scan with detailed output
|
||||
trivy image --format json -o scan-report.json your-image:tag
|
||||
|
||||
# Scan Dockerfile
|
||||
trivy config Dockerfile
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security-scan.yml
|
||||
name: Security Scan
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
scan:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Build image
|
||||
run: docker build -t app:${{ github.sha }} .
|
||||
|
||||
- name: Run Trivy scan
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
image-ref: 'app:${{ github.sha }}'
|
||||
format: 'table'
|
||||
exit-code: '1'
|
||||
severity: 'HIGH,CRITICAL'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Runtime Monitoring
|
||||
|
||||
### Container inspection
|
||||
|
||||
```bash
|
||||
# Check container security settings
|
||||
docker inspect --format='
|
||||
Privileged: {{.HostConfig.Privileged}}
|
||||
ReadonlyRootfs: {{.HostConfig.ReadonlyRootfs}}
|
||||
User: {{.Config.User}}
|
||||
CapDrop: {{.HostConfig.CapDrop}}
|
||||
CapAdd: {{.HostConfig.CapAdd}}
|
||||
' container_name
|
||||
```
|
||||
|
||||
### Resource monitoring
|
||||
|
||||
```bash
|
||||
# Real-time stats
|
||||
docker stats container_name
|
||||
|
||||
# CPU limit check
|
||||
docker inspect --format='{{.HostConfig.NanoCpus}}' container_name
|
||||
|
||||
# Memory limit check
|
||||
docker inspect --format='{{.HostConfig.Memory}}' container_name
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📝 DAARION-specific Rules
|
||||
|
||||
### Services that MUST have hardening:
|
||||
|
||||
| Service | Priority | Notes |
|
||||
|---------|----------|-------|
|
||||
| daarion-web | 🔴 Critical | Post-incident, see Dockerfile.secure |
|
||||
| dagi-gateway | 🔴 Critical | Public-facing |
|
||||
| dagi-router | 🟡 High | Core routing |
|
||||
| All others | 🟡 High | Apply baseline |
|
||||
|
||||
### Network rules:
|
||||
|
||||
```yaml
|
||||
# Internal services: bind to localhost
|
||||
ports:
|
||||
- "127.0.0.1:PORT:PORT"
|
||||
|
||||
# Public services: use Nginx reverse proxy
|
||||
# Never expose directly to 0.0.0.0
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ Verification Checklist
|
||||
|
||||
Before deploying any container:
|
||||
|
||||
- [ ] Image scanned with Trivy (no HIGH/CRITICAL)
|
||||
- [ ] `read_only: true` set
|
||||
- [ ] `cap_drop: [ALL]` set
|
||||
- [ ] `security_opt: [no-new-privileges:true]` set
|
||||
- [ ] CPU/memory limits set
|
||||
- [ ] Non-root user configured
|
||||
- [ ] Health check defined
|
||||
- [ ] Restart policy is "no" for new deployments
|
||||
- [ ] Port bound to 127.0.0.1 (unless public)
|
||||
- [ ] No privileged mode
|
||||
- [ ] No dangerous volume mounts
|
||||
316
security/hardening/kubernetes.md
Normal file
316
security/hardening/kubernetes.md
Normal file
@@ -0,0 +1,316 @@
|
||||
# ☸️ Kubernetes Security Hardening — DAARION
|
||||
|
||||
**Версія:** 1.0.0
|
||||
**Статус:** Reference (для майбутньої K8s міграції)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Критичні налаштування
|
||||
|
||||
### 1. NetworkPolicy (Egress deny-by-default)
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-egress
|
||||
namespace: daarion
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress: [] # Deny all outbound by default
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-dns-only
|
||||
namespace: daarion
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Egress
|
||||
egress:
|
||||
- to:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
name: kube-system
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
```
|
||||
|
||||
### 2. PodSecurityStandard: Restricted
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: daarion
|
||||
labels:
|
||||
pod-security.kubernetes.io/enforce: restricted
|
||||
pod-security.kubernetes.io/audit: restricted
|
||||
pod-security.kubernetes.io/warn: restricted
|
||||
```
|
||||
|
||||
### 3. Secure Pod Template
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: secure-pod
|
||||
namespace: daarion
|
||||
spec:
|
||||
# Security Context (Pod level)
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
runAsGroup: 1001
|
||||
fsGroup: 1001
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
# Service Account
|
||||
serviceAccountName: minimal-sa
|
||||
automountServiceAccountToken: false
|
||||
|
||||
containers:
|
||||
- name: app
|
||||
image: your-image:tag
|
||||
|
||||
# Security Context (Container level)
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1001
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
# Resource limits (CRITICAL for anti-mining)
|
||||
resources:
|
||||
requests:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
limits:
|
||||
cpu: "1000m" # Max 1 CPU
|
||||
memory: "512Mi"
|
||||
|
||||
# Liveness/Readiness probes
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: 8080
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /ready
|
||||
port: 8080
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
|
||||
# Volume mounts (if needed)
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: cache
|
||||
mountPath: /app/cache
|
||||
|
||||
# Temporary volumes
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir:
|
||||
sizeLimit: 64Mi
|
||||
- name: cache
|
||||
emptyDir:
|
||||
sizeLimit: 128Mi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Security Policies
|
||||
|
||||
### ResourceQuota (Namespace limits)
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ResourceQuota
|
||||
metadata:
|
||||
name: daarion-quota
|
||||
namespace: daarion
|
||||
spec:
|
||||
hard:
|
||||
requests.cpu: "10"
|
||||
requests.memory: 20Gi
|
||||
limits.cpu: "20"
|
||||
limits.memory: 40Gi
|
||||
pods: "50"
|
||||
```
|
||||
|
||||
### LimitRange (Default limits)
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: LimitRange
|
||||
metadata:
|
||||
name: daarion-limits
|
||||
namespace: daarion
|
||||
spec:
|
||||
limits:
|
||||
- type: Container
|
||||
default:
|
||||
cpu: "500m"
|
||||
memory: "256Mi"
|
||||
defaultRequest:
|
||||
cpu: "100m"
|
||||
memory: "128Mi"
|
||||
max:
|
||||
cpu: "2"
|
||||
memory: "1Gi"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Runtime Detection (Falco)
|
||||
|
||||
### Falco Rule: Crypto Mining Detection
|
||||
|
||||
```yaml
|
||||
# falco-rules.yaml
|
||||
- rule: Detect Crypto Mining Process
|
||||
desc: Detect processes commonly used for cryptocurrency mining
|
||||
condition: >
|
||||
spawned_process and
|
||||
(proc.name in (xmrig, minerd, cpuminer, cgminer, bfgminer, ethminer,
|
||||
catcal, softirq, vrarhpb, G4NQXBp) or
|
||||
proc.cmdline contains "stratum+" or
|
||||
proc.cmdline contains "pool" or
|
||||
proc.cmdline contains "cryptonight")
|
||||
output: >
|
||||
Crypto mining process detected
|
||||
(user=%user.name command=%proc.cmdline container=%container.name
|
||||
image=%container.image.repository)
|
||||
priority: CRITICAL
|
||||
tags: [cryptomining, mitre_execution]
|
||||
|
||||
- rule: Detect Connection to Mining Pool
|
||||
desc: Detect outbound connections to known mining pool ports
|
||||
condition: >
|
||||
outbound and
|
||||
(fd.sport in (3333, 5555, 7777, 14433, 45700, 45560, 14444, 9999))
|
||||
output: >
|
||||
Connection to potential mining pool
|
||||
(user=%user.name command=%proc.cmdline connection=%fd.name
|
||||
container=%container.name)
|
||||
priority: CRITICAL
|
||||
tags: [cryptomining, network]
|
||||
|
||||
- rule: High CPU in Container
|
||||
desc: Detect containers with sustained high CPU usage
|
||||
condition: >
|
||||
container and
|
||||
container.cpu.usage > 80
|
||||
output: >
|
||||
High CPU usage in container
|
||||
(container=%container.name cpu=%container.cpu.usage%)
|
||||
priority: WARNING
|
||||
tags: [performance, cryptomining]
|
||||
```
|
||||
|
||||
### Falco Deployment
|
||||
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: falco
|
||||
namespace: falco
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: falco
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: falco
|
||||
spec:
|
||||
serviceAccountName: falco
|
||||
containers:
|
||||
- name: falco
|
||||
image: falcosecurity/falco:latest
|
||||
securityContext:
|
||||
privileged: true
|
||||
volumeMounts:
|
||||
- name: proc
|
||||
mountPath: /host/proc
|
||||
readOnly: true
|
||||
- name: rules
|
||||
mountPath: /etc/falco/rules.d
|
||||
volumes:
|
||||
- name: proc
|
||||
hostPath:
|
||||
path: /proc
|
||||
- name: rules
|
||||
configMap:
|
||||
name: falco-rules
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitoring & Alerting
|
||||
|
||||
### Prometheus Rules
|
||||
|
||||
```yaml
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: PrometheusRule
|
||||
metadata:
|
||||
name: daarion-security-rules
|
||||
namespace: monitoring
|
||||
spec:
|
||||
groups:
|
||||
- name: security
|
||||
rules:
|
||||
- alert: HighCPUUsage
|
||||
expr: >
|
||||
sum(rate(container_cpu_usage_seconds_total{namespace="daarion"}[5m]))
|
||||
by (pod) > 0.8
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High CPU usage in pod {{ $labels.pod }}"
|
||||
|
||||
- alert: UnauthorizedNetworkConnection
|
||||
expr: >
|
||||
increase(falco_events_total{rule=~".*mining.*"}[5m]) > 0
|
||||
for: 1m
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Potential crypto mining detected"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ K8s Security Checklist
|
||||
|
||||
Before deploying to Kubernetes:
|
||||
|
||||
- [ ] Namespace has PodSecurityStandard: restricted
|
||||
- [ ] NetworkPolicy: deny egress by default
|
||||
- [ ] All pods have resource limits
|
||||
- [ ] All pods run as non-root
|
||||
- [ ] All pods have readOnlyRootFilesystem
|
||||
- [ ] All pods drop ALL capabilities
|
||||
- [ ] seccompProfile: RuntimeDefault
|
||||
- [ ] No privileged containers
|
||||
- [ ] ServiceAccount tokens not auto-mounted
|
||||
- [ ] Falco or similar runtime detection deployed
|
||||
- [ ] Resource quotas set on namespace
|
||||
Reference in New Issue
Block a user