Skip to content

Commit

Permalink
Upload public SSH key for git user
Browse files Browse the repository at this point in the history
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:

hashicorp/terraform#5744
hashicorp/terraform#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.
  • Loading branch information
keymon committed Mar 23, 2016
1 parent 961d527 commit 2cf5a8c
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 0 deletions.
15 changes: 15 additions & 0 deletions terraform/concourse/aws-get-aws-key-id.sh
Original file line number Diff line number Diff line change
@@ -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
19 changes: 19 additions & 0 deletions terraform/concourse/aws-upload-aws-key.sh
Original file line number Diff line number Diff line change
@@ -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

48 changes: 48 additions & 0 deletions terraform/concourse/codecommit.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,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"))}"
}
}

1 change: 1 addition & 0 deletions terraform/concourse/git_ssh_key_id
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Empty file git_ssh_key_id to avoid terraform fail during the first run.
4 changes: 4 additions & 0 deletions terraform/concourse/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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}"
}
4 changes: 4 additions & 0 deletions terraform/concourse/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}

0 comments on commit 2cf5a8c

Please sign in to comment.