Skip to content

tested secrets#55

Open
breardon2011 wants to merge 2 commits intomainfrom
secrets-change
Open

tested secrets#55
breardon2011 wants to merge 2 commits intomainfrom
secrets-change

Conversation

@breardon2011
Copy link
Contributor

@breardon2011 breardon2011 commented Mar 11, 2026

Projects & Sealed Secrets

Adds the full projects and sealed secrets system — secrets are encrypted at rest in Postgres, sealed into opaque osb_sealed_* tokens inside the VM, and transparently replaced with real values by a MITM proxy on outbound HTTPS requests. The real secret value never exists in VM memory.

What's included

Core infrastructure

  • internal/secretsproxy/ — HTTP CONNECT MITM proxy that intercepts outbound HTTPS and replaces sealed tokens with real secret values in headers and request bodies
  • internal/crypto/ — AES-256-GCM encryption for secrets at rest (key via OPENSANDBOX_SECRET_ENCRYPTION_KEY)
  • internal/secretsproxy/ca.go — per-worker CA generation, persisted across restarts
  • internal/firecracker/ — iptables redirect rules to route VM HTTPS traffic through the proxy; sealed env injection on sandbox create, checkpoint restore, and golden snapshot paths

API & control plane

  • internal/api/projects.go + internal/controlplane/projects.go — full CRUD for projects and secrets (create, update with partial merge, list, delete)
  • internal/db/migrations/014_projects.up.sql — projects, org_secrets, secret_groups tables
  • internal/db/store.go — all project/secret DB operations with encrypted storage
  • Sandbox create now accepts project param to inherit config defaults and sealed secrets

CLI

  • oc project create/list/get/update/delete — project lifecycle management
  • oc secret set/list/delete — secret management scoped to projects
  • oc create --project — create sandbox with project config

SDKs

  • TypeScript: Project class with full CRUD + secrets, Sandbox.create({ project }) support
  • Python: Project class with full CRUD + secrets, Sandbox.create(project=) support

Docs

  • Mintlify docs for projects/secrets across all three surfaces (TypeScript SDK, Python SDK, CLI)
  • Updated sandbox docs to reference the project parameter

How sealed secrets work

User sets secret → PG (AES-256-GCM encrypted)
                 → Server decrypts on sandbox create
                 → Worker seals into osb_sealed_<hash> token
                 → VM env has osb_sealed_* (real value never in VM)
                 → VM makes HTTPS request with sealed token
                 → MITM proxy replaces osb_sealed_* → real value
                 → Request reaches external API with real credentials

Testing

Unit tests

  • internal/crypto/encrypt_test.go — AES-256-GCM encrypt/decrypt round-trip, wrong-key rejection
  • internal/secretsproxy/replacer_test.go — token replacement in headers, bodies, partial matches, edge cases

SDK integration tests (run against dev server)

  • sdks/typescript/examples/test-projects.ts — 8-step test: create project → set secrets → create sandbox with project → verify env vars are sealed (osb_sealed_*) inside VM → cleanup
  • sdks/python/examples/test_projects.py — equivalent 8-step test in Python

Manual testing against dev server

  • Created projects, set secrets, verified partial update doesn't wipe unset fields
  • Created sandboxes with project, exec'd into VM to confirm $ANTHROPIC_API_KEY resolves to osb_sealed_* token
  • Confirmed env output contains no plaintext secret values
  • Verified real API key never appears anywhere in VM environment

End-to-end proxy replacement test (scripts/test-proxy-secrets.sh)

  • Takes a real Anthropic API key as input
  • Creates project → sets key as encrypted secret → creates sandbox
  • Verifies secret is sealed inside VM (osb_sealed_*)
  • Verifies real key never appears in VM env
  • Calls Anthropic API from inside the sandbox — proxy replaces the sealed token with the real key, API returns 200
  • Full chain proven: PG (encrypted) → server (decrypted) → worker (sealed) → VM (opaque token) → proxy (replaced) → Anthropic (real key) → 200 OK

@vercel
Copy link

vercel bot commented Mar 11, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
opensandbox Ready Ready Preview, Comment Mar 11, 2026 1:17am

Request Review

…yption key rotation

Three security improvements to the sealed secrets system:

1. Egress allowlist enforcement (#4 - highest priority)
   Thread project egress allowlist through the full stack so the MITM proxy
   actually enforces it. Previously the allowlist was stored in the DB but
   never passed to the proxy — any host could receive sealed tokens.
   - Add EgressAllowlist to SandboxConfig and CreateSandboxRequest proto
   - Control plane reads project.EgressAllowlist and passes via gRPC
   - Worker extracts and passes to CreateSealedEnvs() in all 3 code paths
     (manager.go Create, snapshot.go warm fork, snapshot.go golden create)
   - Proxy now blocks outbound HTTPS to hosts not in the allowlist

2. mTLS on gRPC (#1 - control plane ↔ worker)
   New internal/grpctls package. When OPENSANDBOX_GRPC_TLS_{CA,CERT,KEY}
   env vars are set, all gRPC connections use mutual TLS 1.3 with client
   cert verification. Falls back to insecure when unset (backwards compatible).
   - Worker gRPC server requires client certs
   - Control plane persistent pool (redis_registry) and ad-hoc connections
     both use mTLS client credentials

3. Encryption key rotation (#3)
   New internal/crypto/keyring.go adds versioned encryption. Ciphertext gets
   a 2-byte version header; decryption tries the matching version key, then
   falls back to primary for legacy (pre-rotation) data.
   - OPENSANDBOX_SECRET_ENCRYPTION_KEY = primary key
   - OPENSANDBOX_SECRET_ENCRYPTION_KEY_V1..V9 = previous keys
   - To rotate: generate new key, move old to _V1, set new as primary
   - All existing tests pass + 4 new keyring tests (rotation, legacy fallback)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@breardon2011 breardon2011 marked this pull request as ready for review March 11, 2026 16:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant