LemonSec/docs/SECURITY.md

6.3 KiB

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

# 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

  1. Isolate

    # Stop all services
    docker-compose down
    
    # Block all traffic temporarily
    sudo ufw default deny incoming
    
  2. 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
    
  3. 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

  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