Merge branch '21383-misc-fixes'. Refs #21383
[arvados.git] / tools / salt-install / terraform / aws / services / main.tf
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: CC-BY-SA-3.0
4
5 terraform {
6   required_version = "~> 1.3.0"
7   required_providers {
8     aws = {
9       source = "hashicorp/aws"
10       version = "~> 4.38.0"
11     }
12   }
13 }
14
15 provider "aws" {
16   region = local.region_name
17   default_tags {
18     tags = merge(local.custom_tags, {
19       Arvados = local.cluster_name
20       Terraform = true
21     })
22   }
23 }
24
25 resource "aws_iam_instance_profile" "keepstore_instance_profile" {
26   name = "${local.cluster_name}-keepstore-00-iam-role"
27   role = data.terraform_remote_state.data-storage.outputs.keepstore_iam_role_name
28 }
29
30 resource "aws_iam_instance_profile" "compute_node_instance_profile" {
31   name = "${local.cluster_name}-compute-node-00-iam-role"
32   role = local.compute_node_iam_role_name
33 }
34
35 resource "aws_iam_instance_profile" "dispatcher_instance_profile" {
36   name = "${local.cluster_name}_dispatcher_instance_profile"
37   role = aws_iam_role.cloud_dispatcher_iam_role.name
38 }
39
40 resource "aws_secretsmanager_secret" "ssl_password_secret" {
41   name = local.ssl_password_secret_name
42   recovery_window_in_days = 0
43 }
44
45 resource "aws_iam_instance_profile" "default_instance_profile" {
46   name = "${local.cluster_name}_default_instance_profile"
47   role = aws_iam_role.default_iam_role.name
48 }
49
50 resource "aws_instance" "arvados_service" {
51   for_each = toset(concat(local.public_hosts, local.private_hosts))
52   ami = local.instance_ami_id
53   instance_type = try(var.instance_type[each.value], var.instance_type.default)
54   user_data = templatefile("user_data.sh", {
55     "hostname": each.value,
56     "deploy_user": var.deploy_user,
57     "ssh_pubkey": file(local.pubkey_path)
58   })
59   private_ip = local.private_ip[each.value]
60   subnet_id = contains(local.user_facing_hosts, each.value) ? local.public_subnet_id : local.private_subnet_id
61   vpc_security_group_ids = [ local.arvados_sg_id ]
62   iam_instance_profile = try(local.instance_profile[each.value], local.instance_profile.default).name
63   tags = {
64     Name = "${local.cluster_name}_arvados_service_${each.value}"
65   }
66   root_block_device {
67     volume_type = "gp3"
68     volume_size = try(var.instance_volume_size[each.value], var.instance_volume_size.default)
69   }
70   metadata_options {
71     # Sets IMDSv2 to required. Default is "optional".
72     http_tokens = "required"
73     http_endpoint = "enabled"
74   }
75   lifecycle {
76     ignore_changes = [
77       # Avoids recreating the instance when the latest AMI changes.
78       # Use 'terraform taint' or 'terraform apply -replace' to force
79       # an AMI change.
80       ami,
81     ]
82   }
83 }
84
85 resource "aws_iam_policy" "compute_node_ebs_autoscaler" {
86   name = "${local.cluster_name}_compute_node_ebs_autoscaler"
87   policy = jsonencode({
88     Version: "2012-10-17",
89     Id: "compute-node EBS Autoscaler policy",
90     Statement: [{
91       Effect: "Allow",
92       Action: [
93           "ec2:AttachVolume",
94           "ec2:DescribeVolumeStatus",
95           "ec2:DescribeVolumes",
96           "ec2:DescribeTags",
97           "ec2:ModifyInstanceAttribute",
98           "ec2:DescribeVolumeAttribute",
99           "ec2:CreateVolume",
100           "ec2:DeleteVolume",
101           "ec2:CreateTags"
102       ],
103       Resource: "*"
104     }]
105   })
106 }
107
108 resource "aws_iam_policy_attachment" "compute_node_ebs_autoscaler_attachment" {
109   name = "${local.cluster_name}_compute_node_ebs_autoscaler_attachment"
110   roles = [ local.compute_node_iam_role_name ]
111   policy_arn = aws_iam_policy.compute_node_ebs_autoscaler.arn
112 }
113
114 resource "aws_iam_policy" "cloud_dispatcher_ec2_access" {
115   name = "${local.cluster_name}_cloud_dispatcher_ec2_access"
116   policy = jsonencode({
117     Version: "2012-10-17",
118     Id: "arvados-dispatch-cloud policy",
119     Statement: [{
120       Effect: "Allow",
121       Action: [
122         "ec2:DescribeKeyPairs",
123         "ec2:ImportKeyPair",
124         "ec2:RunInstances",
125         "ec2:DescribeInstances",
126         "ec2:CreateTags",
127         "ec2:TerminateInstances"
128       ],
129       Resource: "*"
130     },
131     {
132       Effect: "Allow",
133       Action: [
134         "iam:PassRole",
135       ],
136       Resource: "arn:aws:iam::*:role/${aws_iam_instance_profile.compute_node_instance_profile.name}"
137     }]
138   })
139 }
140
141 resource "aws_iam_role" "cloud_dispatcher_iam_role" {
142   name = "${local.cluster_name}-dispatcher-00-iam-role"
143   assume_role_policy = "${file("../assumerolepolicy.json")}"
144 }
145
146 resource "aws_iam_policy_attachment" "cloud_dispatcher_ec2_access_attachment" {
147   name = "${local.cluster_name}_cloud_dispatcher_ec2_access_attachment"
148   roles = [ aws_iam_role.cloud_dispatcher_iam_role.name ]
149   policy_arn = aws_iam_policy.cloud_dispatcher_ec2_access.arn
150 }
151
152 resource "aws_eip_association" "eip_assoc" {
153   for_each = local.private_only ? [] : toset(local.public_hosts)
154   instance_id = aws_instance.arvados_service[each.value].id
155   allocation_id = local.eip_id[each.value]
156 }
157
158 resource "aws_iam_role" "default_iam_role" {
159   name = "${local.cluster_name}-default-iam-role"
160   assume_role_policy = "${file("../assumerolepolicy.json")}"
161 }
162
163 resource "aws_iam_policy" "ssl_privkey_password_access" {
164   name = "${local.cluster_name}_ssl_privkey_password_access"
165   policy = jsonencode({
166     Version: "2012-10-17",
167     Statement: [{
168       Effect: "Allow",
169       Action: "secretsmanager:GetSecretValue",
170       Resource: "${aws_secretsmanager_secret.ssl_password_secret.arn}"
171     }]
172   })
173 }
174
175 # Every service node needs access to the SSL privkey password secret for
176 # nginx to be able to use it.
177 resource "aws_iam_policy_attachment" "ssl_privkey_password_access_attachment" {
178   name = "${local.cluster_name}_ssl_privkey_password_access_attachment"
179   roles = [
180     aws_iam_role.cloud_dispatcher_iam_role.name,
181     aws_iam_role.default_iam_role.name,
182     local.keepstore_iam_role_name,
183   ]
184   policy_arn = aws_iam_policy.ssl_privkey_password_access.arn
185 }