Security
SSL/TLS, firewall, container hardening, và các best practices bảo mật cho Docker deployment
SSL/TLS với Let's Encrypt
HTTPS là bắt buộc cho production. Let's Encrypt cung cấp SSL certificate miễn phí, tự động renew:
Cài đặt Certbot và lấy certificate
# Cài Certbot trên Ubuntu sudo apt install -y certbot # Tạm dừng Nginx container (Certbot cần port 80) docker compose stop nginx # Lấy certificate (standalone mode) sudo certbot certonly --standalone \ -d app.example.com \ --email admin@example.com \ --agree-tos --no-eff-email # Certificate được lưu tại: # /etc/letsencrypt/live/app.example.com/fullchain.pem # /etc/letsencrypt/live/app.example.com/privkey.pem # Copy vào thư mục project sudo cp /etc/letsencrypt/live/app.example.com/fullchain.pem ./nginx/ssl/ sudo cp /etc/letsencrypt/live/app.example.com/privkey.pem ./nginx/ssl/ sudo chown $USER:$USER ./nginx/ssl/*.pem # Khởi động lại Nginx docker compose start nginx
Auto-renew certificate
# Tạo script renew cat > /home/$USER/renew-ssl.sh << 'EOF' #!/bin/bash cd /home/$USER/my-app # Dừng Nginx, renew cert, copy, restart docker compose stop nginx certbot renew --quiet cp /etc/letsencrypt/live/app.example.com/fullchain.pem ./nginx/ssl/ cp /etc/letsencrypt/live/app.example.com/privkey.pem ./nginx/ssl/ docker compose start nginx EOF chmod +x /home/$USER/renew-ssl.sh # Cron job: chạy mỗi ngày lúc 3:00 AM (crontab -l; echo "0 3 * * * /home/$USER/renew-ssl.sh >> /var/log/ssl-renew.log 2>&1") | crontab -
Firewall (UFW)
Cấu hình UFW (Uncomplicated Firewall) để chỉ cho phép traffic cần thiết:
# Cho phép SSH (quan trọng! nếu quên sẽ bị lock out) sudo ufw allow 22/tcp # Cho phép HTTP và HTTPS sudo ufw allow 80/tcp sudo ufw allow 443/tcp # Bật firewall sudo ufw enable # Kiểm tra rules sudo ufw status verbose
-p hoặc ports: trong
compose), nó tạo iptables rules trực tiếp, bỏ qua UFW. Nghĩa là nếu bạn vô tình dùng
ports: "5432:5432" cho PostgreSQL, UFW không chặn được — port 5432 vẫn mở ra
internet.
Giải pháp: Hạn chế Docker iptables
# Tạo/sửa file /etc/docker/daemon.json sudo tee /etc/docker/daemon.json << 'EOF' { "iptables": false } EOF # Restart Docker daemon sudo systemctl restart docker # SAU KHI TẮT iptables, thêm rule NAT thủ công cho ports cần expose sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 172.17.0.2:80 sudo iptables -t nat -A PREROUTING -p tcp --dport 443 -j DNAT --to-destination 172.17.0.2:443
ports: cho bất kỳ service nào ngoài Nginx. Khi
chỉ Nginx expose ports, UFW chỉ cần quản lý port 80/443, và mọi service internal đều an toàn.
Container Hardening
Các best practices để giảm attack surface của containers:
Mặc định, processes trong container chạy với quyền root. Nếu attacker escape container, họ sẽ có root trên host.
# Tạo non-root user RUN adduser --disabled-password --gecos "" appuser USER appuser # Hoặc dùng numeric UID (không phụ thuộc /etc/passwd) USER 1001
Trong docker-compose, cũng có thể set:
backend: user: "1001:1001"
Ngăn attacker ghi malware hoặc modify binaries bên trong container:
frontend: read_only: true tmpfs: - /tmp # Cho phép ghi vào /tmp (nếu app cần) - /var/run # Nginx PID file
Container chỉ được ghi vào tmpfs (RAM-based, mất khi restart) và mounted volumes.
Linux capabilities cho phép fine-grained permissions. Drop tất cả và chỉ thêm những gì cần:
backend: cap_drop: - ALL # Drop tất cả capabilities cap_add: - NET_BIND_SERVICE # Chỉ thêm nếu cần bind port < 1024
Ngăn container sử dụng quá nhiều tài nguyên (DoS protection):
backend: deploy: resources: limits: cpus: "1.0" # Max 1 CPU core memory: 512M # Max 512 MB RAM reservations: cpus: "0.25" # Guaranteed 0.25 CPU memory: 128M # Guaranteed 128 MB RAM
Ngăn processes trong container leo thang quyền (privilege escalation):
backend: security_opt: - no-new-privileges:true
Flag này ngăn setuid, setgid, và các cơ chế leo quyền khác bên trong container.
Base Image Security
Chọn base image đúng giảm đáng kể attack surface:
Alpine-based
node:20-alpine(~50 MB vs ~350 MB)postgres:16-alpine(~80 MB vs ~430 MB)redis:7-alpine(~30 MB vs ~130 MB)- Ít packages = ít CVEs tiềm tàng
Best Practices
- Pin version cụ thể (không dùng
:latest) - Scan images:
docker scout cves myimage - Update base images định kỳ (monthly)
- Dùng official images từ Docker Hub
Security Checklist
Checklist nhanh trước khi đưa hệ thống lên production:
[Network] ✓ Chỉ Nginx expose ports ra ngoài (80/443) ✓ Database và Redis dùng internal network ✓ UFW chỉ mở port 22, 80, 443 ✓ Hiểu rằng Docker bypass UFW [SSL/TLS] ✓ HTTPS bật cho tất cả traffic ✓ HTTP redirect sang HTTPS ✓ SSL auto-renew đã cấu hình ✓ TLS 1.2+ only (disable TLS 1.0/1.1) [Containers] ✓ Chạy dưới non-root user ✓ Base images pinned version ✓ Resource limits đã set ✓ no-new-privileges enabled [Secrets] ✓ .env file có permission 600 ✓ .env nằm trong .gitignore ✓ Passwords đủ mạnh (16+ chars) ✓ JWT secret đủ dài (32+ chars) [Headers] ✓ X-Frame-Options: SAMEORIGIN ✓ X-Content-Type-Options: nosniff ✓ Strict-Transport-Security enabled ✓ CORS cấu hình chặt chẽ