Inject the corporate CA certificate into containers
Build App / compute-version (pull_request) Successful in 6s
Build App / build-macos (pull_request) Successful in 2m30s
Build App / build-windows (pull_request) Successful in 5m16s
Build Container / build-container (pull_request) Successful in 10m15s
Build App / build-linux (pull_request) Successful in 6m35s
Build App / create-tag (pull_request) Skipped
Build App / sync-to-github (pull_request) Skipped
Build App / compute-version (pull_request) Successful in 6s
Build App / build-macos (pull_request) Successful in 2m30s
Build App / build-windows (pull_request) Successful in 5m16s
Build Container / build-container (pull_request) Successful in 10m15s
Build App / build-linux (pull_request) Successful in 6m35s
Build App / create-tag (pull_request) Skipped
Build App / sync-to-github (pull_request) Skipped
Behind a TLS-terminating corporate proxy every HTTPS call inside a container fails — npm, pip, git, curl, the browser-view pane, and Claude Code's own API requests. There was no mechanism at all: installing the certificate by hand inside a container is lost on Reset and had to be repeated per project. A global CA path in AppSettings with a per-project override on Project, taking either a single certificate file or a directory. It is bind-mounted read-only at /tmp/.host-ca (mirroring /tmp/.host-ssh and /tmp/.host-aws) and applied by entrypoint.sh on every start, so it survives recreation, migration and Reset. Four things this gets right that are easy to get wrong: * update-ca-certificates globs *.crt case-sensitively, so a .pem that is merely copied in is ignored in silence. Certificates are renamed, by container_cert_name() in Rust and a mirrored few lines of shell. * The system store only serves curl/git/apt. Node — and so Claude Code itself — needs NODE_EXTRA_CA_CERTS, Python needs REQUESTS_CA_BUNDLE/SSL_CERT_FILE, and Chromium reads neither: it wants ~/.pki/nssdb, seeded with certutil (libnss3-tools, added to the image). * Those vars are set from Rust at creation, never exported by the entrypoint — a terminal is a docker exec and sees nothing the entrypoint exported. They are emitted empty when no CA is configured, since docker commit bakes env into the snapshot image. * triple-c.ca-fingerprint hashes the certificate bytes as well as the path, so a CA rotated in at the same location still forces a recreation. Verified end to end against a real container and a self-signed CA: curl, node, python and git all complete a TLS handshake against a server signed by it and all three fail in the same container without it; the env vars are visible from a docker exec session; the store is cleaned when the setting is cleared. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KSP2KNPhuWKQ4DL5TZEn3k
This commit is contained in:
+32
-2
@@ -824,8 +824,8 @@ Notes:
|
||||
## Settings
|
||||
|
||||
Access global settings via the **Settings** tab in the sidebar. The panel is a set of collapsible
|
||||
sections: **General**, **Claude Authentication**, **Backends**, **Container**, **Git / SSH**,
|
||||
**Tools** and **Updates**.
|
||||
sections: **General**, **Claude Authentication**, **Backends**, **Container**, **Certificates**,
|
||||
**Git / SSH**, **Tools** and **Updates**.
|
||||
|
||||
### Claude Authentication
|
||||
|
||||
@@ -855,6 +855,36 @@ Environment variables applied to **all** project containers. Per-project variabl
|
||||
|
||||
Path to your SSH key directory (typically `~/.ssh`). This is mounted into **all** containers that don't have a per-project SSH path set. Per-project SSH paths take precedence.
|
||||
|
||||
### Corporate CA Certificate
|
||||
|
||||
If your organisation's network inspects TLS (a corporate proxy, a VPN that terminates HTTPS at the
|
||||
edge), containers need your organisation's root certificate or **every** HTTPS call inside them
|
||||
fails — `npm install`, `pip`, `git clone` over HTTPS, `curl`, the browser-view pane, and Claude
|
||||
Code's own calls to the API.
|
||||
|
||||
Point this at either a **single certificate file** or a **folder** of them. It is mounted read-only
|
||||
into every container and applied on every start, so it survives container recreation, base-image
|
||||
migration and Reset — unlike a certificate you install by hand inside a running container, which is
|
||||
lost the first time any of those happens.
|
||||
|
||||
The status line under the field tells you how many certificates were found and the names they will
|
||||
be installed as inside the container. That rename matters: the container's trust store only reads
|
||||
files ending in `.crt`, so a `.pem` is renamed rather than merely copied, which is the step that is
|
||||
easiest to get wrong by hand.
|
||||
|
||||
Inside the container the certificate is trusted by:
|
||||
|
||||
| Consumer | How |
|
||||
|---|---|
|
||||
| curl, git, apt, wget | the system trust store (`update-ca-certificates`) |
|
||||
| Node, npm, **Claude Code itself** | `NODE_EXTRA_CA_CERTS` |
|
||||
| Python, pip, requests | `REQUESTS_CA_BUNDLE` and `SSL_CERT_FILE` |
|
||||
| Chrome / Chromium (browser view) | its own NSS database at `~/.pki/nssdb` |
|
||||
|
||||
A per-project override lives in **Project Home → Config → Access**; leave it blank to use this
|
||||
global setting. Changing either recreates the project's container on its next start — replacing the
|
||||
certificate file in place counts as a change, so a rotated CA is picked up too.
|
||||
|
||||
### Default Git Name / Email
|
||||
|
||||
Sets `git user.name` and `git user.email` inside all containers. Per-project Git Name / Email settings take precedence. This is useful so you don't have to set the same name and email on every project.
|
||||
|
||||
Reference in New Issue
Block a user