Terraform - 在单独文件中创建安全组ID并用于EC2实例创建

6

我使用了这个模块在AWS VPC中创建了一个安全组。我如何在单独的文件中引用所创建的资源?我正在同一仓库的不同目录中创建我们的堡垒机实例。

我的堡垒机配置如下,使用Terraform EC2模块,并且如果我硬编码vpc安全组ID,则可以正常工作,但我希望它能够直接从创建安全组时获取,因为这可能会在未来更改。

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"
      }
    }

我创建安全组的方式如下: 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"      
        }
      ]
    }

在我创建了bastion_sg.tf之后,我需要将安全组ID输出到outputs.tf中,然后才能在bastion/main.tf中像下面这样引用它吗?
    module "bastion_sg"
        source "../../global/vpc"

然后以某种方式将该ID传递到vpc_security_group_id = ?


嘿,你目前是如何存储状态的?是本地项目还是远程,比如S3文件夹? - einonsy
@einonsy 你好,它在 Terraform Cloud 上,所以是远程的。 - cjspencer
2个回答

6
我不会使用terraform-aws-modules,而是直接使用aws提供的资源,如aws_security_group和aws_security_group_rules。自Terraform 0.12以来,这些单资源模块没有任何好处,只会增加复杂性。
以下是使用直接aws提供商资源和无需多余模块的代码示例:
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
}

示例:在另一个模块中引用输出:

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
}

嗨,谢谢回复。但是如果安全组被其他实例使用怎么办?如果它们具有相同的规则,我不想为每种实例类型创建一个安全组。 - cjspencer
哦,这个也完全包含在这里了。您可以在多个实例上引用相同的安全组。那是一个单独的问题。如果您想进一步探讨,请发布一个单独的问题并在此处链接给我。 - Alain O'Dea
1
https://stackoverflow.com/questions/62512826/how-do-i-create-a-aws-security-group-and-use-it-in-different-tf-files - cjspencer
@cjspencer 我可以看一下后续问题。如果这个答案对这个问题有用,请将其接受为正确答案。 - Alain O'Dea
1
从技术上讲,目前它还不能工作,但如果我能够在Terraform中创建一个安全组,可以在单独的配置文件中使用,那么它将起作用。 - cjspencer

2

从你正在使用的模块文档中,这些是输出

在你自己的terraform中引用它们的方式是:

module.bastion-sg.this_security_group_id

因此,您的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 = [module.bastion-sg.this_security_group_id]
  subnet_id              = var.subnet
  iam_instance_profile   = "aws-example-ec2-role"

  tags = {
    Layer = "Bastion"
  }
}

感谢您的回复,当我尝试运行terraform plan时,出现了以下错误:错误:引用未声明的模块位于main.tf第12行,在模块“ec2-instance”中: 12: vpc_security_group_ids = [module.bastion-sg.this_security_group_id]根模块中没有声明名为“bastion-sg”的模块调用。因此,我在bastion/main.tf中添加了以下内容:module "bastion-sg" { source = "../../global/vpc" } - cjspencer
现在我收到的错误是:在 main.tf 的第 16 行,在模块“ec2-instance”中: 16: vpc_security_group_ids = [module.bastion-sg.this_security_group_id]模块“bastion-sg”中未声明名称为“this_security_group_id”的输出值。 - cjspencer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接