Files
ubuntu-post-install/SECURITY-IMPROVEMENTS.md
T
Claude f564b4b6d8 Remove Keycloak; standardize on Authelia for SSO
Keycloak never reliably ran (fiddly reverse-proxy/hostname config) and the
repo has standardized on Authelia for SSO + 2FA. This rips Keycloak out
entirely:

- Delete the install block, whiptail menu entry, uninstall plumbing, and
  EXISTING_SERVICES detection from both 24.04 and 26.04 scripts
- Delete docker-compose-keycloak.yml, fix-keycloak-proxy.sh, and
  KEYCLOAK-SETUP-GUIDE.md
- Remove the Keycloak block from caddy-setup-helper.sh
- Update docs (CADDY-FAIL2BAN-SETUP.md, SECURITY-IMPROVEMENTS.md,
  NEW-SCRIPT-STRUCTURE.md, SCRIPT-FLOW-INTRO.txt) to reference Authelia

Also documents the fail2ban/Authelia overlap: Authelia handles failed-login
regulation (per-account lockout); the Caddy fail2ban jail is complementary
firewall-level IP banning. Neither does geo-blocking — noted CrowdSec / Caddy
GeoIP as the path for that.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 03:44:26 +00:00

293 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Security and Infrastructure Improvements
## Summary of Changes
This document describes the comprehensive security and infrastructure improvements made to the Ubuntu post-installation script.
## Issues Fixed
### 1. Docker Directory Ownership
**Problem:** Docker directories were being created as root, causing permission issues when running Docker without sudo.
**Solution:**
- Added `ensure_docker_dir_ownership()` helper function
- Applied to ALL 25+ services (Immich, ActualBudget, Jellyfin, etc.)
- Fixed disaster recovery path (line 309)
- All Docker directories now properly owned by sudo user
**Impact:** Docker containers can now be managed without requiring root/sudo for every command.
---
### 2. Password & Credential Management
**Problem:** Weak default passwords and credentials hardcoded in compose files.
**Solutions Implemented:**
#### Password Requirements
- **Minimum length:** 12 characters (16+ recommended)
- **Character set:** Letters and numbers ONLY (no special characters)
- **Auto-generation:** Press ENTER to generate secure passwords automatically
- **Validation:** Real-time password validation with retry loop
#### Generated Secrets
- Services that need cryptographic secrets generate them automatically (e.g. Authelia's JWT, session, and storage secrets via `openssl rand`).
#### Environment Variables
- All credentials moved to `.env` file
- Passwords and secrets securely stored
- No more hardcoded passwords in docker-compose.yml
---
### 3. Environment Variable Management (.env Files)
**Services Now Using .env Files:**
- ✅ Authelia (JWT/session/storage secrets + SMTP password)
- ✅ ActualBudget (timezone and config)
- ✅ Immich (already had .env)
- ✅ FindMyDevice (already had .env)
- ✅ wg-easy (already had .env)
- ✅ Kopia (already had .env)
**Benefits:**
- Passwords not visible in docker-compose.yml files
- Easy to backup separately from compose files
- Can be excluded from version control
- Easier credential rotation
---
### 4. Caddy2 Reverse Proxy Integration
**Existing Integration:**
All services already include Caddy2 reverse proxy configuration via the `configure_caddy_for_service()` function.
**Features:**
- Automatic HTTPS via Let's Encrypt
- HTTP/2 support
- Security headers (HSTS, X-Frame-Options, etc.)
- JSON logging for fail2ban
- Automatic certificate renewal
**Example Caddy Configuration:**
```
photos.yourdomain.com {
reverse_proxy localhost:2283
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Frame-Options "SAMEORIGIN"
X-Content-Type-Options "nosniff"
X-XSS-Protection "1; mode=block"
Referrer-Policy "strict-origin-when-cross-origin"
}
log {
output file /var/log/caddy/photos-access.log
format json
}
}
```
---
### 5. Fail2ban Integration
**Existing fail2ban Labels:**
All services already include fail2ban monitoring labels:
```yaml
labels:
- "io.podman.annotations.label/fail2ban.enable=true"
- "io.podman.annotations.label/fail2ban.filter=caddy-auth"
```
**Services with fail2ban monitoring:**
- ActualBudget
- Authelia
- All other internet-facing services
**fail2ban Configuration:**
- Filter: `/etc/fail2ban/filter.d/caddy-auth.conf`
- Jail: `/etc/fail2ban/jail.d/caddy.conf`
- Ban after: 5 failed attempts
- Ban duration: 3600 seconds (1 hour)
- Detection window: 600 seconds
**Note:** When Authelia is in use, it provides its own failed-login regulation
(account lockout after repeated failures). The Caddy fail2ban jail is
complementary defense-in-depth at the HTTP layer. See
`CADDY-FAIL2BAN-SETUP.md` for complete configuration.
---
## Helper Functions Added
### `ensure_docker_dir_ownership(dir1 [dir2 ...])`
Ensures Docker directories are owned by the actual user (not root).
**Usage:**
```bash
mkdir -p "$SERVICE_DIR"
ensure_docker_dir_ownership "$SERVICE_DIR"
```
### `generate_password([length])`
Generates secure alphanumeric passwords (no special characters).
**Usage:**
```bash
PASSWORD=$(generate_password 20) # 20-character password
```
### `validate_password(password [min_length])`
Validates passwords for compatibility (alphanumeric only).
**Validation Rules:**
- Minimum length (default: 12 characters)
- Alphanumeric only (a-zA-Z0-9)
- Returns 0 if valid, 1 if invalid
**Usage:**
```bash
if validate_password "$USER_PASSWORD" 12; then
echo "Password accepted"
fi
```
---
## Password Requirements Reference
### Password Rules
- **Minimum:** 12 characters
- **Recommended:** 16+ characters
- **Format:** Alphanumeric only (a-zA-Z0-9)
- **No special characters:** `!@#$%^&*()` etc. are NOT allowed
- **Generation:** Press ENTER for auto-generated secure passwords
### Why No Special Characters?
Some services and database connection strings mishandle special characters in
certain authentication flows. Restricting to alphanumeric ensures broad
compatibility while remaining cryptographically strong.
### Password Strength with Alphanumeric Only
- 12 characters: ~62^12 = 3.2 × 10^21 combinations
- 16 characters: ~62^16 = 4.7 × 10^28 combinations
- 20 characters: ~62^20 = 7.0 × 10^35 combinations
This is cryptographically secure for all practical purposes.
---
## Verification Checklist
After running the updated script:
### Docker Ownership
```bash
# Check docker directory ownership
ls -la ~/docker/
# All directories should be owned by your user, not root
# Test docker without sudo
docker ps
# Should work without permission errors
```
### Caddy2
```bash
# Check Caddy is running
docker ps | grep caddy
# Check logs
docker logs caddy
# Test HTTPS redirect
curl -I http://yourdomain.com
# Should redirect to HTTPS
```
### fail2ban
```bash
# Check fail2ban status
sudo fail2ban-client status caddy-auth
# Test ban
# (Make 5 failed login attempts)
sudo fail2ban-client status caddy-auth
# Should show banned IP
```
---
## Migration Guide
If you have existing services:
### Existing ActualBudget
1. Backup existing data: `cp -r ~/docker/actualbudget ~/docker/actualbudget.backup`
2. Run updated script and select "Reconfigure" when prompted
3. New .env file will be created
4. Verify ownership: `ls -la ~/docker/actualbudget`
5. Restart container: `cd ~/docker/actualbudget && docker compose restart`
---
## Troubleshooting
### Permission Denied Errors
```bash
# Fix ownership of all docker directories
sudo chown -R $USER:$USER ~/docker
```
### Caddy Certificate Errors
```bash
# Check Caddy logs
docker logs caddy
# Common issues:
# 1. DNS not pointing to server
# 2. Ports 80/443 not open
# 3. Firewall blocking Let's Encrypt
# Test DNS:
dig auth.yourdomain.com
# Test port accessibility:
sudo ufw status
```
---
## Security Best Practices
1. **Change default passwords:** Even with auto-generation, review and update if needed
2. **Enable fail2ban:** Monitor and ban malicious IPs
3. **Regular updates:** Keep containers updated (use Watchtower in notify mode)
4. **Backup .env files:** Store securely, separate from compose files
5. **Use HTTPS everywhere:** Configure Caddy2 for all public services
6. **Limit exposed ports:** Only expose necessary ports to the internet
7. **Monitor logs:** Regular review of Caddy and fail2ban logs
---
## Additional Resources
- **Caddy + fail2ban Setup:** `CADDY-FAIL2BAN-SETUP.md`
- **Main Script:** `ubuntu-post-install.sh`
- **Caddy Helper:** `caddy-setup-helper.sh`
---
## Support
If you encounter issues:
1. Check logs: `docker logs <container-name>`
2. Verify ownership: `ls -la ~/docker`
3. Review this document for troubleshooting steps
4. Check existing documentation in repository