【发布时间】:2016-07-04 10:04:00
【问题描述】:
我们需要将公司防火墙中的一些弹性 IP 列入白名单,作为 SSH 的允许目标 IP。有没有办法使用 Terraform 配置堡垒实例并为其分配特定的弹性 IP?同样,当堡垒被摧毁时,它是否将该 EIP 返回到预置池?显然,我们不希望从我们的 AWS 账户中释放 EIP。
【问题讨论】:
标签: amazon-web-services terraform
我们需要将公司防火墙中的一些弹性 IP 列入白名单,作为 SSH 的允许目标 IP。有没有办法使用 Terraform 配置堡垒实例并为其分配特定的弹性 IP?同样,当堡垒被摧毁时,它是否将该 EIP 返回到预置池?显然,我们不希望从我们的 AWS 账户中释放 EIP。
【问题讨论】:
标签: amazon-web-services terraform
现有答案已过时。由于此更改,现在可以关联现有的弹性 IP:https://github.com/hashicorp/terraform/pull/5236
文档:https://www.terraform.io/docs/providers/aws/r/eip_association.html
摘录:
aws_eip_association
提供 AWS EIP 关联作为顶层 资源,用于将弹性 IP 与 AWS 实例关联和解除关联 和网络接口。
注意:aws_eip_association 在 EIP 是 预先存在或分发给客户或用户,因此不能 改变。
【讨论】:
当前,当您可以选择将弹性 IP 附加到实例或弹性网络接口时,Terraform 仅支持将弹性 IP 附加到 EIP creation 上的 EC2 实例。 NAT Gateways 目前允许您在创建 NAT 网关时将 EIP 与其关联,但这是一个稍微特殊的情况。
instance module 本身只允许对实例是否获得正常的公共 IP 地址进行布尔选择。有一个 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 的approach,因此在任何试图破坏 EIP 的计划中都会出错,就像故障保险一样。
这至少应该允许您使用 Terraform 构建和销毁短期实例,但每次都将相同的 EIP 应用于实例,这样您就不必更改防火墙上的任何内容。
仅使用 Terraform 的稍微简单一点的方法是将 EIP 定义放在与堡垒实例相同的 .tf 文件/文件夹中,但您将无法使用 Terraform 销毁该文件夹中的任何内容(包括堡垒实例本身) 如果您保留 lifecycle 配置块,因为它只会在计划期间导致错误。删除块只会让您在每次销毁实例时重新销毁 EIP。
【讨论】:
我花了一些时间解决这个问题,发现其他答案很有帮助,但不完整。
对于那些尝试使用 Terraform 重新分配 AWS 弹性 IP 的人,我们可以使用 terraform_remote_state 和 aws_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 init 和terraform apply 以获取您的弹性IP。然后进入server 文件夹,并运行相同的两个命令来获取您的服务器及其关联的弹性IP。在服务器文件夹中,您可以运行 terraform destroy 和 terraform apply,新服务器将获得相同的弹性 IP。
【讨论】:
我们不希望从我们的 AWS 账户中释放 EIP。
是的,您可以阻止它。将prevent_destroy 设置为 true
resource "aws_eip" "bastion_eip" {
count = "${var.num_bastion}"
lifecycle {
prevent_destroy = true
}
}
关于分配的EIP,请参考@ydaetskcoR的回复
【讨论】:
allocation_id 参数
如果您使用的是自动扩缩组,则可以在用户数据中进行。 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
【讨论】: