[Common Issue] Using an SSH key via environment variable during build

Some workflows require use of an SSH private key during build - for instance, logging in to a server to restart your backend, or using git clone on a private repo during build. There are better ways to accomplish this goal for most use cases, but in case you choose to do that, below is an approach that can work.

First, create an ssh key and add the public key (shorter one) to your service (e.g. on your GitHub repo settings, or in ~/.ssh/authorized_keys on your server)

Then, take the private key (longer one) and transform it into something suitable for the build environment. This means that it wouldn’t have carriage returns in it, so I’ve edited the key I use with this pattern, in my Netlify Build Environment Variables on the Build & Deploy settings page, as shown in this screenshot:

There, I configure my SSH_KEY variable, setting it to a value like this:

-----BEGIN RSA PRIVATE KEY-----_MIIEpAIBAAKCAQEAoCGgoxalJiAF5WKQ...

You can see your own key will look more like:

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoCGgoxalJiAF5WKQ...

So you can see, I’ve just replaced carriage returns with underscores. Then I use this sequence as part of my build command:
mkdir -p ~/.ssh && echo -e "${SSH_KEY//_/\\n}" > ~/.ssh/id_rsa && chmod og-rwx ~/.ssh/id_rsa

Now you’ll have a mostly-usable SSH key in your build environment. I say “mostly” since there are still some things to consider:

  • You’ll need to set these settings for git (which you would & can use manually if you ran ssh interactively): -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no . This stack overflow article shows how to apply them to the git config: https://stackoverflow.com/questions/7772190/passing-ssh-options-to-git-clone
  • You’ll need to do this BEFORE YOUR BUILD STARTS and BEFORE YOU NEED THE KEY. So - this may be a challenge considering you might have a package.json that we try to use with npm install before the build runs. You’ll have to do something to prevent us from running npm instal , such as not having a package.json file in the root of your repo, or make that package optional - and then install it later, AFTER you’ve run those build commands.

I don’t have a great demonstration of that use pattern to share - if you require the package before your build starts, the submodule route mentioned in this article (about hugo, but generally applicable) outlines how this process can happen at clone time rather than post-dependency-installation time. Even without a specific example, hopefully this provides some ideas on how you can approach this process.

1 Like

Just bumped into this issue and was able to find a solution using this article. I created this shell script to execute the necessary steps:

#!/usr/bin/env bash

# Check if we're running in a Netlify environment
# See https://www.netlify.com/docs/continuous-deployment/#environment-variables
if [ ! -z "${DEPLOY_PRIME_URL}" ]; then

    # Init .ssh dir and expand $SSH_KEY
    mkdir -p ~/.ssh
    echo -e "${SSH_KEY//_/\\n}" > ~/.ssh/id_rsa
    chmod og-rwx ~/.ssh/id_rsa

    # Uncomment to debug
    # ls -la ~/.ssh
    # cat ~/.ssh/id_rsa

    # Add host keys, comment out if not needed
    ssh-keyscan -H github.com >> ~/.ssh/known_hosts
    ssh-keyscan -H bitbucket.org >> ~/.ssh/known_hosts

fi;

You can trigger the script using the npm “preinstall” hook:

{
  ...
  "scripts": {
    "preinstall": "bash netlify-setup.sh",
  }
}
1 Like

thank you for sharing!