Variables in a Terraform configuration can be marked as sensitive in both the configuration and the Terraform Cloud / Enterprise interface. Attempting to use sensitive variables as for_each arguments will result in an error.
Problem
The developer wishes to use a sensitive variable in a configuration to create multiple resources using a 
for_each argument. Since the variable is marked sensitive, an error occurs like the following:
╷
│ Error: Invalid for_each argument
│
│ on main.tf line 11, in resource "random_pet" "p":
│ 11: for_each = var.lengths
│ ├────────────────
│ │ var.lengths has a sensitive value
│
│ Sensitive values, or values derived from sensitive values, cannot be used as for_each arguments. If used, the sensitive value
│ could be exposed as a resource instance key.
Prerequisites
- Terraform 0.14.0 or later
 
Cause
- Either the Terraform configuration declares the variable as sensitive:
 
# In this example, the desire is that the values 4 and 7 be secret,
# while foo and bar can be known.
variable "lengths" {
sensitive = true
type = map(number)
default = {
foo = 4
bar = 7
}
}
- Or the variable is marked sensitive in the TFC / TFE workspace variables page.
 - 
And the configuration attempts to use the sensitive variable in a 
for_eachexpression: 
resource "random_pet" "p" {
  for_each = var.lengths
  length   = each.value
}
Solution 1
The 
nonsensitive function can be used to explicitly tell Terraform that a given expression should not be treated as sensitive. This function should be used with care, as it could lead to information that was intended to be sensitive and redacted from output to be leaked. However, in this case it is appropriate because the part of the variable of interest for use as for_each keys is actually not sensitive.
Note: This function is only available in Terraform v0.15 and later.
A configuration using 
nonsensitive looks like the following:
variable "pets" {
  sensitive = true
  type = map(number)
  default = {
    foo = 4
    bar = 7
  }
}
resource "random_pet" "p" {
  for_each = nonsensitive(toset(keys(var.pets)))
  length   = var.pets[each.key]
}
Solution 2
One option to work around this error is to split up the values that will be making up the keys from the values that will contain the sensitive values. Terraform can parse expressions using functions to determine if they contain sensitive values, so the 
keys function can serve to do the split.
The following configuration produces the error:
# In this example, the desire is that the values 4 and 7 be secret,
# while foo and bar can be known.
variable "lengths" {
sensitive = true
type = map(number)
default = {
foo = 4
bar = 7
}
}
resource "random_pet" "p" {
for_each = var.lengths
length = each.value
}
The error can be avoided by looping over the keys in a separate variable, and using 
each.key  to refer to the values in the original map:variable "pets" {
  type = set(string)
  default = [
    "foo",
    "bar"
  ]
}
variable "pet_lengths" {
  sensitive = true
  type = map(number)
  default = {
    foo = 4
    bar = 7
  }
}
resource "random_pet" "p" {
  for_each = var.pets
  length   = var.pet_lengths[each.key]
}
Outcome
After making the changes to split the keys into a separate map or set, rerun the plan to ensure the plan succeeds without error.
Solution 1 output:
# random_pet.p["bar"] will be created
+ resource "random_pet" "p" {
+ id = (known after apply)
+ length = (sensitive)
+ separator = "-"
}
# random_pet.p["foo"] will be created
+ resource "random_pet" "p" {
+ id = (known after apply)
+ length = (sensitive)
+ separator = "-"
}
Plan: 2 to add, 0 to change, 0 to destroy.
Solution 2 output:
# random_pet.p["bar"] will be created
+ resource "random_pet" "p" {
+ id = (known after apply)
+ length = (sensitive)
+ separator = "-"
}
# random_pet.p["foo"] will be created
+ resource "random_pet" "p" {
+ id = (known after apply)
+ length = (sensitive)
+ separator = "-"
}
Plan: 2 to add, 0 to change, 0 to destroy.