Files
sentryagent-idp/docs/compliance/secrets-rotation.md
SentryAgent.ai Developer fd90b2acd1 feat(phase-3): workstream 6 — SOC 2 Type II Preparation
Implements all 22 WS6 tasks completing Phase 3 Enterprise.

Column-level encryption (AES-256-CBC, Vault-backed key) via EncryptionService
applied to credentials.secret_hash, credentials.vault_path,
webhook_subscriptions.vault_secret_path, and agent_did_keys.vault_key_path.
Backward-compatible: isEncrypted() guard skips decryption for existing
plaintext rows until next read-write cycle.

Audit chain integrity (CC7.2): AuditRepository computes SHA-256 Merkle hash
on every INSERT (hash = SHA-256(eventId+timestamp+action+outcome+agentId+orgId+prevHash)).
AuditVerificationService walks the full chain verifying hash continuity.
AuditChainVerificationJob runs hourly; sets agentidp_audit_chain_integrity
Prometheus gauge to 1 (pass) or 0 (fail).

TLS enforcement (CC6.7): TLSEnforcementMiddleware registered as first
middleware in Express stack; 301 redirect on non-https X-Forwarded-Proto
in production.

SecretsRotationJob (CC9.2): hourly scan for credentials expiring within 7
days; increments agentidp_credentials_expiring_soon_total.

ComplianceController + routes: GET /audit/verify (auth+audit:read scope,
30/min rate-limit); GET /compliance/controls (public, Cache-Control 60s).
ComplianceStatusStore: module-level map updated by jobs, consumed by controller.

Prometheus: 2 new metrics (agentidp_credentials_expiring_soon_total,
agentidp_audit_chain_integrity); 6 alerting rules in alerts.yml.

Compliance docs: soc2-controls-matrix.md, encryption-runbook.md,
audit-log-runbook.md, incident-response.md, secrets-rotation.md.

Tests: 557 unit tests passing (35 suites); 26 new tests (EncryptionService,
AuditVerificationService); 19 compliance integration tests. TypeScript clean.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 00:41:53 +00:00

4.8 KiB

Secrets Rotation Runbook — SentryAgent.ai AgentIdP

Control: SOC 2 CC9.2 — Secrets Rotation Last updated: 2026-03-31


Overview

AgentIdP manages three categories of secrets that require periodic rotation:

  1. Agent client secrets — Per-credential client secrets used for OAuth 2.0 token issuance
  2. OIDC signing keys — RSA/EC keys used to sign ID tokens
  3. AES-256-CBC encryption key — Column-level database encryption key (see encryption-runbook.md)

1. Agent Credential (Client Secret) Rotation

API endpoint

POST /api/v1/agents/:agentId/credentials/:credentialId/rotate

Requires Bearer token with agents:write scope.

Procedure

# 1. List active credentials for the agent
curl -s -H "Authorization: Bearer <token>" \
  "https://api.sentryagent.ai/v1/agents/<agentId>/credentials?status=active"

# 2. Rotate the credential (generate new secret)
curl -s -X POST \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"expiresAt": "2027-03-31T00:00:00.000Z"}' \
  "https://api.sentryagent.ai/v1/agents/<agentId>/credentials/<credentialId>/rotate"

# Response includes the new clientSecret — store it immediately; it is never shown again

Key points

  • The new clientSecret is returned once only — store it securely before the response is discarded
  • The agent's previous secret is immediately invalidated (Vault KV v2 version overwritten)
  • An audit event credential.rotated is logged to the immutable audit chain
  • A credential.rotated webhook event is dispatched to all active subscriptions
Credential type Recommended rotation interval
Production agent credentials 90 days
Staging / development credentials 180 days
Service account credentials 365 days (annual)
Credentials involved in a security incident Immediately

Automated expiry detection

SecretsRotationJob runs hourly and queries credentials expiring within 7 days. Prometheus alert CredentialExpiryApproaching fires immediately when any are detected. Respond to this alert by rotating the flagged credential(s) before the expiry date.


2. OIDC Signing Key Rotation

Overview

OIDC signing keys are managed by OIDCKeyService (src/services/OIDCKeyService.ts). Keys are stored in the oidc_keys PostgreSQL table. The current active key is used to sign all new ID tokens; public keys are exposed via GET /.well-known/jwks.json.

When to rotate

  • Key compromise or suspected exposure
  • Scheduled rotation (recommended every 90 days for production)
  • Algorithm upgrade (e.g. RS256 → ES256)

Rotation procedure

OIDC key rotation is handled automatically by OIDCKeyService.ensureCurrentKey():

# Force generation of a new signing key by calling the internal rotate endpoint
# (or trigger by redeploying with OIDC_FORCE_KEY_ROTATION=true)

# 1. Mark current key as inactive (if manual rotation is required)
psql "$DATABASE_URL" -c "
  UPDATE oidc_keys
  SET active = false
  WHERE active = true;"

# 2. Restart the application — ensureCurrentKey() will generate a new key on startup
kubectl rollout restart deployment/agentidp

JWKS update behavior

  • Old public keys remain in GET /.well-known/jwks.json for 24 hours after rotation (grace period for in-flight tokens)
  • After the grace period, old keys are removed from the JWKS endpoint
  • Redis JWKS cache TTL is configured by JWKS_CACHE_TTL_SECONDS (default: 3600)

Impact on existing tokens

Existing valid tokens signed with the old key continue to work until they expire, as long as the old public key remains in JWKS. After the grace period, old tokens will fail verification.


3. Encryption Key Rotation

See docs/compliance/encryption-runbook.md for the full AES-256-CBC encryption key rotation procedure.

Summary: Generate new 32-byte hex key → write to Vault at ENCRYPTION_KEY_VAULT_PATH → restart app → existing rows re-encrypted lazily on next read-write cycle.


Schedule Recommendations

Secret Type Production Interval Staging Interval Trigger for Immediate Rotation
Agent client secrets 90 days 180 days Credential suspected compromised
OIDC signing keys 90 days 180 days Key file exposed, algorithm upgrade
AES-256-CBC encryption key 365 days (annual) On demand Key exposed, Vault breach, compliance audit requirement
Webhook HMAC secrets Per customer policy N/A Webhook endpoint compromised

Compliance Evidence

For SOC 2 CC9.2 evidence collection:

  • Prometheus metric history: agentidp_credentials_expiring_soon_total
  • Audit log entries with action: credential.rotated — query via GET /audit?action=credential.rotated
  • Key rotation records from Vault audit log
  • This runbook + sign-off from Security Engineering