Create aws_transfer_ssh_key from a map of user to SSH keys

1.1k views Asked by At

I'm trying to create a transfer key from a map users to SSH keys

content_users = {
  "master" = [
    "ssh-rsa ...",
    "ssh-rsa ...",
    "ssh-rsa ...",
  ]
  "test" = [
    "ssh-rsa ...",
    "ssh-rsa ...",
  ]
}

The aws_transfer_user part is easy enough

resource "aws_transfer_user" "content" {
  for_each  = var.content_users
  server_id = aws_transfer_server.content.id
  user_name = each.key
  role      = aws_iam_role.transfer.arn
}

But I am trying to figure out how to do the aws_transfer_key which only accepts one ssh key

resource "aws_transfer_ssh_key" "content" {
  for_each = var.content_users
 server_id = aws_transfer_server.content.id
  user_name = each.key
  body      = "... SSH key ..."
}

I am thinking it is something I just have to follow with https://www.terraform.io/docs/configuration/functions/flatten.html#flattening-nested-structures-for-for_each

2

There are 2 answers

0
Archimedes Trajano On BEST ANSWER
resource "aws_transfer_ssh_key" "content" {
  for_each = toset(flatten([
    for user, keys in var.content_users : [
      for key in keys : "${user}:@:${key}"
    ]
  ]))
  server_id = aws_transfer_server.content.id
  user_name = split(":@:", each.value)[0]
  body      = split(":@:", each.value)[1]
}
0
Chupacabra On

I did this a little different. I didn't like the idea of the resource name containing the full public ssh key value. I use the below code in a module that was created.

I used a map variable like this.

variable "customers" {
  description = "A map of customer usernames and ssh public keys"
  type = map(object({
    keys = list(string)
  }))
}

ex.

customers = {
  cust1 = { 
    keys = [
      "ssh-rsa..."
    ]
  },
  cust2 = {
    keys = [
      "ssh-rsa...",
      "ssh-rsa...",
      "ssh-rsa..."
    ]
  },
}

First I had to flatten it and I also added an index while doing so.

locals {
  customers = flatten([
    for customer, sshkeys in var.customers : [
      for k, v in sshkeys.keys : {
        client = customer
        index  = k
        key    = v
      }
    ]
  ])
}

Then I used it in the resource. The index is required otherwise the map fails and asks you to group the client keys using ..., but we do not want this.

resource "aws_transfer_ssh_key" "this" {
  for_each  = { for each in local.customers : "${each.client}.${each.index}" => each }
  server_id = aws_transfer_server.this.id
  user_name = "customer-${each.value.client}"
  body      = each.value.key
}

This should generate numbered resources for the transfer ssh key like the follwing...

cust1.0
cust2.0
cust2.1
cust2.2

The index value resets for each client. You could add a +1 to the index so it starts at 1 instead of 0 as well.