是否可以使用 Terraform 为堡垒分配特定的 AWS 弹性 IP?

Can a bastion be assigned a specific AWS Elastic IP with Terraform?

我们需要将公司防火墙中的一些弹性 IP 列入白名单,作为 SSH 允许的目标 IP。有没有办法使用 Terraform 配置堡垒实例并为其分配特定的弹性 IP?而且,同样地,当堡垒被摧毁时,return 是否将 EIP 分配给配置池?显然,我们不希望从我们的 AWS 账户中释放 EIP。

we don't want EIPs to be deallocated from our AWS account.

是的,你可以阻止它。将 prevent_destroy 设置为 true

resource "aws_eip" "bastion_eip" {
    count           = "${var.num_bastion}"
    lifecycle {
      prevent_destroy = true
    }
}

关于分配EIP,请参考@ydaetskcoR的回复

目前 Terraform 仅支持将弹性 IP 附加到 EC2 实例 EIP creation when you can choose to optionally attach it to an instance or an Elastic Network Interface. NAT Gateways 目前允许您在创建 NAT 网关时将 EIP 与其关联,但这是一个稍微特殊的情况。

instance module itself only allows a boolean choice of whether the instance gets a normal public IP address or not. There's a GitHub issue 允许实例与预先存在的 EIP 相关联,但在撰写本文时没有支持它的拉取请求。

如果只是想在公司防火墙上打开一个端口一次,而不必为定期拆除的堡垒盒接触它,并且您愿意允许 Terraform 创建和管理EIP 给你然后你可以做类似下面的事情:

resource "aws_instance" "bastion" {
  ami           = "ami-abcdef12"
  instance_type = "t2.micro"
  tags {
    Name = "bastion"
  }
}

output "bastion_id" {
  value = "${aws_instance.bastion.id}"
}

并且在一个单独的文件夹中,您可以拥有 EIP 定义,还可以从堡垒主机的 remote state file 中查找输出的实例 ID,并在应用 EIP 时使用它:

resource "terraform_remote_state" "remote_state" {
  backend = "s3"
  config {
    bucket = "mybucketname"
    key    = "name_of_key_file"
  }
}

resource "aws_eip" "bastion_eip" {
  vpc      = true
  instance = "${terraform_remote_state.remote_state.output.bastion_id}"
  lifecycle {
    prevent_destroy = true
  }
}

在上面的示例中,我使用了 @BMW's ,因此您应该在任何试图破坏 EIP 的计划中遇到错误,就像故障保险一样。

这至少应该允许您使用 Terraform 来构建和销毁短期实例,但每次都对实例应用相同的 EIP,这样您就不必更改防火墙上的任何内容。

一种仅使用 Terraform 的稍微简单的方法是将 EIP 定义放在与堡垒实例相同的 .tf file/folder 中,但您将无法使用 Terraform 销毁该文件夹中的任何内容(包括堡垒实例本身)如果您保留 lifecycle 配置块,因为它只会在计划期间导致错误。删除块只会让您在每次销毁实例时回到销毁 EIP 的状态。

现有答案已过时。由于此更改,现在可以关联现有的弹性 IP:https://github.com/hashicorp/terraform/pull/5236

文档:https://www.terraform.io/docs/providers/aws/r/eip_association.html

摘录:

aws_eip_association

Provides an AWS EIP Association as a top level resource, to associate and disassociate Elastic IPs from AWS Instances and Network Interfaces.

NOTE: aws_eip_association is useful in scenarios where EIPs are either pre-existing or distributed to customers or users and therefore cannot be changed.

我花了一些时间解决这个问题,发现其他答案很有用,但不完整。

对于那些尝试使用 Terraform 重新分配 AWS 弹性 IP 的人,我们可以结合使用 terraform_remote_stateaws_eip_association。让我解释一下。

我们应该使用两个单独的根模块,它们本身位于一个父文件夹中:

parent_folder
├--elasticip
|   └main.tf
└--server
    └main.tf

elasticip/main.tf 中,您可以使用以下代码创建一个弹性 IP,并将状态存储在本地后端,以便您可以从服务器模块访问其输出。输出变量名称不能是'id',因为这会与远程状态变量id 冲突,并且不会起作用。只需使用不同的名称,例如 eip_id.

terraform {                                                                                                             
  backend "local" {                                                                                                     
    path = "../terraform-eip.tfstate"                                                                                   
  }                                                                                                                     
}                                                                                                                       
                                                                                                                    
resource "aws_eip" "main" {
  vpc = true
  lifecycle {
    prevent_destroy = true
  }
}

output "eip_id" {
  value = "${aws_eip.main.id}"
}

然后在server/main.tf下面的代码会创建一个服务器并关联弹性IP。

data "terraform_remote_state" "eip" {
  backend = "local"

  config = {
    path = "../terraform-eip.tfstate"
  }
}

resource "aws_eip_association" "eip_assoc" {
  instance_id   = "${aws_instance.web.id}"
  allocation_id = "${data.terraform_remote_state.eip.eip_id}"
  #For >= 0.12
  #allocation_id = "${data.terraform_remote_state.eip.outputs.eip_id}"
}

resource "aws_instance" "web" {
  ami = "insert-your-AMI-ref"
}

完成所有设置后,您可以进入 elasticip 文件夹、运行 terraform initterraform apply 以获取您的弹性 IP。然后进入 server 文件夹和 运行 相同的两个命令来获取您的服务器及其关联的弹性 IP。在服务器文件夹中,您可以 运行 terraform destroyterraform apply 并且新服务器将获得相同的弹性 IP。

如果您使用的是自动缩放组,则可以在用户数据中进行。 https://forums.aws.amazon.com/thread.jspa?threadID=52601

#!/bin/bash
 
# configure AWS
aws configure set aws_access_key_id {MY_ACCESS_KEY}
aws configure set aws_secret_access_key {MY_SECRET_KEY}
aws configure set region {MY_REGION}
 
# associate Elastic IP
INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id)
ALLOCATION_ID={MY_EIP_ALLOC_ID}
aws ec2 associate-address --instance-id $INSTANCE_ID --allocation-id $ALLOCATION_ID --allow-reassociation