Secret delivery option 6: Server-side bootstrap callback (one-time token fetch) #135
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Parent epic: #129
Overview
Pass only a one-time bootstrap token to the container. On startup, the agent calls
GET /api/v1/bootstrap/{token}to fetch its secrets over TLS. Token is single-use, short-TTL, scoped to a specific deployment. This mirrors HashiCorp Vault's cubbyhole response wrapping pattern without requiring Vault infrastructure.How It Works
Token Properties
maxUses(default: 3)Token Storage
ConcurrentHashMapStartup sequence loads unexpired tokens from PG into memory.
@Scheduledcleanup every 60s removes expired tokens.Security Analysis
One-Time Token Properties
ConcurrentHashMap.remove())Is the Bootstrap Token as Sensitive as the Secrets?
Yes, during its lifetime. But risk profile is much better:
docker inspectfor only 5 minutes (vs env var secrets for container lifetime)Comparison with Vault Cubbyhole
Our pattern is architecturally identical:
Network Security
Agent-to-server communication uses Docker bridge networks. The bootstrap token's short TTL reduces the sniffing window. For SaaS, tenant-scoped networks (
cameleer-tenant-{slug}) provide isolation. mTLS can be added later as hardening.Container Restart Handling
maxUses = restartPolicy + 1(recommended)DockerEventMonitordetectsstart, mints new token viadocker execServer Restart Between Mint and Fetch
With hybrid storage: PG has the token, startup loads it into memory. Container retries with exponential backoff (1s, 2s, 4s, 8s, max 30s). Seamless recovery.
Industry Precedent
This is a well-established production pattern:
Every system without infrastructure-level trust must solve the same bootstrap problem. Our pattern is in the same family.
Standards Alignment
OWASP explicitly ranks delivery approaches:
Platform Compatibility
cameleer3-server:8081cameleer-tenant-{slug})vs K8s Secrets: Not Redundant
Implementation Plan
Server-Side Components
BootstrapTokenStoreConcurrentHashMap<String, TokenEntry>+ PG table;mint(),consume(),cleanup()BootstrapSecretControllerGET /api/v1/bootstrap/{token}— unauthenticated (token IS the auth)BootstrapTokenCleanupJob@Scheduledevery 60s, remove expired tokensDeploymentExecutorchangeCAMELEER_BOOTSTRAP_TOKENinstead of secretsSecurityConfigchange/api/v1/bootstrap/**without JWT authbootstrap_tokenstable:token_hash,deployment_id,secrets_encrypted,expires_at,consumed_at,uses_remainingServerMetricscameleer.bootstrap.{minted,consumed,expired,rejected}countersEstimated: 2-3 days server-side.
Agent-Side
Estimated: 0.5-1 day agent-side.
Non-Java Containers
Migration Path
DeploymentExecutoruses tokens for new deployments; existing unaffectedbuildEnvVars()Advantages Over Alternatives
docker inspectDisadvantages & Mitigations
maxUsesmatching restart policy; logged per-usedocker inspectRecommendation
Verdict: ⭐⭐⭐⭐½ (4.5/5) — Strongly Recommended
This is the recommended primary delivery mechanism for Cameleer3 because:
docker inspectproblem — the #1 security gap today.Implementation Priority
BootstrapTokenStore+ endpointDeploymentExecutorintegrationcameleer3-commonCombines Well With
What NOT to Do
Sources