Using a SSH deploy key in GitHub Actions to access private repositories

I was recently tinkering around with GitHub Actions to see how we could use them improve our CI/CD pipeline. Here is how SSH keys can be used to access additional private repositories. 

Written by: Matthias
Published on: 2019-09-06

Update 2019-09-15: We've published the webfactory/ssh-agent GitHub Action which takes care of starting the SSH agent, adding the key and setting up host keys. With that action, most of the configuration described here is no longer necessary.
Update 2021-03-05: The Action now also supports running Mac OS, Windows- and Docker Container-based workflows. Also, GitHub Deploy (SSH) keys are supported and will be mapped to their respective repositories.

When staging a project to run tests or build a Docker image, you might need to fetch additional dependencies (libraries or "vendors") from private repositories. However, GitHub Actions are limited to accessing the repository they run for.

To solve this, you can create an additional SSH key with sufficient access privileges. Store that key in the secrets storage which is in the "Settings" area of your repository. The secret content is the private SSH key, as you will find it in the id_rsa file.

For the following example, the name of the secret should be SSH_PRIVATE_KEY. Then, have a look at the following workflow definition:

# .github/workflows/my-workflow.yml
# ... other config here
        runs-on: ubuntu-18.04
            -   uses: actions/checkout@v1

            -   name: Setup SSH Keys and known_hosts
                    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
                run: |
                    ssh-agent -a $SSH_AUTH_SOCK > /dev/null
                    ssh-add - <<< "${{ secrets.SSH_PRIVATE_KEY }}"

            -   name: Some task that fetches dependencies
                    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
                run: ./

We start the ssh-agent, binding it to a predictable socket location, and import the SSH private key into the agent. The nice thing about the way this happens is that the private key is never written to disk.

After the setup step has run, the SSH agent will still be running and can be used by other processes. To make this happen, set the SSH_AUTH_SOCK environment variable. Commands like git run ssh under the hood and will make use of the key stored in the agent when they authenticate to other hosts.

Right now, you will have to set the environment variable for every step that needs it, but it looks as if an improvement for this is already underway

Where to register the public SSH key part?

To actually grant the SSH key access, you can – on GitHub – use at least two ways:

  • Deploy keys can be added to individual GitHub repositories. They can give read and/or write access to the particular repository. When pulling a lot of dependencies, however, you'll end up adding the key in many places. Rotating the key probably becomes difficult.
  • A machine user can be used for more fine-grained permissions management and have access to multiple repositories with just one instance of the key being registered. It will, however, count against your number of users on paid GitHub plans.

Interesse geweckt?

Wir hören gerne zu, wenn Sie Fragen oder Anmerkungen zu diesem Thema haben. Und wenn Sie ein Projekt, ein Produkt, ein Problem oder eine Idee mit uns besprechen möchten, freuen wir uns erst recht über ein Gespräch!