Skip to content

Commit 073f8fe

Browse files
[QT-405] Create solo worker module (hashicorp#3148)
* Create solo worker module --------- Co-authored-by: Josh Brand <[email protected]>
1 parent 8c54648 commit 073f8fe

12 files changed

+435
-9
lines changed

enos/enos-modules.hcl

+18-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ module "bats_deps" {
1111

1212
module "boundary" {
1313
source = "app.terraform.io/hashicorp-qti/aws-boundary/enos"
14-
version = ">= 0.2.6"
14+
version = ">= 0.5.0"
1515

1616
project_name = "qti-enos-boundary"
1717
environment = var.environment
@@ -26,6 +26,19 @@ module "boundary" {
2626
alb_listener_api_port = var.alb_listener_api_port
2727
}
2828

29+
module "worker" {
30+
source = "./modules/worker"
31+
32+
common_tags = {
33+
"Project" : "Enos",
34+
"Project Name" : "qti-enos-boundary",
35+
"Enos User" : var.enos_user,
36+
"Environment" : var.environment
37+
}
38+
39+
ssh_aws_keypair = var.aws_ssh_keypair_name
40+
}
41+
2942
module "build_crt" {
3043
source = "./modules/build_crt"
3144
}
@@ -70,6 +83,10 @@ module "random_stringifier" {
7083
source = "./modules/random_stringifier"
7184
}
7285

86+
module "map2list" {
87+
source = "./modules/map2list"
88+
}
89+
7390
module "target" {
7491
source = "./modules/target"
7592
target_count = var.target_count

enos/enos-scenario-e2e-aws.hcl

+2
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ scenario "e2e_aws" {
113113
vpc_id = step.create_base_infra.vpc_id
114114
target_count = 2
115115
additional_tags = step.create_tag1_inputs.tag_map
116+
subnet_ids = step.create_boundary_cluster.subnet_ids
116117
}
117118
}
118119

@@ -142,6 +143,7 @@ scenario "e2e_aws" {
142143
vpc_id = step.create_base_infra.vpc_id
143144
target_count = 1
144145
additional_tags = step.create_tag2_inputs.tag_map
146+
subnet_ids = step.create_boundary_cluster.subnet_ids
145147
}
146148
}
147149

enos/enos-scenario-e2e-database.hcl

+8
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ scenario "e2e_database" {
4646
module = module.random_stringifier
4747
}
4848

49+
step "get_subnets" {
50+
module = module.map2list
51+
variables {
52+
map = step.create_base_infra.vpc_subnets
53+
}
54+
}
55+
4956
step "create_tag_inputs" {
5057
module = module.generate_aws_host_tag_vars
5158
depends_on = [step.create_tag]
@@ -68,6 +75,7 @@ scenario "e2e_database" {
6875
vpc_id = step.create_base_infra.vpc_id
6976
target_count = 1
7077
additional_tags = step.create_tag_inputs.tag_map
78+
subnet_ids = step.get_subnets.list
7179
}
7280
}
7381

enos/enos-scenario-e2e-static-with-vault.hcl

+1
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ scenario "e2e_static_with_vault" {
119119
instance_type = var.target_instance_type
120120
vpc_id = step.create_base_infra.vpc_id
121121
target_count = 1
122+
subnet_ids = step.create_boundary_cluster.subnet_ids
122123
}
123124
}
124125

enos/enos-scenario-e2e-static.hcl

+1
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ scenario "e2e_static" {
9797
instance_type = var.target_instance_type
9898
vpc_id = step.create_base_infra.vpc_id
9999
target_count = 1
100+
subnet_ids = step.create_boundary_cluster.subnet_ids
100101
}
101102
}
102103

enos/enos-scenario-e2e-ui.hcl

+2
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ scenario "e2e_ui" {
135135
vpc_id = step.create_base_infra.vpc_id
136136
target_count = 2
137137
additional_tags = step.create_tag1_inputs.tag_map
138+
subnet_ids = step.create_boundary_cluster.subnet_ids
138139
}
139140
}
140141

@@ -164,6 +165,7 @@ scenario "e2e_ui" {
164165
vpc_id = step.create_base_infra.vpc_id
165166
target_count = 1
166167
additional_tags = step.create_tag2_inputs.tag_map
168+
subnet_ids = step.create_boundary_cluster.subnet_ids
167169
}
168170
}
169171

enos/modules/map2list/main.tf

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
# This module was created as a workaround, because we can't currently use
5+
# the `keys()` function call in Enos scenarios
6+
7+
variable "map" {}
8+
9+
output "list" {
10+
value = keys(var.map)
11+
}

enos/modules/target/main.tf

+2-8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
variable "vpc_id" {}
55
variable "ami_id" {}
6+
variable "subnet_ids" {}
67
variable "target_count" {}
78
variable "environment" {}
89
variable "project_name" {}
@@ -13,13 +14,6 @@ variable "additional_tags" {
1314
default = {}
1415
}
1516

16-
data "aws_subnets" "infra" {
17-
filter {
18-
name = "vpc-id"
19-
values = [var.vpc_id]
20-
}
21-
}
22-
2317
resource "aws_security_group" "boundary_target" {
2418
name_prefix = "boundary-target-sg"
2519
description = "SSH and boundary Traffic"
@@ -50,7 +44,7 @@ resource "aws_instance" "target" {
5044
ami = var.ami_id
5145
instance_type = var.instance_type
5246
vpc_security_group_ids = [aws_security_group.boundary_target.id]
53-
subnet_id = tolist(data.aws_subnets.infra.ids)[count.index % length(data.aws_subnets.infra.ids)]
47+
subnet_id = var.subnet_ids[count.index % length(var.subnet_ids)]
5448
key_name = var.aws_ssh_keypair_name
5549

5650
tags = merge(var.additional_tags, {

enos/modules/worker/main.tf

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
terraform {
5+
required_providers {
6+
enos = {
7+
source = "app.terraform.io/hashicorp-qti/enos"
8+
}
9+
}
10+
}
11+
12+
data "enos_environment" "current" {}
13+
14+
locals {
15+
selected_az = data.aws_availability_zones.available.names[random_integer.az.result]
16+
common_tags = merge(
17+
var.common_tags,
18+
{
19+
Type = var.cluster_tag
20+
Module = "boundary-worker"
21+
Pet = random_pet.worker.id
22+
},
23+
)
24+
}
25+
26+
resource "random_pet" "worker" {
27+
separator = "_"
28+
}
29+
30+
data "aws_availability_zones" "available" {
31+
state = "available"
32+
filter {
33+
name = "zone-name"
34+
values = var.availability_zones
35+
}
36+
}
37+
38+
data "aws_availability_zone" "worker_az" {
39+
name = local.selected_az
40+
}
41+
42+
data "aws_kms_key" "kms_key" {
43+
key_id = var.kms_key_arn
44+
}
45+
46+
resource "random_integer" "az" {
47+
min = 0
48+
max = length(data.aws_availability_zones.available.names) - 1
49+
keepers = {
50+
# Generate a new integer each time the list of aws_availability_zones changes
51+
# keepers have to be strings, sort the list in case order changes but zones don't
52+
listener_arn = join("", sort(data.aws_availability_zones.available.names))
53+
}
54+
}
55+
56+
# Create a subnet so that the worker doesn't share one with a controller
57+
resource "aws_subnet" "default" {
58+
vpc_id = var.vpc_name
59+
cidr_block = "10.13.9.0/24"
60+
map_public_ip_on_launch = true
61+
availability_zone = local.selected_az
62+
tags = merge(
63+
local.common_tags,
64+
{
65+
"Name" = "${var.vpc_name}_worker_${random_pet.worker.id}_subnet"
66+
},
67+
)
68+
}
69+
70+
# The worker instance is a part of this security group, not to be confused with the next rule below
71+
resource "aws_security_group" "default" {
72+
name = "boundary-sg-worker-${random_pet.worker.id}"
73+
description = "SSH to worker to KMS and controllers"
74+
vpc_id = var.vpc_name
75+
76+
ingress {
77+
description = "SSH to the worker instance"
78+
from_port = 22
79+
to_port = 22
80+
protocol = "tcp"
81+
cidr_blocks = ["${data.enos_environment.current.public_ip_address}/32"]
82+
}
83+
84+
egress {
85+
description = "Communication from Boundary worker to controller"
86+
from_port = 9201
87+
to_port = 9201
88+
protocol = "tcp"
89+
cidr_blocks = ["0.0.0.0/0"]
90+
}
91+
92+
egress {
93+
description = "Communication from Boundary worker to controller"
94+
from_port = 443
95+
to_port = 443
96+
protocol = "tcp"
97+
cidr_blocks = ["0.0.0.0/0"]
98+
}
99+
100+
tags = merge(
101+
local.common_tags,
102+
{
103+
"Name" = "${var.vpc_name}_worker_sg"
104+
},
105+
)
106+
}
107+
108+
# This module only manages a rule for the controller SG that is vital to the worker's operation
109+
# This module does _not_ manage the security group itself
110+
resource "aws_vpc_security_group_ingress_rule" "worker_to_controller" {
111+
description = "This rule allows traffic from a worker to controllers over WAN"
112+
security_group_id = var.controller_sg_id
113+
cidr_ipv4 = "${aws_instance.worker.public_ip}/32"
114+
from_port = 9201
115+
to_port = 9201
116+
ip_protocol = "tcp"
117+
}
118+
119+
data "aws_route_table" "default" {
120+
vpc_id = var.vpc_name
121+
122+
filter {
123+
name = "tag:Name"
124+
values = ["enos-vpc_route"]
125+
}
126+
}
127+
128+
resource "aws_route_table_association" "worker_rta" {
129+
subnet_id = aws_subnet.default.id
130+
route_table_id = data.aws_route_table.default.id
131+
}
132+
133+
resource "aws_instance" "worker" {
134+
ami = var.ubuntu_ami_id
135+
instance_type = var.worker_instance_type
136+
vpc_security_group_ids = [aws_security_group.default.id]
137+
subnet_id = aws_subnet.default.id
138+
key_name = var.ssh_aws_keypair
139+
iam_instance_profile = var.iam_instance_profile_name
140+
monitoring = var.worker_monitoring
141+
142+
root_block_device {
143+
iops = var.ebs_iops
144+
volume_size = var.ebs_size
145+
volume_type = var.ebs_type
146+
throughput = var.ebs_throughput
147+
tags = local.common_tags
148+
}
149+
150+
tags = merge(
151+
local.common_tags,
152+
{
153+
Name = "${var.name_prefix}-boundary-worker",
154+
},
155+
)
156+
}
157+
158+
resource "enos_bundle_install" "worker" {
159+
depends_on = [aws_instance.worker, aws_route_table_association.worker_rta]
160+
161+
destination = var.boundary_install_dir
162+
artifactory = var.boundary_artifactory_release
163+
path = var.local_artifact_path
164+
release = var.boundary_release == null ? var.boundary_release : merge(var.boundary_release, { product = "boundary", edition = "oss" })
165+
166+
transport = {
167+
ssh = {
168+
host = aws_instance.worker.public_ip
169+
}
170+
}
171+
}
172+
173+
resource "enos_file" "worker_config" {
174+
depends_on = [enos_bundle_install.worker]
175+
176+
destination = "/etc/boundary/boundary.hcl"
177+
content = templatefile("${path.module}/templates/worker.hcl", {
178+
id = random_pet.worker.id
179+
kms_key_id = data.aws_kms_key.kms_key.id
180+
public_addr = aws_instance.worker.public_ip
181+
type = jsonencode(var.worker_type_tags)
182+
region = data.aws_availability_zone.worker_az.region
183+
controller_addresses = jsonencode(var.controller_addresses)
184+
})
185+
186+
transport = {
187+
ssh = {
188+
host = aws_instance.worker.public_ip
189+
}
190+
}
191+
}
192+
193+
resource "enos_boundary_start" "worker_start" {
194+
depends_on = [
195+
enos_file.worker_config,
196+
aws_vpc_security_group_ingress_rule.worker_to_controller,
197+
]
198+
199+
bin_path = "/opt/boundary/bin"
200+
config_path = "/etc/boundary"
201+
transport = {
202+
ssh = {
203+
host = aws_instance.worker.public_ip
204+
}
205+
}
206+
}

enos/modules/worker/outputs.tf

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
output "worker_ip" {
5+
description = "The public IP of the Boundary worker"
6+
value = aws_instance.worker.public_ip
7+
}
8+
9+
output "worker_tags" {
10+
description = "The tags used in the worker's configuration"
11+
value = var.worker_type_tags
12+
}
13+
14+
output "subnet_ids" {
15+
description = "The ID of the subnet this worker resides in"
16+
value = [aws_subnet.default.id]
17+
}
18+
19+
output "pet_id" {
20+
description = "The ID of the random_pet used in this module"
21+
value = random_pet.worker.id
22+
}

0 commit comments

Comments
 (0)