Files
homelab-optimized/docs/admin/security.md
Gitea Mirror Bot fb00a325d1
Some checks failed
Documentation / Build Docusaurus (push) Failing after 5m14s
Documentation / Deploy to GitHub Pages (push) Has been skipped
Sanitized mirror from private repository - 2026-04-18 11:19:59 UTC
2026-04-18 11:19:59 +00:00

14 KiB

🔐 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:

# 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

# 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

# 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

# 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

# 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:

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# 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

# Store securely in Vaultwarden
emergency_contacts:
  - ISP support
  - Domain registrar
  - Cloudflare support
  - Family members with access

Quick Lockdown Commands

# 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