Files
homelab-optimized/docs/admin/security.md
Gitea Mirror Bot ca723d77b9
Some checks failed
Documentation / Deploy to GitHub Pages (push) Has been cancelled
Documentation / Build Docusaurus (push) Has been cancelled
Sanitized mirror from private repository - 2026-04-20 00:50:49 UTC
2026-04-20 00:50:49 +00:00

486 lines
14 KiB
Markdown

# 🔐 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)