From b2af22bc81a5be7415e5db0233d08d7c17511fa1 Mon Sep 17 00:00:00 2001 From: Hector Rivas Gandara Date: Tue, 22 Mar 2016 17:10:53 +0000 Subject: [PATCH] Upload public SSH key for git user In order to access the codecommit repository via SSH, we must upload a SSH key. We add a required variable for the concourse terraform: `git_rsa_id_pub`, which must have the public SSH key to add, and a new output `git_ssh_key_id` which is the key id of the ssh key and the user that must be used when connecting to the codecommit git repo. But terraform does not currently support upload ssh keys, although the PR is in master and will be released soon: https://github.com/hashicorp/terraform/issues/5744 https://github.com/hashicorp/terraform/pull/5774 To workaround this, we implemented the following workaround: 1. One template_file which contains the public key. If it changes, it will run a script `aws-upload-aws-key.sh` to upload the SSH key to the user. The script takes care of duplicates. 2. A template_file resource will read from a `id_rsa_key_id`, and execute a script to query the ID if the file has changed since last execution. This ensures that the file is updated. We must commit a empty file to avoid terraform fail the first run. 3. Another template_file which reads the previous populated `id_rsa_key_id` file. This allows read the file content and expose it as a terraform output. This workaround can be removed and replaced as the resource `aws_iam_user_ssh_key` is supported and released in the official terraform release. --- terraform/concourse/aws-get-aws-key-id.sh | 15 +++++++ terraform/concourse/aws-upload-aws-key.sh | 19 +++++++++ terraform/concourse/codecommit.tf | 48 +++++++++++++++++++++++ terraform/concourse/git_ssh_key_id | 1 + terraform/concourse/outputs.tf | 4 ++ terraform/concourse/variables.tf | 4 ++ 6 files changed, 91 insertions(+) create mode 100755 terraform/concourse/aws-get-aws-key-id.sh create mode 100755 terraform/concourse/aws-upload-aws-key.sh create mode 100644 terraform/concourse/git_ssh_key_id diff --git a/terraform/concourse/aws-get-aws-key-id.sh b/terraform/concourse/aws-get-aws-key-id.sh new file mode 100755 index 0000000000..fb5b54893f --- /dev/null +++ b/terraform/concourse/aws-get-aws-key-id.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +username="$1" +id_rsa_pub=$(echo $2 | awk '{print $2}') + +for key_id in $(aws iam list-ssh-public-keys --user-name "${username}" --query 'SSHPublicKeys[*].SSHPublicKeyId' | sed -n 's/.*\(AP.*\)".*/\1/p'); do + key=$(aws iam get-ssh-public-key --encoding SSH --user-name "${username}" --ssh-public-key-id "${key_id}" --query 'SSHPublicKey.SSHPublicKeyBody') + if echo "${key}" | grep -q "${id_rsa_pub}"; then + echo $key_id + exit 0 + fi +done +echo "Not found" +exit 1 diff --git a/terraform/concourse/aws-upload-aws-key.sh b/terraform/concourse/aws-upload-aws-key.sh new file mode 100755 index 0000000000..58e2786d03 --- /dev/null +++ b/terraform/concourse/aws-upload-aws-key.sh @@ -0,0 +1,19 @@ +#!/bin/sh +output=$(mktemp) +trap 'rm -f "${output}"' EXIT + +aws iam upload-ssh-public-key --user-name $1 --ssh-public-key-body "$2" > "${output}" 2>&1 +RET="$?" +cat "${output}" + +if [ "${RET}" != "0" ]; then + if grep -q "Duplicate SSH public key uploaded" "${output}"; then + echo "Key is already uploaded." + # Try to find out the key id + exit 0 + else + echo "Error uploading key" + exit "${RET}" + fi +fi + diff --git a/terraform/concourse/codecommit.tf b/terraform/concourse/codecommit.tf index 91d4e4b499..cfdc342382 100644 --- a/terraform/concourse/codecommit.tf +++ b/terraform/concourse/codecommit.tf @@ -31,3 +31,51 @@ resource "aws_iam_user" "git" { # ] # append = true #} + +# Workaround until this PR is released in terraform. +# +# https://github.com/hashicorp/terraform/pull/5774 +# https://github.com/hashicorp/terraform/issues/5744 +# +# We use a template to read a generated ssh public key. If it changed, +# we try to add it to the user using a local_exect provider +# +resource "template_file" "git_rsa_id_pub" { + template = "${git_rsa_id_pub}" + vars { + git_rsa_id_pub = "${var.git_rsa_id_pub}" + } + # Upload the ssh key whenever this template changes + provisioner "local-exec" { + command = "${path.module}/aws-upload-aws-key.sh ${aws_iam_user.git.name} '${template_file.git_rsa_id_pub.rendered}'" + } +} + +# Query the key id of the just uploaded ssh public key, and +# write it to a file git_ssh_key_id which will be read by the next resource. +# +# This template will trigger the local_exec script everytime the file id_rsa_key_id +# is different than the state, and populate it with the right value. +resource "template_file" "git_ssh_key_id_query" { + depends_on = ["template_file.git_rsa_id_pub"] + template = "${git_ssh_key_id}" + # Important, this must be used as variable to be evaluated in render time + vars { + git_ssh_key_id = "${trimspace(file("${path.module}/git_ssh_key_id"))}" + } + provisioner "local-exec" { + command = "${path.module}/aws-get-aws-key-id.sh ${aws_iam_user.git.name} '${template_file.git_rsa_id_pub.rendered}' > ${path.module}/git_ssh_key_id" + } +} + +# We use a template so we can define a terraform output and it will be +# tracked in the terraform state. +resource "template_file" "git_ssh_key_id" { + depends_on = ["template_file.git_ssh_key_id_query"] + template = "${git_ssh_key_id}" + # Important, this must be used as variable to be evaluated in render time + vars { + git_ssh_key_id = "${trimspace(file("${path.module}/git_ssh_key_id"))}" + } +} + diff --git a/terraform/concourse/git_ssh_key_id b/terraform/concourse/git_ssh_key_id new file mode 100644 index 0000000000..d2807ae17f --- /dev/null +++ b/terraform/concourse/git_ssh_key_id @@ -0,0 +1 @@ +Empty file git_ssh_key_id to avoid terraform fail during the first run. diff --git a/terraform/concourse/outputs.tf b/terraform/concourse/outputs.tf index 5b804c3c39..44415142c8 100644 --- a/terraform/concourse/outputs.tf +++ b/terraform/concourse/outputs.tf @@ -29,3 +29,7 @@ output "git_concourse_pool_clone_url_http" { output "git_user_name" { value = "${aws_iam_user.git.name}" } + +output "git_ssh_key_id" { + value = "${template_file.git_ssh_key_id.rendered}" +} diff --git a/terraform/concourse/variables.tf b/terraform/concourse/variables.tf index 16e6012489..123ef3089b 100644 --- a/terraform/concourse/variables.tf +++ b/terraform/concourse/variables.tf @@ -10,3 +10,7 @@ variable "concourse_pool_git_rw_groupname" { description = "Group with permissions to write in concourse pool git repositories" default = "concourse-pool-git-rw" } + +variable "git_rsa_id_pub" { + description = "Public SSH key for the git user" +}