Terraform - Use security group ID created in separate file for EC2 instance creation
Asked Answered
C

2

6

I have used this module to create a security group in AWS VPC. How do I reference the resource created from this in a separate file? I am creating our bastion instance in a separate directory in the same repo.

My bastion config looks like the following, uses the Terraform EC2 module and works if I hard code the vpc security group ID, but I want it to be able to take it directly from when the security group is created as this could change in the future..

terraform/aws/layers/bastion/main.tf

    provider "aws" {
        region = var.region
    }

    module "ec2-instance" {
      source = "terraform-aws-modules/ec2-instance/aws"

      name                   = "bastion"
      instance_count.        = 1
      ami                    = var.image_id
      instance_type          = var.instance_type
      vpc_security_group_ids = ["${}"]
      subnet_id              = var.subnet
      iam_instance_profile   = "aws-example-ec2-role"

      tags = {
        Layer = "Bastion"
      }
    }

This is how I have created the security group: terraform/aws/global/vpc/bastion_sg.tf

        module "bastion-sg" {
          source = "terraform-aws-modules/security-group/aws"
    
      name        = "Bastion"
      description = "Bastion example group"
      vpc_id      = "vpc-12345"
    
      ingress_with_cidr_blocks = [
        {
          from_port   = ##
          to_port     = ##
          protocol    = "##"
          description = "Bastion SSH"
          cidr_blocks = "1.2.3.4/5"
        },
        {
          from_port   = ##
          to_port     = ##
          protocol    = "##"
          description = "Bastion SSH"
          cidr_blocks = "1.2.3.4/5"
        }
      ]
      egress_with_source_security_group_id = [
        {
          from_port                = ##
          to_port                  = ##
          protocol                 = "##"
          description              = "Access to default server security group"
          source_security_group_id = "sg-12345"
        },
        {
          from_port                = ##
          to_port                  = ##
          protocol                 = "##"
          description              = "Access to db"
          source_security_group_id = "sg-12345"      
        }
      ]
    }

Do I need to output the security group ID to outputs.tf where I have created by bastion_sg.tf before I can reference it within bastion/main.tf like below?

    module "bastion_sg"
        source "../../global/vpc"

and then somehow pass the ID into vpc_security_group_id = ?

Cons answered 19/6, 2020 at 12:38 Comment(2)
Hey, how are you currently storing the state, is it local to the project or remote, such as an S3 folder?Unknit
@Unknit hi, its in terraform cloud, so remote.Cons
B
6

I would not use terraform-aws-modules. I would use aws provider resources like aws_security_group and aws_security_group_rules directly. Since Terraform 0.12, there is no benefit to these single-resource modules, just added complexity.

Here's an example of what your code could be with direct aws provider resources and no superfluous modules:

provider "aws" {
    region = var.region
}

resource "aws_instance" "bastion" {
  name                   = "bastion"
  ami                    = var.image_id
  instance_type          = var.instance_type
  vpc_security_group_ids = [aws_security_group.bastion.id]
  subnet_id              = var.subnet
  iam_instance_profile   = "aws-example-ec2-role"

  tags = {
    Layer = "Bastion"
  }
}

resource "aws_security_group" "bastion_from_ssh" {
  name        = "Bastion"
  description = "Bastion example group"
  vpc_id      = "vpc-12345"
}

resource "aws_security_group_rule" "allow_ssh" {
  type                     = "ingress"
  from_port   = ##
  to_port     = ##
  protocol    = "##"
  description = "Bastion SSH"
  cidr_blocks = ["1.2.3.4/5"]
}

resource "aws_security_group_rule" "bastion_to_db" {
  type                     = "egress"
  from_port                = ##
  to_port                  = ##
  protocol                 = "##"
  description              = "Access to default server security group"
  source_security_group_id = "sg-12345"
}

output "security_group_id" {
    value = aws_security_group.bastion_from_ssh.id
}

Example: Referencing the output in another module:

module "bastion" {
   source = "path/to/dir/with/code/above"
   // ... any variables it needs
}

resource "aws_security_group" "app_server" {
  name        = "AppServer"
  description = "App Server group"
  vpc_id      = "vpc-12345"
}

resource "aws_security_group_rule" "allow_ssh_to_app_server" {
  security_group_id = module.bastion.security_group_id
  type = "egress"

  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  description = "SSH to App Server"
  source_security_group_id = aws_security_group.app_server.id
}

resource "aws_security_group_rule" "allow_ssh_from_bastion" {
  security_group_id = aws_security_group.app_server.id
  type = "ingress"

  from_port   = 22
  to_port     = 22
  protocol    = "tcp"
  description = "SSH from Bastion"
  source_security_group_id = module.bastion.security_group_id
}
Ballot answered 20/6, 2020 at 0:52 Comment(5)
Hi, thanks for the response. But what if the security group is used by other instances? I don't want to have to create a security group per instance type if they're the same rulesCons
Oh, that's totally covered here too. You can reference the same security group on multiple instances. That's a separate question. If you want to explore it more, please post a separate question and link me to it here.Lombard
#62513326Cons
@Cons I can take a look at the followup question. If this answer works for this question, please accept it as thecorrect answer.Lombard
Technically it doesn't work for it as of yet, but if I am able to create a security group in Terraform that can be used in separate config files then it will workCons
H
2

From the module documentation that you're using, these are the outputs.

The way to reference them in your own terraform would be:

module.bastion-sg.this_security_group_id

So your terraform/aws/layers/bastion/main.tf file would look like:

provider "aws" {
    region = var.region
}

module "ec2-instance" {
  source = "terraform-aws-modules/ec2-instance/aws"

  name                   = "bastion"
  instance_count.        = 1
  ami                    = var.image_id
  instance_type          = var.instance_type
  vpc_security_group_ids = [module.bastion-sg.this_security_group_id]
  subnet_id              = var.subnet
  iam_instance_profile   = "aws-example-ec2-role"

  tags = {
    Layer = "Bastion"
  }
}
Highboy answered 19/6, 2020 at 14:47 Comment(2)
thanks for the response, when I try to run terraform plan I get Error: Reference to undeclared module on main.tf line 12, in module "ec2-instance": 12: vpc_security_group_ids = [module.bastion-sg.this_security_group_id] No module call named "bastion-sg" is declared in the root module. So I then added this to bastion/main.tf: module "bastion-sg" { source = "../../global/vpc" }Cons
and the error I now get is: on main.tf line 16, in module "ec2-instance": 16: vpc_security_group_ids = [module.bastion-sg.this_security_group_id] An output value with the name "this_security_group_id" has not been declared in module.bastion-sg.Cons

© 2022 - 2024 — McMap. All rights reserved.