Skip to content

Automate Your SSH Deployment Keys

2017-03-07

When you go down the path of certain architectural choices you can end up with a number of repos that you have automated builds being initiated from. This could be anywhere from just a lot of applications you need to manage up through a microservices landscape. Which ever the reason, you have code that needs to be built. If you're lucky you get to use GitHub this is post may help automate some things.

Silvrback blog image sb_float_center

Deployments keys are a good way to keep individual's credentials out of your build system and grant read-only or write access to your individual repos.

A few requirements you will need to take care of ahead of time are:

  • admin access to your target repo
  • a git client installed on your workstation
  • a personal access token created in your GitHub settings page under Personal Access Tokens

Let's say you have admin access to the 3 repos, OrderService, Payment Service and InventoryService. You will need to create 3 distinct sets of keys as GitHub will not allow you to reuse them. First we're going to create some local directories to keep our SSH keys. Most of the time you do this interactively when you're are creating them for your local development environment but when you grab some additional cli parameters you can also supply the passphrase and output path ssh-keygen -t rsa -b 4096 -C $sshEmailAddress -N $sshKeyPhrase -f $sshPrivateKeyPath

Make this call for each of our repos and we have our 3 sets of keys. Next we need to chat up the GitHub API and save our deploy keys to their respective repos. With your username and personal access token you can generate an API Auth header to make those calls successful. Plenty of examples on this but this is what I'm using in my sample:

$username = "your_github_username"
$token = "your_github_access_token"
$authHeader = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$username`:$token"))

Then endpoint we are after lives up at https://api.github.com/repos/$owner/$repo/keys and if you POST a little slug of JSON you're key will be added to your repo. Make sure to set the read-only flag to false if you want your build process to be able to update anything in your repo.

Below is a sample script that can be used to automate this task. It will check to see if that named deployment key already exists and adds it to the repo if it isn't there. It certainly is use at your own risk and void where prohibited. Seriously understand what it does before you go trusting me

$repos = @(
    "OrderService",
    "PaymentService",
    "InventoryService"
)

$sshEmailAddress = "[email protected]"
$sshKeyPhrase = "your_pass_phrase"

$baseUri = "https://api.github.com"

$username = "your_github_username"
$token = "your_github_access_token"
$authHeader = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$username`:$token"))

$deploymentKeyName = "A_Useful_Deploy_Key_Name"
$owner = "your_repo_owner"

$repos | Foreach-Object {
    $repo = $_
    $sshDirectory = "C:\sshkeys\ssh-$repo"

    #make those *nix roots of ssh-keygen happy and rebuild the path as /c/sshkeys/ssh-repo
    $sshPrivateKeyPath = (($sshDirectory -replace "\\", "/") -replace "c\:","/c") + "/id_rsa"

    # Create 'this' repos ssh key directory as ssh-keygen likes its tree in place
    if(!(Test-Path -Path $sshDirectory)){
        New-Item -Type Directory -Path $sshDirectory
        ssh-keygen -t rsa -b 4096 -C $sshEmailAddress -N $sshKeyPhrase -f $sshPrivateKeyPath
    }

    $endpoint = "/repos/$owner/$repo/keys"
    $response = Invoke-WebRequest -Method Get -Uri "$baseUri/repos/$owner/$repo/keys" -Headers @{ "Authorization" = "Basic $authHeader" } | ConvertFrom-Json
    $hasDeploymentKey = $false    
    if($response.title.Length -gt 0 -and $response.title.Contains($deploymentKeyName)){
        Write-Host "$repo has a $deploymentKeyName deployment key" -ForegroundColor Green
    } else {
        Write-Host "$repo does not have a $deploymentKeyName deployment key" -ForegroundColor Red
        $key = Get-Content -Path "$sshDirectory\id_rsa.pub" -Raw | Out-String
        $body = @{ title=$deploymentKeyName; key=$key; read_only=$false } | ConvertTo-Json
        $reponse = Invoke-WebRequest -Method Post -Body $body -Uri "$baseUri/repos/$owner/$repo/keys" -Headers @{ "Authorization" = "Basic $authHeader" }
        Write-Host "Creation of deployment key $deploymentKeyName on $repo was HTTP reponse code $response.StatusCode"
    }
}

Hopefully you've taken away a few useful tips that will help you automate creating of SSH keys for your GitHub repositories.