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" "arvados_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" "compute_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" "arvados_s3_route" {
46 vpc_endpoint_id = aws_vpc_endpoint.s3.id
47 route_table_id = aws_route_table.arvados_subnet_rt.id
49 resource "aws_vpc_endpoint_route_table_association" "compute_s3_route" {
50 vpc_endpoint_id = aws_vpc_endpoint.s3.id
51 route_table_id = aws_route_table.compute_subnet_rt.id
55 # Internet access for Public IP instances
57 resource "aws_internet_gateway" "arvados_gw" {
58 vpc_id = aws_vpc.arvados_vpc.id
60 resource "aws_eip" "arvados_eip" {
61 for_each = toset(local.hostnames)
63 aws_internet_gateway.arvados_gw
66 resource "aws_route_table" "arvados_subnet_rt" {
67 vpc_id = aws_vpc.arvados_vpc.id
69 cidr_block = "0.0.0.0/0"
70 gateway_id = aws_internet_gateway.arvados_gw.id
73 resource "aws_route_table_association" "arvados_subnet_assoc" {
74 subnet_id = aws_subnet.arvados_subnet.id
75 route_table_id = aws_route_table.arvados_subnet_rt.id
79 # Internet access for Private IP instances
81 resource "aws_eip" "compute_nat_gw_eip" {
83 aws_internet_gateway.arvados_gw
86 resource "aws_nat_gateway" "compute_nat_gw" {
87 # A NAT gateway should be placed on a subnet with an internet gateway
88 subnet_id = aws_subnet.arvados_subnet.id
89 allocation_id = aws_eip.compute_nat_gw_eip.id
91 resource "aws_route_table" "compute_subnet_rt" {
92 vpc_id = aws_vpc.arvados_vpc.id
94 cidr_block = "0.0.0.0/0"
95 nat_gateway_id = aws_nat_gateway.compute_nat_gw.id
98 resource "aws_route_table_association" "compute_subnet_assoc" {
99 subnet_id = aws_subnet.compute_subnet.id
100 route_table_id = aws_route_table.compute_subnet_rt.id
103 resource "aws_security_group" "arvados_sg" {
105 vpc_id = aws_vpc.arvados_vpc.id
108 for_each = local.allowed_ports
110 description = "Ingress rule for ${ingress.key}"
111 from_port = "${ingress.value}"
112 to_port = "${ingress.value}"
114 cidr_blocks = ["0.0.0.0/0"]
115 ipv6_cidr_blocks = ["::/0"]
118 # Allows communication between nodes in the VPC
123 cidr_blocks = [ aws_vpc.arvados_vpc.cidr_block ]
125 # Even though AWS auto-creates an "allow all" egress rule,
126 # Terraform deletes it, so we add it explicitly.
131 cidr_blocks = ["0.0.0.0/0"]
132 ipv6_cidr_blocks = ["::/0"]
137 # Route53 split-horizon DNS zones
141 resource "aws_route53_zone" "public_zone" {
142 name = local.arvados_dns_zone
144 resource "aws_route53_record" "public_a_record" {
145 zone_id = aws_route53_zone.public_zone.id
146 for_each = local.public_ip
150 records = [ each.value ]
152 resource "aws_route53_record" "main_a_record" {
153 zone_id = aws_route53_zone.public_zone.id
157 records = [ local.public_ip["controller"] ]
159 resource "aws_route53_record" "public_cname_record" {
160 zone_id = aws_route53_zone.public_zone.id
161 for_each = {for i in local.cname_by_host: i.record => "${i.cname}.${local.arvados_dns_zone}" }
165 records = [ each.value ]
169 resource "aws_route53_zone" "private_zone" {
170 name = local.arvados_dns_zone
172 vpc_id = aws_vpc.arvados_vpc.id
175 resource "aws_route53_record" "private_a_record" {
176 zone_id = aws_route53_zone.private_zone.id
177 for_each = local.private_ip
181 records = [ each.value ]
183 resource "aws_route53_record" "private_main_a_record" {
184 zone_id = aws_route53_zone.private_zone.id
188 records = [ local.private_ip["controller"] ]
190 resource "aws_route53_record" "private_cname_record" {
191 zone_id = aws_route53_zone.private_zone.id
192 for_each = {for i in local.cname_by_host: i.record => "${i.cname}.${local.arvados_dns_zone}" }
196 records = [ each.value ]
200 # Route53's credentials for Let's Encrypt
202 resource "aws_iam_user" "letsencrypt" {
203 name = "${var.cluster_name}-letsencrypt"
207 resource "aws_iam_access_key" "letsencrypt" {
208 user = aws_iam_user.letsencrypt.name
210 resource "aws_iam_user_policy" "letsencrypt_iam_policy" {
211 name = "${var.cluster_name}-letsencrypt_iam_policy"
212 user = aws_iam_user.letsencrypt.name
213 policy = jsonencode({
214 "Version": "2012-10-17",
218 "route53:ListHostedZones",
227 "route53:ChangeResourceRecordSets"
230 "arn:aws:route53:::hostedzone/${aws_route53_zone.public_zone.id}"