🛡️ Security Best Practices
n8n có access đến nhiều systems và data - security là critical. Bài này covers comprehensive security hardening cho production.
Security Checklist
Quick Security Audit:
Text
1N8N SECURITY CHECKLIST2──────────────────────3 4AUTHENTICATION5□ Basic auth enabled6□ Strong passwords (20+ chars)7□ User management configured8□ Session timeout set9 10NETWORK11□ HTTPS only12□ Firewall configured13□ VPN for admin access14□ Rate limiting enabled15 16DATA17□ Encryption key secured18□ Credentials encrypted19□ Backups encrypted20□ Logs sanitized21 22SERVER23□ Updates applied24□ Minimal permissions25□ Non-root user26□ Audit logging enabledAuthentication Hardening
Basic Auth (Minimum):
Bash
1# Strong password requirements2N8N_BASIC_AUTH_ACTIVE=true3N8N_BASIC_AUTH_USER=admin4N8N_BASIC_AUTH_PASSWORD=use_very_long_random_password_here_40chars5 6# Generate strong password7openssl rand -base64 32User Management (Better):
Bash
1# Enable user management2N8N_USER_MANAGEMENT_DISABLED=false3 4# First user becomes owner5# Invite others via email6 7# Email configuration required8N8N_EMAIL_MODE=smtp9N8N_SMTP_HOST=smtp.gmail.com10N8N_SMTP_PORT=58711N8N_SMTP_USER=your@gmail.com12N8N_SMTP_PASS=app_password13N8N_SMTP_SENDER=noreply@yourdomain.com14N8N_SMTP_SSL=trueSession Security:
Bash
1# Session settings2N8N_JWT_AUTH_ACTIVE=false # Use built-in sessions3 4# For JWT auth (advanced)5N8N_JWT_AUTH_ACTIVE=true6N8N_JWKS_URI=https://your-auth-provider/.well-known/jwks.jsonIP Allowlisting:
Bash
1# Restrict editor access by IP2N8N_EDITOR_ACCESS_ALLOWED_IPS=192.168.1.0/24,10.0.0.100Network Security
Firewall Configuration (UFW):
Bash
1# Reset firewall2sudo ufw reset3 4# Default deny5sudo ufw default deny incoming6sudo ufw default allow outgoing7 8# Allow SSH (change port if using non-standard)9sudo ufw allow 22/tcp10 11# Allow HTTP/HTTPS12sudo ufw allow 80/tcp13sudo ufw allow 443/tcp14 15# Allow from specific IPs only (recommended)16# sudo ufw allow from 192.168.1.0/24 to any port 44317 18# Enable firewall19sudo ufw enable20 21# Check status22sudo ufw status verboseFirewall Configuration (iptables):
Bash
1#!/bin/bash2# firewall.sh3 4# Flush existing rules5iptables -F6iptables -X7 8# Default policies9iptables -P INPUT DROP10iptables -P FORWARD DROP11iptables -P OUTPUT ACCEPT12 13# Allow loopback14iptables -A INPUT -i lo -j ACCEPT15 16# Allow established connections17iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT18 19# Allow SSH20iptables -A INPUT -p tcp --dport 22 -j ACCEPT21 22# Allow HTTP/HTTPS23iptables -A INPUT -p tcp --dport 80 -j ACCEPT24iptables -A INPUT -p tcp --dport 443 -j ACCEPT25 26# Rate limiting27iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --set28iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --update --seconds 60 --hitcount 15 -j DROP29 30# Log dropped packets31iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: "32 33# Save rules34iptables-save > /etc/iptables/rules.v4Docker Network Isolation:
yaml
1# docker-compose.yml2services:3 n8n:4 networks:5 - frontend6 - backend7 8 postgres:9 networks:10 - backend # Only backend, not exposed11 12 nginx:13 networks:14 - frontend15 ports:16 - "443:443"17 18networks:19 frontend:20 driver: bridge21 backend:22 driver: bridge23 internal: true # No external accessNginx Security
Hardened nginx.conf:
nginx
1events {2 worker_connections 1024;3}4 5http {6 # Hide nginx version7 server_tokens off;8 9 # Rate limiting10 limit_req_zone $binary_remote_addr zone=n8n_limit:10m rate=10r/s;11 limit_conn_zone $binary_remote_addr zone=conn_limit:10m;12 13 # SSL settings14 ssl_protocols TLSv1.2 TLSv1.3;15 ssl_prefer_server_ciphers off;16 ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;17 ssl_session_cache shared:SSL:10m;18 ssl_session_timeout 1d;19 ssl_session_tickets off;20 ssl_stapling on;21 ssl_stapling_verify on;22 23 # Security headers24 add_header X-Frame-Options "SAMEORIGIN" always;25 add_header X-Content-Type-Options "nosniff" always;26 add_header X-XSS-Protection "1; mode=block" always;27 add_header Referrer-Policy "strict-origin-when-cross-origin" always;28 add_header Strict-Transport-Security "max-age=63072000" always;29 add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;30 31 server {32 listen 443 ssl http2;33 server_name n8n.yourdomain.com;34 35 ssl_certificate /etc/nginx/ssl/fullchain.pem;36 ssl_certificate_key /etc/nginx/ssl/privkey.pem;37 38 # Rate limiting39 limit_req zone=n8n_limit burst=20 nodelay;40 limit_conn conn_limit 10;41 42 # IP allowlist (optional)43 # allow 192.168.1.0/24;44 # deny all;45 46 location / {47 proxy_pass http://n8n:5678;48 proxy_http_version 1.1;49 proxy_set_header Upgrade $http_upgrade;50 proxy_set_header Connection "upgrade";51 proxy_set_header Host $host;52 proxy_set_header X-Real-IP $remote_addr;53 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;54 proxy_set_header X-Forwarded-Proto $scheme;55 56 # Timeout settings57 proxy_connect_timeout 300;58 proxy_send_timeout 300;59 proxy_read_timeout 300;60 }61 62 # Block sensitive paths63 location ~* /webhook-test {64 # Only allow from specific IPs65 allow 10.0.0.0/8;66 deny all;67 proxy_pass http://n8n:5678;68 }69 }70}Secrets Management
Environment Variables Security:
Bash
1# .env file permissions2chmod 600 .env3 4# Ownership5chown root:root .env6 7# Or use Docker secretsDocker Secrets:
yaml
1# docker-compose.yml2services:3 n8n:4 secrets:5 - n8n_encryption_key6 - db_password7 environment:8 - N8N_ENCRYPTION_KEY_FILE=/run/secrets/n8n_encryption_key9 - DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/db_password10 11secrets:12 n8n_encryption_key:13 file: ./secrets/n8n_encryption_key.txt14 db_password:15 file: ./secrets/db_password.txtHashiCorp Vault (Enterprise):
Bash
1# Example: Fetch secrets from Vault2export N8N_ENCRYPTION_KEY=$(vault kv get -field=key secret/n8n/encryption)3export POSTGRES_PASSWORD=$(vault kv get -field=password secret/n8n/postgres)Credential Encryption
Encryption Key Management:
Bash
1# Generate strong key2N8N_ENCRYPTION_KEY=$(openssl rand -hex 24)3 4# Store securely:5# 1. Password manager (1Password, Bitwarden)6# 2. Cloud secrets (AWS Secrets Manager, Azure Key Vault)7# 3. Hardware security module (HSM)8 9# NEVER:10# - Commit to git11# - Store in plaintext12# - Share in chat/emailRotate Encryption Key:
Bash
1# 1. Export all credentials decrypted2docker exec n8n n8n export:credentials --all --decrypted --output=/tmp/creds.json3 4# 2. Stop n8n5docker compose stop n8n6 7# 3. Set new encryption key8export N8N_ENCRYPTION_KEY=$(openssl rand -hex 24)9 10# 4. Start n8n11docker compose up -d n8n12 13# 5. Import credentials14docker exec n8n n8n import:credentials --input=/tmp/creds.json15 16# 6. Securely delete exported file17shred -u /tmp/creds.jsonLogging & Audit
Enable Audit Logging:
Bash
1# Log level for security2N8N_LOG_LEVEL=info3 4# Log output5N8N_LOG_OUTPUT=console,file6N8N_LOG_FILE_LOCATION=/logs/n8n.log7 8# Diagnostic events9N8N_DIAGNOSTICS_ENABLED=false # Disable if privacy concernLog Monitoring Script:
Bash
1#!/bin/bash2# monitor-security.sh3 4LOG_FILE="/logs/n8n.log"5ALERT_EMAIL="admin@yourdomain.com"6 7# Watch for suspicious patterns8tail -F "$LOG_FILE" | while read line; do9 # Failed auth attempts10 if echo "$line" | grep -q "authentication failed"; then11 echo "ALERT: Failed auth - $line" | mail -s "n8n Security Alert" "$ALERT_EMAIL"12 fi13 14 # Multiple rapid requests15 if echo "$line" | grep -q "rate limit exceeded"; then16 echo "ALERT: Rate limit - $line" | mail -s "n8n Security Alert" "$ALERT_EMAIL"17 fi18doneFail2ban Integration:
ini
1# /etc/fail2ban/jail.local2[n8n]3enabled = true4port = 4435filter = n8n6logpath = /var/log/nginx/access.log7maxretry = 58bantime = 36009findtime = 600ini
1# /etc/fail2ban/filter.d/n8n.conf2[Definition]3failregex = ^<HOST> .* "POST /rest/login HTTP/.*" 4014ignoreregex =Webhook Security
Secure Webhook Paths:
Bash
1# Use long random paths2# Instead of: /webhook/test3# Use: /webhook/a3f9b2c8d4e5f6g7h8i9j04 5# Or require authentication6# Check for header in workflowWebhook Validation in Workflow:
JavaScript
1// Code node to validate webhook requests2const authHeader = $input.first().json.headers.authorization;3const expectedToken = 'Bearer your_secret_token';45if (authHeader !== expectedToken) {6 throw new Error('Unauthorized');7}89return $input.all();Rate Limit Webhooks:
nginx
1# nginx.conf2location /webhook {3 limit_req zone=webhook_limit burst=5 nodelay;4 proxy_pass http://n8n:5678;5}6 7# Define zone8limit_req_zone $binary_remote_addr zone=webhook_limit:10m rate=1r/s;Container Security
Run as Non-Root:
yaml
1services:2 n8n:3 image: n8nio/n8n4 user: "1000:1000" # node user5 # ...Read-Only Filesystem:
yaml
1services:2 n8n:3 read_only: true4 tmpfs:5 - /tmp6 volumes:7 - n8n_data:/home/node/.n8n # Only writable volumeSecurity Scanning:
Bash
1# Scan image for vulnerabilities2docker scan n8nio/n8n3 4# Or use Trivy5trivy image n8nio/n8nSecurity Monitoring
Health Check with Security:
Bash
1#!/bin/bash2# security-check.sh3 4echo "=== N8N Security Status ==="5 6# Check SSL certificate7echo -n "SSL Certificate: "8EXPIRY=$(echo | openssl s_client -connect n8n.yourdomain.com:443 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)9echo "$EXPIRY"10 11# Check open ports12echo "Open ports:"13netstat -tlnp | grep LISTEN14 15# Check failed SSH attempts16echo "Failed SSH attempts (last 24h):"17journalctl -u sshd --since "24 hours ago" | grep -c "Failed"18 19# Check n8n auth failures20echo "N8N auth failures:"21grep -c "authentication failed" /logs/n8n.log 2>/dev/null || echo "0"22 23# Check firewall status24echo "Firewall status:"25ufw status | head -5Bài Tập Thực Hành
Security Challenge
Harden your n8n instance:
- Enable strong authentication
- Configure firewall rules
- Harden nginx configuration
- Setup log monitoring
- Test security with scan tools
- Document security configuration
Aim for A+ on SSL Labs! 🛡️
Key Takeaways
Remember
- 🔐 Strong auth - Long passwords, user management
- 🔥 Firewall - Default deny, explicit allow
- 🔒 HTTPS only - TLS 1.2+ minimum
- 📝 Audit logs - Know what's happening
- 🔑 Secrets safe - Never in code or git
- 🔄 Update regularly - Patch vulnerabilities
Tiếp Theo
Bài tiếp theo: Credentials Management - Quản lý và bảo mật API keys, tokens, và database credentials.
