How to merge a string with a for_each object

Hi

I have this resource

resource "aws_msk_scram_secret_association" "msk-sasl" {
  
  cluster_arn     = aws_msk_cluster.msk-cluster.arn
  secret_arn_list = [ aws_secretsmanager_secret.msk-secret.arn, aws_secretsmanager_secret.msk-secret-users[*].arn ]
  
  depends_on = [aws_secretsmanager_secret_version.msk-secret-version, aws_secretsmanager_secret_version.msk-secret-version-users]
}

Where aws_secretsmanager_secret.msk-secret.arn is a string and the aws_secretsmanager_secret.msk-secret-users.arn is a for_each object for multiple users

The output is


β”‚ Error: Incorrect attribute value type
β”‚ 
β”‚   on ../../modules/msk/sasl.tf line 42, in resource "aws_msk_scram_secret_association" "msk-sasl":
β”‚   42:   secret_arn_list = [ aws_secretsmanager_secret.msk-secret.arn, aws_secretsmanager_secret.msk-secret-users[*].arn ]
β”‚     β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚     β”‚ aws_secretsmanager_secret.msk-secret-users is object with 1 attribute "oms"
β”‚     β”‚ aws_secretsmanager_secret.msk-secret.arn is "arn:aws:secretsmanager:eu-central-1:573629863099:secret:AmazonMSK_msk_secret-edd99f97-GLmybr"
β”‚ 
β”‚ Inappropriate value for attribute "secret_arn_list": element 1: string required.
β•΅
β•·
β”‚ Error: Unsupported attribute
β”‚ 
β”‚   on ../../modules/msk/sasl.tf line 42, in resource "aws_msk_scram_secret_association" "msk-sasl":
β”‚   42:   secret_arn_list = [ aws_secretsmanager_secret.msk-secret.arn, aws_secretsmanager_secret.msk-secret-users[*].arn ]
β”‚ 
β”‚ This object does not have an attribute named "arn".
β•΅
Releasing state lock. This may take a few moments...

When trying to load both config in to aws msk , i’m unable to do so, it complains that i can’t mix strings with object. I already tried many alternatives and none work, the closes one was adding a for_each in to that resource, but that tried to created multiple configs and i need only one.

So anyone can give me some hint how to solve this

Thanks in advance
Daniel

Hi @danielmotaleite,

According to the error output, secret_arn_list requires a list of strings. What you have assigned to that attribute is a tuple where the first element is a string, and the second is a list(string). You will need to combine these into a single list, for example:

  secret_arn_list = concat([aws_secretsmanager_secret.msk-secret.arn], aws_secretsmanager_secret.msk-secret-users[*].arn)

Fixing that assignment may get far enough to sort out the rest. I’m not sure how you are getting the second error without a more complete example, so we may need more information if you are still unable to proceed.

Nice, it worked! thanks for the help!!

i did try to use concat, but i didn’t use the on the first element … then i tried to use it only in the second element, but also failed

So now with this, it works:

resource "aws_msk_scram_secret_association" "msk-sasl" {
  cluster_arn     = aws_msk_cluster.msk-cluster.arn
  secret_arn_list = concat([aws_secretsmanager_secret.msk-secret.arn, aws_secretsmanager_secret.msk-secret-users["oms"].arn ])
  
  depends_on = [aws_secretsmanager_secret_version.msk-secret-version, aws_secretsmanager_secret_version.msk-secret-version-users]
}

But if i replace the β€œoms” with * , i would expect that it would dump the arn for all items, instead if fails, reporting the lack of the arn attribute

β•·
β”‚ Error: Unsupported attribute
β”‚ 
β”‚   on ../../modules/msk/sasl.tf line 42, in resource "aws_msk_scram_secret_association" "msk-sasl":
β”‚   42:   secret_arn_list = concat([aws_secretsmanager_secret.msk-secret.arn, aws_secretsmanager_secret.msk-secret-users[*].arn ])
β”‚ 
β”‚ This object does not have an attribute named "arn".

The list is generated like this:

resource "aws_secretsmanager_secret_version" "msk-secret-version-users" {
  for_each      = var.users

  secret_id     = aws_secretsmanager_secret.msk-secret-users[each.value.user].id
  secret_string = jsonencode({ username = "${each.value.user}", password = "${each.value.password}" })
}

The output of the aws_secretsmanager_secret.msk-secret-users is (truncated)

 msk-secret-users = {
      + ba  = {
          + arn                            = "arn:aws:secretsmanager:eu-central-1:573629863099:secret:AmazonMSK_msk_secret-edd99f97-ba"
          + description                    = ""
          + force_overwrite_replica_secret = false
(...)
     	}
      + oms = {
          + arn                            = "arn:aws:secretsmanager:eu-central-1:573629863099:secret:AmazonMSK_msk_secret-edd99f97-oms"
          + description                    = ""
          + force_overwrite_replica_secret = false
(...)

So looks like i should not use [*] there or must call the .arn in a different way… but what use instead?

Thanks again for the help
Best regards
Daniel

Your arguments to concat have a typo, you need to supply multiple lists which are to be concatenated, while you have supplied a single list (this however would probably be a valid argument to flatten).

Without a more complete example, I’m not sure about what the other errors mean. I would create a minimal, reproducible example, using the latest release of terraform, which we can use to narrow the scope of the problem here.

The [*] operator behaves differently for sequences (list and tuple types) than it does for other types, and you’re using it here in a way that only makes sense when applied to a list of objects that all have .id attributes.

Because aws_secretsmanager_secret.msk-secret-users uses for_each, it appears in expressions as a mapping rather than a list. Therefore you need to give Terraform more information about how to produce the resulting list.

If you just need to get a list of all of the ARNs and discard all the map keys then the values function can be a concise way to do that:

values(aws_secretsmanager_secret.msk-secret-users)[*].arn

The above expression first produces a list of the values from that map ordered lexically by their keys. Then we can apply the [*] operator to that list in order to get the .arn attribute from each one, in the same order.


Although I think values will be the best answer for your situation I also want to mention for expressions, which are a more general and therefore more flexible alternative to the splat operator [*], for situations where you need a more complicated expression to extract the resulting values. The above values-based expression is equivalent to the following for expression:

[for s in aws_secretsmanager_secret.msk-secret-users : s.arn]

That is, to take each element of aws_secretsmanager_secret.msk-secret-users, temporarily name it s, and then evaluate s.arn to produce a new sequence of the same length using those values.

Being familiar with for expressions will give you another tool in your toolkit to handle more complex variants of this problem where the splat syntax is insufficient.

1 Like

Thanks for both replies! after fixing my code and try the for solution, it is working correctly.
i prefer the for as it is clear what is doing, while values is (still yet another unknown for me) function… i still have much to learn! :slight_smile:

resource "aws_msk_scram_secret_association" "msk-sasl" {
  cluster_arn     = aws_msk_cluster.msk-cluster.arn
  secret_arn_list = concat( [ aws_secretsmanager_secret.msk-secret.arn] , [ for key, values in  aws_secretsmanager_secret.msk-secret-users: values.arn ] )
  depends_on      = [aws_secretsmanager_secret_version.msk-secret-version, aws_secretsmanager_secret_version.msk-secret-version-users]
}