运行 AWS 上的 Terraform 没有 VPC 端点或 0.0.0.0/0 规则

Running Terraform on AWS without VPC endpoints or 0.0.0.0/0 rules

我有一个 EC2 实例,我将在其上 运行 Terraform 在 AWS 中配置大量其他资源。我不想为该服务器提供出站互联网访问权限,因为它唯一需要访问的是 AWS API,所以我沿着 VPC 端点路径走下去。

在我需要为有 no VPC endpoint 的资源(例如 RDS 和 Elasticache)配置资源之前,它一直运行良好。我不想为该实例提供互联网访问权限并在端口 443 上创建出站 0.0.0.0/0 规则,但我看不到其他方式。

有没有办法限制仅对 AWS API 进行出站 HTTPS 访问?

AWS 提供 a guide 用于计算任何服务端点的 IP 地址以允许出口到它。这依赖于下载所有 AWS 端点的 IP 地址,然后过滤 AMAZON 列表中的 IP 地址,但从 EC2 列表中删除那些。

谢天谢地,我们可以使用 aws_ip_ranges data source 在 Terraform 中直接获取这些 IP 地址,并且可以过滤 AMAZON 范围和 EC2 范围:

data "aws_region" "current" {}

data "aws_ip_ranges" "amazon" {
  regions  = [data.aws_region.current.name]
  services = ["amazon"]
}

data "aws_ip_ranges" "ec2" {
  regions  = [data.aws_region.current.name]
  services = ["ec2"]
}

以上示例将获取您所在区域的 AMAZONEC2 块(它们是 AMAZON 块的子集)的所有 IP 地址 运行英寸

要从 AMAZON 块中删除 EC2 块,我们需要使用 setsubtract function:

locals {
  aws_control_plane = setsubtract(data.aws_ip_ranges.amazon.cidr_blocks, data.aws_ip_ranges.ec2.cidr_blocks)
}

这应该只给我们想要允许我们的安全组出口的 IP 范围。

不幸的是,这可能超过 60 个 CIDR 范围,相当于超过 60 个规则。安全组是 limited to a max of 60 ingress and 60 egress rules:

You can have 60 inbound and 60 outbound rules per security group (making a total of 120 rules). This quota is enforced separately for IPv4 rules and IPv6 rules; for example, a security group can have 60 inbound rules for IPv4 traffic and 60 inbound rules for IPv6 traffic. A rule that references a security group or prefix list ID counts as one rule for IPv4 and one rule for IPv6.

A quota change applies to both inbound and outbound rules. This quota multiplied by the quota for security groups per network interface cannot exceed 1000. For example, if you increase this quota to 100, we decrease the quota for your number of security groups per network interface to 10.

但是,我们可以为每个接口设置多个安全组,这样我们就可以将这些范围分布在多个安全组中,并将多个安全组附加到实例:

为此,我们需要将我们拥有的范围列表分成 60 个块,然后遍历我们将要创建的安全组资源。我们可以用 chunklist function:

locals {
  aws_control_plane_chunked = chunklist(local.aws_control_plane, 60)
}

这是一个列表列表,每个列表最多包含 60 个 CIDR 块。

然后我们可以通过遍历这些列表来创建我们的多个安全组:

resource "aws_security_group" "aws_only_egress" {
  count = length(local.aws_control_plane_chunked)

  name = "aws-only-egress-example-chunk-${count.index + 1}"

  egress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = local.aws_control_plane_chunked[count.index]
  }
}

然后最后我们需要将这些多个安全组附加到我们的实例:

data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "example" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  vpc_security_group_ids = aws_security_group.aws_only_egress.*.id
}