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.