terraform/modules/aws-vpc/main.tf (287 lines of code) (raw):
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
data "aws_region" "current" {
}
# Grab VPN gateway via the `Name` tag
# don't track this under Terraform as it
# will likely never change and would require
# work from NetOps
data "aws_vpn_gateway" "mdc-vpn-gate" {
filter {
name = "tag:Name"
values = ["to-mdc's", "to-mdc"]
}
}
# Create a VPC for the private CI hgweb instances
resource "aws_vpc" "hgci-vpc" {
cidr_block = var.cidr_block
# Enable DNS
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "hgaws VPC"
}
}
# Internet gateway for the VPC
# Facilitates access to the internet
resource "aws_internet_gateway" "hgci-internet-gateway" {
vpc_id = aws_vpc.hgci-vpc.id
tags = {
Name = "Internet gateway"
}
}
# Elastic IP address for the VPC internet gateway
resource "aws_eip" "hgci-internet-eip" {
depends_on = [aws_internet_gateway.hgci-internet-gateway]
vpc = true
tags = {
Name = "VPC Internet gateway elastic IP"
}
}
# Route table to send traffic from the public subnet
# to the internet
resource "aws_route_table" "hgci-pub-routetable" {
vpc_id = aws_vpc.hgci-vpc.id
route {
cidr_block = "10.0.0.0/10"
gateway_id = data.aws_vpn_gateway.mdc-vpn-gate.id
}
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.hgci-internet-gateway.id
}
tags = {
Name = "Public route table"
}
}
# Custom DHCP rules to query internal DNS
resource "aws_vpc_dhcp_options" "dhcp-options" {
domain_name_servers = ["10.48.75.120"]
tags = {
Name = "DHCP options for internal DNS"
}
}
resource "aws_vpc_dhcp_options_association" "dhcp-options-assoc" {
dhcp_options_id = aws_vpc_dhcp_options.dhcp-options.id
vpc_id = aws_vpc.hgci-vpc.id
}
# Public subnets to facilitate internet access from private subnets
module "pubsubnet-a" {
source = "../pubsubnet"
availability_zone = "a"
cidr_block = cidrsubnet(var.cidr_block, 3, 0)
route_table_id = aws_route_table.hgci-pub-routetable.id
vpc_id = aws_vpc.hgci-vpc.id
}
module "pubsubnet-b" {
source = "../pubsubnet"
availability_zone = "b"
cidr_block = cidrsubnet(var.cidr_block, 3, 1)
route_table_id = aws_route_table.hgci-pub-routetable.id
vpc_id = aws_vpc.hgci-vpc.id
}
# Private subnets to hold
module "privsubnet-a" {
source = "../privsubnet"
availability_zone = "a"
cidr_block = cidrsubnet(var.cidr_block, 3, 3)
nat_gateway_id = module.pubsubnet-a.nat_gateway_id
taskcluster_vpc_cidr = var.taskcluster_vpc_cidr
vpc_id = aws_vpc.hgci-vpc.id
vpn_gateway_id = data.aws_vpn_gateway.mdc-vpn-gate.id
}
module "privsubnet-b" {
source = "../privsubnet"
availability_zone = "b"
cidr_block = cidrsubnet(var.cidr_block, 3, 4)
nat_gateway_id = module.pubsubnet-b.nat_gateway_id
taskcluster_vpc_cidr = var.taskcluster_vpc_cidr
vpc_id = aws_vpc.hgci-vpc.id
vpn_gateway_id = data.aws_vpn_gateway.mdc-vpn-gate.id
}
resource "aws_security_group" "lb-securitygroup" {
name = "lb-securitygroup"
description = "Set security rules for application load balancer"
vpc_id = aws_vpc.hgci-vpc.id
tags = {
Name = "load balancer security group"
}
}
resource "aws_security_group_rule" "rule-hgvpc-lb" {
description = "Allow traffic from our VPC to LB listener port"
security_group_id = aws_security_group.lb-securitygroup.id
type = "ingress"
from_port = 443
protocol = "tcp"
to_port = 443
cidr_blocks = [aws_vpc.hgci-vpc.cidr_block]
}
resource "aws_security_group_rule" "rule-tcvpc-lb" {
description = "Allow traffic from Taskcluster VPC to LB listener port"
security_group_id = aws_security_group.lb-securitygroup.id
type = "ingress"
from_port = 443
protocol = "tcp"
to_port = 443
cidr_blocks = [var.taskcluster_vpc_cidr]
}
resource "aws_security_group_rule" "rule-lb-listener" {
description = "Allow traffic to instances on health check/listener port (80)"
security_group_id = aws_security_group.lb-securitygroup.id
type = "egress"
from_port = 80
protocol = "tcp"
to_port = 80
source_security_group_id = aws_security_group.hgci-securitygroup.id
}
# Create a security group for the private CI instances
# Use these rules to INCLUDE traffic
resource "aws_security_group" "hgci-securitygroup" {
name = "hgci-securitygroup"
description = "Set security rules for private CI-only hgweb instances"
vpc_id = aws_vpc.hgci-vpc.id
tags = {
Name = "CI-only hgweb security group"
}
}
resource "aws_security_group_rule" "rule-mozvpn-hgci" {
description = "SSH to instances from MozVPN"
security_group_id = aws_security_group.hgci-securitygroup.id
type = "ingress"
from_port = 22
protocol = "tcp"
to_port = 22
cidr_blocks = [
"10.48.240.0/23",
"10.48.242.0/23",
"10.50.240.0/23",
"10.50.242.0/23",
"10.64.0.0/16",
]
}
resource "aws_security_group_rule" "rule-tcvpc-hgci" {
description = "All traffic from Taskcluster VPC"
security_group_id = aws_security_group.hgci-securitygroup.id
type = "ingress"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [
var.taskcluster_vpc_cidr,
]
}
resource "aws_security_group_rule" "rule-allowself" {
description = "All traffic within group"
security_group_id = aws_security_group.hgci-securitygroup.id
type = "ingress"
from_port = 0
protocol = "-1"
to_port = 0
self = true
}
resource "aws_security_group_rule" "rule-allowout" {
description = "Allow all outgoing"
security_group_id = aws_security_group.hgci-securitygroup.id
type = "egress"
from_port = 0
protocol = "-1"
to_port = 0
cidr_blocks = [
"0.0.0.0/0",
]
}
resource "aws_security_group_rule" "rule-hgci-lb" {
description = "All traffic from load balancers"
security_group_id = aws_security_group.hgci-securitygroup.id
type = "ingress"
from_port = 0
protocol = "-1"
to_port = 0
source_security_group_id = aws_security_group.lb-securitygroup.id
}
resource "aws_acm_certificate" "hgcert" {
domain_name = "*.hgmointernal.net"
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
tags = {
Name = "hg certificate"
}
}
# Load balancer for traffic in this region
resource "aws_lb" "internal-lb" {
name = "${data.aws_region.current.name}-lb"
internal = true
load_balancer_type = "application"
security_groups = [aws_security_group.lb-securitygroup.id]
subnets = [
module.privsubnet-a.subnet_id,
module.privsubnet-b.subnet_id,
]
tags = {
Name = "${data.aws_region.current.name} hg load balancer"
}
}
resource "aws_lb_target_group" "http-mirror-target-group" {
name = "${data.aws_region.current.name}-hg-mirrors"
port = 80
protocol = "HTTP"
vpc_id = aws_vpc.hgci-vpc.id
# Use `/mozilla-central` here since using `/` will cause
# many errors when the LB follows links on the home page
health_check {
enabled = true
interval = 30
path = "/mozilla-central"
port = "traffic-port"
healthy_threshold = 5
unhealthy_threshold = 2
timeout = 5
matcher = "200"
}
}
resource "aws_lb_listener" "mirror-https-listener" {
load_balancer_arn = aws_lb.internal-lb.arn
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-2016-08"
certificate_arn = aws_acm_certificate.hgcert.arn
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.http-mirror-target-group.arn
}
}
resource "aws_instance" "hgweb-backup" {
# Create this instance if `backup_node` is non-zero
count = var.backup_node
ami = var.mirror_ami
instance_type = "c5d.2xlarge"
subnet_id = module.privsubnet-b.subnet_id
vpc_security_group_ids = [
aws_security_group.hgci-securitygroup.id,
]
ebs_optimized = true
user_data = file("${path.module}/user_data.yml")
root_block_device {
delete_on_termination = false
volume_size = 1000
volume_type = "standard"
}
lifecycle {
ignore_changes = [user_data]
}
tags = {
Name = "repo data backup instance"
}
}
# Create a network ACL for the VPC
# Use these rules to EXCLUDE traffic
resource "aws_network_acl" "hgci-networkacl" {
vpc_id = aws_vpc.hgci-vpc.id
subnet_ids = [
module.privsubnet-a.subnet_id,
module.privsubnet-b.subnet_id,
module.pubsubnet-a.subnet_id,
module.pubsubnet-b.subnet_id,
]
ingress {
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
icmp_code = 0
icmp_type = 0
protocol = "-1"
rule_no = 100
to_port = 0
}
# Allow outgoing SSH
egress {
action = "allow"
cidr_block = "0.0.0.0/0"
from_port = 0
icmp_code = 0
icmp_type = 0
protocol = "-1"
rule_no = 100
to_port = 0
}
tags = {
Name = "hg AWS network ACLs"
}
}