Using private git submodules in GitHub CI

Do you need to use submodules in your project? Do you use GitHub CI to build your project in the Cloud automatically?

If so then this article will help you to do this safely and without creating additional users or adding Tokens with a wide permission set. The idea is to use deploy keys that have read-only permissions.

The quick rundown for all you experts:

  • create SSH keypair on your computer
  • add public part as deploy key to private submodule
  • add private key as secret in repo where action is triggered. E.g SSH_KEY
  • add Secret to env with
 env:
          SSH_KEY: ${{secrets.SSH_KEY}}

do the following before pulling the submodules in the run configuration

mkdir $HOME/.ssh && echo "$SSH_KEY" > $HOME/.ssh/id_rsa && chmod 600 $HOME/.ssh/id_rsa

Detailed rundown

Create SSH keypair

Run ssh-keygen on your terminal. Choose a convenient location for the key e.g. /home/your_username/github_key on Linux.

This will create github_key and github_key.pub.

Add deploy key to the submodule

In the settings page of your submodule repository on GitHub add a new deploy key. Use the content of the github_key.pub file.

picture of GitHub settings page, deploy key section

Add the private key as a secret to your project

Now head over to the GitHub settings of your project that will consum the submodule.

Add the contents of github_key as a new repository secret. Choose a name such as SSH_KEY_FOR_SUBMODULE

picture of GitHub settings page, secrets section

Set up the CI

This is the configuration that is building this blog:

# .github/workflows/build_image.yml

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2
      - name: Trigger release build
        env:
          SSH_KEY_FOR_SUBMODULE: ${{secrets.SSH_KEY_FOR_SUBMODULE}}
        run: |
          mkdir $HOME/.ssh && echo "$SSH_KEY_FOR_SUBMODULE" > $HOME/.ssh/id_rsa && chmod 600 $HOME/.ssh/id_rsa && git submodule update --init --recursive && docker login docker.pkg.github.com -u $GITHUB_ACTOR --password $GITHUB_TOKEN && docker build . -t docker.pkg.github.com/blogname

So what is happening here?

Before git submodule update --init --recursive is run, the private key is read from the GitHub Secrets, written into a file that is used as a standard by SSH and the correct permissions are set on the key file.

All this makes the submodule intiliaztion work without problems since the private key verifies that the runner is allowed to read from the submodule repository.

Recap

  • create a keypair
  • distribute the keys as deploy key and GitHub Secret
  • read Secret and save the key into the standard $HOME/.ssh/id_rsa file

This solution guarantees that the runner can only read from the repository, but not give it any further access, which a Token based variant would do (in addition to needing a new GitHub user if done correctly).

Now go enjoy peace of mind when distributing your code all over the place. Happy hacking!

Cover Photo by Paweł Czerwiński on Unsplash

Back to overview