Lý thuyết
50 phút
Bài 9/15

Security Best Practices

Hardening n8n cho production - authentication, firewall, network security, và secure configurations

🛡️ Security Best Practices

Cybersecurity

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 CHECKLIST
2──────────────────────
3
4AUTHENTICATION
5□ Basic auth enabled
6□ Strong passwords (20+ chars)
7□ User management configured
8□ Session timeout set
9
10NETWORK
11□ HTTPS only
12□ Firewall configured
13□ VPN for admin access
14□ Rate limiting enabled
15
16DATA
17□ Encryption key secured
18□ Credentials encrypted
19□ Backups encrypted
20□ Logs sanitized
21
22SERVER
23□ Updates applied
24□ Minimal permissions
25□ Non-root user
26□ Audit logging enabled

Authentication Hardening

Basic Auth (Minimum):

Bash
1# Strong password requirements
2N8N_BASIC_AUTH_ACTIVE=true
3N8N_BASIC_AUTH_USER=admin
4N8N_BASIC_AUTH_PASSWORD=use_very_long_random_password_here_40chars
5
6# Generate strong password
7openssl rand -base64 32

User Management (Better):

Bash
1# Enable user management
2N8N_USER_MANAGEMENT_DISABLED=false
3
4# First user becomes owner
5# Invite others via email
6
7# Email configuration required
8N8N_EMAIL_MODE=smtp
9N8N_SMTP_HOST=smtp.gmail.com
10N8N_SMTP_PORT=587
11N8N_SMTP_USER=your@gmail.com
12N8N_SMTP_PASS=app_password
13N8N_SMTP_SENDER=noreply@yourdomain.com
14N8N_SMTP_SSL=true

Session Security:

Bash
1# Session settings
2N8N_JWT_AUTH_ACTIVE=false # Use built-in sessions
3
4# For JWT auth (advanced)
5N8N_JWT_AUTH_ACTIVE=true
6N8N_JWKS_URI=https://your-auth-provider/.well-known/jwks.json

IP Allowlisting:

Bash
1# Restrict editor access by IP
2N8N_EDITOR_ACCESS_ALLOWED_IPS=192.168.1.0/24,10.0.0.100

Network Security

Firewall Configuration (UFW):

Bash
1# Reset firewall
2sudo ufw reset
3
4# Default deny
5sudo ufw default deny incoming
6sudo ufw default allow outgoing
7
8# Allow SSH (change port if using non-standard)
9sudo ufw allow 22/tcp
10
11# Allow HTTP/HTTPS
12sudo ufw allow 80/tcp
13sudo ufw allow 443/tcp
14
15# Allow from specific IPs only (recommended)
16# sudo ufw allow from 192.168.1.0/24 to any port 443
17
18# Enable firewall
19sudo ufw enable
20
21# Check status
22sudo ufw status verbose

Firewall Configuration (iptables):

Bash
1#!/bin/bash
2# firewall.sh
3
4# Flush existing rules
5iptables -F
6iptables -X
7
8# Default policies
9iptables -P INPUT DROP
10iptables -P FORWARD DROP
11iptables -P OUTPUT ACCEPT
12
13# Allow loopback
14iptables -A INPUT -i lo -j ACCEPT
15
16# Allow established connections
17iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
18
19# Allow SSH
20iptables -A INPUT -p tcp --dport 22 -j ACCEPT
21
22# Allow HTTP/HTTPS
23iptables -A INPUT -p tcp --dport 80 -j ACCEPT
24iptables -A INPUT -p tcp --dport 443 -j ACCEPT
25
26# Rate limiting
27iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --set
28iptables -A INPUT -p tcp --dport 443 -m state --state NEW -m recent --update --seconds 60 --hitcount 15 -j DROP
29
30# Log dropped packets
31iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: "
32
33# Save rules
34iptables-save > /etc/iptables/rules.v4

Docker Network Isolation:

yaml
1# docker-compose.yml
2services:
3 n8n:
4 networks:
5 - frontend
6 - backend
7
8 postgres:
9 networks:
10 - backend # Only backend, not exposed
11
12 nginx:
13 networks:
14 - frontend
15 ports:
16 - "443:443"
17
18networks:
19 frontend:
20 driver: bridge
21 backend:
22 driver: bridge
23 internal: true # No external access

Nginx Security

Hardened nginx.conf:

nginx
1events {
2 worker_connections 1024;
3}
4
5http {
6 # Hide nginx version
7 server_tokens off;
8
9 # Rate limiting
10 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 settings
14 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 headers
24 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 limiting
39 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 settings
57 proxy_connect_timeout 300;
58 proxy_send_timeout 300;
59 proxy_read_timeout 300;
60 }
61
62 # Block sensitive paths
63 location ~* /webhook-test {
64 # Only allow from specific IPs
65 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 permissions
2chmod 600 .env
3
4# Ownership
5chown root:root .env
6
7# Or use Docker secrets

Docker Secrets:

yaml
1# docker-compose.yml
2services:
3 n8n:
4 secrets:
5 - n8n_encryption_key
6 - db_password
7 environment:
8 - N8N_ENCRYPTION_KEY_FILE=/run/secrets/n8n_encryption_key
9 - DB_POSTGRESDB_PASSWORD_FILE=/run/secrets/db_password
10
11secrets:
12 n8n_encryption_key:
13 file: ./secrets/n8n_encryption_key.txt
14 db_password:
15 file: ./secrets/db_password.txt

HashiCorp Vault (Enterprise):

Bash
1# Example: Fetch secrets from Vault
2export 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 key
2N8N_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 git
11# - Store in plaintext
12# - Share in chat/email

Rotate Encryption Key:

Bash
1# 1. Export all credentials decrypted
2docker exec n8n n8n export:credentials --all --decrypted --output=/tmp/creds.json
3
4# 2. Stop n8n
5docker compose stop n8n
6
7# 3. Set new encryption key
8export N8N_ENCRYPTION_KEY=$(openssl rand -hex 24)
9
10# 4. Start n8n
11docker compose up -d n8n
12
13# 5. Import credentials
14docker exec n8n n8n import:credentials --input=/tmp/creds.json
15
16# 6. Securely delete exported file
17shred -u /tmp/creds.json

Logging & Audit

Enable Audit Logging:

Bash
1# Log level for security
2N8N_LOG_LEVEL=info
3
4# Log output
5N8N_LOG_OUTPUT=console,file
6N8N_LOG_FILE_LOCATION=/logs/n8n.log
7
8# Diagnostic events
9N8N_DIAGNOSTICS_ENABLED=false # Disable if privacy concern

Log Monitoring Script:

Bash
1#!/bin/bash
2# monitor-security.sh
3
4LOG_FILE="/logs/n8n.log"
5ALERT_EMAIL="admin@yourdomain.com"
6
7# Watch for suspicious patterns
8tail -F "$LOG_FILE" | while read line; do
9 # Failed auth attempts
10 if echo "$line" | grep -q "authentication failed"; then
11 echo "ALERT: Failed auth - $line" | mail -s "n8n Security Alert" "$ALERT_EMAIL"
12 fi
13
14 # Multiple rapid requests
15 if echo "$line" | grep -q "rate limit exceeded"; then
16 echo "ALERT: Rate limit - $line" | mail -s "n8n Security Alert" "$ALERT_EMAIL"
17 fi
18done

Fail2ban Integration:

ini
1# /etc/fail2ban/jail.local
2[n8n]
3enabled = true
4port = 443
5filter = n8n
6logpath = /var/log/nginx/access.log
7maxretry = 5
8bantime = 3600
9findtime = 600
ini
1# /etc/fail2ban/filter.d/n8n.conf
2[Definition]
3failregex = ^<HOST> .* "POST /rest/login HTTP/.*" 401
4ignoreregex =

Webhook Security

Secure Webhook Paths:

Bash
1# Use long random paths
2# Instead of: /webhook/test
3# Use: /webhook/a3f9b2c8d4e5f6g7h8i9j0
4
5# Or require authentication
6# Check for header in workflow

Webhook Validation in Workflow:

JavaScript
1// Code node to validate webhook requests
2const authHeader = $input.first().json.headers.authorization;
3const expectedToken = 'Bearer your_secret_token';
4
5if (authHeader !== expectedToken) {
6 throw new Error('Unauthorized');
7}
8
9return $input.all();

Rate Limit Webhooks:

nginx
1# nginx.conf
2location /webhook {
3 limit_req zone=webhook_limit burst=5 nodelay;
4 proxy_pass http://n8n:5678;
5}
6
7# Define zone
8limit_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/n8n
4 user: "1000:1000" # node user
5 # ...

Read-Only Filesystem:

yaml
1services:
2 n8n:
3 read_only: true
4 tmpfs:
5 - /tmp
6 volumes:
7 - n8n_data:/home/node/.n8n # Only writable volume

Security Scanning:

Bash
1# Scan image for vulnerabilities
2docker scan n8nio/n8n
3
4# Or use Trivy
5trivy image n8nio/n8n

Security Monitoring

Health Check with Security:

Bash
1#!/bin/bash
2# security-check.sh
3
4echo "=== N8N Security Status ==="
5
6# Check SSL certificate
7echo -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 ports
12echo "Open ports:"
13netstat -tlnp | grep LISTEN
14
15# Check failed SSH attempts
16echo "Failed SSH attempts (last 24h):"
17journalctl -u sshd --since "24 hours ago" | grep -c "Failed"
18
19# Check n8n auth failures
20echo "N8N auth failures:"
21grep -c "authentication failed" /logs/n8n.log 2>/dev/null || echo "0"
22
23# Check firewall status
24echo "Firewall status:"
25ufw status | head -5

Bài Tập Thực Hành

Security Challenge

Harden your n8n instance:

  1. Enable strong authentication
  2. Configure firewall rules
  3. Harden nginx configuration
  4. Setup log monitoring
  5. Test security with scan tools
  6. 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.