# Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: BUSL-1.1 data "aws_caller_identity" "current" {} resource "aws_instance" "controller" { count = var.controller_count ami = var.ubuntu_ami_id instance_type = var.controller_instance_type vpc_security_group_ids = [ aws_security_group.boundary_sg.id, aws_security_group.boundary_aux_sg.id, ] subnet_id = tolist(data.aws_subnets.infra.ids)[count.index % length(data.aws_subnets.infra.ids)] key_name = var.ssh_aws_keypair iam_instance_profile = aws_iam_instance_profile.boundary_profile.name monitoring = var.controller_monitoring ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count root_block_device { iops = var.controller_ebs_iops volume_size = var.controller_ebs_size volume_type = var.controller_ebs_type throughput = var.controller_ebs_throughput tags = local.common_tags encrypted = true } tags = merge(local.common_tags, { Name = "${local.name_prefix}-boundary-controller-${count.index}-${split(":", data.aws_caller_identity.current.user_id)[1]}" Type = local.boundary_cluster_tag, }, ) } resource "aws_instance" "worker" { count = var.worker_count ami = var.ubuntu_ami_id instance_type = var.worker_instance_type vpc_security_group_ids = [aws_security_group.boundary_sg.id] subnet_id = tolist(data.aws_subnets.infra.ids)[count.index % length(data.aws_subnets.infra.ids)] key_name = var.ssh_aws_keypair iam_instance_profile = aws_iam_instance_profile.boundary_profile.name monitoring = var.worker_monitoring ipv6_address_count = local.network_stack[var.ip_version].ipv6_address_count root_block_device { iops = var.worker_ebs_iops volume_size = var.worker_ebs_size volume_type = var.worker_ebs_type throughput = var.worker_ebs_throughput tags = local.common_tags encrypted = true } tags = merge(local.common_tags, { Name = "${local.name_prefix}-boundary-worker-${count.index}-${split(":", data.aws_caller_identity.current.user_id)[1]}", Type = local.boundary_cluster_tag, }, ) } resource "enos_bundle_install" "controller" { depends_on = [aws_instance.controller] for_each = toset([for idx in range(var.controller_count) : tostring(idx)]) destination = var.boundary_install_dir artifactory = var.boundary_artifactory_release path = var.local_artifact_path release = var.boundary_release == null ? var.boundary_release : merge(var.boundary_release, { product = "boundary", edition = "oss" }) transport = { ssh = { host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip } } } resource "enos_remote_exec" "update_path_controller" { depends_on = [enos_bundle_install.controller] for_each = toset([for idx in range(var.controller_count) : tostring(idx)]) environment = { BOUNDARY_INSTALL_DIR = var.boundary_install_dir } scripts = [abspath("${path.module}/scripts/set-up-login-shell-profile.sh")] transport = { ssh = { host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip } } } locals { audit_log_directory = "/var/log/boundary" service_user = "boundary" } resource "enos_file" "controller_config" { depends_on = [enos_bundle_install.controller] destination = "/etc/boundary/boundary.hcl" content = templatefile("${path.module}/${var.controller_config_file_path}", { id = each.value dbuser = var.db_user dbpass = var.db_pass dbhost = var.db_host == null ? aws_db_instance.boundary[0].address : var.db_host dbport = var.db_port dbname = local.db_name db_max_open_connections = var.db_max_open_connections kms_key_id = data.aws_kms_key.kms_key.id listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]" api_port = var.listener_api_port ops_port = var.listener_ops_port cluster_address = var.ip_version == "4" ? aws_instance.controller[tonumber(each.value)].private_ip : format("[%s]", aws_instance.controller[tonumber(each.value)].ipv6_addresses[0]) cluster_port = var.listener_cluster_port region = var.aws_region max_page_size = var.max_page_size audit_log_dir = local.audit_log_directory vault_address = local.network_stack[var.ip_version].vault_address vault_transit_token = var.vault_transit_token }) for_each = toset([for idx in range(var.controller_count) : tostring(idx)]) transport = { ssh = { host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip } } } resource "enos_boundary_init" "controller" { count = !local.is_restored_db && var.controller_count > 0 ? 1 : 0 // init not required when we restore from a snapshot bin_name = var.boundary_binary_name bin_path = var.boundary_install_dir config_path = "/etc/boundary" license = var.boundary_license transport = { ssh = { host = try(var.ip_version == "6" ? aws_instance.controller[0].ipv6_addresses[0] : aws_instance.controller[0].public_ip, null) } } depends_on = [enos_file.controller_config] } resource "enos_boundary_start" "controller_start" { for_each = toset([for idx in range(var.controller_count) : tostring(idx)]) bin_name = var.boundary_binary_name bin_path = var.boundary_install_dir config_path = "/etc/boundary" license = var.boundary_license transport = { ssh = { host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip } } depends_on = [ enos_boundary_init.controller, enos_file.controller_config // required in the case where we restore from a db snapshot, since the init resource will not be created ] } resource "enos_remote_exec" "create_controller_audit_log_dir" { depends_on = [ enos_boundary_start.controller_start ] for_each = toset([for idx in range(var.controller_count) : tostring(idx)]) environment = { LOG_DIR = local.audit_log_directory SERVICE_USER = local.service_user } scripts = [abspath("${path.module}/scripts/create-audit-log-dir.sh")] transport = { ssh = { host = var.ip_version == "6" ? aws_instance.controller[tonumber(each.value)].ipv6_addresses[0] : aws_instance.controller[tonumber(each.value)].public_ip } } } resource "enos_bundle_install" "worker" { depends_on = [aws_instance.worker] for_each = toset([for idx in range(var.worker_count) : tostring(idx)]) destination = var.boundary_install_dir artifactory = var.boundary_artifactory_release path = var.local_artifact_path release = var.boundary_release == null ? var.boundary_release : merge(var.boundary_release, { product = "boundary", edition = "oss" }) transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } } resource "enos_remote_exec" "update_path_worker" { depends_on = [enos_bundle_install.worker] for_each = toset([for idx in range(var.worker_count) : tostring(idx)]) environment = { BOUNDARY_INSTALL_DIR = var.boundary_install_dir } scripts = [abspath("${path.module}/scripts/set-up-login-shell-profile.sh")] transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } } resource "enos_file" "worker_config" { depends_on = [enos_bundle_install.worker] destination = "/etc/boundary/boundary.hcl" content = templatefile("${path.module}/${var.worker_config_file_path}", { id = each.value kms_key_id = data.aws_kms_key.kms_key.id, controller_ips = var.ip_version == "4" ? jsonencode(aws_instance.controller.*.private_ip) : jsonencode(formatlist("[%s]:9201", flatten(aws_instance.controller.*.ipv6_addresses))) listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]" public_address = var.ip_version == "6" ? format("[%s]", aws_instance.worker[tonumber(each.value)].ipv6_addresses[0]) : aws_instance.worker[tonumber(each.value)].public_ip region = var.aws_region type = jsonencode(var.worker_type_tags) recording_storage_path = var.recording_storage_path audit_log_dir = local.audit_log_directory hcp_boundary_cluster_id = var.hcp_boundary_cluster_id vault_address = local.network_stack[var.ip_version].vault_address vault_transit_token = var.vault_transit_token }) for_each = toset([for idx in range(var.worker_count) : tostring(idx)]) transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } } resource "enos_boundary_start" "worker_start" { depends_on = [enos_boundary_start.controller_start, enos_file.worker_config] for_each = toset([for idx in range(var.worker_count) : tostring(idx)]) bin_name = var.boundary_binary_name bin_path = var.boundary_install_dir config_path = "/etc/boundary" license = var.boundary_license recording_storage_path = var.recording_storage_path != "" ? var.recording_storage_path : null transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } } resource "enos_remote_exec" "create_worker_audit_log_dir" { depends_on = [ enos_boundary_start.worker_start, ] for_each = toset([for idx in range(var.worker_count) : tostring(idx)]) environment = { LOG_DIR = local.audit_log_directory SERVICE_USER = local.service_user } scripts = [abspath("${path.module}/scripts/create-audit-log-dir.sh")] transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } } resource "enos_remote_exec" "get_worker_token" { depends_on = [enos_boundary_start.worker_start] for_each = var.hcp_boundary_cluster_id != "" ? toset([for idx in range(var.worker_count) : tostring(idx)]) : [] inline = ["timeout 10s bash -c 'set -eo pipefail; until journalctl -u boundary.service | cat | grep \"Worker Auth Registration Request: .*\" | rev | cut -d \" \" -f 1 | rev | xargs; do sleep 2; done'"] transport = { ssh = { host = var.ip_version == "6" ? aws_instance.worker[tonumber(each.value)].ipv6_addresses[0] : aws_instance.worker[tonumber(each.value)].public_ip } } }