Using SSH Private Keys in Dockerfile aimed for Google Cloud Run

I had a one-user software that I wanted to deploy to Google Cloud Run from some time. It was on Python 3.5 and when I updated the system it lives on, the virtual environment stopped working. It also depened on some lxml-3.7 and that particular version didn’t compile on my new stable Debian installation.

This motivated me to learn docker and gcloud rather quickly.

I was able to create a new docker container in a short time. However as I don’t want to share my git ssh key publicly, I needed a way to put ssh private key, ~/.ssh/id_rsa to this new container securely, without leaving any trace.

I tried a few things but at the end I decided to something like:

FROM python:3.5-stretch as intermediate

# add credentials on build
RUN mkdir /root/.ssh/
# to use docker --build-arg, you can uncomment the following two lines and comment out the line with
COPY
# ARG SSH_PRIVATE_KEY
# RUN echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa
COPY application_sshkey /root/.ssh/id_rsa
RUN chmod 0600 /root/.ssh/id_rsa

# make sure your domain is accepted
RUN touch /root/.ssh/known_hosts
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts

RUN git clone git@bitbucket.org:username/application /root/application

FROM python:3.5-stretch
COPY --from=intermediate /root/application /root/application

RUN pip3 install -r /root/application/requirements.txt

EXPOSE 9090/tcp

WORKDIR /root/application/

CMD python3 manage.py runserver 0.0.0.0:9090

Here application_sshkey is a file I created using ssh-keygen and gave read-only access from Bitbucket.

As you can see, the Dockerfile has two FROM statements. It creates a container to clone the application repository. Then it starts again with a new container and copies repository to this new container. This way it’s not possible to peek into the private key by docker history command.

By the way, there are two methods in the Dockerfile, because gcloud builds does not accept a --build-args parameter similar to docker. I’m sure there are other workarounds for passing secrets to gcloud containers but instead of digging them, I found a working solution for both Docker and Google Cloud Run.