20482: Allow the site admin to create a non-public Arvados cluster.
authorLucas Di Pentima <lucas.dipentima@curii.com>
Sat, 6 May 2023 18:18:54 +0000 (15:18 -0300)
committerLucas Di Pentima <lucas.dipentima@curii.com>
Tue, 9 May 2023 15:24:51 +0000 (12:24 -0300)
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <lucas.dipentima@curii.com>

tools/salt-install/terraform/aws/services/locals.tf
tools/salt-install/terraform/aws/services/main.tf
tools/salt-install/terraform/aws/vpc/locals.tf
tools/salt-install/terraform/aws/vpc/main.tf
tools/salt-install/terraform/aws/vpc/outputs.tf
tools/salt-install/terraform/aws/vpc/terraform.tfvars
tools/salt-install/terraform/aws/vpc/variables.tf

index 523954ce3a53d75d42f8586998cdc600b2e3068e..d515453cb1cfb970c142f6de0abe72286837a5e6 100644 (file)
@@ -6,11 +6,14 @@ locals {
   region_name = data.terraform_remote_state.vpc.outputs.region_name
   cluster_name = data.terraform_remote_state.vpc.outputs.cluster_name
   use_external_db = data.terraform_remote_state.data-storage.outputs.use_external_db
+  private_only = data.terraform_remote_state.vpc.outputs.private_only
   public_ip = data.terraform_remote_state.vpc.outputs.public_ip
   private_ip = data.terraform_remote_state.vpc.outputs.private_ip
   pubkey_path = pathexpand(var.pubkey_path)
-  pubkey_name = "arvados-deployer-key"
+  pubkey_name = "${local.cluster_name}-arvados-deployer-key"
   public_hosts = data.terraform_remote_state.vpc.outputs.public_hosts
   private_hosts = data.terraform_remote_state.vpc.outputs.private_hosts
+  user_facing_hosts = data.terraform_remote_state.vpc.outputs.user_facing_hosts
+  internal_service_hosts = data.terraform_remote_state.vpc.outputs.internal_service_hosts
   ssl_password_secret_name = "${local.cluster_name}-${var.ssl_password_secret_name_suffix}"
 }
index 68ffaf42de8bcf2e8047723c3e513498e112fc26..b214aeb11359494030e7c3e36332142b448b2b93 100644 (file)
@@ -36,6 +36,7 @@ resource "aws_iam_instance_profile" "dispatcher_instance_profile" {
 
 resource "aws_secretsmanager_secret" "ssl_password_secret" {
   name = local.ssl_password_secret_name
+  recovery_window_in_days = 0
 }
 
 resource "aws_iam_instance_profile" "default_instance_profile" {
@@ -52,7 +53,7 @@ resource "aws_instance" "arvados_service" {
     "hostname": each.value
   })
   private_ip = local.private_ip[each.value]
-  subnet_id = contains(local.public_hosts, each.value) ? data.terraform_remote_state.vpc.outputs.public_subnet_id : data.terraform_remote_state.vpc.outputs.private_subnet_id
+  subnet_id = contains(local.user_facing_hosts, each.value) ? data.terraform_remote_state.vpc.outputs.public_subnet_id : data.terraform_remote_state.vpc.outputs.private_subnet_id
   vpc_security_group_ids = [ data.terraform_remote_state.vpc.outputs.arvados_sg_id ]
   # This should be done in a more readable way
   iam_instance_profile = each.value == "controller" ? aws_iam_instance_profile.dispatcher_instance_profile.name : length(regexall("^keep[0-9]+", each.value)) > 0 ? aws_iam_instance_profile.keepstore_instance_profile.name : aws_iam_instance_profile.default_instance_profile.name
@@ -113,7 +114,7 @@ resource "aws_iam_policy_attachment" "cloud_dispatcher_ec2_access_attachment" {
 }
 
 resource "aws_eip_association" "eip_assoc" {
-  for_each = toset(local.public_hosts)
+  for_each = local.private_only ? [] : toset(local.public_hosts)
   instance_id = aws_instance.arvados_service[each.value].id
   allocation_id = data.terraform_remote_state.vpc.outputs.eip_id[each.value]
 }
index 00e9d9494c34640abbdbd35cdd0b7c9e4290a791..a6e56c5859f8945543de144ade36431cd3ac565e 100644 (file)
@@ -9,10 +9,18 @@ locals {
     ssh: "22",
   }
   availability_zone = data.aws_availability_zones.available.names[0]
-  public_hosts = [ "controller", "workbench" ]
-  private_hosts = [ "keep0", "shell" ]
+  route53_public_zone = one(aws_route53_zone.public_zone[*])
+  iam_user_letsencrypt = one(aws_iam_user.letsencrypt[*])
+  iam_access_key_letsencrypt = one(aws_iam_access_key.letsencrypt[*])
+  public_hosts = var.private_only ? [] : var.user_facing_hosts
+  private_hosts = concat(
+    var.internal_service_hosts,
+    var.private_only ? var.user_facing_hosts : []
+  )
   arvados_dns_zone = "${var.cluster_name}.${var.domain_name}"
-  public_ip = { for k, v in aws_eip.arvados_eip: k => v.public_ip }
+  public_ip = {
+    for k, v in aws_eip.arvados_eip: k => v.public_ip
+  }
   private_ip = {
     "controller": "10.1.1.11",
     "workbench": "10.1.1.15",
index eba48b9f9ed320cfa93ef67060afa3f58f7a44e8..6f1fe96ecc62dee8ddadd09e891b6d64d23addb0 100644 (file)
@@ -135,10 +135,11 @@ resource "aws_security_group" "arvados_sg" {
 
 # PUBLIC DNS
 resource "aws_route53_zone" "public_zone" {
+  count = var.private_only ? 0 : 1
   name = local.arvados_dns_zone
 }
 resource "aws_route53_record" "public_a_record" {
-  zone_id = aws_route53_zone.public_zone.id
+  zone_id = try(local.route53_public_zone.id, "")
   for_each = local.public_ip
   name = each.key
   type = "A"
@@ -146,15 +147,20 @@ resource "aws_route53_record" "public_a_record" {
   records = [ each.value ]
 }
 resource "aws_route53_record" "main_a_record" {
-  zone_id = aws_route53_zone.public_zone.id
+  count = var.private_only ? 0 : 1
+  zone_id = try(local.route53_public_zone.id, "")
   name = ""
   type = "A"
   ttl = 300
   records = [ local.public_ip["controller"] ]
 }
 resource "aws_route53_record" "public_cname_record" {
-  zone_id = aws_route53_zone.public_zone.id
-  for_each = {for i in local.cname_by_host: i.record => "${i.cname}.${local.arvados_dns_zone}" }
+  zone_id = try(local.route53_public_zone.id, "")
+  for_each = {
+    for i in local.cname_by_host: i.record =>
+      "${i.cname}.${local.arvados_dns_zone}"
+    if var.private_only == false
+  }
   name = each.key
   type = "CNAME"
   ttl = 300
@@ -196,16 +202,19 @@ resource "aws_route53_record" "private_cname_record" {
 # Route53's credentials for Let's Encrypt
 #
 resource "aws_iam_user" "letsencrypt" {
+  count = var.private_only ? 0 : 1
   name = "${var.cluster_name}-letsencrypt"
   path = "/"
 }
 
 resource "aws_iam_access_key" "letsencrypt" {
-  user = aws_iam_user.letsencrypt.name
+  count = var.private_only ? 0 : 1
+  user = local.iam_user_letsencrypt.name
 }
 resource "aws_iam_user_policy" "letsencrypt_iam_policy" {
+  count = var.private_only ? 0 : 1
   name = "${var.cluster_name}-letsencrypt_iam_policy"
-  user = aws_iam_user.letsencrypt.name
+  user = local.iam_user_letsencrypt.name
   policy = jsonencode({
     "Version": "2012-10-17",
     "Statement": [{
@@ -223,7 +232,7 @@ resource "aws_iam_user_policy" "letsencrypt_iam_policy" {
         "route53:ChangeResourceRecordSets"
       ],
       "Resource" : [
-        "arn:aws:route53:::hostedzone/${aws_route53_zone.public_zone.id}"
+        "arn:aws:route53:::hostedzone/${local.route53_public_zone.id}"
       ]
     }]
   })
index 09faa04a297f2e14f71a11c4c927068e17b70376..e1c0fe171929e8faecc2550dcd0f45de9ac54253 100644 (file)
@@ -41,16 +41,28 @@ output "private_hosts" {
   value = local.private_hosts
 }
 
+output "user_facing_hosts" {
+  value = var.user_facing_hosts
+}
+
+output "internal_service_hosts" {
+  value = var.internal_service_hosts
+}
+
+output "private_only" {
+  value = var.private_only
+}
+
 output "route53_dns_ns" {
-  value = aws_route53_zone.public_zone.name_servers
+  value = try(local.route53_public_zone.name_servers, [])
 }
 
 output "letsencrypt_iam_access_key_id" {
-  value = aws_iam_access_key.letsencrypt.id
+  value = try(local.iam_access_key_letsencrypt.id, "")
 }
 
 output "letsencrypt_iam_secret_access_key" {
-  value = aws_iam_access_key.letsencrypt.secret
+  value = try(local.iam_access_key_letsencrypt.secret, "")
   sensitive = true
 }
 
index cac62ed6f12c56c29eb5b32c567c44d85a010431..296e3130c38eec202f87885b423d6fff702fe6d7 100644 (file)
@@ -5,3 +5,6 @@
 region_name = "us-east-1"
 # cluster_name = "xarv1"
 # domain_name = "example.com"
+
+# Uncomment this to create an non-publicly accessible Arvados cluster
+# private_only = true
\ No newline at end of file
index 4237c56c805c40f49e7ad99f643285b6a82ed224..276f31433499faee401580630b6a9343ced8e633 100644 (file)
@@ -19,4 +19,22 @@ variable "cluster_name" {
 variable "domain_name" {
   description = "The domain name under which your Arvados cluster will be hosted"
   type = string
+}
+
+variable "private_only" {
+  description = "Don't create infrastructure reachable from the public Internet"
+  type = bool
+  default = false
+}
+
+variable "user_facing_hosts" {
+  description = "List of hostnames for nodes that hold user-accesible Arvados services"
+  type = list(string)
+  default = [ "controller", "workbench" ]
+}
+
+variable "internal_service_hosts" {
+  description = "List of hostnames for nodes that hold internal Arvados services"
+  type = list(string)
+  default = [ "keep0", "shell" ]
 }
\ No newline at end of file