Files
Charon/docs/configuration/emergency-setup.md
akanealw eec8c28fb3
Some checks are pending
Go Benchmark / Performance Regression Check (push) Waiting to run
Cerberus Integration / Cerberus Security Stack Integration (push) Waiting to run
Upload Coverage to Codecov / Backend Codecov Upload (push) Waiting to run
Upload Coverage to Codecov / Frontend Codecov Upload (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (go) (push) Waiting to run
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Waiting to run
CrowdSec Integration / CrowdSec Bouncer Integration (push) Waiting to run
Docker Build, Publish & Test / build-and-push (push) Waiting to run
Docker Build, Publish & Test / Security Scan PR Image (push) Blocked by required conditions
Quality Checks / Auth Route Protection Contract (push) Waiting to run
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Waiting to run
Quality Checks / Backend (Go) (push) Waiting to run
Quality Checks / Frontend (React) (push) Waiting to run
Rate Limit integration / Rate Limiting Integration (push) Waiting to run
Security Scan (PR) / Trivy Binary Scan (push) Waiting to run
Supply Chain Verification (PR) / Verify Supply Chain (push) Waiting to run
WAF integration / Coraza WAF Integration (push) Waiting to run
changed perms
2026-04-22 18:19:14 +00:00

751 lines
17 KiB
Markdown
Executable File

# Emergency Break Glass Protocol - Configuration Guide
**Version:** 1.0
**Last Updated:** January 26, 2026
**Purpose:** Complete reference for configuring emergency break glass access
---
## Table of Contents
- [Overview](#overview)
- [Environment Variables Reference](#environment-variables-reference)
- [Docker Compose Examples](#docker-compose-examples)
- [Firewall Configuration](#firewall-configuration)
- [Secrets Manager Integration](#secrets-manager-integration)
- [Security Hardening](#security-hardening)
---
## Overview
Charon's emergency break glass protocol provides a 3-tier system for emergency access recovery:
- **Tier 1:** Emergency token via main application endpoint (Layer 7 bypass)
- **Tier 2:** Separate emergency server on dedicated port (network isolation)
- **Tier 3:** Direct system access (SSH/console)
This guide covers configuration for Tiers 1 and 2. Tier 3 requires only SSH access to the host.
---
## Environment Variables Reference
### Required Variables
#### `CHARON_EMERGENCY_TOKEN`
**Purpose:** Secret token for emergency break glass access (Tier 1 & 2)
**Format:** 64-character hexadecimal string
**Security:** CRITICAL - Store in secrets manager, never commit to version control
**Generation:**
```bash
# Recommended method (OpenSSL)
openssl rand -hex 32
# Alternative (Python)
python3 -c "import secrets; print(secrets.token_hex(32))"
# Alternative (/dev/urandom)
head -c 32 /dev/urandom | xxd -p -c 64
```
**Example:**
```yaml
environment:
- CHARON_EMERGENCY_TOKEN=a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2
```
**Validation:**
- Minimum length: 32 characters (produces 64-char hex)
- Must be hexadecimal (0-9, a-f)
- Must be unique per deployment
- Rotate every 90 days
---
### Optional Variables
#### `CHARON_MANAGEMENT_CIDRS`
**Purpose:** IP ranges allowed to use emergency token (Tier 1)
**Format:** Comma-separated CIDR notation
**Default:** `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,127.0.0.0/8` (RFC1918 + localhost)
**Examples:**
```yaml
# Office network only
- CHARON_MANAGEMENT_CIDRS=192.168.1.0/24
# Office + VPN
- CHARON_MANAGEMENT_CIDRS=192.168.1.0/24,10.8.0.0/24
# Multiple offices
- CHARON_MANAGEMENT_CIDRS=192.168.1.0/24,192.168.2.0/24,10.10.0.0/16
# Allow from anywhere (NOT RECOMMENDED)
- CHARON_MANAGEMENT_CIDRS=0.0.0.0/0,::/0
```
**Security Notes:**
- Be as restrictive as possible
- Never use `0.0.0.0/0` in production
- Include VPN subnet if using VPN for emergency access
- Update when office networks change
#### `CHARON_EMERGENCY_SERVER_ENABLED`
**Purpose:** Enable separate emergency server on dedicated port (Tier 2)
**Format:** Boolean (`true` or `false`)
**Default:** `false`
**When to enable:**
- ✅ Production deployments with CrowdSec
- ✅ High-security environments
- ✅ Deployments with restrictive firewalls
- ❌ Simple home labs (Tier 1 sufficient)
**Example:**
```yaml
environment:
- CHARON_EMERGENCY_SERVER_ENABLED=true
```
#### `CHARON_EMERGENCY_BIND`
**Purpose:** Address and port for emergency server (Tier 2)
**Format:** `IP:PORT`
**Default:** `127.0.0.1:2020`
**Note:** Port 2020 avoids conflict with Caddy admin API (port 2019)
**Options:**
```yaml
# Localhost only (most secure - requires SSH tunnel)
- CHARON_EMERGENCY_BIND=127.0.0.1:2020
# Listen on all interfaces (DANGER - requires firewall rules)
- CHARON_EMERGENCY_BIND=0.0.0.0:2020
# Specific internal IP (VPN interface)
- CHARON_EMERGENCY_BIND=10.8.0.1:2020
# IPv6 localhost
- CHARON_EMERGENCY_BIND=[::1]:2020
# Dual-stack all interfaces
- CHARON_EMERGENCY_BIND=0.0.0.0:2020 # or [::]:2020 for IPv6
```
**⚠️ Security Warning:** Never bind to `0.0.0.0` without firewall protection. Use SSH tunneling instead.
#### `CHARON_EMERGENCY_USERNAME`
**Purpose:** Basic Auth username for emergency server (Tier 2)
**Format:** String
**Default:** None (Basic Auth disabled)
**Example:**
```yaml
environment:
- CHARON_EMERGENCY_USERNAME=admin
```
**Security Notes:**
- Optional but recommended
- Use strong, unique username (not "admin" in production)
- Combine with strong password
- Consider using mTLS instead (future enhancement)
#### `CHARON_EMERGENCY_PASSWORD`
**Purpose:** Basic Auth password for emergency server (Tier 2)
**Format:** String
**Default:** None (Basic Auth disabled)
**Example:**
```yaml
environment:
- CHARON_EMERGENCY_PASSWORD=${EMERGENCY_PASSWORD} # From .env file
```
**Security Notes:**
- NEVER hardcode in docker-compose.yml
- Use `.env` file or secrets manager
- Minimum 20 characters recommended
- Rotate every 90 days
---
## Docker Compose Examples
### Example 1: Minimal Configuration (Homelab)
**Use case:** Simple home lab, Tier 1 only, no emergency server
```yaml
version: '3.8'
services:
charon:
image: ghcr.io/wikid82/charon:latest
container_name: charon
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "8080:8080"
volumes:
- charon_data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=UTC
- CHARON_ENV=production
- CHARON_ENCRYPTION_KEY=${CHARON_ENCRYPTION_KEY} # From .env
- CHARON_EMERGENCY_TOKEN=${CHARON_EMERGENCY_TOKEN} # From .env
volumes:
charon_data:
driver: local
```
**.env file:**
```bash
# Generate with: openssl rand -base64 32
CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here
# Generate with: openssl rand -hex 32
CHARON_EMERGENCY_TOKEN=your-64-char-hex-token-here
```
---
### Example 2: Production Configuration (Tier 1 + Tier 2)
**Use case:** Production deployment with emergency server, VPN access
```yaml
version: '3.8'
services:
charon:
image: ghcr.io/wikid82/charon:latest
container_name: charon
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "8080:8080"
# Emergency server (localhost only - use SSH tunnel)
- "127.0.0.1:2020:2020"
volumes:
- charon_data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=UTC
- CHARON_ENV=production
- CHARON_ENCRYPTION_KEY=${CHARON_ENCRYPTION_KEY}
# Emergency Token (Tier 1)
- CHARON_EMERGENCY_TOKEN=${CHARON_EMERGENCY_TOKEN}
- CHARON_MANAGEMENT_CIDRS=10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
# Emergency Server (Tier 2)
- CHARON_EMERGENCY_SERVER_ENABLED=true
- CHARON_EMERGENCY_BIND=0.0.0.0:2020
- CHARON_EMERGENCY_USERNAME=${CHARON_EMERGENCY_USERNAME}
- CHARON_EMERGENCY_PASSWORD=${CHARON_EMERGENCY_PASSWORD}
healthcheck:
test: ["CMD", "curl", "--fail", "http://localhost:8080/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
charon_data:
driver: local
```
**.env file:**
```bash
CHARON_ENCRYPTION_KEY=your-32-byte-base64-key-here
CHARON_EMERGENCY_TOKEN=your-64-char-hex-token-here
CHARON_EMERGENCY_USERNAME=emergency-admin
CHARON_EMERGENCY_PASSWORD=your-strong-password-here
```
---
### Example 3: Security-Hardened Configuration
**Use case:** High-security environment with Docker secrets, read-only filesystem
```yaml
version: '3.8'
services:
charon:
image: ghcr.io/wikid82/charon:latest
container_name: charon
restart: unless-stopped
read_only: true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
- "443:443/udp"
- "8080:8080"
- "127.0.0.1:2020:2020"
volumes:
- charon_data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
# tmpfs for writable directories
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
- type: tmpfs
target: /var/log/caddy
tmpfs:
size: 100M
secrets:
- charon_encryption_key
- charon_emergency_token
- charon_emergency_password
environment:
- TZ=UTC
- CHARON_ENV=production
- CHARON_ENCRYPTION_KEY_FILE=/run/secrets/charon_encryption_key
- CHARON_EMERGENCY_TOKEN_FILE=/run/secrets/charon_emergency_token
- CHARON_MANAGEMENT_CIDRS=10.8.0.0/24 # VPN subnet only
- CHARON_EMERGENCY_SERVER_ENABLED=true
- CHARON_EMERGENCY_BIND=0.0.0.0:2020
- CHARON_EMERGENCY_USERNAME=emergency-admin
- CHARON_EMERGENCY_PASSWORD_FILE=/run/secrets/charon_emergency_password
volumes:
charon_data:
driver: local
secrets:
charon_encryption_key:
external: true
charon_emergency_token:
external: true
charon_emergency_password:
external: true
```
**Create secrets:**
```bash
# Create secrets from files
echo "your-encryption-key" | docker secret create charon_encryption_key -
echo "your-emergency-token" | docker secret create charon_emergency_token -
echo "your-emergency-password" | docker secret create charon_emergency_password -
# Verify secrets
docker secret ls
```
---
### Example 4: Development Configuration
**Use case:** Local development, emergency server for testing
```yaml
version: '3.8'
services:
charon:
image: ghcr.io/wikid82/charon:nightly
container_name: charon-dev
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080"
- "2020:2020" # Emergency server on all interfaces for testing
volumes:
- charon_data:/app/data
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- TZ=UTC
- CHARON_ENV=development
- CHARON_DEBUG=1
- CHARON_ENCRYPTION_KEY=dev-key-not-for-production-32bytes
- CHARON_EMERGENCY_TOKEN=test-emergency-token-for-e2e-32chars
- CHARON_EMERGENCY_SERVER_ENABLED=true
- CHARON_EMERGENCY_BIND=0.0.0.0:2020
- CHARON_EMERGENCY_USERNAME=admin
- CHARON_EMERGENCY_PASSWORD=admin
volumes:
charon_data:
driver: local
```
**⚠️ WARNING:** This configuration is ONLY for local development. Never use in production.
---
## Firewall Configuration
### iptables Rules (Linux)
**Block public access to emergency port:**
```bash
# Allow localhost
iptables -A INPUT -i lo -p tcp --dport 2020 -j ACCEPT
# Allow VPN subnet (example: 10.8.0.0/24)
iptables -A INPUT -s 10.8.0.0/24 -p tcp --dport 2020 -j ACCEPT
# Block everything else
iptables -A INPUT -p tcp --dport 2020 -j DROP
# Save rules
iptables-save > /etc/iptables/rules.v4
```
### UFW Rules (Ubuntu/Debian)
```bash
# Allow from specific subnet only
ufw allow from 10.8.0.0/24 to any port 2020 proto tcp
# Enable firewall
ufw enable
# Verify rules
ufw status numbered
```
### firewalld Rules (RHEL/CentOS)
```bash
# Create new zone for emergency access
firewall-cmd --permanent --new-zone=emergency
firewall-cmd --permanent --zone=emergency --add-source=10.8.0.0/24
firewall-cmd --permanent --zone=emergency --add-port=2020/tcp
# Reload firewall
firewall-cmd --reload
# Verify
firewall-cmd --zone=emergency --list-all
```
### Docker Network Isolation
**Create dedicated network for emergency access:**
```yaml
services:
charon:
networks:
- public
- emergency
networks:
public:
driver: bridge
emergency:
driver: bridge
internal: true # No external connectivity
```
---
## Secrets Manager Integration
### HashiCorp Vault
**Store secrets:**
```bash
# Store emergency token
vault kv put secret/charon/emergency \
token="$(openssl rand -hex 32)" \
username="emergency-admin" \
password="$(openssl rand -base64 32)"
# Read secrets
vault kv get secret/charon/emergency
```
**Docker Compose with Vault:**
```yaml
services:
charon:
image: ghcr.io/wikid82/charon:latest
environment:
- CHARON_EMERGENCY_TOKEN=${VAULT_CHARON_EMERGENCY_TOKEN}
- CHARON_EMERGENCY_USERNAME=${VAULT_CHARON_EMERGENCY_USERNAME}
- CHARON_EMERGENCY_PASSWORD=${VAULT_CHARON_EMERGENCY_PASSWORD}
```
**Retrieve from Vault:**
```bash
# Export secrets from Vault
export VAULT_CHARON_EMERGENCY_TOKEN=$(vault kv get -field=token secret/charon/emergency)
export VAULT_CHARON_EMERGENCY_USERNAME=$(vault kv get -field=username secret/charon/emergency)
export VAULT_CHARON_EMERGENCY_PASSWORD=$(vault kv get -field=password secret/charon/emergency)
# Start with secrets
docker-compose up -d
```
### AWS Secrets Manager
**Store secrets:**
```bash
# Create secret
aws secretsmanager create-secret \
--name charon/emergency \
--description "Charon emergency break glass credentials" \
--secret-string '{
"token": "YOUR_TOKEN_HERE",
"username": "emergency-admin",
"password": "YOUR_PASSWORD_HERE"
}'
```
**Retrieve in Docker Compose:**
```bash
#!/bin/bash
# Retrieve secret
SECRET=$(aws secretsmanager get-secret-value \
--secret-id charon/emergency \
--query SecretString \
--output text)
# Parse JSON and export
export CHARON_EMERGENCY_TOKEN=$(echo $SECRET | jq -r '.token')
export CHARON_EMERGENCY_USERNAME=$(echo $SECRET | jq -r '.username')
export CHARON_EMERGENCY_PASSWORD=$(echo $SECRET | jq -r '.password')
# Start Charon
docker-compose up -d
```
### Azure Key Vault
**Store secrets:**
```bash
# Create Key Vault
az keyvault create \
--name charon-vault \
--resource-group charon-rg \
--location eastus
# Store secrets
az keyvault secret set \
--vault-name charon-vault \
--name emergency-token \
--value "YOUR_TOKEN_HERE"
az keyvault secret set \
--vault-name charon-vault \
--name emergency-username \
--value "emergency-admin"
az keyvault secret set \
--vault-name charon-vault \
--name emergency-password \
--value "YOUR_PASSWORD_HERE"
```
**Retrieve secrets:**
```bash
#!/bin/bash
# Retrieve secrets
export CHARON_EMERGENCY_TOKEN=$(az keyvault secret show \
--vault-name charon-vault \
--name emergency-token \
--query value -o tsv)
export CHARON_EMERGENCY_USERNAME=$(az keyvault secret show \
--vault-name charon-vault \
--name emergency-username \
--query value -o tsv)
export CHARON_EMERGENCY_PASSWORD=$(az keyvault secret show \
--vault-name charon-vault \
--name emergency-password \
--query value -o tsv)
# Start Charon
docker-compose up -d
```
---
## Security Hardening
### Best Practices Checklist
- [ ] **Emergency token** stored in secrets manager (not in docker-compose.yml)
- [ ] **Token rotation** scheduled every 90 days
- [ ] **Management CIDRs** restricted to minimum necessary networks
- [ ] **Emergency server** bound to localhost only (127.0.0.1)
- [ ] **SSH tunneling** used for emergency server access
- [ ] **Firewall rules** block public access to port 2019
- [ ] **Basic Auth** enabled on emergency server with strong credentials
- [ ] **Audit logging** monitored for emergency access
- [ ] **Alerts configured** for emergency token usage
- [ ] **Backup procedures** tested and documented
- [ ] **Recovery runbooks** reviewed by team
- [ ] **Quarterly drills** scheduled to test procedures
### Network Hardening
**VPN-Only Access:**
```yaml
environment:
# Only allow emergency access from VPN subnet
- CHARON_MANAGEMENT_CIDRS=10.8.0.0/24
# Emergency server listens on VPN interface only
- CHARON_EMERGENCY_BIND=10.8.0.1:2020
```
**mTLS for Emergency Server** (Future Enhancement):
```yaml
environment:
- CHARON_EMERGENCY_TLS_ENABLED=true
- CHARON_EMERGENCY_TLS_CERT=/run/secrets/emergency_tls_cert
- CHARON_EMERGENCY_TLS_KEY=/run/secrets/emergency_tls_key
- CHARON_EMERGENCY_TLS_CA=/run/secrets/emergency_tls_ca
```
### Monitoring & Alerting
**Prometheus Metrics:**
```yaml
# Emergency access metrics
charon_emergency_token_attempts_total{result="success"}
charon_emergency_token_attempts_total{result="failure"}
charon_emergency_server_requests_total
```
**Alert Rules:**
```yaml
groups:
- name: charon_emergency_access
rules:
- alert: EmergencyTokenUsed
expr: increase(charon_emergency_token_attempts_total{result="success"}[5m]) > 0
labels:
severity: critical
annotations:
summary: "Emergency break glass token was used"
description: "Someone used the emergency token to disable security. Review audit logs."
- alert: EmergencyTokenBruteForce
expr: increase(charon_emergency_token_attempts_total{result="failure"}[5m]) > 10
labels:
severity: warning
annotations:
summary: "Multiple failed emergency token attempts detected"
description: "Possible brute force attack on emergency endpoint."
```
---
## Validation & Testing
### Configuration Validation
```bash
# Validate docker-compose.yml syntax
docker-compose config
# Verify environment variables are set
docker-compose config | grep EMERGENCY
# Test container starts successfully
docker-compose up -d
docker logs charon | grep -i emergency
```
### Functional Testing
**Test Tier 1:**
```bash
# Test emergency token works
curl -X POST https://charon.example.com/api/v1/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN"
# Expected: {"success":true, ...}
```
**Test Tier 2:**
```bash
# Create SSH tunnel
ssh -L 2020:localhost:2020 admin@server &
# Test emergency server health
curl http://localhost:2020/health
# Test emergency endpoint
curl -X POST http://localhost:2020/emergency/security-reset \
-H "X-Emergency-Token: $CHARON_EMERGENCY_TOKEN" \
-u admin:password
# Close tunnel
kill %1
```
---
## Related Documentation
- [Emergency Lockout Recovery Runbook](../runbooks/emergency-lockout-recovery.md)
- [Emergency Token Rotation](../runbooks/emergency-token-rotation.md)
- [Security Documentation](../security.md)
- [Break Glass Protocol Design](../plans/break_glass_protocol_redesign.md)
---
**Version History:**
- v1.0 (2026-01-26): Initial release