User Guide: Security Hardening
Understanding Security in cliproxyapi++
cliproxyapi++ is built with a "Defense in Depth" philosophy, meaning multiple layers of security protect your deployments. This guide explains how to configure and use these security features effectively.
Quick Security Checklist
Before deploying to production:
# 1. Verify Docker image is signed
docker pull KooshaPari/cliproxyapi-plusplus:latest
docker trust verify KooshaPari/cliproxyapi-plusplus:latest
# 2. Set secure file permissions
chmod 600 auths/*.json
chmod 700 auths/
# 3. Enable TLS
# Edit config.yaml to enable TLS (see below)
# 4. Enable encryption
# Generate encryption key and set in config.yaml
# 5. Configure rate limiting
# Set appropriate limits in config.yamlContainer Security
Hardened Docker Deployment
docker-compose.yml:
services:
cliproxy:
image: KooshaPari/cliproxyapi-plusplus:latest
container_name: cliproxyapi++
# Security options
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=100m
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
# Non-root user
user: "65534:65534"
# Volumes (writable only for these)
volumes:
- ./config.yaml:/config/config.yaml:ro
- ./auths:/auths:rw
- ./logs:/logs:rw
- ./tls:/tls:ro
# Network
ports:
- "8317:8317"
# Resource limits
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '0.5'
memory: 256M
restart: unless-stoppedExplanation:
no-new-privileges: Prevents processes from gaining more privilegesread_only: Makes container filesystem immutable (attackers can't modify binaries)tmpfs:noexec: Prevents execution of files in/tmpcap_drop:ALL: Drops all Linux capabilitiescap_add:NET_BIND_SERVICE: Only adds back the ability to bind portsuser:65534:65534: Runs as non-root "nobody" user
Seccomp Profiles (Advanced)
Custom seccomp profile:
# Save seccomp profile
cat > seccomp-profile.json << 'EOF'
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": ["read", "write", "open", "close", "socket", "bind", "listen"],
"action": "SCMP_ACT_ALLOW"
}
]
}
EOF
# Use in docker-compose
security_opt:
- seccomp:./seccomp-profile.jsonTLS Configuration
Enable HTTPS
config.yaml:
server:
port: 8317
tls:
enabled: true
cert_file: "/tls/tls.crt"
key_file: "/tls/tls.key"
min_version: "1.2"
cipher_suites:
- "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
- "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"Generate Self-Signed Certificate (Testing)
# Generate private key
openssl genrsa -out tls.key 2048
# Generate certificate
openssl req -new -x509 -key tls.key -out tls.crt -days 365 \
-subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
# Set permissions
chmod 600 tls.key
chmod 644 tls.crtUse Let's Encrypt (Production)
# Install certbot
sudo apt-get install certbot
# Generate certificate
sudo certbot certonly --standalone -d proxy.example.com
# Copy to tls directory
sudo cp /etc/letsencrypt/live/proxy.example.com/fullchain.pem tls/tls.crt
sudo cp /etc/letsencrypt/live/proxy.example.com/privkey.pem tls/tls.key
# Set permissions
sudo chown $USER:$USER tls/tls.key tls/tls.crt
chmod 600 tls/tls.key
chmod 644 tls/tls.crtCredential Encryption
Enable Encryption
config.yaml:
auth:
encryption:
enabled: true
key: "YOUR_32_BYTE_ENCRYPTION_KEY_HERE"Generate Encryption Key
# Method 1: Using openssl
openssl rand -base64 32
# Method 2: Using Python
python3 -c "import secrets; print(secrets.token_urlsafe(32))"
# Method 3: Using /dev/urandom
head -c 32 /dev/urandom | base64Environment Variable (Recommended)
auth:
encryption:
enabled: true
key: "${CLIPROXY_ENCRYPTION_KEY}"# Set in environment
export CLIPRO_ENCRYPTION_KEY="$(openssl rand -base64 32)"
# Use in docker-compose
environment:
- CLIPRO_ENCRYPTION_KEY=${CLIPRO_ENCRYPTION_KEY}Migrating Existing Credentials
When enabling encryption, existing credentials remain unencrypted. To encrypt them:
# 1. Enable encryption in config.yaml
# 2. Restart service
# 3. Re-add credentials (they will be encrypted)
curl -X POST http://localhost:8317/v0/management/auths \
-H "Content-Type: application/json" \
-d '{
"provider": "claude",
"type": "api_key",
"token": "sk-ant-xxxxx"
}'Access Control
IP Allowlisting
config.yaml:
server:
security:
ip_allowlist:
enabled: true
allowed_ips:
- "10.0.0.0/8" # Private network
- "192.168.1.100" # Specific IP
- "203.0.113.0/24" # Public networkBlock all except allowed:
server:
security:
ip_allowlist:
enabled: true
allowed_ips:
- "10.0.0.0/8"
deny_all: true # Block all except allowed_ipsIP Denylisting
server:
security:
ip_denylist:
enabled: true
denied_ips:
- "192.0.2.0/24" # Test network
- "198.51.100.100" # Specific IPIP-Based Rate Limiting
server:
security:
rate_limiting:
enabled: true
requests_per_second: 10
burst: 20
per_ip: trueRate Limiting
Global Rate Limiting
server:
rate_limit:
enabled: true
requests_per_second: 100
burst: 200Per-Provider Rate Limiting
providers:
claude:
rate_limit:
requests_per_minute: 100
tokens_per_minute: 100000
openai:
rate_limit:
requests_per_minute: 500
tokens_per_minute: 200000Quota-Based Rate Limiting
providers:
claude:
quota:
limit: 1000000 # Tokens per month
reset: "monthly"Security Headers
Enable Security Headers
config.yaml:
server:
security:
headers:
enabled: true
strict_transport_security: "max-age=31536000; includeSubDomains"
content_type_options: "nosniff"
frame_options: "DENY"
xss_protection: "1; mode=block"
content_security_policy: "default-src 'self'"Headers added to all responses:
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'Audit Logging
Enable Audit Logging
config.yaml:
logging:
audit:
enabled: true
file: "/logs/audit.log"
format: "json"
events:
- "auth_success"
- "auth_failure"
- "token_refresh"
- "config_change"
- "provider_request"
- "security_violation"View Audit Logs
# View all audit events
tail -f logs/audit.log
# Filter for auth failures
grep "auth_failure" logs/audit.log
# Filter for security violations
grep "security_violation" logs/audit.log
# Pretty print JSON logs
cat logs/audit.log | jq '.'Audit Log Format
{
"timestamp": "2026-02-19T23:00:00Z",
"event_type": "auth_failure",
"provider": "claude",
"user_id": "user@example.com",
"ip": "192.168.1.100",
"result": "invalid_token",
"details": {
"reason": "Token expired"
}
}Security Monitoring
Enable Metrics
config.yaml:
metrics:
enabled: true
port: 9090
path: "/metrics"Security metrics exposed:
# HELP cliproxy_auth_failures_total Total authentication failures
# TYPE cliproxy_auth_failures_total counter
cliproxy_auth_failures_total{provider="claude"} 5
# HELP cliproxy_rate_limit_violations_total Total rate limit violations
# TYPE cliproxy_rate_limit_violations_total counter
cliproxy_rate_limit_violations_total{ip="192.168.1.100"} 10
# HELP cliproxy_security_events_total Total security events
# TYPE cliproxy_security_events_total counter
cliproxy_security_events_total{event_type="suspicious_activity"} 1Query Metrics
# Get auth failure rate
curl http://localhost:9090/metrics | grep auth_failures
# Get rate limit violations
curl http://localhost:9090/metrics | grep rate_limit_violations
# Get all security events
curl http://localhost:9090/metrics | grep security_eventsIncident Response
Block Suspicious IP
# Add to denylist
curl -X POST http://localhost:8317/v0/management/security/ip-denylist \
-H "Content-Type: application/json" \
-d '{
"ip": "192.168.1.100",
"reason": "Suspicious activity"
}'Revoke Credentials
# Delete credential
curl -X DELETE http://localhost:8317/v0/management/auths/claudeEnable Maintenance Mode
server:
maintenance_mode: true
message: "Scheduled maintenance in progress"Security Best Practices
Development
- [ ] Never commit credentials to version control
- [ ] Use pre-commit hooks to scan for secrets
- [ ] Enable security headers in development
- [ ] Test with different user permissions
- [ ] Review audit logs regularly
Staging
- [ ] Use staging-specific credentials
- [ ] Enable all security features
- [ ] Test rate limiting
- [ ] Verify TLS configuration
- [ ] Monitor security metrics
Production
- [ ] Use production TLS certificates (not self-signed)
- [ ] Enable encryption for credentials
- [ ] Configure IP allowlisting
- [ ] Set appropriate rate limits
- [ ] Enable comprehensive audit logging
- [ ] Set up security alerts
- [ ] Regular security audits
- [ ] Rotate credentials quarterly
- [ ] Keep dependencies updated
Troubleshooting
TLS Certificate Issues
Problem: certificate verify failed
Solutions:
- Verify certificate file exists:
ls -la tls/tls.crt - Check certificate is valid:
openssl x509 -in tls/tls.crt -text -noout - Verify key matches cert:
openssl x509 -noout -modulus -in tls/tls.crt | openssl md5 - Check file permissions:
chmod 600 tls/tls.key
Encryption Key Issues
Problem: decryption failed
Solutions:
- Verify encryption key is 32 bytes
- Check key is set in config/environment
- Ensure key hasn't changed
- If key changed, re-add credentials
Rate Limiting Too Strict
Problem: Legitimate requests blocked
Solutions:
- Increase rate limit in config
- Increase burst size
- Whitelist trusted IPs
- Use per-user rate limiting instead of per-IP
IP Allowlisting Issues
Problem: Can't access from allowed IP
Solutions:
- Verify IP address:
curl ifconfig.me - Check CIDR notation
- Verify allowlist is enabled
- Check denylist doesn't block
Audit Logs Not Working
Problem: No events in audit log
Solutions:
- Verify audit logging is enabled
- Check file permissions on log directory
- Verify events are enabled in config
- Check disk space
Security Audits
Pre-Deployment Checklist
#!/bin/bash
# security-check.sh
echo "Running security checks..."
# Check file permissions
echo "Checking file permissions..."
find auths/ -type f ! -perm 600
find auths/ -type d ! -perm 700
# Check for secrets
echo "Scanning for secrets..."
git secrets --scan
# Check TLS
echo "Verifying TLS..."
openssl x509 -in tls/tls.crt -checkend 86400
# Check dependencies
echo "Scanning dependencies..."
trivy fs .
echo "Security checks complete!"Run before deployment:
./security-check.shNext Steps
- See SPEC.md for technical security details
- See ../auth/ for authentication security
- See ../operations/ for operational security
- See ../../api/ for API security