docs: correct the container CA instructions, they did not work

The mount command in the Docker section was written from reasoning and
never run. Testing it showed it fails.

Mounting the bundle over /etc/ssl/certs/ca-certificates.crt lands
correctly, and the file contains the right CA, but curlimages/curl does
not read that path by default and still fails with exit 60. The runtime
has to be pointed at the file explicitly.

Verified commands now in the doc:

  NODE_EXTRA_CA_CERTS=/ca.pem   node:20-slim        npm i is-odd -> added 2 packages
  NODE_EXTRA_CA_CERTS=/ca.pem   node:20-slim        safedep-test-pkg -> code E403
  CURL_CA_BUNDLE=/ca.pem        curlimages/curl     http=200

So PMG does block a malicious package inside a container once the
certificate is passed in. SSL_CERT_FILE was also tried and does not work
for curl, so it is not documented.

Also notes that the docker commands need an account with sudo, since
testuser deliberately has none.
This commit is contained in:
Sahilb315
2026-07-28 23:05:31 +05:30
parent 0deb8fa4ff
commit a814bf648e
2 changed files with 52 additions and 7 deletions
+13 -5
View File
@@ -529,11 +529,19 @@ Do not bind `0.0.0.0`. The state file would record `0.0.0.0`, which is not a val
properly needs `bpf_get_netns_cookie()` in the hook to select a target per namespace. properly needs `bpf_get_netns_cookie()` in the hook to select a target per namespace.
- **A non loopback bind exposes the MITM proxy.** Acceptable on an isolated runner, otherwise it - **A non loopback bind exposes the MITM proxy.** Acceptable on an isolated runner, otherwise it
needs a firewall rule. needs a firewall rule.
- **CA trust inside the container is unsolved and may be unsolvable from the host.** A container has - **CA trust inside the container cannot be arranged from the host.** A container has its own trust
its own trust store, and nothing on the host reaches into it. Injecting the CA requires the store and nothing on the host reaches into it. With the certificate mounted and the runtime told
process that starts the container to mount it. So for containers the guarantee degrades to fail to read it, the full flow works: `npm i is-odd` succeeded inside `node:20-slim` and
closed: traffic is mediated, the install fails, nothing unanalysed enters. That is the correct `safedep-test-pkg` was blocked with 403. But that requires the process starting the container to
security outcome and a poor usability one. cooperate, which is the assumption the whole layer exists to remove. Without it the guarantee
degrades to fail closed: traffic is mediated, the install fails, nothing unanalysed enters. That
is the correct security outcome and a poor usability one.
Mounting over the image's CA bundle path is not sufficient on its own. Tested against
`curlimages/curl`: the mount lands and the file is correct, but curl does not read
`/etc/ssl/certs/ca-certificates.crt` by default and still fails. The runtime has to be pointed at
the file explicitly, through `NODE_EXTRA_CA_CERTS`, `CURL_CA_BUNDLE` or `--cacert`. Per runtime
again, which is the same shape as the host side problem.
Note `docker pull` was already covered before any of this, since the daemon runs on the host. Note `docker pull` was already covered before any of this, since the daemon runs on the host.
+39 -2
View File
@@ -535,6 +535,9 @@ The state file would then hold `0.0.0.0`, which is not a valid destination.
### Test it ### Test it
Run this from an account that can use `sudo`.
The `testuser` account cannot.
```bash ```bash
sudo docker run --rm curlimages/curl:latest \ sudo docker run --rm curlimages/curl:latest \
-4 -sS -m 20 -o /dev/null https://registry.npmjs.org/is-odd -4 -sS -m 20 -o /dev/null https://registry.npmjs.org/is-odd
@@ -562,17 +565,51 @@ It fails at trust, not at the address.
### To make a container succeed ### To make a container succeed
The person who starts the container must pass the certificate in: The person who starts the container must pass the certificate in.
Mount the bundle, then tell the program where it is.
For a Node image, such as `node:20-slim`:
```bash ```bash
sudo docker run --rm \ sudo docker run --rm \
-v /var/lib/pmg-ebpf-poc/pmg-ca-bundle.pem:/etc/ssl/certs/ca-certificates.crt:ro \ -v /var/lib/pmg-ebpf-poc/pmg-ca-bundle.pem:/ca.pem:ro \
-e NODE_EXTRA_CA_CERTS=/ca.pem \
-w /tmp node:20-slim sh -c "npm i is-odd"
```
For a curl image:
```bash
sudo docker run --rm \
-v /var/lib/pmg-ebpf-poc/pmg-ca-bundle.pem:/ca.pem:ro \
-e CURL_CA_BUNDLE=/ca.pem \
curlimages/curl:latest -4 -sS https://registry.npmjs.org/is-odd curlimages/curl:latest -4 -sS https://registry.npmjs.org/is-odd
``` ```
Mounting the file alone is not enough.
The program must also be told to read it.
A mount over `/etc/ssl/certs/ca-certificates.crt` does not work for every image.
It was tested and it failed with `curlimages/curl`.
That image does not read that file by default, even though the file is there.
Always set the environment variable, or pass `--cacert`.
There is no way to do this from the host. There is no way to do this from the host.
A container cannot be given a certificate it was not started to accept. A container cannot be given a certificate it was not started to accept.
### A blocked package inside a container
With the certificate passed in, PMG blocks as it does on the host:
```bash
sudo docker run --rm \
-v /var/lib/pmg-ebpf-poc/pmg-ca-bundle.pem:/ca.pem:ro \
-e NODE_EXTRA_CA_CERTS=/ca.pem \
-w /tmp node:20-slim sh -c "npm i safedep-test-pkg"
```
This prints `npm ERR! code E403`.
### Limits ### Limits
- Only the default bridge network works. - Only the default bridge network works.