1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: CC-BY-SA-3.0
8 source = "hashicorp/aws"
14 region = var.region_name
17 Arvados = var.cluster_name
22 resource "aws_vpc" "arvados_vpc" {
23 cidr_block = "10.1.0.0/16"
24 enable_dns_hostnames = true
25 enable_dns_support = true
27 resource "aws_subnet" "public_subnet" {
28 vpc_id = aws_vpc.arvados_vpc.id
29 availability_zone = local.availability_zone
30 cidr_block = "10.1.1.0/24"
32 resource "aws_subnet" "private_subnet" {
33 vpc_id = aws_vpc.arvados_vpc.id
34 availability_zone = local.availability_zone
35 cidr_block = "10.1.2.0/24"
41 resource "aws_vpc_endpoint" "s3" {
42 vpc_id = aws_vpc.arvados_vpc.id
43 service_name = "com.amazonaws.${var.region_name}.s3"
45 resource "aws_vpc_endpoint_route_table_association" "compute_s3_route" {
46 vpc_endpoint_id = aws_vpc_endpoint.s3.id
47 route_table_id = aws_route_table.private_subnet_rt.id
51 # Internet access for Public IP instances
53 resource "aws_internet_gateway" "internet_gw" {
54 vpc_id = aws_vpc.arvados_vpc.id
56 resource "aws_eip" "arvados_eip" {
57 for_each = toset(local.public_hosts)
59 aws_internet_gateway.internet_gw
62 resource "aws_route_table" "public_subnet_rt" {
63 vpc_id = aws_vpc.arvados_vpc.id
65 cidr_block = "0.0.0.0/0"
66 gateway_id = aws_internet_gateway.internet_gw.id
69 resource "aws_route_table_association" "public_subnet_assoc" {
70 subnet_id = aws_subnet.public_subnet.id
71 route_table_id = aws_route_table.public_subnet_rt.id
75 # Internet access for Private IP instances
77 resource "aws_eip" "nat_gw_eip" {
79 aws_internet_gateway.internet_gw
82 resource "aws_nat_gateway" "nat_gw" {
83 # A NAT gateway should be placed on a subnet with an internet gateway
84 subnet_id = aws_subnet.public_subnet.id
85 allocation_id = aws_eip.nat_gw_eip.id
87 resource "aws_route_table" "private_subnet_rt" {
88 vpc_id = aws_vpc.arvados_vpc.id
90 cidr_block = "0.0.0.0/0"
91 nat_gateway_id = aws_nat_gateway.nat_gw.id
94 resource "aws_route_table_association" "private_subnet_assoc" {
95 subnet_id = aws_subnet.private_subnet.id
96 route_table_id = aws_route_table.private_subnet_rt.id
99 resource "aws_security_group" "arvados_sg" {
101 vpc_id = aws_vpc.arvados_vpc.id
104 for_each = local.allowed_ports
106 description = "Ingress rule for ${ingress.key}"
107 from_port = "${ingress.value}"
108 to_port = "${ingress.value}"
110 cidr_blocks = ["0.0.0.0/0"]
111 ipv6_cidr_blocks = ["::/0"]
114 # Allows communication between nodes in the VPC
119 cidr_blocks = [ aws_vpc.arvados_vpc.cidr_block ]
121 # Even though AWS auto-creates an "allow all" egress rule,
122 # Terraform deletes it, so we add it explicitly.
127 cidr_blocks = ["0.0.0.0/0"]
128 ipv6_cidr_blocks = ["::/0"]
133 # Route53 split-horizon DNS zones
137 resource "aws_route53_zone" "public_zone" {
138 name = local.arvados_dns_zone
140 resource "aws_route53_record" "public_a_record" {
141 zone_id = aws_route53_zone.public_zone.id
142 for_each = local.public_ip
146 records = [ each.value ]
148 resource "aws_route53_record" "main_a_record" {
149 zone_id = aws_route53_zone.public_zone.id
153 records = [ local.public_ip["controller"] ]
155 resource "aws_route53_record" "public_cname_record" {
156 zone_id = aws_route53_zone.public_zone.id
157 for_each = {for i in local.cname_by_host: i.record => "${i.cname}.${local.arvados_dns_zone}" }
161 records = [ each.value ]
165 resource "aws_route53_zone" "private_zone" {
166 name = local.arvados_dns_zone
168 vpc_id = aws_vpc.arvados_vpc.id
171 resource "aws_route53_record" "private_a_record" {
172 zone_id = aws_route53_zone.private_zone.id
173 for_each = local.private_ip
177 records = [ each.value ]
179 resource "aws_route53_record" "private_main_a_record" {
180 zone_id = aws_route53_zone.private_zone.id
184 records = [ local.private_ip["controller"] ]
186 resource "aws_route53_record" "private_cname_record" {
187 zone_id = aws_route53_zone.private_zone.id
188 for_each = {for i in local.cname_by_host: i.record => "${i.cname}.${local.arvados_dns_zone}" }
192 records = [ each.value ]
196 # Route53's credentials for Let's Encrypt
198 resource "aws_iam_user" "letsencrypt" {
199 name = "${var.cluster_name}-letsencrypt"
203 resource "aws_iam_access_key" "letsencrypt" {
204 user = aws_iam_user.letsencrypt.name
206 resource "aws_iam_user_policy" "letsencrypt_iam_policy" {
207 name = "${var.cluster_name}-letsencrypt_iam_policy"
208 user = aws_iam_user.letsencrypt.name
209 policy = jsonencode({
210 "Version": "2012-10-17",
214 "route53:ListHostedZones",
223 "route53:ChangeResourceRecordSets"
226 "arn:aws:route53:::hostedzone/${aws_route53_zone.public_zone.id}"