You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/enos/modules/aws_worker/main.tf

270 lines
8.1 KiB

# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: BUSL-1.1
terraform {
required_providers {
enos = {
source = "registry.terraform.io/hashicorp-forge/enos"
}
}
}
data "enos_environment" "current" {}
data "aws_caller_identity" "current" {}
locals {
selected_az = data.aws_availability_zones.available.names[random_integer.az.result]
common_tags = merge(
var.common_tags,
{
Type = var.cluster_tag
Module = "boundary-worker"
Pet = random_pet.worker.id
},
)
}
resource "random_pet" "worker" {
separator = "_"
}
data "aws_availability_zones" "available" {
state = "available"
filter {
name = "zone-name"
values = var.availability_zones
}
}
data "aws_availability_zone" "worker_az" {
name = local.selected_az
}
data "aws_kms_key" "kms_key" {
key_id = var.kms_key_arn
}
resource "random_integer" "az" {
min = 0
max = length(data.aws_availability_zones.available.names) - 1
keepers = {
# Generate a new integer each time the list of aws_availability_zones changes
# keepers have to be strings, sort the list in case order changes but zones don't
listener_arn = join("", sort(data.aws_availability_zones.available.names))
}
}
# Create a subnet so that the worker doesn't share one with a controller
resource "aws_subnet" "default" {
vpc_id = var.vpc_id
cidr_block = "10.13.9.0/24"
ipv6_cidr_block = var.ip_version != "4" ? cidrsubnet(var.vpc_cidr_ipv6, 8, 0) : null
map_public_ip_on_launch = true
assign_ipv6_address_on_creation = var.ip_version != "4"
availability_zone = local.selected_az
tags = merge(
local.common_tags,
{
"Name" = "${var.vpc_id}_worker_${random_pet.worker.id}_subnet"
},
)
}
# The worker instance is a part of this security group, not to be confused with the next rule below
resource "aws_security_group" "default" {
name = "boundary-sg-worker-${random_pet.worker.id}"
description = "SSH to worker to KMS and controllers"
vpc_id = var.vpc_id
ingress {
description = "SSH to the worker instance"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = var.ip_version == "6" ? [] : flatten([
# allow ingress from ipv4 to allow for test setup from ci
formatlist("%s/32", data.enos_environment.current.public_ipv4_addresses)
])
ipv6_cidr_blocks = var.ip_version == "4" ? [] : (data.enos_environment.current.public_ipv6_addresses != null ? [for ip in data.enos_environment.current.public_ipv6_addresses : cidrsubnet("${ip}/64", 0, 0)] : [])
}
ingress {
description = "Communication from Boundary controller to worker"
from_port = 9202
to_port = 9202
protocol = "tcp"
cidr_blocks = var.ip_version == "6" ? [] : ["0.0.0.0/0"]
ipv6_cidr_blocks = var.ip_version == "4" ? [] : ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = var.ip_version == "6" ? [] : ["0.0.0.0/0"]
ipv6_cidr_blocks = var.ip_version == "4" ? [] : ["::/0"]
}
tags = merge(
local.common_tags,
{
"Name" = "${var.vpc_id}_worker_sg"
},
)
}
# This module only manages a rule for the controller SG that is vital to the worker's operation
# This module does _not_ manage the security group itself
resource "aws_vpc_security_group_ingress_rule" "worker_to_controller" {
description = "This rule allows traffic from a worker to controllers over WAN"
security_group_id = var.controller_sg_id
cidr_ipv4 = var.ip_version == "4" ? "${aws_instance.worker.public_ip}/32" : null
cidr_ipv6 = var.ip_version == "4" ? null : cidrsubnet("${aws_instance.worker.ipv6_addresses[0]}/64", 0, 0)
from_port = 9201
to_port = 9201
ip_protocol = "tcp"
}
data "aws_vpc" "vpc" {
id = var.vpc_id
}
resource "aws_route_table_association" "worker_rta" {
subnet_id = aws_subnet.default.id
route_table_id = data.aws_vpc.vpc.main_route_table_id
}
resource "aws_instance" "worker" {
ami = var.ubuntu_ami_id
instance_type = var.worker_instance_type
vpc_security_group_ids = [aws_security_group.default.id]
subnet_id = aws_subnet.default.id
key_name = var.ssh_aws_keypair
iam_instance_profile = aws_iam_instance_profile.boundary_profile.name
monitoring = var.worker_monitoring
ipv6_address_count = var.ip_version == "4" ? 0 : 1
root_block_device {
iops = var.ebs_iops
volume_size = var.ebs_size
volume_type = var.ebs_type
throughput = var.ebs_throughput
tags = local.common_tags
encrypted = true
}
tags = merge(
local.common_tags,
{
Name = "${var.name_prefix}-boundary-worker-${split(":", data.aws_caller_identity.current.user_id)[1]}",
},
)
}
resource "enos_bundle_install" "worker" {
depends_on = [aws_instance.worker, aws_route_table_association.worker_rta]
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.ipv6_addresses[0] : aws_instance.worker.public_ip
}
}
}
resource "enos_remote_exec" "update_path_worker" {
depends_on = [enos_bundle_install.worker]
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.ipv6_addresses[0] : aws_instance.worker.public_ip
}
}
}
locals {
audit_log_directory = "/var/log/boundary"
service_user = "boundary"
}
resource "enos_file" "worker_config" {
depends_on = [enos_bundle_install.worker]
destination = "/etc/boundary/boundary.hcl"
content = templatefile("${path.module}/${var.config_file_path}", {
id = random_pet.worker.id
kms_key_id = data.aws_kms_key.kms_key.id
controller_ips = var.ip_version == "4" ? jsonencode(var.controller_addresses) : jsonencode(formatlist("[%s]:9201", var.controller_addresses))
listener_address = var.ip_version == "4" ? "0.0.0.0" : "[::]"
public_address = var.ip_version == "6" ? format("[%s]", aws_instance.worker.ipv6_addresses[0]) : aws_instance.worker.public_ip
type = jsonencode(var.worker_type_tags)
region = data.aws_availability_zone.worker_az.region
recording_storage_path = var.recording_storage_path
audit_log_dir = local.audit_log_directory
vault_address = var.ip_version == "4" ? var.vault_address : try(format("[%s]", var.vault_address), "")
vault_transit_token = var.vault_transit_token
})
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
}
}
}
resource "enos_boundary_start" "worker_start" {
depends_on = [
enos_file.worker_config,
aws_vpc_security_group_ingress_rule.worker_to_controller,
]
bin_path = "/opt/boundary/bin"
config_path = "/etc/boundary"
recording_storage_path = var.recording_storage_path != "" ? var.recording_storage_path : null
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
}
}
}
resource "enos_remote_exec" "create_worker_audit_log_dir" {
depends_on = [
enos_boundary_start.worker_start,
]
environment = {
NEW_DIR = local.audit_log_directory
SERVICE_USER = local.service_user
}
scripts = [abspath("${path.module}/scripts/create-dir.sh")]
transport = {
ssh = {
host = var.ip_version == "6" ? aws_instance.worker.ipv6_addresses[0] : aws_instance.worker.public_ip
}
}
}
resource "random_string" "cluster_id" {
length = 8
lower = true
upper = false
numeric = false
special = false
}