Sanitized mirror from private repository - 2026-03-31 23:50:30 UTC
This commit is contained in:
485
docs/admin/security.md
Normal file
485
docs/admin/security.md
Normal file
@@ -0,0 +1,485 @@
|
||||
# 🔐 Security Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide covers security best practices for the homelab, including authentication, network security, secrets management, and incident response.
|
||||
|
||||
---
|
||||
|
||||
## 🏰 Security Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||
│ SECURITY LAYERS │
|
||||
├─────────────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ EXTERNAL │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Cloudflare WAF + DDoS Protection + Bot Management │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ GATEWAY ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Nginx Proxy Manager (SSL Termination + Rate Limiting) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ AUTHENTICATION ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Authentik SSO (OAuth2/OIDC + MFA + User Management) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ NETWORK ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Tailscale (Zero-Trust Mesh VPN) + Wireguard (Site-to-Site) │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ APPLICATION ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────────────────────┐ │
|
||||
│ │ Vaultwarden (Secrets) + Container Isolation + Least Privilege │ │
|
||||
│ └─────────────────────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Authentication & Access Control
|
||||
|
||||
### Authentik SSO
|
||||
|
||||
All services use centralized authentication through Authentik:
|
||||
|
||||
```yaml
|
||||
# Services integrated with Authentik SSO:
|
||||
- Grafana (OAuth2)
|
||||
- Portainer (OAuth2)
|
||||
- Proxmox (LDAP)
|
||||
- Mattermost (OAuth2)
|
||||
- Seafile (OAuth2)
|
||||
- Paperless-NGX (OAuth2)
|
||||
- Various internal apps (Forward Auth)
|
||||
```
|
||||
|
||||
### Multi-Factor Authentication (MFA)
|
||||
|
||||
| Service | MFA Type | Status |
|
||||
|---------|----------|--------|
|
||||
| Authentik | TOTP + WebAuthn | ✅ Required |
|
||||
| Vaultwarden | TOTP + FIDO2 | ✅ Required |
|
||||
| Synology DSM | TOTP | ✅ Required |
|
||||
| Proxmox | TOTP | ✅ Required |
|
||||
| Tailscale | Google SSO | ✅ Required |
|
||||
|
||||
### Access Levels
|
||||
|
||||
```yaml
|
||||
# Role-Based Access Control
|
||||
roles:
|
||||
admin:
|
||||
description: Full access to all systems
|
||||
access:
|
||||
- All Portainer environments
|
||||
- Authentik admin
|
||||
- DSM admin
|
||||
- Proxmox root
|
||||
|
||||
operator:
|
||||
description: Day-to-day operations
|
||||
access:
|
||||
- Container management
|
||||
- Service restarts
|
||||
- Log viewing
|
||||
|
||||
viewer:
|
||||
description: Read-only monitoring
|
||||
access:
|
||||
- Grafana dashboards
|
||||
- Uptime Kuma status
|
||||
- Read-only Portainer
|
||||
|
||||
family:
|
||||
description: Consumer access only
|
||||
access:
|
||||
- Plex/Jellyfin streaming
|
||||
- Photo viewing
|
||||
- Limited file access
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🌐 Network Security
|
||||
|
||||
### Firewall Rules
|
||||
|
||||
```bash
|
||||
# Synology Firewall - Recommended rules
|
||||
# Control Panel > Security > Firewall
|
||||
|
||||
# Allow Tailscale
|
||||
Allow: 100.64.0.0/10 (Tailscale CGNAT)
|
||||
|
||||
# Allow local network
|
||||
Allow: 192.168.0.0/16 (RFC1918)
|
||||
Allow: 10.0.0.0/8 (RFC1918)
|
||||
|
||||
# Block everything else by default
|
||||
Deny: All
|
||||
|
||||
# Specific port rules
|
||||
Allow: TCP 443 from Cloudflare IPs only
|
||||
Allow: TCP 80 from Cloudflare IPs only (redirect to 443)
|
||||
```
|
||||
|
||||
### Cloudflare Configuration
|
||||
|
||||
```yaml
|
||||
# Cloudflare Security Settings
|
||||
ssl_mode: full_strict # End-to-end encryption
|
||||
min_tls_version: "1.2"
|
||||
always_use_https: true
|
||||
|
||||
# WAF Rules
|
||||
waf_enabled: true
|
||||
bot_management: enabled
|
||||
ddos_protection: automatic
|
||||
|
||||
# Rate Limiting
|
||||
rate_limit:
|
||||
requests_per_minute: 100
|
||||
action: challenge
|
||||
|
||||
# Access Rules
|
||||
ip_access_rules:
|
||||
- action: block
|
||||
filter: known_bots
|
||||
- action: challenge
|
||||
filter: threat_score > 10
|
||||
```
|
||||
|
||||
### Port Exposure
|
||||
|
||||
```yaml
|
||||
# Only these ports exposed to internet (via Cloudflare)
|
||||
exposed_ports:
|
||||
- 443/tcp # HTTPS (Nginx Proxy Manager)
|
||||
|
||||
# Everything else via Tailscale/VPN only
|
||||
internal_only:
|
||||
- 22/tcp # SSH
|
||||
- 8080/tcp # Portainer
|
||||
- 9090/tcp # Prometheus
|
||||
- 3000/tcp # Grafana
|
||||
- All Docker services
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔒 Secrets Management
|
||||
|
||||
### Vaultwarden
|
||||
|
||||
Central password manager for all credentials:
|
||||
|
||||
```yaml
|
||||
# Vaultwarden Security Settings
|
||||
vaultwarden:
|
||||
admin_token: # Argon2 hashed
|
||||
signups_allowed: false
|
||||
invitations_allowed: true
|
||||
|
||||
# Password policy
|
||||
password_hints_allowed: false
|
||||
password_iterations: 600000 # PBKDF2 iterations
|
||||
|
||||
# 2FA enforcement
|
||||
require_device_email: true
|
||||
|
||||
# Session security
|
||||
login_ratelimit_seconds: 60
|
||||
login_ratelimit_max_burst: 10
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
|
||||
```bash
|
||||
# Never store secrets in docker-compose.yml
|
||||
# Use Docker secrets or environment files
|
||||
|
||||
# Bad ❌
|
||||
environment:
|
||||
- DB_PASSWORD="REDACTED_PASSWORD"
|
||||
|
||||
# Good ✅ - Using .env file
|
||||
environment:
|
||||
- DB_PASSWORD="REDACTED_PASSWORD"
|
||||
|
||||
# Better ✅ - Using Docker secrets
|
||||
secrets:
|
||||
- db_password
|
||||
```
|
||||
|
||||
### Secret Rotation
|
||||
|
||||
```yaml
|
||||
# Secret rotation schedule
|
||||
rotation_schedule:
|
||||
api_tokens: 90 days
|
||||
oauth_secrets: 180 days
|
||||
database_passwords: 365 days
|
||||
ssl_certificates: auto (Let's Encrypt)
|
||||
ssh_keys: on compromise only
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐳 Container Security
|
||||
|
||||
### Docker Security Practices
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml security settings
|
||||
services:
|
||||
myservice:
|
||||
# Run as non-root
|
||||
user: "1000:1000"
|
||||
|
||||
# Read-only root filesystem
|
||||
read_only: true
|
||||
|
||||
# Disable privilege escalation
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
|
||||
# Limit capabilities
|
||||
cap_drop:
|
||||
- ALL
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE # Only if needed
|
||||
|
||||
# Resource limits
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1.0'
|
||||
memory: 512M
|
||||
```
|
||||
|
||||
### Container Scanning
|
||||
|
||||
```bash
|
||||
# Scan images for vulnerabilities
|
||||
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \
|
||||
aquasec/trivy image myimage:latest
|
||||
|
||||
# Scan all running containers
|
||||
for img in $(docker ps --format '{{.Image}}' | sort -u); do
|
||||
echo "Scanning: $img"
|
||||
docker run --rm aquasec/trivy image "$img" --severity HIGH,CRITICAL
|
||||
done
|
||||
```
|
||||
|
||||
### Image Security
|
||||
|
||||
```yaml
|
||||
# Only use trusted image sources
|
||||
trusted_registries:
|
||||
- docker.io/library/ # Official images
|
||||
- ghcr.io/ # GitHub Container Registry
|
||||
- lscr.io/linuxserver/ # LinuxServer.io
|
||||
|
||||
# Always pin versions
|
||||
# Bad ❌
|
||||
image: nginx:latest
|
||||
|
||||
# Good ✅
|
||||
image: nginx:1.25.3-alpine
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🛡️ Backup Security
|
||||
|
||||
### Encrypted Backups
|
||||
|
||||
```bash
|
||||
# Hyper Backup encryption settings
|
||||
encryption:
|
||||
enabled: true
|
||||
type: client-side # Encrypt before transfer
|
||||
algorithm: AES-256-CBC
|
||||
key_storage: local # Never store key on backup destination
|
||||
|
||||
# Verify encryption
|
||||
# Check that backup files are not readable without key
|
||||
file backup.hbk
|
||||
# Should show: "data" not "text" or recognizable format
|
||||
```
|
||||
|
||||
### Backup Access Control
|
||||
|
||||
```yaml
|
||||
# Separate credentials for backup systems
|
||||
backup_credentials:
|
||||
hyper_backup:
|
||||
read_only: true # Cannot delete backups
|
||||
separate_user: backup_user
|
||||
|
||||
syncthing:
|
||||
ignore_delete: true # Prevent sync of deletions
|
||||
|
||||
offsite:
|
||||
encryption_key: stored_offline
|
||||
access: write_only # Cannot read existing backups
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Security Monitoring
|
||||
|
||||
### Log Aggregation
|
||||
|
||||
```yaml
|
||||
# Critical logs to monitor
|
||||
security_logs:
|
||||
- /var/log/auth.log # Authentication attempts
|
||||
- /var/log/nginx/access.log # Web access
|
||||
- Authentik audit logs # SSO events
|
||||
- Docker container logs # Application events
|
||||
```
|
||||
|
||||
### Alerting Rules
|
||||
|
||||
```yaml
|
||||
# prometheus/rules/security.yml
|
||||
groups:
|
||||
- name: security
|
||||
rules:
|
||||
- alert: REDACTED_APP_PASSWORD
|
||||
expr: increase(authentik_login_failures_total[1h]) > 10
|
||||
labels:
|
||||
severity: warning
|
||||
annotations:
|
||||
summary: "High number of failed login attempts"
|
||||
|
||||
- alert: SSHBruteForce
|
||||
expr: increase(sshd_auth_failures_total[5m]) > 5
|
||||
labels:
|
||||
severity: critical
|
||||
annotations:
|
||||
summary: "Possible SSH brute force attack"
|
||||
|
||||
- alert: UnauthorizedContainerStart
|
||||
expr: changes(container_start_time_seconds[1h]) > 0
|
||||
labels:
|
||||
severity: info
|
||||
annotations:
|
||||
summary: "New container started"
|
||||
```
|
||||
|
||||
### Security Dashboard
|
||||
|
||||
Key metrics to display in Grafana:
|
||||
- Failed authentication attempts
|
||||
- Active user sessions
|
||||
- SSL certificate expiry
|
||||
- Firewall blocked connections
|
||||
- Container privilege changes
|
||||
- Unusual network traffic patterns
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Incident Response
|
||||
|
||||
### Response Procedure
|
||||
|
||||
```
|
||||
1. DETECT
|
||||
└─► Alerts from monitoring
|
||||
└─► User reports
|
||||
└─► Anomaly detection
|
||||
|
||||
2. CONTAIN
|
||||
└─► Isolate affected systems
|
||||
└─► Block malicious IPs
|
||||
└─► Disable compromised accounts
|
||||
|
||||
3. INVESTIGATE
|
||||
└─► Review logs
|
||||
└─► Identify attack vector
|
||||
└─► Assess data exposure
|
||||
|
||||
4. REMEDIATE
|
||||
└─► Patch vulnerabilities
|
||||
└─► Rotate credentials
|
||||
└─► Restore from backup if needed
|
||||
|
||||
5. RECOVER
|
||||
└─► Restore services
|
||||
└─► Verify integrity
|
||||
└─► Monitor for recurrence
|
||||
|
||||
6. DOCUMENT
|
||||
└─► Incident report
|
||||
└─► Update procedures
|
||||
└─► Implement improvements
|
||||
```
|
||||
|
||||
### Emergency Contacts
|
||||
|
||||
```yaml
|
||||
# Store securely in Vaultwarden
|
||||
emergency_contacts:
|
||||
- ISP support
|
||||
- Domain registrar
|
||||
- Cloudflare support
|
||||
- Family members with access
|
||||
```
|
||||
|
||||
### Quick Lockdown Commands
|
||||
|
||||
```bash
|
||||
# Block all external access immediately
|
||||
# On Synology:
|
||||
sudo iptables -I INPUT -j DROP
|
||||
sudo iptables -I INPUT -s 100.64.0.0/10 -j ACCEPT # Keep Tailscale
|
||||
|
||||
# Stop all non-essential containers
|
||||
docker stop $(docker ps -q --filter "name!=essential-service")
|
||||
|
||||
# Force logout all Authentik sessions
|
||||
docker exec authentik-server ak invalidate_sessions --all
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Security Checklist
|
||||
|
||||
### Weekly
|
||||
- [ ] Review failed login attempts
|
||||
- [ ] Check for container updates
|
||||
- [ ] Verify backup integrity
|
||||
- [ ] Review Cloudflare analytics
|
||||
|
||||
### Monthly
|
||||
- [ ] Rotate API tokens
|
||||
- [ ] Review user access
|
||||
- [ ] Run vulnerability scans
|
||||
- [ ] Test backup restoration
|
||||
- [ ] Update SSL certificates (if manual)
|
||||
|
||||
### Quarterly
|
||||
- [ ] Full security audit
|
||||
- [ ] Review firewall rules
|
||||
- [ ] Update incident response plan
|
||||
- [ ] Test disaster recovery
|
||||
- [ ] Review third-party integrations
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
- [Authentik SSO Setup](../infrastructure/authentik-sso.md)
|
||||
- [Cloudflare Configuration](../infrastructure/cloudflare-dns.md)
|
||||
- [Backup Strategies](backup-strategies.md)
|
||||
- [Disaster Recovery](../troubleshooting/disaster-recovery.md)
|
||||
- [Tailscale Setup](../infrastructure/tailscale-setup-guide.md)
|
||||
Reference in New Issue
Block a user