Inserting a private CA certificate into a VS Code devcontainer

3 minute read

I’ve always wondered how much productivity loss SSL inspection causes due to various platforms and applications having very difficult means of trusting an internal CA certificate. Where I work, we’ve certainly lost a lot. But hey, there is a really easy workaround with VS Code devcontainers that will make them work behind a firewall with very little effort.

Preparation

Before we jump into how to solve this problem, we need to get into collecting the certificate and understanding how a Dockerfile fits into running a devcontainer.

Collecting the cert

The first step is to get your hands on the internal root CA’s public certificate. You could ask whatever team manages your network security for a copy or try to figure out the correct certificate from your operating system’s certificate store, but the easiest way is to simply navigate to any external website and look at the certificate chain. This will be different in different browsers, but the idea is that you want to export the rootest root CA certificate in base64 encoding. You do not need to include the certificate chain because it is the root certificate (and therefore has no chain).

Working with Dockerfiles

If you have done much work with devcontainers, then you are likely wondering what I mean by a Dockerfile. Most of the configuration happens in the .devcontainer/devcontainer.json file, right? For advanced customizations, you can leverage a Dockerfile (info is also in the devcontainers references docs) that you also place in the .devcontainer directory. Then, instead of using the image property in the devcontainer.json file, you would use "build": { "dockerfile": "Dockerfile" }.

For example, here’s a very simple Go devcontainer configuration:

{
    "name": "Go",
    "image": "mcr.microsoft.com/devcontainers/go:dev-1.23-bookworm",
    "postCreateCommand": "go version"
}

If we wanted to use a Dockerfile, you’d switch it up to be:

{
    "name": "Go",
    "build": { "dockerfile": "Dockerfile" },
    "postCreateCommand": "go version"
}

And the beginning of your Dockerfile would start with (assuming this was a single stage build):

FROM mcr.microsoft.com/devcontainers/go:dev-1.23-bookworm

Inserting the certificate into the devcontainer

With the certificate and an understanding of how the Dockerfile works with devcontainers, all we need to do is to add 3 additional steps:

  1. COPY to insert the certification onto the filesystem of the container. This step will leverage heredoc syntax
  2. RUN to run the update-ca-certificates command (info about compatibility can be found here)
    1. This devcontainer base uses Debian, which includes the update-ca-certificates command.
  3. Create the NODE_EXTRA_CA_CERTS environment variable.

You can see all three steps have been applied in the below Dockerfile:

FROM mcr.microsoft.com/devcontainers/go:dev-1.23-bookworm

# Place the certificate into the certificate directory
# The extra blank line at the end is required!
COPY <<EOF /usr/local/share/ca-certificates/root.crt
-----BEGIN CERTIFICATE-----
<base64 cert>
-----END CERTIFICATE-----

EOF

# Execute the command to update the ca certs
RUN update-ca-certificates

# Add the cert to the NODE_EXTRA_CA_CERTS environment variable
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/root.crt

Conclusion

With that all in place, simply build (or rebuild) your devcontainer and you can test if it is working by running a curl command against an https:// website.

Leave a Comment