Posted on :: Tags: , , , , ,

I had a one-user software application that I had wanted to deploy to Google Cloud Run for some time. It was on Python 3.5, and when I updated the system it lives on, the virtual environment stopped working. It also depended on 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 an SSH private key (~/.ssh/id_rsa) into this new container securely, without leaving any trace.

I tried a few things, but in the end, I decided to do 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 COPY line below.
# 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 granted read-only access to on 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 the repository to this new container. This way, it is not possible to peek into the private key using the docker history command.

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