Complete security hardening checklist for deploying VideoAnnotator in production environments.
-
API Keys Generated: Create production-specific API keys
uv run python -m scripts.manage_tokens create \ --user-id prod_admin \ --username "Production Admin" \ --email admin@yourdomain.com \ --scopes read,write,admin \ --expires-in-days 90 -
Key Expiration Set: Production keys expire within 90 days
# Verify expiration uv run python -m scripts.manage_tokens list -
Test Keys Removed: Delete all development/test keys
# List all keys uv run python -m scripts.manage_tokens list # Revoke test keys uv run python -m scripts.manage_tokens revoke va_api_test...
-
AUTH_REQUIRED=true: Authentication enabled (default in v1.3.0+)
# Verify in environment echo $AUTH_REQUIRED # Should be empty or "true"
-
Keys Stored Securely: Using secrets manager, not hardcoded
- AWS Secrets Manager
- HashiCorp Vault
- Azure Key Vault
- Environment variables only (minimum security)
-
HTTPS Enabled: All traffic encrypted with TLS/SSL
# nginx example server { listen 443 ssl; ssl_certificate /path/to/cert.pem; ssl_certificate_key /path/to/key.pem; ssl_protocols TLSv1.2 TLSv1.3; location / { proxy_pass http://localhost:18011; } }
-
CORS Restricted: Specific origins only, no wildcards
export CORS_ORIGINS="https://app.yourdomain.com,https://admin.yourdomain.com" # Never: CORS_ORIGINS="*"
-
Firewall Rules: API server not directly exposed to internet
# Only allow reverse proxy sudo ufw allow from 127.0.0.1 to any port 18011 sudo ufw deny 18011 -
Rate Limiting: Prevent abuse (implement in reverse proxy)
# nginx rate limiting limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s; location /api/ { limit_req zone=api_limit burst=20 nodelay; }
-
Database Encryption: SQLite file encrypted or on encrypted volume
# Use LUKS, dm-crypt, or cloud provider encryption -
Token Storage Secure:
tokens/tokens.jsonhas proper permissionschmod 600 tokens/tokens.json chmod 600 tokens/encryption.key chown videoannotator:videoannotator tokens/* -
Storage Path Permissions: Job storage not world-readable
chmod 750 storage/ chown -R videoannotator:videoannotator storage/
-
Backup Strategy: Regular backups of database and tokens
# Example backup script #!/bin/bash DATE=$(date +%Y%m%d_%H%M%S) tar -czf "backup_${DATE}.tar.gz" \ videoannotator.db \ tokens/ \ storage/ aws s3 cp "backup_${DATE}.tar.gz" s3://backups/videoannotator/
-
DEBUG=false: Debug mode disabled
export DEBUG=false # Or remove DEBUG variable entirely
-
Secure Defaults: Review all environment variables
# .env.production AUTH_REQUIRED=true CORS_ORIGINS=https://app.yourdomain.com DEBUG=false LOG_LEVEL=INFO VIDEOANNOTATOR_STORAGE_DIR=/var/lib/videoannotator/storage -
Log Sanitization: No sensitive data in logs
- API keys masked in logs
- User emails partially redacted
- File paths sanitized
-
Storage Retention: Automatic cleanup configured
# config.yaml storage: retention_days: 90 auto_cleanup: true cleanup_schedule: "0 2 * * *" # 2 AM daily
-
Centralized Logging: Logs sent to monitoring service
- Papertrail
- Datadog
- CloudWatch
- ELK Stack
-
Security Alerts: Monitor for suspicious activity
# Example alert rules - name: Failed Authentication Attempts condition: "count(401 responses) > 10 in 5 minutes" action: email_admin - name: Unusual API Usage condition: "requests per minute > 1000" action: email_admin
-
Access Logs: All API requests logged with user context
tail -f logs/api_requests.log
-
Error Monitoring: Exception tracking enabled
- Sentry
- Rollbar
- Bugsnag
-
Non-Root User: Run as dedicated user account
sudo useradd -r -s /bin/false videoannotator sudo chown -R videoannotator:videoannotator /opt/videoannotator
-
System Updates: OS and dependencies up to date
sudo apt update && sudo apt upgrade -y -
Minimal Packages: Only necessary software installed
# Remove unnecessary packages sudo apt autoremove -y -
SELinux / AppArmor: Mandatory access control enabled
# Check SELinux status sestatus # Or AppArmor sudo aa-status
# Dockerfile.production
FROM python:3.12-slim
# Run as non-root user
RUN useradd -r -u 1000 videoannotator
# Install dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copy application
COPY --chown=videoannotator:videoannotator . /app
WORKDIR /app
# Set secure permissions
RUN chmod 750 /app && \
mkdir -p /app/storage /app/tokens /app/logs && \
chown -R videoannotator:videoannotator /app
# Switch to non-root user
USER videoannotator
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:18011/health || exit 1
# Start application
CMD ["uv", "run", "videoannotator"]# docker-compose.production.yml
version: '3.8'
services:
videoannotator:
build:
context: .
dockerfile: Dockerfile.production
restart: unless-stopped
environment:
- AUTH_REQUIRED=true
- CORS_ORIGINS=https://app.yourdomain.com
- DEBUG=false
- LOG_LEVEL=INFO
volumes:
- ./storage:/app/storage:rw
- ./tokens:/app/tokens:ro
- ./logs:/app/logs:rw
ports:
- "127.0.0.1:18011:18011" # Only localhost
networks:
- internal
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
- /var/tmp
nginx:
image: nginx:alpine
restart: unless-stopped
ports:
- "443:443"
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./certs:/etc/nginx/certs:ro
networks:
- internal
depends_on:
- videoannotator
networks:
internal:
driver: bridge# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: videoannotator
namespace: production
spec:
replicas: 2
selector:
matchLabels:
app: videoannotator
template:
metadata:
labels:
app: videoannotator
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 1000
containers:
- name: videoannotator
image: videoannotator:1.3.0
ports:
- containerPort: 18011
env:
- name: AUTH_REQUIRED
value: "true"
- name: CORS_ORIGINS
valueFrom:
configMapKeyRef:
name: videoannotator-config
key: cors_origins
- name: API_KEY
valueFrom:
secretKeyRef:
name: videoannotator-secrets
key: api_key
resources:
limits:
cpu: "2"
memory: "4Gi"
requests:
cpu: "1"
memory: "2Gi"
livenessProbe:
httpGet:
path: /health
port: 18011
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 18011
initialDelaySeconds: 5
periodSeconds: 5
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: storage
mountPath: /app/storage
- name: tokens
mountPath: /app/tokens
readOnly: true
- name: tmp
mountPath: /tmp
volumes:
- name: storage
persistentVolumeClaim:
claimName: videoannotator-storage
- name: tokens
secret:
secretName: videoannotator-tokens
- name: tmp
emptyDir: {}# 1. Verify HTTPS is enforced
curl -I http://yourdomain.com/api/v1/health
# Should redirect to HTTPS or return 301/302
# 2. Test authentication is required
curl http://yourdomain.com/api/v1/jobs
# Should return 401 Unauthorized
# 3. Test CORS restrictions
curl -H "Origin: http://evil.com" \
-H "Access-Control-Request-Method: POST" \
-X OPTIONS https://yourdomain.com/api/v1/jobs
# Should NOT include access-control-allow-origin header
# 4. Verify API key works
curl -H "Authorization: Bearer $API_KEY" \
https://yourdomain.com/api/v1/jobs
# Should return 200 OK
# 5. Test rate limiting (if configured)
for i in {1..100}; do
curl https://yourdomain.com/api/v1/health &
done
# Should eventually return 429 Too Many RequestsConsider hiring security professionals to test:
- SQL injection attempts
- XSS vulnerabilities
- CSRF attacks
- Authentication bypass attempts
- Rate limit bypass
- File upload exploits
# Scan Docker image
docker scan videoannotator:1.3.0
# Scan dependencies
uv run pip-audit
# Check for CVEs
uv run safety check- Review access logs for anomalies
- Check error rates in monitoring
- Verify backup completion
-
Update dependencies
uv sync --upgrade
-
Review and rotate API keys
-
Check disk space usage
-
Review security alerts
- Rotate API keys (90-day expiration)
- Update SSL certificates (if not automated)
- Review and update CORS origins
- Security audit
- Penetration testing
-
Immediate Actions:
# Revoke all API keys uv run python -m scripts.manage_tokens revoke-all # Stop API server systemctl stop videoannotator # Review access logs grep -i "suspicious" logs/api_requests.log
-
Investigation:
- Review all logs for unauthorized access
- Check database for data exfiltration
- Identify attack vector
- Document timeline
-
Recovery:
- Patch vulnerability
- Generate new API keys
- Notify affected users
- Update security measures
- Resume service
# 1. Immediately revoke compromised key
uv run python -m scripts.manage_tokens revoke va_api_compromised_key
# 2. Generate new keys
uv run python -m scripts.manage_tokens create \
--user-id admin \
--expires-in-days 90
# 3. Update all applications using the old key
# 4. Review logs for unauthorized usage
grep "va_api_compromised_key" logs/api_requests.log-
Data Minimization: Only store necessary data
-
Right to Erasure: Implement data deletion
uv run videoannotator job delete <job_id> --purge
-
Data Portability: Export user data in standard format
-
Consent Management: Track user consent for processing
-
Breach Notification: 72-hour notification process
- BAA in Place: Business Associate Agreement signed
- Audit Logging: All PHI access logged
- Encryption at Rest: Database and storage encrypted
- Encryption in Transit: HTTPS/TLS enabled
- Access Controls: Role-based access implemented
- Security Issues: security@yourdomain.com
- Emergency Contact: +1-XXX-XXX-XXXX
- Incident Response Team: incidents@yourdomain.com
- Authentication Guide - API key management
- CORS Configuration - Cross-origin security
- Deployment Guide - Production deployment