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.

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
jobs:
    build:
        runs-on: ubuntu-18.04
        steps:
            -   uses: actions/checkout@v1
            -   name: Setup SSH Keys and known_hosts
                env:
                    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
                run: |
                    mkdir -p ~/.ssh
                    ssh-keyscan github.com >> ~/.ssh/known_hosts
                    ssh-agent -a $SSH_AUTH_SOCK > /dev/null
                    ssh-add - <<< " ${{ secrets.SSH_PRIVATE_KEY }} "
            -   name: Some task that fetches dependencies
                env:
                    SSH_AUTH_SOCK: /tmp/ssh_agent.sock
                run: ./fetch-deps.sh

We first run ssh-keyscan to detect GitHub's SSH host keys. This for sure could be improved if worker nodes had these keys already set up. We then start the ssh-agent , binding it to a predictable socket location, and finally 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.
Was this helpful for you? Let @webfactory or @mpdude_de know!