Skip to content

Trust and proxy delivery into boxes - #36

Merged
czpython merged 1 commit into
mainfrom
dru-459-trust-delivery
Sep 7, 2026
Merged

czpython merged 1 commit into
mainfrom
dru-459-trust-delivery

Conversation

@czpython

@czpython czpython commented Sep 6, 2026 •

Copy link
Copy Markdown
Owner

What changes

A box that sends its HTTPS through the proxy now trusts the proxy's CA from its first session, with no manual step.

  • The proxy implementation of the seam hands the box the public certificate, base64, in SECRETS_PROXY_CA, next to HTTPS_PROXY, https_proxy, and NO_PROXY. It also sets SSL_CERT_FILE, REQUESTS_CA_BUNDLE, and CURL_CA_BUNDLE to the system bundle, and NODE_EXTRA_CA_CERTS to the certificate file.
  • The API reads the certificate from the proxy's volume at SECRETS_PROXY_CA_FILE, parses it, and hands out its public bytes and nothing else. A file that holds a private key, the mitmproxy-ca.pem beside the public one, is refused. A request with secrets on a proxy provider needs SECRETS_PROXY_URL and SECRETS_PROXY_CA_FILE, and answers 409 without them.
  • One writer, environment.trust, gives the shell lines that install the certificate at /usr/local/share/ca-certificates/drukbox.crt and run update-ca-certificates, beside persist, bashrc, and cloud_init. The lines read the exported variable, and a failed install ends the script. The cloud providers get them from cloud_init, as root. The exe setup script gets them with sudo -n. The docker sandbox image does the same in its entrypoint, since the docker provider runs no script.
  • exe takes a setup script of at most 10 KiB, per ssh exe.dev doc for new. The API refuses a longer one with a clear error before the call.
  • Provisioning checks the whole boot environment against the pam_env rules before any provider call. A value pam_env would drop fails the host with a clear error.
  • A box without secrets gets none of this.
  • The suite carries a self-signed test certificate in env/, and CI mounts it into the API for the black-box run.

Where this differs from the ticket

  • The base64 certificate stays in the box's environment after the install, in /etc/environment and ~/.bashrc like every other variable. The ticket puts it in env, and dropping it after the install would need one more step per provider for a public certificate.
  • The docker sandbox image carries its own three shell lines for the install. The docker provider runs no script, so the writer cannot reach it. The published sandbox image must be rebuilt for this to take effect.

Names

New names, open to change: SECRETS_PROXY_CA_FILE, SECRETS_PROXY_CA, environment.trust.

Gates

uv run ruff check, uv run ruff format --check, uv run pyright, and uv run pytest are green.

Acceptance

Run on the acceptance stack with this branch built into the API and exchange image, the proxy on the host's tailnet address, and a live subscription token as a static anthropic secret. Docker used a sandbox image built from this branch's images/local plus Claude Code. Exe used the deployment's own image, which ships Claude Code as a standalone binary and no node, so the check installed Ubuntu's node for its own node -e step. No manual step touched the CA. 13 of 13 on docker and 13 of 13 on exe:

  • A box with a secret became active. A plain session saw HTTPS_PROXY, https_proxy, NO_PROXY, SECRETS_PROXY_CA, SSL_CERT_FILE, REQUESTS_CA_BUNDLE, CURL_CA_BUNDLE, and NODE_EXTRA_CA_CERTS.
  • The certificate was installed at the path NODE_EXTRA_CA_CERTS names, and the system bundle verified it.
  • curl https://api.anthropic.com/ showed our CA as the issuer. node -e reached the same host through the proxy with our CA as the issuer. claude -p answered ok.
  • The value appeared nowhere in the session.
  • A box without secrets became active with none of the variables and no certificate.
  • Both hosts deleted cleanly.

The stack was restored afterwards, and the branch images, the token file, and the CA directory were removed from the host.

Review

One adversarial review, four findings, all applied.

  • A SECRETS_PROXY_CA_FILE that named mitmproxy's key-and-certificate file would have put the private key into every box. The API now parses the file and hands out the public bytes only, and refuses a file with a private key. Tests cover both.
  • The exe setup script embedded the certificate three times and could pass exe's 10 KiB limit. The install lines now read the exported variable, and a script over the limit is refused with a clear error. A test covers it.
  • A failed certificate install let the setup script go on. Each install line now ends the script on failure.
  • A certificate long enough to break the pam_env line limit was written anyway on docker and raised an uncaught error on the clouds. Provisioning now validates the whole boot environment first and fails the host with the reason. A test covers it.

The exe half of the acceptance was repeated after the fixes, since they change the exe setup script.

@czpython
czpython force-pushed the dru-459-trust-delivery branch from 533b714 to 53c2a30 Compare September 6, 2026 14:39
@czpython
czpython force-pushed the dru-458-secrets-proxy branch 3 times, most recently from 37e510a to 452d069 Compare September 7, 2026 05:02
@czpython
czpython changed the base branch from dru-458-secrets-proxy to main September 7, 2026 05:08
@czpython
czpython force-pushed the dru-459-trust-delivery branch 3 times, most recently from 66463f0 to 3df0ceb Compare September 7, 2026 05:17
…crets

A box that sends its HTTPS through the proxy must trust the proxy's CA.
The proxy implementation of the seam now hands the box the public
certificate, base64, in SECRETS_PROXY_CA, next to the proxy address. The
API reads the certificate from the proxy's volume, at
SECRETS_PROXY_CA_FILE, parses it, and hands out its public bytes and
nothing else. A file that holds a private key is refused. A request with
secrets on a proxy provider needs both settings, and answers 409 without
them.

The box installs the certificate at boot, in
/usr/local/share/ca-certificates/drukbox.crt, with update-ca-certificates.
One writer, environment.trust, gives the shell lines beside persist,
bashrc, and cloud_init. The lines read the exported variable, and a
failed install ends the script. The cloud providers get them from
cloud_init as root. The exe setup script gets them with sudo -n, since it
runs as a user, and exe refuses a script over 10 KiB, so the API answers
that with a clear error first. The docker sandbox image does the same in
its entrypoint. A box without secrets gets none of this.

SSL_CERT_FILE, REQUESTS_CA_BUNDLE, and CURL_CA_BUNDLE point at the system
bundle, and NODE_EXTRA_CA_CERTS at the certificate, so curl, Python, and
Node trust the proxy from the first session. Provisioning checks the
whole boot environment against the pam_env rules before any provider
call, so a value pam_env would drop fails the host with a clear error
instead of a silent loss. The test suite carries a self-signed
certificate for the setting, and CI mounts it into the API.
@czpython
czpython force-pushed the dru-459-trust-delivery branch from 3df0ceb to e8c3b62 Compare September 7, 2026 05:19
@czpython
czpython merged commit 2300801 into main Sep 7, 2026
6 checks passed
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