Checking out a private submodule in a GitHub Action pipeline with a limited deploy key

I prefer to have any authentication identifiers be as narrow as possible when they’re defined in a pipeline or similar, and this proved to be a challenge when it comes to private git submodules inside a GitHub Action pipeline.

A common way to solve this is by defining a personal access token (a PAT), but this has a severe limitation: it needs access to both the project you’re deploying and the external submodule. But why does that matter? Because it means that you can’t configure the PAT under an organisation and re-use it across all your projects without making the PAT have access to all the repositories as well.

You effectively end up with a super-PAT that isn’t limited to just deploying the submodule.

Instead, you have to do it rather manually and as a two-step process. First, check out your project as you’d usually do with the checkout action, and then do the manual dance of configuring ssh with your deploy key and fetch submodules explicitly with git.

You’ll end up with something resembling these two workflow steps (based on a few posts on Stack Overflow and suggestions from a few LLMs):

      - name: Checkout and setup
        uses: actions/checkout@v6.0.1
        with:
          submodules: false
      - run: |
          mkdir -p ~/.ssh
          touch ~/.ssh/id_deploy_key
          chmod 0600 ~/.ssh/id_deploy_key
          echo '${{ secrets.LIBRARY_DEPLOY_PRIVATE_KEY }}' > ~/.ssh/id_deploy_key
          GIT_SSH_COMMAND="ssh -i ~/.ssh/id_deploy_key" git submodule update --init --recursive
        shell: bash

This is slightly verbose, but it works nicely in practice. Stick the deploy key in an organization secret under the name LIBRARY_DEPLOY_PRIVATE_KEY, and it’ll be available to any workflow that needs access to your private submodule.

And if it leaks – it just affects your common library, which shouldn’t contain any valuable secrets (.. outside of your code, at least) and your generic library code.

The best way would be that actions itself supported providing a deploy key for a given submodule, but it doesn’t seem like GitHub wants to support that from the tickets I read while researching this.