We started using Concourse at $job, as a replacement for Jenkins. One common thing that almost every Concourse job/pipeline/task will need is access to our git repository, which means Concourse needs an SSH key for our repos.

I googled around for examples of other people using Concourse with SSH keys, and wasn’t able to find any example of anyone storing their SSH keys in AWS SSM Parameter Store. So I’ll post my own example and hopefully help the next person who googles it.

Add your public key to GitHub

This step is GitHub-specific, but the general principal would apply to any git hosting provider. In GitHub, you need to add your public key as a deploy key.

Add your private key to AWS Parameter Store

Which is how Concourse will be able to fetch the private key. You can add the private key to SSM Parameter Store using the AWS CLI like this:

aws ssm put-parameter \
--name /concourse/main/github_private_key \
--type SecureString \
--value $(cat /path/to/your/id_rsa)

Or create the parameter using Terraform or however you normally spin up AWS resources, which is how I did it.

Note that the name of the parameter is pretty important, /concourse/main/github_private_key. By default Concourse will look for parameters who’s names look like /concourse/main/NAME_OF_PARAMETER. The /concourse/main parts, by default, need to be that literal string. Notice the Credential Lookup Rules in Concourse’s documentation for more on that.

Using the private key inside Concourse

Now that your private key is stored in SSM, make sure your Concourse server has IAM permissions to access the parameter (ssm:GetParameter).

Then you can use, for example, a Concourse git-resource which uses the private key.

---
resources:
- name: my-repo
  type: git
  source:
    branch: master
    uri: git@github.com:yourcompany/yourrepo.git
    private_key: ((github_private_key))

Notice how Concourse uses the lookup rules described above. The name of the parameter (((github_private_key))), matches the third part of the name of the SSM parameter that we created above. And due to the lookup rules, it just works.