1

I am having trouble passing the output of one module into another module in Terraform. In my main.tf, I am creating a security group. I want to pass the id of this security group to the vpc_security_group_ids of my EC2 instance creation. Here is my code:


    ├── main.tf
    ├── modules
    │   ├── security-groups
    │   │   ├── main.tf
    │   │   ├── outputs.tf
    │   │   └── variables.tf
    │   └── vm-deploy
    │       ├── main.tf
    │       ├── output.tf
    │       └── variables.tf
    └── variables.tf

main.tf


    module "security-groups" {
      source= "./modules/security-groups"
    
      for_each= var.security-groups
    
      name= each.value.name
      description= each.value.description
      vpc_id= data.aws_vpc.vpc.id
    }
    
    module "vm-deploy" {
      source= "./modules/vm-deploy"
    
      for_each= var.instances
    
      ami= each.value.ami
      iam_instance_role= each.value.iam_instance_role
      instance_type= each.value.instance_type
      key_name= each.value.key_name
      private_ip= each.value.private_ip
      subnet_id= each.value.subnet_id
      user_data= each.value.user_data
      vpc_security_group_ids= [module.security-groups.id]
      kms_key_id= each.value.kms_key_id
      root_size= each.value.root_size
    }        

modules/security-groups/main.tf:


    resource "aws_security_group" "security_group" {
      name= var.name
      description   = var.description
      vpc_id= var.vpc_id
      tags= var.tags

modules/security-groups/outputs.tf:


    output "id" {
      value= aws_security_group.security_group.id
    }

modules/vm-deploy/main.tf:


    resource "aws_instance" "ec2_instance" {
        ami= var.ami
        iam_instance_profile= var.iam_instance_role
        instance_type= var.instance_type
        key_name= var.key_name
        private_ip= var.private_ip
        subnet_id= var.subnet_id
        user_data= var.user_data
        vpc_security_group_ids= var.security_group_ids
        root_block_device {
          delete_on_termination = false
          encrypted= true
          kms_key_id= var.kms_key_id
          volume_size= var.root_size
          volume_type= "gp2"
        }
      }

         

When I execute terraform plan, I get the following error:


    │   on main.tf line 45, in module "vm-deploy":
    │   45:   vpc_security_group_ids= [module.security-groups.id]
    │     ├────────────────
    │     │ module.security-groups is object with 1 attribute "sg-default"
    │ 
    │ This object does not have an attribute named "id".

1 Answers1

2

You create both modules with the for_each loop. Thus, this line vpc_security_group_ids = [module.security-groups.id] in your root module is incorrect, because module.security-groups is not a single object, but a list of objects.

If you intend to pass all security group ids created by module.security-groups, you should use a splat expression, e.g. vpc_security_group_ids = module.security-groups[*].id. Or, if you want to select one SG module per instance, then you should access it like so: vpc_security_group_ids = [module.security-groups["sg-default"].id], where "sg-default" is a key that comes from var.security-groups which you use in module.security-groups's for_each. If you don't understand the last example, check Terraform for_each docs.

Anton
  • 1,793
  • 10
  • 20
  • Thank you for the reply, Anton. I tried both variations per your suggestion. `vpc_security_group_ids= module.security-groups["*"].id`, and `vpc_security_group_ids= module.security-groups["name"].id` both error with Invalid Index. module.security-groups is object with 1 attribute "sg-default". The given key does not identify an element in this collection value.` – virtualramblings Apr 01 '23 at 17:19
  • 1
    @virtualramblings try [*] without quotes or `module.security-groups["sg-default"].id`. – Anton Apr 01 '23 at 17:35
  • Hey Anton. Putting the sg-default in quotes worked! Thank you for your help. – virtualramblings Apr 01 '23 at 17:43