amazon-web-servicesterraformssh-keys

Attach multiple SSH Keys to a user in a SFTP server


I want to create multiple unique SSH keys for multiple users for an AWS SFTP server. In my module call, I'm creating users and SSH keys by passing a map of objects :

module "users" {
  source = "../../sftp_user"
  users = {
    "user1" = {
      region     = "us-east-1",
      server_id  = module.sftp_server.server_id,
      (...other args),
      public_keys = ["ssh key 1", "ssh key 2", "ssh key 3"]
     },
     {
      "user2" = {(...args)}
   }

This is how my resource block looks like for attaching SSH Keys to the user. Currently I'm only able to attach the first SSH Key with it's user :

resource "aws_transfer_ssh_key" "sshkeysattachment" {
  for_each = var.users
  server_id = each.value.server_id
  user_name = each.key
  body = each.value.public_keys[0]                   # the first SSH key will be fetched
  depends_on = [aws_transfer_user.users]             # this confirms that the users are created first
}

I have tried using count keyword with the for_each keyword. But terraform says that :

The "count" and "for_each" meta-arguments are mutually-exclusive, only one should be used to be explicit about the number of
ā”‚ resources to be created.

For this code :

resource "aws_transfer_ssh_key" "sshkeysattachment" {
  for_each = {
    for user, config in var.users : 
      "${user}-${count.index}" => config if length(config.public_keys) > 0 
  }

  count     = length(each.value.public_keys)
  server_id = each.value.server_id
  user_name = each.key

  body = each.value.public_keys[count.index]

  depends_on = [aws_transfer_user.user]
}

Solution

  • I tried to flatten the map into a set of strings which will be of the form: "<username>:@:<ssh-key>" and put the set in for_each. Then, I performed split(":@:", each.value) to split the key which is inside the set and then mapping first index ([0]) to user_name and second index ([1]) to body, similar is the case for server_id as well.

    resource "aws_transfer_ssh_key" "ssh_keys_attachment" {
      depends_on = [aws_transfer_user.user]
      for_each = toset(flatten([
        for user, config in var.users : [
          for key in config.public_keys : "${user}:@:${key}"
        ]
      ]))
    
      server_id = aws_transfer_user.user[split(":@:", each.key)[0]].server_id
      user_name = split(":@:", each.value)[0]
      body      = split(":@:", each.value)[1]
    }
    

    Reference: https://stackoverflow.com/a/65294075/15176148