Complete production-ready Caddy infrastructure with security hardening
- Add comprehensive Caddy role with HTTPS/TLS, DNS challenges, and systemd security - Implement optimized systemd overrides with enhanced security restrictions - Create detailed documentation with usage examples and variable references - Establish proper Ansible configuration with vault integration - Update site.yml for infrastructure orchestration with role-based deployment - Add host-specific configuration structure for scalable multi-environment setup
This commit is contained in:
@@ -1,2 +1,237 @@
|
||||
# Install and configure caddy
|
||||
Installs and configures caddy.
|
||||
# Caddy Web Server Role
|
||||
|
||||
A comprehensive Ansible role for installing and configuring [Caddy](https://caddyserver.com/) web server with automatic HTTPS, DNS challenges, and production security hardening.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔐 **Automatic HTTPS** with Let's Encrypt certificates
|
||||
- 🌐 **DNS Challenge Support** for wildcard certificates (Cloudflare provider)
|
||||
- 🛡️ **Security Hardening** with systemd restrictions and capability bounds
|
||||
- 🔧 **Flexible Configuration** for static sites and reverse proxies
|
||||
- 📝 **Production Ready** with proper logging and monitoring
|
||||
- 🎯 **Role-Based Architecture** with host-specific overrides
|
||||
|
||||
## Requirements
|
||||
|
||||
- Systemd-based Linux distribution (tested on Arch Linux)
|
||||
- Ansible 2.9+
|
||||
- For DNS challenges: Cloudflare account with API token
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Basic Static Site Setup
|
||||
|
||||
```yaml
|
||||
# host_vars/myserver/main.yml
|
||||
caddy_tls_enabled: true
|
||||
caddy_domain: "example.com"
|
||||
caddy_tls_email: "admin@example.com"
|
||||
```
|
||||
|
||||
### Production Setup with DNS Challenge
|
||||
|
||||
```yaml
|
||||
# host_vars/myserver/main.yml
|
||||
caddy_tls_enabled: true
|
||||
caddy_domain: "example.com"
|
||||
caddy_tls_email: "{{ vault_caddy_tls_email }}"
|
||||
caddy_dns_provider: "cloudflare"
|
||||
cloudflare_api_token: "{{ vault_cloudflare_api_token }}"
|
||||
|
||||
# host_vars/myserver/vault.yml (encrypted)
|
||||
vault_caddy_tls_email: "admin@example.com"
|
||||
vault_cloudflare_api_token: "your-api-token-here"
|
||||
```
|
||||
|
||||
## Required Variables
|
||||
|
||||
### For HTTPS/TLS
|
||||
|
||||
| Variable | Required When | Description | Example |
|
||||
|----------|---------------|-------------|---------|
|
||||
| `caddy_tls_enabled` | Always for HTTPS | Enable TLS/HTTPS | `true` |
|
||||
| `caddy_tls_email` | HTTPS enabled | Email for Let's Encrypt | `"admin@example.com"` |
|
||||
| `caddy_domain` | HTTPS enabled | Primary domain | `"example.com"` |
|
||||
|
||||
### For DNS Challenge (Wildcard Certificates)
|
||||
|
||||
| Variable | Required When | Description | Example |
|
||||
|----------|---------------|-------------|---------|
|
||||
| `caddy_dns_provider` | DNS challenge | DNS provider | `"cloudflare"` |
|
||||
| `cloudflare_api_token` | Cloudflare DNS | API token for DNS | `"{{ vault_token }}"` |
|
||||
|
||||
## Optional Variables
|
||||
|
||||
### Service Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `caddy_version` | `"latest"` | Caddy version to install |
|
||||
| `caddy_config_file` | `"/etc/caddy/Caddyfile"` | Main config file path |
|
||||
| `caddy_service_enabled` | `true` | Enable systemd service |
|
||||
| `caddy_service_state` | `"started"` | Service state |
|
||||
| `caddy_admin_listen` | `"127.0.0.1:2019"` | Admin API endpoint |
|
||||
|
||||
### Directory Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `caddy_config_dir` | `"/etc/caddy"` | Configuration directory |
|
||||
| `caddy_data_dir` | `"/var/lib/caddy"` | Data/state directory |
|
||||
| `caddy_log_dir` | `"/var/log/caddy"` | Log directory |
|
||||
| `caddy_web_root` | `"/var/www"` | Web root directory |
|
||||
|
||||
### Security Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `caddy_systemd_security` | `true` | Enable systemd security restrictions |
|
||||
| `caddy_firewall_ports` | `[80, 443]` | Ports to open in firewall |
|
||||
|
||||
### Logging Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `caddy_log_level` | `"INFO"` | Logging level (ERROR, WARN, INFO, DEBUG) |
|
||||
| `caddy_log_format` | `"common"` | Log format (common, json) |
|
||||
|
||||
### ACME Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `caddy_acme_ca` | Let's Encrypt Prod | ACME CA directory URL |
|
||||
| `caddy_dns_resolvers` | `["1.1.1.1:53", "1.0.0.1:53"]` | DNS resolvers |
|
||||
| `caddy_dns_propagation_timeout` | `120` | DNS propagation timeout (seconds) |
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Multiple Sites
|
||||
|
||||
```yaml
|
||||
caddy_sites:
|
||||
# Static file serving
|
||||
- domain: "static.example.com"
|
||||
root: "/var/www/static"
|
||||
dns_challenge: true
|
||||
|
||||
# Reverse proxy to backend service
|
||||
- domain: "api.example.com"
|
||||
backend: "localhost:8080"
|
||||
dns_challenge: true
|
||||
extra_config: |
|
||||
header_up Host {upstream_hostport}
|
||||
header_up X-Real-IP {remote_host}
|
||||
|
||||
# HTTP-only internal site
|
||||
- domain: "internal.example.com"
|
||||
root: "/var/www/internal"
|
||||
tls: "off"
|
||||
```
|
||||
|
||||
### Custom Systemd Security
|
||||
|
||||
```yaml
|
||||
caddy_systemd_security: false # Disable if you need custom security settings
|
||||
```
|
||||
|
||||
### Staging Environment
|
||||
|
||||
```yaml
|
||||
# Use Let's Encrypt staging for testing
|
||||
caddy_acme_ca: "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
This role implements production-grade security hardening:
|
||||
|
||||
### Systemd Security Restrictions
|
||||
|
||||
- **NoNewPrivileges**: Prevents privilege escalation
|
||||
- **CapabilityBoundingSet**: Limits to `CAP_NET_ADMIN` and `CAP_NET_BIND_SERVICE`
|
||||
- **ProtectSystem=strict**: Read-only filesystem protection
|
||||
- **ProtectKernelLogs/Modules/Tunables**: Kernel protection
|
||||
- **RestrictAddressFamilies**: Limits to IPv4, IPv6, and Unix sockets
|
||||
- **RestrictNamespaces/Realtime/SUIDSGID**: Additional restrictions
|
||||
- **MemoryDenyWriteExecute**: Prevents code injection
|
||||
- **SystemCallFilter=@system-service**: Whitelist system calls
|
||||
|
||||
### File System Security
|
||||
|
||||
- Dedicated `caddy` user and group
|
||||
- Proper directory permissions
|
||||
- Read-only configuration binding
|
||||
- Isolated temporary files
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
roles/caddy/
|
||||
├── defaults/main.yml # Default variables with documentation
|
||||
├── tasks/main.yml # Installation and configuration tasks
|
||||
├── handlers/main.yml # Service restart/reload handlers
|
||||
├── templates/
|
||||
│ ├── Caddyfile.j2 # Main Caddyfile template
|
||||
│ ├── index.html.j2 # Default welcome page
|
||||
│ └── systemd-override.conf.j2 # Security hardening overrides
|
||||
├── meta/main.yml # Role metadata and dependencies
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Example Playbooks
|
||||
|
||||
### Basic Deployment
|
||||
|
||||
```yaml
|
||||
- name: Deploy Caddy Web Server
|
||||
hosts: webservers
|
||||
become: yes
|
||||
roles:
|
||||
- caddy
|
||||
```
|
||||
|
||||
### Full Infrastructure
|
||||
|
||||
```yaml
|
||||
- name: Secure VPS Setup
|
||||
hosts: production
|
||||
become: yes
|
||||
roles:
|
||||
- security # Firewall, SSH hardening, etc.
|
||||
- caddy # Web server with HTTPS
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This role automatically handles Caddy installation, including:
|
||||
|
||||
- Standard Caddy binary for HTTP-only setups
|
||||
- Custom build with Cloudflare DNS plugin when DNS challenge is enabled
|
||||
- System user and directory creation
|
||||
- Systemd service configuration
|
||||
|
||||
## Compatibility
|
||||
|
||||
- **Tested**: Arch Linux
|
||||
- **Should work**: CentOS/RHEL 8+, Ubuntu 18.04+, Debian 10+
|
||||
- **Requires**: systemd, curl/wget
|
||||
|
||||
## Contributing
|
||||
|
||||
When modifying this role:
|
||||
|
||||
1. Update defaults in `defaults/main.yml` with clear documentation
|
||||
2. Use host-specific overrides in `host_vars/` for sensitive values
|
||||
3. Leverage Ansible Vault for secrets (`vault_*` variables)
|
||||
4. Test changes against the security hardening requirements
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Secrets**: Always use Ansible Vault for API tokens and sensitive data
|
||||
- **Firewall**: Role opens ports 80 and 443; ensure firewall is configured
|
||||
- **DNS**: DNS challenge requires API access to your DNS provider
|
||||
- **Monitoring**: Monitor certificate expiration and renewal
|
||||
|
||||
## License
|
||||
|
||||
This role is part of the rick-infra project infrastructure configuration.
|
||||
|
||||
Reference in New Issue
Block a user