# Emergency Access Server A fail-safe webserver that provides secure access to multiple decryption key parts with mandatory notification system integration. Designed for emergency scenarios where key retrieval must be monitored and logged. ## Features - **Multiple key support**: Configure multiple decryption keys with individual routes and notification backends - **Fail-safe design**: All operations require successful notification delivery - **Dynamic endpoint system**: Emergency key access and health monitoring with configurable routes - **dschep/ntfy integration**: Real-time notifications via multiple backends (Pushover, Pushbullet, Slack, etc.) - **Real-time log monitoring**: All application logs automatically sent to notification backends - **Configurable security**: Extremely long random endpoint paths (100+ characters) and file locations per key - **Caddy reverse proxy ready**: Runs on localhost for secure proxy setup - **Systemd integration**: Automatic startup and service management - **Comprehensive logging**: Detailed audit trail of all operations with live notifications ## Architecture The system consists of multiple key endpoints and a health monitoring endpoint: 1. **Emergency Key Endpoints** (e.g., `/emergency-key-backup-a7f9d2e1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8a1d4b7c0e3f6d9a2b5c8e1f4a7b0d3`): - Each serves a specific decryption key part - Extremely long paths (100+ characters) to prevent accidental access - Individual notification backends per key - Custom messages per key type - Fails closed if notifications cannot be sent - Supports unlimited number of keys 2. **Health Check Endpoint** (`/health-check-f8d9e2a1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8`): - Verifies all system components required for emergency access - Tests both health and all key notification backends - Validates file system access for dummy and all key files - Ensures complete emergency system readiness for all configured keys - Used for regular system verification **Log Monitoring**: All application logs (WARNING level and above by default) are automatically sent to the health backends for real-time monitoring and alerting. The server runs on localhost:1127 by default and is designed to be accessed through a Caddy reverse proxy for security and TLS termination. ## Installation ### Quick Install Run the automated installation script as root: ```bash sudo ./install.sh ``` ### Manual Installation 1. **Install system dependencies**: ```bash # Ubuntu/Debian sudo apt-get update sudo apt-get install python3 python3-pip python3-venv # RHEL/CentOS/Fedora (venv is built-in with Python 3.3+) sudo dnf install python3 python3-pip # Verify venv is available python3 -m venv --help ``` 2. **Create service user**: ```bash sudo groupadd --system emergency-access sudo useradd --system --gid emergency-access --home-dir /opt/emergency-access \ --shell /bin/false emergency-access ``` 3. **Setup directories**: ```bash sudo mkdir -p /opt/emergency-access /etc/emergency-access sudo chown emergency-access:emergency-access /opt/emergency-access /etc/emergency-access sudo chmod 755 /opt/emergency-access sudo chmod 750 /etc/emergency-access ``` 4. **Install application**: ```bash sudo cp *.py requirements.txt /opt/emergency-access/ sudo cp config.json.example /etc/emergency-access/config.json sudo chown -R emergency-access:emergency-access /opt/emergency-access ``` 5. **Setup Python environment**: ```bash sudo -u emergency-access python3 -m venv /opt/emergency-access/venv sudo -u emergency-access /opt/emergency-access/venv/bin/pip install -r /opt/emergency-access/requirements.txt ``` 6. **Install systemd service**: ```bash sudo cp emergency-access.service /etc/systemd/system/ sudo systemctl daemon-reload ``` ## Configuration ### Main Configuration File Copy and edit the example configuration to `/etc/emergency-access/config.json`: ```bash sudo cp config.json.example /etc/emergency-access/config.json sudo nano /etc/emergency-access/config.json ``` Configuration structure: ```json { "server": { "host": "127.0.0.1", "port": 1127 }, "routes": { "health_route": "/health-check-f8d9e2a1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8" }, "files": { "dummy_file": "/etc/emergency-access/dummy.txt" }, "keys": { "backup_key": { "route": "/emergency-key-backup-a7f9d2e1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8a1d4b7c0e3f6d9a2b5c8e1f4a7b0d3", "file": "/etc/emergency-access/backup-key.txt", "backends": ["matrix_sec", "pushover_emergency"], "message": "🚨 EMERGENCY: Backup decryption key accessed from server" }, "master_key": { "route": "/emergency-key-master-x3k8m9n2p5q7r1t4u6v9w2y5z8b1c4d7e0f3g6h9j2k5l8m1n4o7p0q3r6s9t2u5v8w1x4y7z0a3b6c9d2e5f8", "file": "/etc/emergency-access/master-key.txt", "backends": ["matrix_sec", "pushover_critical", "slack_emergency"], "message": "🚨 CRITICAL: Master decryption key accessed from server" }, "recovery_key": { "route": "/emergency-key-recovery-q5w7r8t1u3i6o9p0a2s4d6f8g0h2j4k7l9z1x3c5v7b9n1m3q6w8e0r2t4y6u8i0o2p4a6s8d0f2g4h6j8k0l2z4x6c8v0", "file": "/etc/emergency-access/recovery-key.txt", "backends": ["matrix_sec", "email_emergency"], "message": "🚨 EMERGENCY: Recovery decryption key accessed from server" }, "admin_key": { "route": "/emergency-key-admin-z9x7c5v3b1n8m6k4j2h0g9f7d5s3a1p0o9i8u7y6t5r4e3w2q1z0x9c8v7b6n5m4k3j2h1g0f9d8s7a6p5o4i3u2y1t0r9", "file": "/etc/emergency-access/admin-key.txt", "backends": [ "matrix_sec", "pushover_critical", "slack_emergency", "email_critical" ], "message": "🚨 CRITICAL ALERT: Administrator master key accessed from server" } }, "notifications": { "health_backends": ["matrix_health"], "config_path": "/etc/emergency-access/ntfy.yml", "health_message": "✅ Emergency access server health check completed", "log_level": "WARNING", "send_all_logs": true } } ``` ### Configuration Options #### Server Settings - `host`: Bind address (default: `127.0.0.1` for localhost only) - `port`: Listen port (default: `1127`) #### Route Settings - `health_route`: Path for health checks - must be 100+ characters long to prevent accidental access #### Keys Configuration Each key in the `keys` object supports: - `route`: Unique random path for this specific key - must be 100+ characters long to prevent accidental access - `file`: Path to the key file for this specific key - `backends`: List of notification backend names for this specific key - `message`: Custom message sent when this specific key is accessed #### File Settings - `dummy_file`: Path to dummy content for health checks #### Notification Settings - `health_backends`: List of backend names from `/etc/emergency-access/ntfy.yml` for health check notifications and all application logs - `config_path`: Path to the ntfy configuration file (default: `/etc/emergency-access/ntfy.yml`) - `health_message`: Message sent for health checks - `log_level`: Minimum log level to send to health backends ("INFO", "WARNING", "ERROR") - `send_all_logs`: Whether to send application logs to health backends (true/false) #### Backend Name Examples - `matrix_sec`: Matrix backend for security alerts - `pushover_emergency`: Pushover backend for emergency notifications - `slack_critical`: Slack backend for critical alerts - Any backend name configured in `/etc/emergency-access/ntfy.yml` ### Key and Dummy Files 1. **Create key files for each configured key**: ```bash # Backup key echo "YOUR_BACKUP_KEY_PART_HERE" | sudo tee /etc/emergency-access/backup-key.txt sudo chown emergency-access:emergency-access /etc/emergency-access/backup-key.txt sudo chmod 600 /etc/emergency-access/backup-key.txt # Master key echo "YOUR_MASTER_KEY_PART_HERE" | sudo tee /etc/emergency-access/master-key.txt sudo chown emergency-access:emergency-access /etc/emergency-access/master-key.txt sudo chmod 600 /etc/emergency-access/master-key.txt # Recovery key echo "YOUR_RECOVERY_KEY_PART_HERE" | sudo tee /etc/emergency-access/recovery-key.txt sudo chown emergency-access:emergency-access /etc/emergency-access/recovery-key.txt sudo chmod 600 /etc/emergency-access/recovery-key.txt # Admin key echo "YOUR_ADMIN_KEY_PART_HERE" | sudo tee /etc/emergency-access/admin-key.txt sudo chown emergency-access:emergency-access /etc/emergency-access/admin-key.txt sudo chmod 600 /etc/emergency-access/admin-key.txt ``` 2. **Create dummy file**: ```bash echo "system_healthy" | sudo tee /etc/emergency-access/dummy.txt sudo chown emergency-access:emergency-access /etc/emergency-access/dummy.txt sudo chmod 644 /etc/emergency-access/dummy.txt ``` ## dschep/ntfy Backend Setup The system uses a dedicated ntfy configuration file at `/etc/emergency-access/ntfy.yml`. Configure your notification backends in this file and reference them by name in the main configuration. ### Configuring Notification Backends 1. **Edit the dedicated ntfy config** (`/etc/emergency-access/ntfy.yml`): ```yaml backends: - matrix_sec - matrix_health - pushover_emergency matrix_sec: backend: matrix url: https://your-matrix-server.com roomId: "!emergency-security:your-matrix-server.com" userId: "@emergency-bot:your-matrix-server.com" password: "your-matrix-bot-password" matrix_health: backend: matrix url: https://your-matrix-server.com roomId: "!emergency-health:your-matrix-server.com" userId: "@emergency-bot:your-matrix-server.com" password: "your-matrix-bot-password" pushover_emergency: backend: pushover user_key: YOUR_PUSHOVER_USER_KEY priority: 2 retry: 60 expire: 3600 sound: siren ``` 2. **Reference backend names** in emergency access config: ```json "notifications": { "key_backends": ["matrix_sec", "pushover_emergency"], "health_backends": ["matrix_health"], "config_path": "/etc/emergency-access/ntfy.yml" } ``` ### Adding Additional Backends Add more backends to `/etc/emergency-access/ntfy.yml` as needed: ```yaml # Additional backends in /etc/emergency-access/ntfy.yml backends: - matrix_sec - matrix_health - pushover_emergency - slack_critical - email_emergency slack_critical: backend: slack token: YOUR_SLACK_BOT_TOKEN recipient: "#emergency-alerts" email_emergency: backend: email smtp_server: smtp.gmail.com smtp_port: 587 username: your-email@gmail.com password: your-app-password to: emergency-team@company.com from: emergency-access@company.com ``` ## Service Management ### Start and Enable Service ```bash # Start the service sudo systemctl start emergency-access # Enable automatic startup sudo systemctl enable emergency-access # Check status sudo systemctl status emergency-access ``` ### Monitoring and Logs ```bash # View real-time logs sudo journalctl -u emergency-access -f # View log file sudo tail -f /var/log/emergency-access.log # Check service health (through Caddy proxy) curl https://your-domain.com/health-check-b8e3f4a2 # Or directly to local service (for testing) curl http://localhost:1127/health-check-b8e3f4a2 ``` ## Usage ### Emergency Key Access ```bash # Access backup key curl https://your-domain.com/emergency-key-backup-a7f9d2e1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8a1d4b7c0e3f6d9a2b5c8e1f4a7b0d3 # Expected response: { "success": true, "key_id": "backup_key", "key_part": "YOUR_BACKUP_KEY_PART_HERE", "timestamp": 1703123456.789, "notified_backends": ["matrix_sec", "pushover_emergency"] } # Access master key curl https://your-domain.com/emergency-key-master-x3k8m9n2p5q7r1t4u6v9w2y5z8b1c4d7e0f3g6h9j2k5l8m1n4o7p0q3r6s9t2u5v8w1x4y7z0a3b6c9d2e5f8 # Expected response: { "success": true, "key_id": "master_key", "key_part": "YOUR_MASTER_KEY_PART_HERE", "timestamp": 1703123456.789, "notified_backends": ["matrix_sec", "pushover_critical", "slack_emergency"] } # Access admin key curl https://your-domain.com/emergency-key-admin-z9x7c5v3b1n8m6k4j2h0g9f7d5s3a1p0o9i8u7y6t5r4e3w2q1z0x9c8v7b6n5m4k3j2h1g0f9d8s7a6p5o4i3u2y1t0r9 # Expected response: { "success": true, "key_id": "admin_key", "key_part": "YOUR_ADMIN_KEY_PART_HERE", "timestamp": 1703123456.789, "notified_backends": ["matrix_sec", "pushover_critical", "slack_emergency", "email_critical"] } ``` ### Health Check ```bash # Regular health monitoring curl https://your-domain.com/health-check-f8d9e2a1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8 # Expected response (all systems operational): { "status": "ok", "timestamp": 1703123456.789, "health_backends_notified": ["matrix_health"], "dummy_content_length": 14, "keys_accessible": 4, "key_files_status": { "backup_key": true, "master_key": true, "recovery_key": true, "admin_key": true }, "key_backends_status": { "backup_key": { "backends": ["matrix_sec", "pushover_emergency"], "success": true }, "master_key": { "backends": ["matrix_sec", "pushover_critical", "slack_emergency"], "success": true }, "recovery_key": { "backends": ["matrix_sec", "email_emergency"], "success": true }, "admin_key": { "backends": ["matrix_sec", "pushover_critical", "slack_emergency", "email_critical"], "success": true } }, "emergency_system_ready": true } # Error response (when components fail): { "status": "error", "message": "System components failed", "details": [ "dummy file access failed: Permission denied", "key file access failed for 'master_key'", "key backends failed for 'recovery_key': Configuration error" ], "health_notifications": true, "dummy_file_access": false, "key_files_status": { "backup_key": true, "master_key": false, "recovery_key": true, "admin_key": true }, "key_backends_status": { "backup_key": { "backends": ["matrix_sec", "pushover_emergency"], "success": true }, "master_key": { "backends": ["matrix_sec", "pushover_critical"], "success": true }, "recovery_key": { "backends": ["matrix_sec", "email_emergency"], "success": false, "error": "Configuration error" }, "admin_key": { "backends": ["matrix_sec", "pushover_critical", "slack_emergency", "email_critical"], "success": true } } } ``` ## Security Considerations ### Caddy Reverse Proxy Setup 1. **Basic Caddyfile configuration**: ```caddy emergency.yourdomain.com { tls your-email@example.com reverse_proxy localhost:1127 header { X-Content-Type-Options nosniff X-Frame-Options DENY } rate_limit { zone emergency { key {remote_host} events 10 window 1m } } } ``` 2. **Path-based routing**: ```caddy yourdomain.com { handle /emergency/* { uri strip_prefix /emergency reverse_proxy localhost:1127 } } ``` 3. **IP-restricted access**: ```caddy :443 { @allowed_ips remote_ip 192.168.0.0/16 handle @allowed_ips { reverse_proxy localhost:1127 } handle { respond "Access Denied" 403 } } ``` ### Network Security The service binds only to localhost (127.0.0.1:1127) and is accessed through your existing Caddy reverse proxy. No additional firewall configuration is required. ### File Permissions - Key file: `600` (owner read-only) - Config file: `640` (owner read/write, group read) - Application files: `644` (standard read permissions) ### Monitoring 1. **Set up regular health checks**: ```bash # Cron job for health monitoring through Caddy */5 * * * * curl -s https://yourdomain.com/health-check-b8e3f4a2 > /dev/null # Or direct to service for internal monitoring */5 * * * * curl -s http://localhost:1127/health-check-b8e3f4a2 > /dev/null ``` 2. **Monitor notification delivery**: - Configure notification backends (Pushover, Pushbullet, etc.) - Set up monitoring of notification delivery in your backends - Monitor log files for errors - All application logs are automatically sent to health backends for real-time monitoring ## Troubleshooting ### Common Issues 1. **Service won't start**: ```bash sudo journalctl -u emergency-access -n 50 sudo systemctl status emergency-access ``` 2. **Notification failures**: ```bash # Test dschep/ntfy installation and configuration ntfy -c /etc/emergency-access/ntfy.yml send "test message" # Check ntfy configuration cat /etc/emergency-access/ntfy.yml # Test specific backend ntfy -c /etc/emergency-access/ntfy.yml -b matrix_sec send "test message" ``` 3. **File permission errors**: ```bash sudo chown -R emergency-access:emergency-access /opt/emergency-access sudo chown emergency-access:emergency-access /etc/emergency-access/* ``` ### Configuration Validation Test your setup before deployment: ```bash # Validate configuration sudo -u emergency-access /opt/emergency-access/venv/bin/python /opt/emergency-access/main.py --validate # Test notifications manually with your backend ntfy -c /etc/emergency-access/ntfy.yml -b matrix_sec send "Test notification" ntfy -c /etc/emergency-access/ntfy.yml -b pushover_emergency send "Test emergency notification" ``` ## Development ### Running in Development Mode ```bash # Create virtual environment python3 -m venv venv source venv/bin/activate # Install dependencies pip install -r requirements.txt # Run with development config EMERGENCY_CONFIG=config.json python main.py ``` ### Testing ```bash # Run comprehensive test suite python test.py # Run quick configuration tests only python test.py --quick # Test specific endpoints (replace with your actual paths) curl http://localhost:1127/emergency-key-backup-[YOUR_SECURE_PATH] curl http://localhost:1127/emergency-key-master-[YOUR_SECURE_PATH] curl http://localhost:1127/health-check-[YOUR_SECURE_PATH] # Generate new configuration with secure paths python generate_secure_paths.py --keys 3 --output config ``` ## Multiple Key Implementation Details ### Path Security #### Path Length Requirements - **Minimum**: 100 characters - **Recommended**: 120+ characters - **Example length**: `/emergency-key-backup-a7f9d2e1b4c7f3e6d9a2b5c8e1f4d7a0b3c6e9f2a5d8b1c4e7f0a3d6b9c2e5f8a1d4b7c0e3f6d9a2b5c8e1f4a7b0d3` (130 chars) #### Why Ultra-Long Paths? 1. **Prevent accidental access**: Impossible to guess or stumble upon 2. **Reduce false positives**: No accidental emergency notifications 3. **Security through obscurity**: Additional layer of protection 4. **URL safety**: Only lowercase letters and numbers ### Dynamic Route Registration The application dynamically registers routes for each configured key: ```python for key_id, key_config in config.keys.items(): handler = create_key_handler(key_config) endpoint_name = f'get_key_part_{key_id}' app.add_url_rule(key_config.route, endpoint_name, handler, methods=['GET']) ``` ### Individual Key Handlers Each key gets its own handler function with specific configuration: ```python def create_key_handler(key_config): def get_key_part(): # Send notifications to key-specific backends notification_success, successful_backends = send_ntfy_notification( key_config.backends, key_config.message, "EMERGENCY ACCESS ALERT" ) # Return key with key ID return jsonify({ 'success': True, 'key_id': key_config.key_id, 'key_part': content, 'timestamp': time.time(), 'notified_backends': successful_backends }) return get_key_part ``` ### Health Check Validation Health checks now validate all configured keys: ```python # Test all key files for key_id, key_config in config.keys.items(): key_file_success, key_content = read_file_safely(key_config.file_path) key_files_status[key_id] = key_file_success ``` ### Generate Secure Configuration Use the included path generator for cryptographically secure paths: ```bash # Generate new configuration with secure paths python generate_secure_paths.py --keys 3 --output config # Generate complete setup including Caddy config and setup scripts python generate_secure_paths.py --keys 4 --domain your-domain.com --output all # Generate just secure paths for existing configuration python generate_secure_paths.py --keys 2 --output paths ``` The path generator creates: - **Configuration file**: Complete JSON config with secure paths - **Caddy configuration**: Reverse proxy setup with path restrictions - **Setup script**: Automated key file creation with proper permissions - **Security validation**: Ensures all paths meet minimum length requirements ### Security Best Practices #### Path Storage - Store paths in secure password manager - Document which path corresponds to which key - Never store paths in plain text logs - Use the path generator for cryptographically secure random paths #### Access Monitoring - Monitor reverse proxy logs for path access - Set up alerts for any key access - Regularly audit notification delivery - Implement rate limiting to prevent brute force attempts #### Emergency Procedures 1. **Key Compromise**: Change the path, not the key content 2. **False Positive**: Investigate immediately, check logs 3. **Path Leak**: Generate new paths and update configuration 4. **Notification Failure**: Validate all backends before deployment ### Migration Considerations This implementation removes legacy single-key support for enhanced security: #### Clean Architecture - Removed all legacy single-key configuration support - Simplified configuration structure with only `keys` section - All paths must be 100+ characters for security - Each key requires explicit configuration - No backward compatibility to ensure security by default ## License This project is designed for emergency access scenarios. Use responsibly and ensure proper security measures are in place. ## Support For issues and questions: 1. Check the logs: `/var/log/emergency-access.log` 2. Verify configuration: `/etc/emergency-access/config.json` 3. Test notification systems independently 4. Monitor service status: `systemctl status emergency-access` 5. Use path generator: `python generate_secure_paths.py --help` ### Validation Commands ```bash # Validate configuration python -c "from config import Config; Config('/etc/emergency-access/config.json')" # Test file access sudo -u emergency-access cat /etc/emergency-access/backup-key.txt # Test notifications ntfy -c /etc/emergency-access/ntfy.yml -b matrix_sec send "Test message" # Generate new secure paths python generate_secure_paths.py --keys 3 --path-length 120 ```