# Security Hardening Guide ## Overview This stack implements defense in depth with multiple security layers: 1. **Network**: Cloudflare → Traefik → Service 2. **Authentication**: Authelia (SSO + 2FA) 3. **Authorization**: Access control rules 4. **Detection**: CrowdSec (IPS/IDS) 5. **Encryption**: TLS 1.3, strong ciphers 6. **Monitoring**: Logs, metrics, alerts ## Pre-Deployment Checklist ### 1. Server Hardening ```bash # Update system sudo apt update && sudo apt upgrade -y # Install fail2ban sudo apt install fail2ban # Configure fail2ban for SSH cat < secrets/authelia_jwt_secret.txt # Session Secret (32+ chars) openssl rand -hex 32 > secrets/authelia_session_secret.txt # Storage Encryption Key (32+ chars) openssl rand -hex 32 > secrets/authelia_storage_key.txt # Authelia user password docker run --rm authelia/authelia:latest \ authelia crypto hash generate argon2 \ --password 'YourStrongPassword123!' ``` ### 4. Cloudflare Security - [ ] SSL/TLS mode: Full (strict) - [ ] Always Use HTTPS: ON - [ ] Security Level: High - [ ] Browser Integrity Check: ON - [ ] Challenge Passage: 30 minutes - [ ] Minimum TLS Version: 1.2 ## Post-Deployment Security ### 1. Verify CrowdSec is Working ```bash # Check CrowdSec is detecting attacks docker-compose exec crowdsec cscli metrics # View active decisions (bans) docker-compose exec crowdsec cscli decisions list # Simulate an attack to test curl -I http://your-ip/.env docker-compose exec crowdsec cscli decisions list # Should show your IP banned ``` ### 2. Configure Authelia Notifications Edit `authelia/configuration.yml`: ```yaml notifier: smtp: address: smtp.gmail.com:587 username: your-email@gmail.com password: ${SMTP_PASSWORD} sender: "Authelia " ``` Test: Try logging in with wrong password 3 times → should get email. ### 3. Enable CrowdSec Notifications ```bash # Install Discord/Slack plugin docker-compose exec crowdsec cscli notifications add slack # Configure in CrowdSec container docker-compose exec crowdsec sh -c "cat > /etc/crowdsec/notifications/slack.yaml" << 'EOF' type: slack name: slack_default log_level: info format: | {{range . -}} {{$alert := . -}} {{range .Decisions -}} :warning: *CrowdSec Alert* *IP:* {{.Value}} *Reason:* {{.Scenario}} *Duration:* {{.Duration}} {{end -}} {{end -}} webhook: https://hooks.slack.com/services/YOUR/WEBHOOK/URL EOF ``` ### 4. Regular Security Tasks **Weekly:** ```bash # Check for new decisions docker-compose exec crowdsec cscli decisions list # Review failed logins docker-compose logs authelia | grep "unsuccessful" # Update images docker-compose pull docker-compose up -d ``` **Monthly:** ```bash # Rotate secrets ./scripts/rotate-secrets.sh # You need to create this # Review access logs docker-compose logs traefik | grep -E "(401|403|429)" # Backup tar czf backup-$(date +%Y%m%d).tar.gz traefik/ authelia/ crowdsec/ .env ``` ## Threat Model ### What This Stack Protects Against | Threat | Mitigation | |--------|-----------| | Credential stuffing | Authelia rate limiting, fail2ban | | Brute force attacks | CrowdSec detection, progressive delays | | DDoS | Cloudflare, rate limiting | | MITM | TLS 1.3, HSTS, certificate pinning | | Session hijacking | Secure cookies, short expiration | | XSS/CSRF | Security headers, SameSite cookies | | SQL injection | Parameterized queries (app responsibility) | ### What It Doesn't Protect Against - Zero-day vulnerabilities in applications - Social engineering - Compromised client devices - Insider threats - Application-level logic bugs ## Incident Response ### If You Suspect a Breach 1. **Isolate** ```bash # Stop all services docker-compose down # Block all traffic temporarily sudo ufw default deny incoming ``` 2. **Investigate** ```bash # Check logs docker-compose logs > incident-$(date +%Y%m%d).log # Check CrowdSec decisions docker-compose exec crowdsec cscli decisions list # Check for unknown containers docker ps -a ``` 3. **Recover** ```bash # Rotate all secrets # Change all passwords # Re-deploy from clean backup ``` ## Security Testing ### Automated Scans ```bash # Test TLS configuration docker run --rm drwetter/testssl.sh https://lemonlink.eu # Test headers curl -I https://lemonlink.eu | grep -E "(strict-transport-security|content-security-policy|x-frame-options)" # Test rate limiting for i in {1..20}; do curl -s -o /dev/null -w "%{http_code}" https://auth.lemonlink.eu/; done ``` ### Manual Penetration Testing 1. Try accessing internal services from external IP 2. Attempt SQL injection in login forms 3. Test XSS payloads 4. Verify 2FA can't be bypassed 5. Check for information disclosure in headers ## Compliance Notes This setup helps with: - **GDPR**: Encryption, access logs, data retention - **ISO 27001**: Defense in depth, monitoring - **SOC 2**: Audit trails, access controls But does NOT make you compliant by itself. You must: - Document all data flows - Implement data retention policies - Conduct regular audits - Train users on security ## Additional Resources - [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/) - [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/) - [CIS Docker Benchmark](https://www.cisecurity.org/benchmark/docker) - [Cloudflare Security Center](https://dash.cloudflare.com/?to=/:account/:zone/security)