Skip to content

Security Best Practices

Security considerations and hardening for Tempo deployments.

Overview

This guide covers security best practices for deploying Tempo in production.

Critical Security Requirements

JWT Secret Key

MUST be set in production via .env as JWT_SECRET_KEY (production Compose fails closed if missing). The API also rejects the historical placeholder string at startup.

  • Generate a secure random key: openssl rand -base64 32
  • Minimum 32 characters
  • Store in gitignored .env (or a secrets manager)
  • Never commit to version control
  • Rotate periodically

HTTPS

REQUIRED for production deployments. JWT tokens are stored in httpOnly cookies, which require HTTPS for secure transmission.

  • Use valid SSL/TLS certificates
  • Configure reverse proxy (Nginx, Traefik, etc.)
  • Redirect HTTP to HTTPS
  • Use strong cipher suites

Database Security

  • Set POSTGRES_PASSWORD in .env (required by production Compose; no default in the file)
  • Use strong passwords (minimum 16 characters); existing volumes must match the password already in the cluster
  • Restrict database access to the application (Compose does not publish Postgres by default)
  • Use connection encryption if accessing remotely
  • Regular security updates

Authentication Security

Password Requirements

Tempo enforces NIST/CISA-aligned rules for new passwords (registration and password change):

  • Length: 16–64 characters
  • Encoding: UTF-8 length must not exceed 72 bytes (bcrypt limit)
  • Complexity: No mandatory mixed case, digits, or symbols—prefer memorable passphrases
  • Additional checks: common-password blocklist; password must not contain the username (when the username is at least 3 characters); no single character repeated five or more times in a row

Existing credentials remain valid until the user sets a new password. BCrypt hashing is already implemented.

JWT Configuration

  • Set appropriate expiration (default: 7 days)
  • Use secure random secret key
  • Configure issuer and audience
  • Store tokens in httpOnly cookies (already implemented)

Registration Lock

  • Registration is automatically locked after first user
  • Prevents unauthorized account creation
  • Single-user deployment pattern
  • Forgotten passphrase: host-only reset-password on the API process (Docker exec or dotnet Tempo.Api.dll reset-password). Not a public HTTP route, not email, and not a way to add a second account. See How do I reset my password?.

Network Security

Firewall Configuration

  • Expose the reverse proxy (80/443), not Compose service ports
  • Production Compose publishes only 127.0.0.1:3004 by default (Postgres and API stay on the Compose network)
  • Use firewall rules to restrict access
  • Consider VPN for administrative access
  • Block unnecessary network traffic

CORS Configuration

The default production path does not need CORS: the command center is same-origin /api, and the daily driver is native. Production Compose does not set CORS__AllowedOrigins.

Only configure CORS if you intentionally expose the API to a browser on another origin:

CORS__AllowedOrigins: "https://yourdomain.com"
  • Only include trusted domains
  • Don't use wildcards in production
  • Test CORS configuration thoroughly

Reverse Proxy

Use a reverse proxy (Nginx, Traefik) to: - Terminate SSL/TLS - Hide internal service ports - Add security headers - Implement rate limiting - Use one upstream to 127.0.0.1:3004 (see production.md)

Application Security

Input Validation

  • All file uploads are validated (size, MIME type)
  • File paths are sanitized
  • SQL injection prevented by Entity Framework parameterization
  • XSS protection via React's built-in escaping

File Upload Security

  • Maximum file size limits (50MB default, 500MB for bulk import)
  • MIME type validation
  • File extension validation
  • Storage outside web root

Error Handling

  • Don't expose sensitive information in error messages
  • Log errors securely
  • Use generic error messages for users
  • Detailed errors only in development mode

Data Security

Data Encryption

  • Use HTTPS for data in transit
  • Consider database encryption at rest
  • Encrypt backups
  • Secure media file storage

Backup Security

  • Encrypt backup files
  • Store backups securely
  • Limit backup access
  • Test restore procedures

Data Privacy

  • All data stored locally (no cloud sync)
  • User controls all data
  • No third-party data sharing
  • GDPR considerations for EU users

Container Security

Image Security

  • Use official base images
  • Keep images updated
  • Scan images for vulnerabilities
  • Use specific version tags (not latest)

Container Configuration

  • Run containers as non-root user (if possible)
  • Limit container capabilities
  • Use read-only filesystems where possible
  • Implement resource limits

Secrets Management

  • Use Docker secrets or environment variables
  • Never hardcode secrets
  • Rotate secrets regularly
  • Use secrets management tools (HashiCorp Vault, etc.)

Monitoring and Auditing

Logging

  • Log authentication events
  • Log security-relevant actions
  • Monitor for suspicious activity
  • Retain logs appropriately

Monitoring

  • Monitor failed login attempts
  • Track unusual API usage
  • Monitor resource usage
  • Set up alerts for anomalies

Regular Updates

  • Keep dependencies updated
  • Apply security patches promptly
  • Monitor security advisories
  • Test updates in staging first

Security Headers

Configure security headers in reverse proxy:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'" always;

Checklist

Pre-Deployment

  • JWT secret key configured via .env (JWT_SECRET_KEY) — done by production Compose
  • Database password configured via .env (POSTGRES_PASSWORD) — done by production Compose
  • HTTPS configured
  • Postgres/API unpublished; command center loopback only — done by production Compose
  • CORS only if you expose the API to a browser on another origin (not required by default)
  • Firewall rules set
  • Reverse proxy configured (one upstream to 127.0.0.1:3004)
  • Security headers added

Ongoing

  • Regular security updates
  • Monitor logs for suspicious activity
  • Review access logs
  • Test backup and restore
  • Rotate secrets periodically
  • Review and update dependencies

Incident Response

If a security issue is discovered:

  1. Assess the severity
  2. Contain the issue
  3. Notify affected users if necessary
  4. Apply fixes
  5. Review and improve security measures
  6. Document the incident

Reporting Security Issues

Report security vulnerabilities responsibly:

  • Email: [security contact if available]
  • GitHub: Create a private security advisory
  • Do not disclose publicly until fixed

Next Steps