Ephemeral values: Why do conditionals based on ephemeral values result in ephemeral values?

I have a use case where I have an object containing both ephemeral values and normal values (local.cloud_run_secrets_with_nulls). I want to return the keys of the values which are not null. To do that I use {for key, value in local.cloud_run_secrets_with_nulls: key => value if value != null} along with keys(local.object) which work, except Terraform marks it all as ephemeral. Now I intend to use that object as for_each for a resource but I can’t since it’s marked as ephemeral by Terraform.

Specifically the use case is this:

locals {
  # Secrets that may contain null values
  cloud_run_secrets_with_nulls = {
    MY_API_PASS   = ephemeral.random_password.my_pass.result
    MY_OTHER_PASS = var.other_pass_possibly_null
  }
  # Change the versions bellow to rotate secrets (not relevant in this post/question/issue, but kept for completeness)
  cloud_run_secrets_versions = {
    MY_OTHER_PASS = 2
  }

  # Filter out null secrets
  cloud_run_secrets = {
    for key, value in local.cloud_run_secrets_with_nulls :
    key => value if value != null
  }
  cloud_run_secrets_keys = toset(nonsensitive(keys(local.cloud_run_secrets)))
}

### Google Secret Manager
resource "google_secret_manager_secret" "main" {
  for_each = local.cloud_run_secrets_keys

  secret_id = "secret--${lower(replace(each.key, "_", "-"))}"
}

resource "google_secret_manager_secret_version" "main" {
  for_each = google_secret_manager_secret.main

  secret                 = each.value.id
  secret_data_wo_version = lookup(local.cloud_run_secrets_versions, each.key, 1)
  secret_data_wo         = local.cloud_run_secrets[each.key]
}

I would assume that the keys of the local.cloud_run_secrets would remain non-ephemeral, but instead Terraform marks everything as ephemeral (all keys, all values) just because there is a single condition which in one case operates on an ephemeral value.

My concern is easier to spot in this other scenario where I take only the keys directly:

locals {
  obj = {
    MY_API_PASS   = ephemeral.random_password.my_pass.result
    MY_OTHER_PASS = var.other_pass_possibly_null
  }

  obj_keys = [
    for key, value in local.obj :
    key if value != null
  ]
}

Here the array is only ever filled with non ephemeral values, the local.obj keys, but because of that condition containing an ephemeral value in one case the whole object is marked as ephemeral. All values I have in the array are not ephemeral, why does that condition make the whole array as ephemeral???

What’s the difference between doing this checking with an ephemeral value and checking with a non-ephemeral variable which may change it’s value from time to time while still not being stored in the state???

Hi @adelinn,

Your for expression is using a condition based on an ephemeral value to derive what keys to include in the final collection. If the ephemeral value were to change, then it could change what keys are in cloud_run_secrets, and hence change the values included in cloud_run_secrets_keys.

The short explanation is that if an ephemeral value has any influence over an expression result, then that result must also be ephemeral.