How to pass SSH key to Docker build in Teamcity or elsewhere

When building in Docker, it is often we need to access private repos using authorized SSH key. However, since Docker builds are isolated from build agent, the keys remain outside of a container being built. Historically, people came up with many workarounds including passing the key to the container via ARG, forwarding SSH_AUTH_SOCK and other risky tricks.

To solve this long-standing problem, Docker 18.09 got an experimental feature that passes an available ssh key loaded to ssh-agent to the docker build. This key can be used in any of the RUN steps of Dockerfile.

To use it in Teamcity, other build system or even locally:

  1. Add a Build feature “SSH Agent” and chose a key you want to load to a local ssh-agent running at a build agent.
    For using it locally, you need to run ssh-agent and supply it with a private key for authentication.
  2. Set environment variable DOCKER_BUILDKIT=1. It can be done either via env.DOCKER_BUILDKIT as TC build parameter or simply run export DOCKER_BUILDKIT=1 as the first build step.
  3. Update docker build command in your Dockerfile to: docker build --ssh default Dockerfile .
    –ssh default will make the ssh key available within Docker build.
  4. Update the very first Dockerfile line with
    # syntax=docker/dockerfile:1.0.0-experiment
  5. (Optional) Ensure that a private repo (i.e. hosted on Github) is accessible via SSH. Something in line with this in your Dockerfile:
    RUN mkdir -p ~/.ssh && chmod 700 ~/.ssh && git config --globalurl."ssh://".insteadOf "" \
    && ssh-keyscan >> ~/.ssh/known_hosts && chmod 644 ~/.ssh/known_hosts
  6. Finally, pass the key to RUN command in your Dockerfile:
    RUN --mount=type=ssh git pull
    Here, –mount=type=ssh will use the default key from ssh-agent for authentication with the private repo.

There is a possibility to provide multiple keys for using at different steps of Docker build. More information can be found in these awesome blogs: 1, 2

So what is SecretKeeper?

One day I got a password sent to me over email at work. Then some time later – by Slack, Teams, Skype for Business, Skype, you name it. And yes, I totally get it – there are various password managers, tools and solutions that let you share a secret securely – why don’t we all use them? But there is no need to perform an epic eye-roll (yes, it’s a signature move of many security people) and blame incompetent users for doing something not completely secure…

The better question to ask is – if I wanted to share a secret securely, would it be actually that simple? So simple that it doesn’t create an entry barrier, doesn’t drain your colleagues energy and doesn’t require many extra step, manuals and precautions. As simple as sending it via a chat. Turned out, sharing sensitive information wasn’t that simple at all. Security always comes with strings attached, in a form of additional complexity, MFA, captcha, 16-letter-at-least-one-digit passwords and so forth.

Therefore, I decided to create SecretKeeper. I wanted it to be:

  • Used for sharing “secrets” – sensitive bits of information or files between two users.
  • It has to be deadly simple to use – one page, one button, one click.
  • Secure as it can be – goes without saying
  • Easily deployable to your hosting provider (so you can control your own instance)

The idea is incredibly simple – it is a web application that saves your secret (text or file) encrypted for a short amount of time. It generates a one-time link that you can share. Once the secret is read, it is deleted forever. There are no additional passwords or controls to protect the link – but it is a sha-256 hash of a random number, a long string that is hard to guess.

So, you want to share “hello” with your buddy. You open SecretKeeper:


You write hello in the textbox, chose the time of life for the secret – and get a link for sharing.


SecretKeeper is meant to be hosted by you, your organization or a hosting provider you trust. Therefore, I spent some nights making deployment as simple as one-click. There are two options:

  • Docker container
  • Azure AppService

The entire code is open-source, you can make sure there are no backdoors. It runs Kestrel, .NET Core 2.2, generates random links using secure algorithm (no System.Random!) and gets along with certificates really well. By the way, there is no other way to run it but with HTTPS. I even went full pro-mode on and audited it with Burp Professional and fixed some caching and HSTS configuration issues.

You can try out a working version of Appservice with SecretKeeper here:

I finally made all the final adjustments to call it 1.0 release, but there are many exciting features I would like to add to the tool – for example, add additional protections, such as password, or login with your SSO account to make it Enterprise-ready (chuckles). Anyway, a help is welcome, just check the list of open issues.