Peter
Peter

Reputation: 6035

How do I add a CA root certificate inside a docker image?

I am running an ASP.NET Core 1.1 Web API in a Docker 1.13.1 container on Ubuntu 14.04.

When the code attempts to retrieve some data from an HTTPS server, I get this certificate authentication error:

 An error occurred while sending the request. ---> System.Net.Http.CurlException: Peer certificate cannot be authenticated with given CA certificates
   at System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
   at System.Net.Http.CurlHandler.MultiAgent.FinishRequest(StrongToWeakReference`1 easyWrapper, CURLcode messageResult)

The HTTPS server is internal with certificate signed by our corporate CA, so am aware that I may need to register the internal CA.

Everything I've found so far about this error and Docker talks to getting docker itself running, connecting to repos etc. My Docker is working fine, and the Web API runs on the Ubuntu server outside of the container without a problem.

1) Do I need to add a CA root certificate inside a docker image?

2) If so, how do I do it?

3) If not, how do I fix this?

Upvotes: 121

Views: 377483

Answers (8)

KLAUS
KLAUS

Reputation: 31

a little context so that people are aware of my use case and the solution :

  1. I am under corporate proxy, and i wanted to make requests to a server from inside the docker.
  2. I have 2 Way ssl CN authentication mechanism setup at the server which i am requesting to.
  3. I was getting these errors : [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)/(_ssl.c:1007).
  4. I have a .pem and .key file from which i have to use for authentication, which was working fine locally, and for these two methods i requested certificate chain (.pem) (if you have it in crt you can simply that or convert it into one)

Two things worked for me :

  1. Updating the System Certificate Store:
  • Copy the certificate file to /usr/local/share/ca-certificates/ and provide a .crt/ extention.

  • Install ca-certificates package

  • Run update-ca-certificates to update the system certificate store.

     COPY certificates/xxxx.pem /usr/local/share/ca-certificates/xxxx.crt
     RUN apt-get update && \
         apt-get install -y ca-certificates && \
         update-ca-certificates 
     ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
    
  1. Simply copying the certificate also works:

    COPY certificates/xxxx.pem /etc/ssl/certs/ca-certificates.crt
    ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
    

then i have simply requested like this:

ssl_context = ssl.create_default_context()
ssl_context.verify_mode = ssl.CERT_REQUIRED
ssl_context.load_cert_chan(
    certfile=self.client_cert_path,
    keyfile=self.client_key_path
)
async with httpx.AsyncClient(verify=self.ssl_context) as client:
    response = await client.get(endpoint)

Also if you want to avoid all this (doing stuff inside docker), you can simply pass the bundle in create_default_context like this :

ssl_context = ssl.create_default_context(cafile='/path/to/ca_bundle/')
ssl_context.verfiy_mode = ssl.CERT_REQUIRED
ssl_context.load_cert_chan(
    certfile=self.client_cert_path,
    keyfile=self.client_key_path
)
async with httpx.AsyncClient(verify=self.ssl_context) as client:
    response = await client.get(endpoint)

Upvotes: 0

Gringo
Gringo

Reputation: 21

If u are like me and dont really want to include the root-ca inside a build docker image

U can mount the cert on runtime as a file and just pass the mounted ca-cert file path as a parameter for whatever service u where about to access

e.g. with curls inside e kubernetes pod it looks like

curl --cacert path/to/ca-root.pem https://<service>.<namespace>.svc.cluster.local:4000/

Upvotes: 2

john321
john321

Reputation: 1

sudo apt -y install ca-certificates curl gnupg lsb-release

curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg apt update

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt -y install docker-ce docker-ce-cli containerd.io

sudo systemctl enable --now docker

Dockefile:

FROM nginx:latest COPY index.html /usr/share/nginx/html/index.html

sudo docker build -t mywebapp .

sudo docker run -d -p 80:80 mywebapp

Upvotes: -4

Jobin James
Jobin James

Reputation: 1040

Another option is to use OpenSSL. Replace domain_name with the URL you can retrieve the CA

RUN openssl s_client -connect <domain_name>:443 -showcerts </dev/null 2>/dev/null | sed -e '/-----BEGIN/,/-----END/!d' | tee "/usr/local/share/ca-certificates/ca.crt" >/dev/null && \
update-ca-certificates

Upvotes: 5

Peter
Peter

Reputation: 6035

To simplify/standardise all container builds, we now host our certificates on a central HTTPS server and build them into our containers like this:

# Debian stretch based container
RUN curl -ks 'https://cert.host.server/ssl_certs/EnterpriseRootCA.crt' -o '/usr/local/share/ca-certificates/EnterpriseRootCA.crt'
RUN /usr/sbin/update-ca-certificates

Alpine-based containers don't have the tools immediately available so require a bit more work to achieve the same:

# Alpine based containers
RUN apk update && apk add curl
WORKDIR /usr/local/share/ca-certificates
RUN curl -ks 'https://cert.host.server/ssl_certs/EnterpriseRootCA.crt' -o '/usr/local/share/ca-certificates/EnterpriseRootCA.crt'
RUN /usr/sbin/update-ca-certificates

If you also want to update your Java truststore (same as on any computer):

RUN keytool -keystore /usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts -storepass changeit -noprompt -trustcacerts -importcert -alias EnterpriseRootCA -file EnterpriseRootCA.crt

Upvotes: 52

banoth ravinder
banoth ravinder

Reputation: 1364

Installing ca-certificates locate cert_file_name.crt file in the same directory as Dockerfile.

# Install ca-certificates
# Please locate cert_file_name.crt file in the same directory as Dockerfile.
COPY cert_file_name.crt /usr/share/ca-certificates/
RUN echo cert_file_name.crt >> /etc/ca-certificates.conf
RUN update-ca-certificates

This will update certificates in the Dockerfile.

Upvotes: 13

damiankloip
damiankloip

Reputation: 644

It's also worth noting that this definitely needs to use the .crt extension. I initially tried this with a .pem cert file (I thought they were interchangeable, so others might also), which is not linked by update-ca-certificates.

Upvotes: 50

cebe
cebe

Reputation: 3819

The task itself is not specific to docker as you would need to add that CA on a normal system too. There is an answer on the askubuntu community on how to do this.

So in a Dockerfile you would do the following (don't forget chmod in case you're running the container with a user other than root):

ADD your_ca_root.crt /usr/local/share/ca-certificates/foo.crt
RUN chmod 644 /usr/local/share/ca-certificates/foo.crt && update-ca-certificates

Upvotes: 184

Related Questions