module. is a object, known only after apply - terraform

I'm trying to create a ssm parameter in aws for dyanamo db table with name and arn so it can be referenced by another application. I've tried a few different things but can't figure out what I'm doing wrong here. Can anyone tell me what is wrong here?
Thank you
Here's my main file with the module.
main.tf
locals {
prefix = "/this/is/a/test"
}
module "test_table" {
source = "git#github.com:test/terraform-modules.git//dynamodb"
name = "dynamo-${local.environment}"
ssm_parameter_prefix = local.prefix
tags = {
Environment = local.environment
}
}
resource "aws_ssm_parameter" "table_name" {
provider = aws.east
name = "${local.prefix}/new/table-name"
type = "String"
value = module.test_table.name
}
resource "aws_ssm_parameter" "table_arn" {
provider = aws.east
name = "${local.prefix}/new/table-arn"
type = "String"
value = module.test_table.arn
}
Here is the output
outputs.tf
output "test_table" {
value = module.test_table
}
output "table_arn" {
value = module.test_table.arn
}
output "table_name" {
value = module.test_table.name
}
Terraform Error
│ Error: Unsupported attribute
│
│ on dynamo.tf line, in resource "aws_ssm_parameter" "table_name":
│ 118: value = module.test_table.name
│ ├────────────────
│ │ module.test_table is a object, known only after apply
│
│ This object does not have an attribute named "name".
╵
╷
│ Error: Unsupported attribute
│
│ on dynamo.tf line, in resource "aws_ssm_parameter" "table_arn":
│ 125: value = module.test_table.arn
│ ├────────────────
│ │ module.test_table is a object, known only after apply
│
│ This object does not have an attribute named "arn".
╵

The output blocks you showed declare output values named table_arn and table_name, but your references are to module.test_table.name and module_test.table.arn.
You'll need to either change the output value names to match the references, or change the references to match the output value names. Specifically, you'll need to either remove the table_ prefix from each of your output value names, or add table_ to the front of the references like module.test_table.table_name and module.test_table.table_arn.

Related

Parse yaml file to run a for_each loop in terraform for multiple resources creation

I have the following config.yaml file
entities:
admins:
someone#somewhere.com
viewers:
anotherone#somewhere.com
And I want to create vault entities based on the users below the yaml nodes admins and viewers
locals {
config = yamldecode(file("config.yaml"))
admins = keys(local.config["entities"]["admins"]...)
viewers = keys(local.config["entities"]["viewers"]...)
}
resource "vault_identity_entity" "admins" {
for_each = toset(local.admins)
name = each.key
policies = ["test"]
metadata = {
foo = "bar"
}
}
resource "vault_identity_entity" "viewers" {
for_each = toset(local.viewers)
name = each.key
policies = ["test"]
metadata = {
foo = "bar"
}
}
The code above fails with:
│ Error: Invalid expanding argument value
│
│ on ../../../../entities/main.tf line 3, in locals:
│ 3: admins = keys(local.config["entities"]["admins"]...)
│ ├────────────────
│ │ while calling keys(inputMap)
│ │ local.config["entities"]["admins"] is "someone#somewhere.com"
│
│ The expanding argument (indicated by ...) must be of a tuple, list, or set
│ type.
╵
╷
│ Error: Invalid index
│
│ on ../../../../entities/main.tf line 4, in locals:
│ 4: viewers = keys(local.config["entities"]["viewers"]...)
│ ├────────────────
│ │ local.config["entities"] is object with 2 attributes
│
│ The given key does not identify an element in this collection value.
How should I structure my yaml file?
It seems like you want the YAML to be a hash of a hash of a list of strings. You can restructure for that like:
entities:
admins:
- someone#somewhere.com
viewers:
- anotherone#somewhere.com
This will recast to map(map(list(string))) when yamldecode from a YAML format string to HCL2.
However, you are also attempting to convert the type with the ellipsis operator ... in your locals, and returning only the keys. I am unsure why you are doing that, and both should be removed:
admins = local.config["entities"]["admins"]
viewers = local.config["entities"]["viewers"]
Afterwards, you can convert to a set type with toset like you are doing already, and then leverage that within the for_each meta-argument as per usual:
for_each = toset(local.admins)
for_each = toset(local.viewers)
This will result in the desired behavior.

Migrating Azure Key Vault secrets from one Azure subscription to another

I have multiple Azure subscriptions, and I'm working on getting the key vault from one to another. I've written a terraform program to do this. Here I'm calling the data blocks and using for each loop condition from one subscription and using the output value of those as input values in another subscription. But I'm getting the error please help. Below is the code
data "azurerm_key_vault" "ewo1" {
provider = azurerm.demo-eworx-terraform-automation
name = "demo-eworx-keyvault"
resource_group_name = "demo-eworx-rg"
}
output "vault_uri_ewo1" {
value = data.azurerm_key_vault.ewo1.vault_uri
}
data "azurerm_key_vault_secret" "ewo1" {
provider = azurerm.demo-eworx-terraform-automation
for_each = toset(["demo-eworx-terraform-automation-client-secret", "demo-eworx-terraform-automation-client-id", "demo-eworx-terraform-automation-tenant-id", "demo-eworx-terraform-automation-subscription-id"])
name = each.key
key_vault_id = data.azurerm_key_vault.ewo1.id
}
output "secret_value" {
value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
}
data "azurerm_key_vault" "ewo11" {
provider = azurerm.terraform-automation
name = "demo-bteb-keyvault"
resource_group_name = "bteb-demo-work"
}
output "vault_uri_ewo11" {
value = data.azurerm_key_vault.ewo11.vault_uri
}
resource "azurerm_key_vault_secret" "ewo11" {
provider = azurerm.terraform-automation
for_each = toset(["demo-eworx-terraform-automation-client-secret", "demo-eworx-terraform-automation-client-id", "demo-eworx-terraform-automation-tenant-id", "demo-eworx-terraform-automation-subscription-id"])
name = each.key
value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
key_vault_id = data.azurerm_key_vault.ewo11.id
}
I need to migrate azure key vaults secrets from one subscription to another subscription. I have written the above terraform code, I'm passing the data "azurerm_key_vault" "ewo1" output value as resource "azurerm_key_vault_secret" "ewo11" value input. But getting below error.
Can some check and help me in solving the issue
error message:
Error: Incorrect attribute value type
│
│ on demo-keyvault-migration.tf line 38, in resource "azurerm_key_vault_secret" "ewo11":
│ 38: value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
│ ├────────────────
│ │ data.azurerm_key_vault_secret.ewo1 is object with 4 attributes
│
│ Inappropriate value for attribute "value": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│ on demo-keyvault-migration.tf line 38, in resource "azurerm_key_vault_secret" "ewo11":
│ 38: value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
│ ├────────────────
│ │ data.azurerm_key_vault_secret.ewo1 is object with 4 attributes
│
│ Inappropriate value for attribute "value": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│ on demo-keyvault-migration.tf line 38, in resource "azurerm_key_vault_secret" "ewo11":
│ 38: value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
│ ├────────────────
│ │ data.azurerm_key_vault_secret.ewo1 is object with 4 attributes
│
│ Inappropriate value for attribute "value": string required.
╵
╷
│ Error: Incorrect attribute value type
│
│ on demo-keyvault-migration.tf line 38, in resource "azurerm_key_vault_secret" "ewo11":
│ 38: value = [ for secret in data.azurerm_key_vault_secret.ewo1 : secret.name]
│ ├────────────────
│ │ data.azurerm_key_vault_secret.ewo1 is object with 4 attributes
│
╵
There are a couple of issues here, but the primary one is related to the azurerm_key_vault_secret data source. You are querying the data source while using for_each. That means that the result will be an object with key value pairs. That is why you are getting this in the output:
data.azurerm_key_vault_secret.ewo1 is object with 4 attributes
as in for_each you will use four keys:
for_each = toset(["demo-eworx-terraform-automation-client-secret", "demo-eworx-terraform-automation-client-id", "demo-eworx-terraform-automation-tenant-id", "demo-eworx-terraform-automation-subscription-id"])
The easiest and probably the cleanest way to fix the error is as follows:
resource "azurerm_key_vault_secret" "ewo11" {
provider = azurerm.terraform-automation
for_each = data.azurerm_key_vault_secret.ewo1
name = each.key
value = each.value.value
key_vault_id = data.azurerm_key_vault.ewo11.id
}
Here it is a bit unfortunate that each.value.value [1] has to be used due to the attribute naming, but there is not another way. Also, please make sure you understand how the for_each meta-argument [2] works.
[1] https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/key_vault_secret#value
[2] https://developer.hashicorp.com/terraform/language/meta-arguments/for_each

Dynamic block of lifecycle_rule not working in terraform 1.0.6

The following block within a google_cloud_storage resource
dynamic "lifecycle_rule" {
for_each = var.bucket_lifecycle_rule
content {
condition {
age = lifecycle_rule.age
with_state = lifecycle_rule.with_state
}
action {
type = lifecycle_rule.type
storage_class = lifecycle_rule.storage_class
}
}
}
with the following variable declaration
variable "bucket_lifecycle_rule" {
description = "Lifecycle rules"
type = list(object({
age = string
with_state = string
type = string
storage_class = string
}))
default = [
{
age = 30
with_state = "ANY"
type = "SetStorageClass"
storage_class = "COLDLINE"
},
{
age = 120
with_state = "ANY"
type = "Delete"
storage_class = ""
},
]
}
errors out as follows:
│ Error: Unsupported attribute
│
│ on main.tf line 18, in resource "google_storage_bucket" "my_bucket":
│ 18: age = lifecycle_rule.age
│
│ This object does not have an attribute named "age".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 19, in resource "google_storage_bucket" "my_bucket":
│ 19: with_state = lifecycle_rule.with_state
│
│ This object does not have an attribute named "with_state".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 22, in resource "google_storage_bucket" "my_bucket":
│ 22: type = lifecycle_rule.type
│
│ This object does not have an attribute named "type".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 23, in resource "google_storage_bucket" "my_bucket":
│ 23: storage_class = lifecycle_rule.storage_class
│
│ This object does not have an attribute named "storage_class".
why is that?
You have to reference the properties from your objects with value:
dynamic "lifecycle_rule" {
for_each = var.bucket_lifecycle_rule
content {
condition {
age = lifecycle_rule.value.age
with_state = lifecycle_rule.value.with_state
}
action {
type = lifecycle_rule.value.type
storage_class = lifecycle_rule.value.storage_class
}
}
}
In the Terraform docs there is a note about this:
The iterator object has two attributes:
key is the map key or list element index for the current element. If
the for_each expression produces a set value then key is identical to value and should not be used.
value is the value of the current element.

Separate structure for variables.tf gets "Object, known only after apply"

I have recently separated terraform files from it's variable file as per below structure
(root)
| main.tf
| users.tf
| roles.tf
├── Configuration (folder)
├──── azure-pipelines.yml
├──── .gitignore
├──── variables.tf
and since then I am getting bellow error messages
│ Error: Unsupported attribute
│
│ on main.tf line 77, in resource "azurerm_key_vault_secret" "primary_account_storage_access_key":
│ 77: name = "${module.variables.storage-account_name}-access-key"
│ ├────────────────
│ │ module.variables is a object, known only after apply
│
│ This object does not have an attribute named "storage-account_name".
╵
╷
│ Error: Unsupported attribute
│
│ on main.tf line 78, in resource "azurerm_key_vault_secret" "primary_account_storage_access_key":
│ 78: value = module.variables.storage-access_key
│ ├────────────────
│ │ module.variables is a object, known only after apply
│
│ This object does not have an attribute named "storage-access_key".
╵
This is how problematic resource "primary_account_storage_access_key" is defined
resource "azurerm_key_vault_secret" "primary_account_storage_access_key" {
depends_on = [azurerm_key_vault_access_policy.terraform_sp_access]
key_vault_id = data.azurerm_key_vault.azvault.id
name = "${module.variables.storage-account_name}-access-key"
value = module.variables.storage-access_key
}
Module is defined as below:
module "variables" {
source = "./Configuration"
}
I have no issue with utilizing the same module in other resources placed in the same file (main.tf)
terraform {
backend "azurerm" {
resource_group_name = module.variables.storage-resource_group_name
storage_account_name = module.variables.storage-storage_account_name
container_name = module.variables.storage-container_name
key = module.variables.storage-key
}
}
Found articles here on the site focusing on the error suggesting
"splat" operator with "toset" / "one" function, however that did not help:
name = "${toset(module.variables[*].storage-account_name)}-access-key"
value = toset(module.variables[*].storage-access_key)
name = "${one(module.variables[*].storage-account_name)}-access-key"
value = one(module.variables[*].storage-access_key)
Content of variables.tf what child module variables uses:
variable "storage-resource_group_name" {
type = string
default = "Reporting-HFM-integration-rg"
}
variable "storage-account_name" {
type = string
default = "reportinghfmintegration"
}
variable "storage-container_name" {
type = string
default = "tfstate-blob"
}
variable "storage-key" {
type = string
default = "terraform.tfstate"
}
variable "storage-access_key" {
type = string
default = "u3K..."
}
variable "keyVault-name" {
type = string
default = "se-dataplat-dwvault-prod"
}
variable "keyVault-resource_group_name" {
type = string
default = "AzureDataPlatform-dwtools-prod-rg"
}
variable "keyVault-id" {
type = string
default = "/subscriptions/23a89ca1-9743-4b3b-b5ff-41cea9985deb/resourceGroups/..."
}

How can I reference a variable in `main.tf`?

I have two terraform files main.tf and var.tfvars:
main.tf:
provider "google" {
project = var.project_id
region = var.gcp_region
}
provider "aws" {
region = var.aws_region
alias = "aws"
}
vars.tfvars:
variable "gcp_region" {
type = string
default = "asia-southeast1"
}
variable "aws_region" {
type = string
default = "ap-southeast-2"
}
variable "project_id" {
type = string
default = "test-oidc-arosha"
}
when I run terraform apply, I got below error:
Error: Reference to undeclared input variable
│
│ on local.tf line 6, in locals:
│ 6: state_backet = "${local.component_name}-${local.part_name}-deployment-${var.aws_region}-${data.aws_caller_identity.current.account_id}"
│
│ An input variable with the name "aws_region" has not been declared. This variable can be declared
│ with a variable "aws_region" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on main.tf line 2, in provider "google":
│ 2: project = var.project_id
│
│ An input variable with the name "project_id" has not been declared. This variable can be declared
│ with a variable "project_id" {} block.
╵
╷
│ Error: Reference to undeclared input variable
│
│ on main.tf line 3, in provider "google":
│ 3: region = var.gcp_region
│
│ An input variable with the name "gcp_region" has not been declared. This variable can be declared
│ with a variable "gcp_region" {} block.
I don't understand why I got this error even I already specified the default values for each variable.
My terraform version is:
$ terraform --version
Terraform v1.0.0
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v3.45.0
+ provider registry.terraform.io/hashicorp/google v3.72.0
Change the name of you vars.tfvars file to variables.tf and it should pick up the default value. .tfvars files are for inputs to variables which are in turn defined in the variables.tf file (or any .tf file actually, doesn't matter what you call it.)
you need to add variable definition to your main.tf and then use your variable in var.tf approapriately
example
variable "aws_region" {
type = string
default = "ap-southeast-2"
}
var.tfvars
example
aws_region = {
Name = "created by jatin/terraform",
instance_type="t2.micro"
}

Resources