Search code examples
amazon-web-servicesterraformterraform-provider-awsamazon-vpc

The given value is not suitable for module terraform error


I am building a terraform module for a Cloud Native application hosted on AWS to aid in learning both technologies but I run into an error informing me "The given value is not suitable for module terraform error...".

My module is designed as follows:

Root
  modules
    Application module (main, vars, output.tf files)
    Network module (main, vars, output.tf files)
    Security module (main, vars, output.tf files)
  main.tf
  vars.tf
  output.tf

But I have hit a snag while testing the Application module.

In the network module, I have code for creating an AWS VPC with multiple public subnets.

network module main.tf

resource "aws_subnet" "public_subnets" {
  for_each   = {for subnet, value in var.public_subnets : subnet => value}
  vpc_id            = aws_vpc.main_vpc.id
  cidr_block        = cidrsubnet(var.main_vpc_cidr, 8, index((var.public_subnets), each.value)+1)
  availability_zone = data.aws_availability_zones.azs.names[index(var.public_subnets, each.value)]
    
  tags = {
    Name        = each.value
    environment = var.environment
  }
}

network module output.tf

output "public_subnets" {
  value = aws_subnet.public_subnets
}

root module main.tf

module "network" {
  source = "./modules/network"
  main_vpc_cidr   = "10.0.0.0/16"
  vpc_name        = "main_vpc"
  environment     = "Testing"
  public_subnets  = ["public_subnet 1", "public_subnet 2"]
  private_subnets = ["private_subnet 1", "private_subnet 2"]
  wildcard        = "0.0.0.0/0"
}
    
module "security" {
  source = "./modules/security"
  wildcard    = "0.0.0.0/0"
  environment = "Testing"
  main_vpc_id = "module.network.vpc_id"
}
    
module "application" {
  source = "./modules/application"
  alb_name       = "nginx-alb"
  environment    = "Testing"
  alb_id         = "module.security.alb_sg"
  public_subnets = "module.network.public_subnets"
  main_vpc_id    = "module.network.vpc_id"
}

application module main.tf

resource "aws_lb" "nginx_alb" {
  name               = var.alb_name
  internal           = false
  load_balancer_type = "application"
  security_groups    = [var.alb_id]
  subnets = var.public_subnets
    
  tags = {
    environment = var.environment
  }
}

application module vars.tf

variable "public_subnets" {
  type = list(map(any))
}

When I run terraform plan to test the code, I get the following error

    │ Error: Invalid value for input variable
    │ 
    │   on main.tf line 23, in module "application":
    │   23:   public_subnets = "module.network.public_subnets"
    │ 
    │ The given value is not suitable for module.application.var.public_subnets declared at modules/application/vars.tf:13,1-26:
    │ list of map of any single type required.

Important to note that I have tried various tweaks to test the code e.g running a for loop on the public_subnets output value to ensure it returns a single string such as

[for subnet in aws_subnets.public_subnets: subnet.id]

Each time, I get the same error such as

     Error: Invalid value for input variable
    │ 
    │   on main.tf line 23, in module "application":
    │   23:   public_subnets = "module.network.public_subnets"
    │ 
    │ The given value is not suitable for module.application.var.public_subnets declared at modules/application/vars.tf:13,1-26:
    │ list of map of string required.

For clarity, I have provided the output of the public_subnets obtained via terraform plan below:

    + public_subnets = [
          + {
              + arn                                            = (known after apply)
              + assign_ipv6_address_on_creation                = false
              + availability_zone                              = "us-east-1a"
              + availability_zone_id                           = (known after apply)
              + cidr_block                                     = "10.0.1.0/24"
              + customer_owned_ipv4_pool                       = null
              + enable_dns64                                   = false
              + enable_lni_at_device_index                     = null
              + enable_resource_name_dns_a_record_on_launch    = false
              + enable_resource_name_dns_aaaa_record_on_launch = false
              + id                                             = (known after apply)
              + ipv6_cidr_block                                = null
              + ipv6_cidr_block_association_id                 = (known after apply)
              + ipv6_native                                    = false
              + map_customer_owned_ip_on_launch                = null
              + map_public_ip_on_launch                        = false
              + outpost_arn                                    = null
              + owner_id                                       = (known after apply)
              + private_dns_hostname_type_on_launch            = (known after apply)
              + tags                                           = {
                  + Name        = "public_subnet 1"
                  + environment = "Testing"
                }
              + tags_all                                       = {
                  + Name        = "public_subnet 1"
                  + environment = "Testing"
                }
              + timeouts                                       = null
              + vpc_id                                         = (known after apply)
            },
          + {
              + arn                                            = (known after apply)
              + assign_ipv6_address_on_creation                = false
              + availability_zone                              = "us-east-1b"
              + availability_zone_id                           = (known after apply)
              + cidr_block                                     = "10.0.2.0/24"
              + customer_owned_ipv4_pool                       = null
              + enable_dns64                                   = false
              + enable_lni_at_device_index                     = null
              + enable_resource_name_dns_a_record_on_launch    = false
              + enable_resource_name_dns_aaaa_record_on_launch = false
              + id                                             = (known after apply)
              + ipv6_cidr_block                                = null
              + ipv6_cidr_block_association_id                 = (known after apply)
              + ipv6_native                                    = false
              + map_customer_owned_ip_on_launch                = null
              + map_public_ip_on_launch                        = false
              + outpost_arn                                    = null
              + owner_id                                       = (known after apply)
              + private_dns_hostname_type_on_launch            = (known after apply)
              + tags                                           = {
                  + Name        = "public_subnet 2"
                  + environment = "Testing"
                }
              + tags_all                                       = {
                  + Name        = "public_subnet 2"
                  + environment = "Testing"
                }
              + timeouts                                       = null
              + vpc_id                                         = (known after apply)
            },
        ]

I would really appreciate assistance as i've been stuck on this for days.


Solution

  • public_subnets = "module.network.public_subnets"

    Your are assigning a literal string saying "module.network.public_subnets"

    Lose the quotes:

    public_subnets = module.network.public_subnets

    Also note that aws_lb.subnets is a list of strings, not a list of maps. You should fix the type of application.subnets accordingly.

    To check the types of your expressions, you can run terraform console and use the type function.

    This terraform works and builds a plan:

    diff --git a/main.tf b/main.tf
    new file mode 100644
    index 0000000..d522474
    --- /dev/null
    +++ b/main.tf
    @@ -0,0 +1,8 @@
    +module "network" {
    +  source = "./modules/network"
    +}
    +
    +module "application" {
    +  source         = "./modules/application"
    +  public_subnets = module.network.public_subnets
    +}
    diff --git a/modules/application/main.tf b/modules/application/main.tf
    new file mode 100644
    index 0000000..aa5c42d
    --- /dev/null
    +++ b/modules/application/main.tf
    @@ -0,0 +1,5 @@
    +resource "aws_lb" "nginx_alb" {
    +  internal           = false
    +  load_balancer_type = "application"
    +  subnets            = var.public_subnets
    +}
    diff --git a/modules/application/vars.tf b/modules/application/vars.tf
    new file mode 100644
    index 0000000..6f187cb
    --- /dev/null
    +++ b/modules/application/vars.tf
    @@ -0,0 +1,3 @@
    +variable "public_subnets" {
    +  type = list(string)
    +}
    diff --git a/modules/network/main.tf b/modules/network/main.tf
    new file mode 100644
    index 0000000..402057b
    --- /dev/null
    +++ b/modules/network/main.tf
    @@ -0,0 +1,4 @@
    +resource "aws_subnet" "public_subnets" {
    +  for_each = toset(["test"])
    +  vpc_id   = "test"
    +}
    diff --git a/modules/network/outpuf.tf b/modules/network/outpuf.tf
    new file mode 100644
    index 0000000..9eed5a3
    --- /dev/null
    +++ b/modules/network/outpuf.tf
    @@ -0,0 +1,3 @@
    +output "public_subnets" {
    +  value = [for subnet in aws_subnet.public_subnets : subnet.id]
    +}
    diff --git a/providers.tf b/providers.tf
    new file mode 100644
    index 0000000..12ae8b8
    --- /dev/null
    +++ b/providers.tf
    @@ -0,0 +1,4 @@
    +
    +provider "aws" {
    +  region = "us-east-1"
    +}
    

    If I put the quotes back, it gives me the same exact error as you are getting.