Skip to content

fix(network-proxy): keep MITM CA private signer in memory only#324

Merged
andrei-hasna merged 3 commits into
mainfrom
upstream-sync/cluster-20-proxy-ca-key-memory
Jul 21, 2026
Merged

fix(network-proxy): keep MITM CA private signer in memory only#324
andrei-hasna merged 3 commits into
mainfrom
upstream-sync/cluster-20-proxy-ca-key-memory

Conversation

@andrei-hasna

Copy link
Copy Markdown
Contributor

What

Re-expresses upstream openai/codex #29013 (c5a9a95ab6, "Keep managed MITM CA private keys in proxy memory") onto our fork.

The managed MITM CA private signer is now generated per proxy process and kept only in process memory — it is never written to $CODEWITH_HOME/proxy. Only the public CA material is persisted, content-addressed:

  • One managed CA is generated per proxy process; the private KeyPair lives only inside ManagedMitmCa (shared process-wide via Arc<ManagedMitmCa> behind a LazyLock<Mutex<..>> cache keyed by proxy dir).
  • Only content-addressed public certs (ca-<sha256>.pem) and trust bundles (ca-bundle-<sha256>.pem) are written under $CODEWITH_HOME/proxy.
  • Each active public cert holds a cross-process shared file lease; a per-dir exclusive artifacts lock lets a fresh process prune certs/bundles left behind by inactive proxy processes (skips any cert whose lease is still held).
  • Generated trust-bundle paths are validated by their content hash (is_generated_trust_bundle_path / is_generated_managed_ca_artifact_path).
  • Per-host leaf certs are signed from the in-memory signer (mitm.rs now holds Arc<ManagedMitmCa>).

Because no CA private key is written to disk, no deny-read sandbox rule is required. Our fork already exposes only the content-addressed trust bundle as a readable sandbox root (with_managed_mitm_ca_readable_root), so there was no deny-read-of-key rule to remove — the change keeps ordinary sandbox setup independent of CA-key state.

Upstream refs

  • openai/codex #29013 c5a9a95ab6 — primary change ported here.
  • openai/codex #29014 527ccb4a5d — the startup custom-CA follow-up; intentionally not pulled (out of scope), so the trust-bundle builder keeps our single-arg / native-cert-loading form (pre-#29014 tree).

How it was re-expressed onto our fork

Our network-proxy/src/certs.rs sits at the pre-#29014 base, so the port keeps our existing managed_ca_trust_bundle_for_cert_path / build_managed_ca_trust_bundle and is_managed_mitm_ca_trust_bundle_path shapes and only layers in #29013:

  • load_or_create_ca() (read cert+key from disk) → ManagedMitmCa::create() + persist_managed_ca_certificate() (public cert only).
  • managed_ca_paths()managed_ca_dir(); removed ca.pem/ca.key fixed-path constants.
  • generate_ca() now returns the KeyPair (kept in memory) instead of serialized key PEM.
  • Removed validate_existing_ca_key_file (no on-disk key to validate).
  • Removed the now-unused is_current_generated_trust_bundle_path (its only remaining caller lives in the un-ported #29014); the public path check now uses the content-hash is_generated_trust_bundle_path.

Tests (ported from #29013)

  • managed_ca_private_key_is_not_persisted — only the public cert + lock files land on disk.
  • managed_ca_artifact_pruning_preserves_only_active_certificates — leased certs survive; unleased certs/bundles and their leases are pruned; unrelated files untouched.
  • generated_trust_bundle_path_requires_matching_content_hash — tampered bundles are rejected.

Verification

  • Blacksmith box cargo check -p codex-network-proxy: PASS
  • cargo nextest -p codex-network-proxy (test-fast): 164 passed / 0 failed (incl. the 3 new tests)
  • cargo clippy -p codex-network-proxy --tests -- -D warnings: clean (exit 0)
  • just fmt-check: clean

Adapt cluster — opened for human review (overlaps our fork customizations); not auto-merged.

Re-express upstream openai/codex #29013 (c5a9a95ab6) onto our fork.
Generate one managed MITM CA per proxy process and retain the private
signer only in process memory. Persist only content-addressed public CA
certificates (ca-<sha256>.pem) under $CODEWITH_HOME/proxy, hold a
cross-process shared lease per active cert, and prune artifacts left by
inactive proxy processes. Validate generated trust-bundle paths by their
content hash. Per-host leaf certs are signed from the in-memory signer,
shared process-wide via Arc<ManagedMitmCa>.

No CA private key is written to disk, so no deny-read sandbox rule is
needed (our fork already exposes only the content-addressed trust bundle
as a readable sandbox root).

Adapted to our pre-#29014 tree: keeps the single-arg trust-bundle
builder and native-cert loading and does not pull the startup custom-CA
follow-up (#29014).
@andrei-hasna
andrei-hasna force-pushed the upstream-sync/cluster-20-proxy-ca-key-memory branch from 290ad17 to 935852b Compare July 20, 2026 16:29
@andrei-hasna

Copy link
Copy Markdown
Contributor Author

Not merged (automated merge pass): Bazel test on ubuntu-24.04 is failing (both gnu and musl; bazel exit 3 = tests failed). The windows-only fleet_comms failures are tolerated, but a real ubuntu Bazel failure is not. Please get ubuntu Bazel green before merge.

@andrei-hasna
andrei-hasna merged commit 9b3665d into main Jul 21, 2026
34 of 39 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant