6.3 KiB
6.3 KiB
Security Hardening Guide
Overview
This stack implements defense in depth with multiple security layers:
- Network: Cloudflare → Traefik → Service
- Authentication: Authelia (SSO + 2FA)
- Authorization: Access control rules
- Detection: CrowdSec (IPS/IDS)
- Encryption: TLS 1.3, strong ciphers
- Monitoring: Logs, metrics, alerts
Pre-Deployment Checklist
1. Server Hardening
# Update system
sudo apt update && sudo apt upgrade -y
# Install fail2ban
sudo apt install fail2ban
# Configure fail2ban for SSH
cat <<EOF | sudo tee /etc/fail2ban/jail.local
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
EOF
sudo systemctl restart fail2ban
# Disable password SSH (use keys only)
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
# Configure firewall (UFW)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 100.64.0.0/10 to any port 22 # Tailscale SSH only
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
2. Docker Security
# Install Docker rootless (optional but recommended)
dockerd-rootless-setuptool.sh install
# Or use userns-remap
echo '{"userns-remap": "default"}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
# Enable Docker Content Trust
export DOCKER_CONTENT_TRUST=1
3. Secret Generation
# Generate all secrets
cd LemonSec
# JWT Secret (32+ chars)
openssl rand -hex 32 > 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
# 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:
notifier:
smtp:
address: smtp.gmail.com:587
username: your-email@gmail.com
password: ${SMTP_PASSWORD}
sender: "Authelia <security@lemonlink.eu>"
Test: Try logging in with wrong password 3 times → should get email.
3. Enable CrowdSec Notifications
# 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:
# 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:
# 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
-
Isolate
# Stop all services docker-compose down # Block all traffic temporarily sudo ufw default deny incoming -
Investigate
# 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 -
Recover
# Rotate all secrets # Change all passwords # Re-deploy from clean backup
Security Testing
Automated Scans
# 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
- Try accessing internal services from external IP
- Attempt SQL injection in login forms
- Test XSS payloads
- Verify 2FA can't be bypassed
- 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