Skip to content

Security Hardening and Rotation

Production deployments should have:

  • HTTPS for all user traffic.
  • PostgreSQL, Redis, management gRPC, and metrics not exposed publicly.
  • Root password, every security-domain key, and the cluster secret managed in a Secret Manager or Kubernetes Secret.
  • No default weak secrets.
  • Database and secrets backed up and restored together.
  • Metrics restricted by source or authentication.
SecretImpact if lostRotation difficultyHandling
jwt.secretExisting tokens become invalidMediumPlan rotation and expect re-login
security.opaque_server_setup_secretOPAQUE password records may failHighDo not routinely rotate; back it up
security.credential_encryption_keyEncrypted Provider credentials cannot be decryptedHighMigrate credentials before replacement
security.totp_encryption_keyExisting TOTP enrollment cannot be verifiedHighMigrate ciphertext or schedule user re-enrollment
security.email_outbox_encryption_keyQueued email payloads cannot be decryptedHighDrain the queue, then replace it on every replica together
Proxy, media-swarm, provider-session, and file-token keysIssued URLs, announcements, sessions, or tokens expireMediumReplace on every replica and accept the short-lived expiry
Login-discovery and WebAuthn-enumeration keysTemporary decoys changeLowReplace on every replica together
cluster.secretNode-to-node auth failsMediumCoordinate all replicas
management.auth_tokenCLI/management TCP authLowRotate regularly if TCP is used
metrics.auth.bearer_tokenMetrics scrape authLowSync monitoring config
SMTP/OAuth2/Provider credentialsEmail, login, or media failuresMediumFollow upstream rotation policy
  1. Back up PostgreSQL, config files, and all production secrets.
  2. Identify the target and blast radius: login, Provider credentials, cluster, management, or metrics.
  3. Validate in a production-like test environment.
  4. Prepare rollback: old secret, old config, old image, or database backup.
  5. Notify users if re-login or Provider rebind may be required.
  6. Rotate during a quiet window and watch login failures, Provider decrypt errors, and WebSocket reconnects.
  1. Generate a new secret.
  2. Update secret storage.
  3. Restart all SyncTV replicas.
  4. Expect old access and refresh tokens to fail.
  5. Watch 401, login success rate, and WebSocket reconnects.

Helm injects Secrets through environment variables. Change the version marker in values to trigger a rollout after updating the Secret:

existingSecret: "synctv-production-secret"
secretRolloutChecksum: "2026-07-28-jwt-rotation"
Terminal window
helm upgrade --install synctv ./helm/synctv \
-n synctv \
-f values.production.yaml
kubectl -n synctv rollout status deploy/synctv

When a Secret controller updates the object without a Reloader, restart the Deployment explicitly and wait for every replica:

Terminal window
kubectl -n synctv rollout restart deploy/synctv
kubectl -n synctv rollout status deploy/synctv

Cluster, signing, and encryption key rotations must converge every replica on the same version. Watch node authentication, login, and decryption errors throughout the rollout.

If security.credential_encryption_key must change, do not simply replace it and start the service. A safe flow is:

  1. Back up the database and old key.
  2. Stop writes to Provider credentials.
  3. Decrypt existing Provider credentials with the old key.
  4. Encrypt them with the new key and write them back.
  5. Update configuration to the new key.
  6. Start SyncTV and verify Provider login, browse, and playback.

If no migration tool exists, keep the old key or delete and recreate affected Provider credentials.

The OPAQUE setup secret is a long-lived server secret for password authentication. Do not rotate it unless you have an account password migration or forced reset plan.

If it leaks:

  • Assess scope immediately.
  • Force password reset or OPAQUE record recreation.
  • Rotate JWT secret and clear sessions.
  • Keep audit records and an incident timeline.
ItemAction
TLSPublic traffic only over HTTPS/WSS
CORSAllow only real frontend origins, no path
Trusted proxyTrust only actual reverse proxy addresses
Rate limitsConfigure login, verification, WebSocket, and API limits
WebAuthnMatch rp_origin to real HTTPS origin
OAuth2Exact redirect URL and Redis-backed state
ProviderEncrypt credentials; no tokens in sourceConfig
LogsJSON logs without secrets, cookies, or JWTs
MetricsNo public exposure; use bearer or platform auth
BackupsBack up and restore database and secrets together