main.tf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# VPC Endpoint =================================================================

# Security Group ---------------------------------------------------------------
# Created only when Interface endpoints are defined.
# Owned by this module rather than passed in, matching how the vpc module
# owns its own IAM role/policy for flow logs rather than accepting one externally.

resource "aws_security_group" "interface_endpoints" {
  for_each = length(local.interface_endpoints) > 0 ? { sg = true } : {}

  name        = "${var.name_prefix}-${local.region_abbr}-vpce-sg"
  description = "Allow HTTPS from VPC CIDR to interface VPC endpoints"
  vpc_id      = var.vpc_id

  tags = merge(var.tags, local.module_tags, {
    Name          = "${var.name_prefix}-${local.region_abbr}-vpce-sg"
    resource-type = "security-group"
  })

  lifecycle {
    precondition {
      condition     = length("${var.name_prefix}-${local.region_abbr}-vpce-sg") <= 255
      error_message = "Assembled security group name exceeds AWS's 255-character limit"
    }
  }
}

resource "aws_vpc_security_group_ingress_rule" "interface_endpoints_https" {
  for_each = length(local.interface_endpoints) > 0 ? { sg = true } : {}

  security_group_id = aws_security_group.interface_endpoints["sg"].id
  description       = "HTTPS from VPC CIDR"
  cidr_ipv4         = var.vpc_cidr_block
  from_port         = 443
  to_port           = 443
  ip_protocol       = "tcp"

  tags = merge(var.tags, local.module_tags, {
    Name          = "${var.name_prefix}-${local.region_abbr}-vpce-sg-ingress-https"
    resource-type = "security-group-rule"
  })
}

resource "aws_vpc_security_group_egress_rule" "interface_endpoints_all" {
  for_each = length(local.interface_endpoints) > 0 ? { sg = true } : {}

  security_group_id = aws_security_group.interface_endpoints["sg"].id
  description       = "All outbound"
  cidr_ipv4         = "0.0.0.0/0"
  ip_protocol       = "-1"

  tags = merge(var.tags, local.module_tags, {
    Name          = "${var.name_prefix}-${local.region_abbr}-vpce-sg-egress-all"
    resource-type = "security-group-rule"
  })
}

# Gateway Endpoints ------------------------------------------------------------
# Route-table-based, no ENI, no cost. S3 and DynamoDB are the only AWS
# services that currently support the Gateway type.

resource "aws_vpc_endpoint" "gateway" {
  for_each = local.gateway_endpoints

  vpc_id            = var.vpc_id
  service_name      = "com.amazonaws.${var.aws_region}.${each.value.service_name}"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = var.route_table_ids
  policy            = each.value.policy

  tags = merge(var.tags, local.module_tags, {
    Name          = "${var.name_prefix}-${local.region_abbr}-vpce-${each.key}"
    resource-type = "vpc-endpoint"
  })
}

# Interface Endpoints ----------------------------------------------------------
# ENI-based, placed in the given subnets, DNS-resolved in-VPC when enabled.

resource "aws_vpc_endpoint" "interface" {
  for_each = local.interface_endpoints

  vpc_id              = var.vpc_id
  service_name        = "com.amazonaws.${var.aws_region}.${each.value.service_name}"
  vpc_endpoint_type   = "Interface"
  subnet_ids          = var.subnet_ids
  security_group_ids  = [aws_security_group.interface_endpoints["sg"].id]
  private_dns_enabled = each.value.private_dns_enabled
  policy              = each.value.policy

  tags = merge(var.tags, local.module_tags, {
    Name          = "${var.name_prefix}-${local.region_abbr}-vpce-${each.key}"
    resource-type = "vpc-endpoint"
  })
}