Secret Management
The Secret Management system provides encrypted storage, rotation, and access control for sensitive configuration values. The SecretController at /api/v1/config/secrets handles API keys, database credentials, OAuth tokens, and other secrets with AES-256-GCM encryption, per-service access control, and automatic rotation policies.
SecretController
@RestController
@RequestMapping("/api/v1/config/secrets")
@Tag(name = "Secret Management", description = "Endpoints for managing encrypted secrets")
public class SecretController {
private final SecretManagementService secretService;
}Create a Secret
Create a new encrypted secret with optional rotation policy and service-level access control.
Endpoint: POST /api/v1/config/secrets
curl -X POST http://localhost:8888/api/v1/config/secrets \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com" \
-d '{
"secretKey": "openai-api-key",
"value": "sk-proj-abc123...",
"secretType": "API_KEY",
"environment": "production",
"rotationPolicy": "MANUAL",
"rotationDays": 90,
"description": "OpenAI API key for the AI service",
"allowedServices": ["ai-service", "ml-service"],
"tags": ["ai", "external-api"]
}'Response:
{
"id": "sec-001",
"secretKey": "openai-api-key",
"secretType": "API_KEY",
"environment": "production",
"description": "OpenAI API key for the AI service",
"version": 1,
"rotationPolicy": "MANUAL",
"lastRotatedAt": null,
"nextRotationAt": "2026-05-13T10:00:00Z",
"expiresAt": null,
"tags": ["ai", "external-api"],
"createdAt": "2026-02-12T10:00:00Z",
"updatedAt": "2026-02-12T10:00:00Z"
}The secret value is never returned in the creation response. Only metadata is returned. The value is encrypted using AES-256-GCM before storage.
Secret Types
| Type | Description |
|---|---|
API_KEY | Third-party API keys |
DATABASE_CREDENTIAL | Database connection credentials |
OAUTH_TOKEN | OAuth access/refresh tokens |
CERTIFICATE | TLS certificates and private keys |
ENCRYPTION_KEY | Encryption keys |
WEBHOOK_SECRET | Webhook signing secrets |
CUSTOM | Any other secret type |
Rotation Policies
| Policy | Description |
|---|---|
MANUAL | Manual rotation only |
AUTOMATIC | Auto-rotate on the configured schedule |
ON_DEMAND | Rotation triggered by external events |
Get Secret Value
Retrieve and decrypt a secret value. Requires service-level access control -- only services listed in allowedServices can access the secret.
Endpoint: GET /api/v1/config/secrets/value
curl "http://localhost:8888/api/v1/config/secrets/value?key=openai-api-key&environment=production" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com" \
-H "X-Service-Name: ai-service"Response:
{
"key": "openai-api-key",
"value": "sk-proj-abc123..."
}Every secret value access is logged in the audit trail. Unauthorized access attempts (wrong service name, missing permissions) are denied and flagged.
List Secrets (Metadata Only)
List all secrets for a tenant. Only metadata is returned -- never the actual values.
Endpoint: GET /api/v1/config/secrets
curl "http://localhost:8888/api/v1/config/secrets?page=0&size=20" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000"Update a Secret
Update a secret's value. The previous value is preserved in version history.
Endpoint: PUT /api/v1/config/secrets/{secretId}
curl -X PUT http://localhost:8888/api/v1/config/secrets/sec-001 \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com" \
-d '{
"value": "sk-proj-xyz789...",
"reason": "API key regenerated in OpenAI dashboard"
}'Rotate a Secret
Explicit rotation operation that updates the value and resets the rotation timer.
Endpoint: POST /api/v1/config/secrets/{secretId}/rotate
curl -X POST http://localhost:8888/api/v1/config/secrets/sec-001/rotate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com" \
-d '{
"newValue": "sk-proj-new-key..."
}'Get Secrets for a Service
Retrieve all secrets that a specific service is authorized to access, in a given environment.
Endpoint: GET /api/v1/config/secrets/service/{serviceName}
curl "http://localhost:8888/api/v1/config/secrets/service/ai-service?environment=production" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com"Response:
{
"openai-api-key": "sk-proj-abc123...",
"embedding-api-key": "emb-key-xyz..."
}Secrets Needing Rotation
List secrets that have exceeded their rotation period.
Endpoint: GET /api/v1/config/secrets/rotation/pending
curl http://localhost:8888/api/v1/config/secrets/rotation/pending \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000"Expiring Secrets
List secrets that will expire within a specified number of days.
Endpoint: GET /api/v1/config/secrets/expiring
curl "http://localhost:8888/api/v1/config/secrets/expiring?withinDays=30" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000"Rotate Encryption Key
Re-encrypt all secrets in the tenant with a new master encryption key. This is used during key rotation for compliance.
Endpoint: POST /api/v1/config/secrets/encryption-key/rotate
curl -X POST http://localhost:8888/api/v1/config/secrets/encryption-key/rotate \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000" \
-H "X-User-ID: 550e8400-e29b-41d4-a716-446655440001" \
-H "X-User-Email: admin@acme.com" \
-d '{
"oldKeyId": "key-v1",
"newKeyId": "key-v2"
}'Response:
{
"secretsRotated": 42
}Secret Statistics
Endpoint: GET /api/v1/config/secrets/stats
curl http://localhost:8888/api/v1/config/secrets/stats \
-H "Authorization: Bearer ${TOKEN}" \
-H "X-Tenant-ID: 550e8400-e29b-41d4-a716-446655440000"Encryption Details
Secrets are encrypted using AES-256-GCM (Galois/Counter Mode):
| Property | Value |
|---|---|
| Algorithm | AES/GCM/NoPadding |
| Key Length | 256 bits |
| IV Length | 12 bytes (96 bits) |
| Tag Length | 128 bits |
| Key Derivation | PBKDF2 with HMAC-SHA256 |
The encryption key is stored in Kubernetes secrets and referenced via environment variables. It is never stored in the database.