2 | ## Requirements
3 |
4 | | Name | Version |
5 | |------|---------|
6 | | aws | ~> 3.0 |
7 |
8 | ## Providers
9 |
10 | No provider.
11 |
12 | ## Inputs
13 |
14 | | Name | Description | Type | Default | Required |
15 | |------|-------------|------|---------|:--------:|
16 | | after\_start | Run arbitrary commands after starting the Boundary service | `list(string)` | `[]` | no |
17 | | auto\_scaling\_group\_name | The name of the Auto Scaling group | `string` | n/a | yes |
18 | | before\_start | Run arbitrary commands before starting the Boundary service | `list(string)` | `[]` | no |
19 | | boundary\_release | The version of Boundary to install | `string` | n/a | yes |
20 | | bucket\_name | The name of the bucket to upload the contents of the
cloud-init-output.log file | `string` | n/a | yes |
21 | | desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group
at the time of its creation and the capacity it attempts to maintain. | `number` | `0` | no |
22 | | iam\_instance\_profile | The name or the Amazon Resource Name (ARN) of the instance profile associated
with the IAM role for the instance | `string` | `""` | no |
23 | | image\_id | The ID of the Amazon Machine Image (AMI) that was assigned during registration | `string` | n/a | yes |
24 | | instance\_type | Specifies the instance type of the EC2 instance | `string` | n/a | yes |
25 | | key\_name | The name of the key pair | `string` | `""` | no |
26 | | max\_size | The maximum size of the group | `number` | n/a | yes |
27 | | min\_size | The minimum size of the group | `number` | n/a | yes |
28 | | security\_groups | A list that contains the security groups to assign to the instances in the Auto
Scaling group | `list(string)` | `[]` | no |
29 | | tags | One or more tags. You can tag your Auto Scaling group and propagate the tags to
the Amazon EC2 instances it launches. | `map(string)` | `{}` | no |
30 | | target\_group\_arns | The Amazon Resource Names (ARN) of the target groups to associate with the Auto
Scaling group | `list(string)` | `[]` | no |
31 | | vpc\_zone\_identifier | A comma-separated list of subnet IDs for your virtual private cloud | `list(string)` | n/a | yes |
32 | | write\_files | Write out arbitrary content to files, optionally setting permissions | list(object({
content = string
owner = string
path = string
permissions = string
})) | `[]` | no |
33 |
34 | ## Outputs
35 |
36 | | Name | Description |
37 | |------|-------------|
38 | | auto\_scaling\_group\_name | The name of the controller Auto Scaling group |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/.terraform.lock.hcl:
--------------------------------------------------------------------------------
1 | # This file is maintained automatically by "terraform init".
2 | # Manual edits may be lost in future updates.
3 |
4 | provider "registry.terraform.io/hashicorp/aws" {
5 | version = "3.59.0"
6 | constraints = ">= 2.49.0, ~> 3.0, >= 3.38.0, >= 3.40.0, >= 3.44.0"
7 | hashes = [
8 | "h1:tuHv/1slRRVPlm6a53fWdIV0oqnBe9cOkr0J9as76Cc=",
9 | "zh:0b33154c805071af15839184f3faafeb1549d26a2f1fe721393461790c5ddb46",
10 | "zh:1c5c6793cbec328394c6dda686298d9f6bb7b4c6a39e3dc48dc3035dea9aeda0",
11 | "zh:20b590b9d9f0a18fdc9f0fb18bb2d9d5349b14039899ecf66e4ae5513606405b",
12 | "zh:3e9010dbb0655b5d05e5e98bfe3e1e73cfa5ff6b364dfd73e8eeeb5e1e58c643",
13 | "zh:47a46895d2592fbe7c904107ab6af25abbb17de230852859c06eee95ab282823",
14 | "zh:615745b8c25b111cfe204d52553ea530d84abba7fb8be6b5b00476184407b556",
15 | "zh:701e0f2e5191729601b6d7591e5c3f5d77439125a74116786cca3bc6d7abf0d9",
16 | "zh:7217637b5726bfd09dc9b4f75aef643530e8b673f6de6e06f660a70f4d3170e2",
17 | "zh:8097811557dd5fffcc77e921d3a49dfaa203d4640ac3859a64dcd927122ade8b",
18 | "zh:9a23df54c62dcf74e88aa309700651a6e77e173429ef0307ee15aaa7ff2f47d0",
19 | "zh:e5fa052b9285332a1ebb360ab14676bca88efdaac96cdd809207b23f8e732bb0",
20 | ]
21 | }
22 |
23 | provider "registry.terraform.io/hashicorp/null" {
24 | version = "3.1.0"
25 | constraints = ">= 2.0.0"
26 | hashes = [
27 | "h1:xhbHC6in3nQryvTQBWKxebi3inG5OCgHgc4fRxL0ymc=",
28 | "zh:02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2",
29 | "zh:53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515",
30 | "zh:5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521",
31 | "zh:9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2",
32 | "zh:a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e",
33 | "zh:a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53",
34 | "zh:c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d",
35 | "zh:cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8",
36 | "zh:e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70",
37 | "zh:fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b",
38 | "zh:fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e",
39 | ]
40 | }
41 |
42 | provider "registry.terraform.io/hashicorp/random" {
43 | version = "3.1.0"
44 | constraints = ">= 2.2.0, >= 3.1.0"
45 | hashes = [
46 | "h1:rKYu5ZUbXwrLG1w81k7H3nce/Ys6yAxXhWcbtk36HjY=",
47 | "zh:2bbb3339f0643b5daa07480ef4397bd23a79963cc364cdfbb4e86354cb7725bc",
48 | "zh:3cd456047805bf639fbf2c761b1848880ea703a054f76db51852008b11008626",
49 | "zh:4f251b0eda5bb5e3dc26ea4400dba200018213654b69b4a5f96abee815b4f5ff",
50 | "zh:7011332745ea061e517fe1319bd6c75054a314155cb2c1199a5b01fe1889a7e2",
51 | "zh:738ed82858317ccc246691c8b85995bc125ac3b4143043219bd0437adc56c992",
52 | "zh:7dbe52fac7bb21227acd7529b487511c91f4107db9cc4414f50d04ffc3cab427",
53 | "zh:a3a9251fb15f93e4cfc1789800fc2d7414bbc18944ad4c5c98f466e6477c42bc",
54 | "zh:a543ec1a3a8c20635cf374110bd2f87c07374cf2c50617eee2c669b3ceeeaa9f",
55 | "zh:d9ab41d556a48bd7059f0810cf020500635bfc696c9fc3adab5ea8915c1d886b",
56 | "zh:d9e13427a7d011dbd654e591b0337e6074eef8c3b9bb11b2e39eaaf257044fd7",
57 | "zh:f7605bd1437752114baf601bdf6931debe6dc6bfe3006eb7e9bb9080931dca8a",
58 | ]
59 | }
60 |
--------------------------------------------------------------------------------
/modules/boundary/variables.tf:
--------------------------------------------------------------------------------
1 | variable "after_start" {
2 | default = []
3 | description = "Run arbitrary commands after starting the Boundary service"
4 | type = list(string)
5 | }
6 |
7 | variable "auto_scaling_group_name" {
8 | description = "The name of the Auto Scaling group"
9 | type = string
10 | }
11 |
12 | variable "before_start" {
13 | default = []
14 | description = "Run arbitrary commands before starting the Boundary service"
15 | type = list(string)
16 | }
17 |
18 | variable "boundary_release" {
19 | description = "The version of Boundary to install"
20 | type = string
21 | }
22 |
23 | variable "bucket_name" {
24 | description = <
85 | ## Requirements
86 |
87 | | Name | Version |
88 | |------|---------|
89 | | terraform | ~> 1.0 |
90 | | terraform | >= 0.13 |
91 |
92 | ## Providers
93 |
94 | | Name | Version |
95 | |------|---------|
96 | | aws | n/a |
97 | | random | n/a |
98 |
99 | ## Inputs
100 |
101 | | Name | Description | Type | Default | Required |
102 | |------|-------------|------|---------|:--------:|
103 | | boundary\_release | The version of Boundary to install | `string` | `"0.1.0"` | no |
104 | | cidr\_block | The IPv4 network range for the VPC, in CIDR notation. For example, 10.0.0.0/16. | `string` | `"10.0.0.0/16"` | no |
105 | | controller\_desired\_capacity | The capacity the controller Auto Scaling group attempts to maintain | `number` | `3` | no |
106 | | controller\_instance\_type | Specifies the instance type of the controller EC2 instance | `string` | `"t3.small"` | no |
107 | | controller\_max\_size | The maximum size of the controller group | `number` | `3` | no |
108 | | controller\_min\_size | The minimum size of the controller group | `number` | `3` | no |
109 | | key\_name | The name of the key pair | `string` | `""` | no |
110 | | private\_subnets | List of private subnets | `list(string)` | `[]` | no |
111 | | public\_subnets | List of public subnets | `list(string)` | `[]` | no |
112 | | tags | One or more tags | `map(string)` | `{}` | no |
113 | | vpc\_id | The ID of the VPC | `string` | `""` | no |
114 | | worker\_desired\_capacity | The capacity the worker Auto Scaling group attempts to maintain | `number` | `3` | no |
115 | | worker\_instance\_type | Specifies the instance type of the worker EC2 instance | `string` | `"t3.small"` | no |
116 | | worker\_max\_size | The maximum size of the worker group | `number` | `3` | no |
117 | | worker\_min\_size | The minimum size of the worker group | `number` | `3` | no |
118 |
119 | ## Outputs
120 |
121 | | Name | Description |
122 | |------|-------------|
123 | | dns\_name | The public DNS name of the controller load balancer |
124 | | s3command | The S3 cp command used to display the contents of the cloud-init-output.log |
125 |
126 |
127 |
128 | ## License
129 |
130 | [MIT License](LICENSE)
131 |
--------------------------------------------------------------------------------
/modules/controller/main.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | required_providers {
3 | aws = {
4 | source = "hashicorp/aws"
5 | version = "~> 3.0"
6 | }
7 | }
8 | }
9 |
10 | locals {
11 | configuration = templatefile(
12 | "${path.module}/templates/configuration.hcl.tpl",
13 | {
14 | # Database URL for PostgreSQL
15 | database_url = format(
16 | "postgresql://%s:%s@%s/%s",
17 | module.postgresql.db_instance_username,
18 | module.postgresql.db_instance_password,
19 | module.postgresql.db_instance_endpoint,
20 | module.postgresql.db_instance_name
21 | )
22 |
23 | keys = [
24 | {
25 | key_id = aws_kms_key.root.key_id
26 | purpose = "root"
27 | },
28 | {
29 | key_id = aws_kms_key.auth.key_id
30 | purpose = "worker-auth"
31 | }
32 | ]
33 | }
34 | )
35 | }
36 |
37 | data "aws_instances" "controllers" {
38 | instance_state_names = ["running"]
39 |
40 | instance_tags = {
41 | "aws:autoscaling:groupName" = module.controllers.auto_scaling_group_name
42 | }
43 | }
44 |
45 | data "aws_s3_bucket" "boundary" {
46 | bucket = var.bucket_name
47 | }
48 |
49 | resource "aws_security_group" "alb" {
50 | egress {
51 | cidr_blocks = ["0.0.0.0/0"]
52 | from_port = 0
53 | protocol = "-1"
54 | to_port = 0
55 | }
56 |
57 | dynamic "ingress" {
58 | for_each = [80, 443]
59 |
60 | content {
61 | cidr_blocks = ["0.0.0.0/0"]
62 | from_port = ingress.value
63 | protocol = "TCP"
64 | to_port = ingress.value
65 | }
66 | }
67 |
68 | name = "Boundary Application Load Balancer"
69 |
70 | tags = merge(
71 | {
72 | Name = "Boundary Application Load Balancer"
73 | },
74 | var.tags
75 | )
76 |
77 | vpc_id = var.vpc_id
78 | }
79 |
80 | resource "aws_security_group" "controller" {
81 | name = "Boundary controller"
82 | tags = var.tags
83 | vpc_id = var.vpc_id
84 | }
85 |
86 | resource "aws_security_group_rule" "ssh" {
87 | count = var.key_name != "" ? 1 : 0
88 |
89 | from_port = 22
90 | protocol = "TCP"
91 | security_group_id = aws_security_group.controller.id
92 | source_security_group_id = one(aws_security_group.bastion[*].id)
93 | to_port = 22
94 | type = "ingress"
95 | }
96 |
97 | resource "aws_security_group_rule" "ingress" {
98 | from_port = 9200
99 | protocol = "TCP"
100 | security_group_id = aws_security_group.controller.id
101 | source_security_group_id = aws_security_group.alb.id
102 | to_port = 9200
103 | type = "ingress"
104 | }
105 |
106 | resource "aws_security_group_rule" "egress" {
107 | cidr_blocks = ["0.0.0.0/0"]
108 | from_port = 0
109 | protocol = "-1"
110 | security_group_id = aws_security_group.controller.id
111 | to_port = 0
112 | type = "egress"
113 | }
114 |
115 | resource "aws_security_group" "postgresql" {
116 | ingress {
117 | from_port = 5432
118 | protocol = "TCP"
119 | security_groups = [aws_security_group.controller.id]
120 | to_port = 5432
121 | }
122 |
123 | tags = var.tags
124 | vpc_id = var.vpc_id
125 | }
126 |
127 | module "alb" {
128 | source = "terraform-aws-modules/alb/aws"
129 | version = "~> 6.5"
130 |
131 | http_tcp_listeners = [
132 | {
133 | port = 80
134 | protocol = "HTTP"
135 | }
136 | ]
137 |
138 | load_balancer_type = "application"
139 | name = "boundary"
140 | security_groups = [aws_security_group.alb.id]
141 | subnets = var.public_subnets
142 | tags = var.tags
143 |
144 | target_groups = [
145 | {
146 | name = "boundary"
147 | backend_protocol = "HTTP"
148 | backend_port = 9200
149 | }
150 | ]
151 |
152 | vpc_id = var.vpc_id
153 | }
154 |
155 | resource "random_password" "postgresql" {
156 | length = 16
157 | special = false
158 | }
159 |
160 | module "postgresql" {
161 | source = "terraform-aws-modules/rds/aws"
162 | version = "~> 3.4"
163 |
164 | allocated_storage = 5
165 | backup_retention_period = 0
166 | backup_window = "03:00-06:00"
167 | engine = "postgres"
168 | engine_version = var.engine_version
169 | family = "postgres12"
170 | identifier = "boundary"
171 | instance_class = "db.t2.micro"
172 | maintenance_window = "Mon:00:00-Mon:03:00"
173 | major_engine_version = "12"
174 | name = "boundary"
175 | password = random_password.postgresql.result
176 | port = 5432
177 | storage_encrypted = false
178 | subnet_ids = var.private_subnets
179 | tags = var.tags
180 | username = "boundary"
181 | vpc_security_group_ids = [aws_security_group.postgresql.id]
182 | }
183 |
184 | module "controllers" {
185 | source = "../boundary"
186 |
187 | after_start = [
188 | "grep 'Initial auth information' /var/log/cloud-init-output.log && aws s3 cp /var/log/cloud-init-output.log s3://${var.bucket_name}/{{v1.local_hostname}}/cloud-init-output.log || true"
189 | ]
190 |
191 | auto_scaling_group_name = "BoundaryController"
192 |
193 | # Initialize the DB before starting the service and install the AWS
194 | # CLI.
195 | before_start = [
196 | "curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip",
197 | "unzip awscliv2.zip",
198 | "./aws/install",
199 | "boundary database init -config /etc/boundary/configuration.hcl -log-format json"
200 | ]
201 |
202 | boundary_release = var.boundary_release
203 | bucket_name = var.bucket_name
204 | desired_capacity = var.desired_capacity
205 | iam_instance_profile = aws_iam_instance_profile.controller.arn
206 | image_id = var.image_id
207 | instance_type = var.instance_type
208 | key_name = var.key_name
209 | max_size = var.max_size
210 | min_size = var.min_size
211 | security_groups = [aws_security_group.controller.id]
212 | tags = var.tags
213 | target_group_arns = module.alb.target_group_arns
214 | vpc_zone_identifier = var.private_subnets
215 |
216 | write_files = [
217 | {
218 | content = local.configuration
219 | owner = "root:root"
220 | path = "/etc/boundary/configuration.hcl"
221 | permissions = "0644"
222 | }
223 | ]
224 | }
225 |
226 | # https://www.boundaryproject.io/docs/configuration/kms/awskms#authentication
227 | #
228 | # Allows the controllers to invoke the Decrypt, DescribeKey, and Encrypt
229 | # routines for the worker-auth and root keys.
230 | data "aws_iam_policy_document" "controller" {
231 | statement {
232 | actions = [
233 | "kms:Decrypt",
234 | "kms:DescribeKey",
235 | "kms:Encrypt"
236 | ]
237 |
238 | effect = "Allow"
239 |
240 | resources = [aws_kms_key.auth.arn, aws_kms_key.root.arn]
241 | }
242 |
243 | statement {
244 | actions = [
245 | "s3:*"
246 | ]
247 |
248 | effect = "Allow"
249 |
250 | resources = [
251 | "${data.aws_s3_bucket.boundary.arn}/",
252 | "${data.aws_s3_bucket.boundary.arn}/*"
253 | ]
254 | }
255 | }
256 |
257 | data "aws_iam_policy_document" "assume_role_policy" {
258 | statement {
259 | actions = ["sts:AssumeRole"]
260 |
261 | effect = "Allow"
262 |
263 | principals {
264 | identifiers = ["ec2.amazonaws.com"]
265 | type = "Service"
266 | }
267 | }
268 | }
269 |
270 | resource "aws_iam_policy" "controller" {
271 | name = "BoundaryControllerServiceRolePolicy"
272 | policy = data.aws_iam_policy_document.controller.json
273 | }
274 |
275 | resource "aws_iam_role" "controller" {
276 | assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
277 | name = "ServiceRoleForBoundaryController"
278 | tags = var.tags
279 | }
280 |
281 | resource "aws_iam_role_policy_attachment" "controller" {
282 | policy_arn = aws_iam_policy.controller.arn
283 | role = aws_iam_role.controller.name
284 | }
285 |
286 | resource "aws_iam_instance_profile" "controller" {
287 | role = aws_iam_role.controller.name
288 | }
289 |
290 | # The root key used by controllers
291 | resource "aws_kms_key" "root" {
292 | deletion_window_in_days = 7
293 | key_usage = "ENCRYPT_DECRYPT"
294 | tags = merge(var.tags, { Purpose = "root" })
295 | }
296 |
297 | # The worker-auth AWS KMS key used by controllers and workers
298 | resource "aws_kms_key" "auth" {
299 | deletion_window_in_days = 7
300 | key_usage = "ENCRYPT_DECRYPT"
301 | tags = merge(var.tags, { Purpose = "worker-auth" })
302 | }
303 |
304 | resource "aws_security_group" "bastion" {
305 | count = var.key_name != "" ? 1 : 0
306 |
307 | egress {
308 | cidr_blocks = ["0.0.0.0/0"]
309 | from_port = 0
310 | protocol = "-1"
311 | to_port = 0
312 | }
313 |
314 | ingress {
315 | cidr_blocks = ["0.0.0.0/0"]
316 | from_port = 22
317 | protocol = "TCP"
318 | to_port = 22
319 | }
320 |
321 | name = "Boundary Bastion"
322 | tags = var.tags
323 | vpc_id = var.vpc_id
324 | }
325 |
326 | resource "aws_instance" "bastion" {
327 | count = var.key_name != "" ? 1 : 0
328 |
329 | ami = var.image_id
330 | associate_public_ip_address = true
331 | instance_type = "t3.micro"
332 | key_name = var.key_name
333 | subnet_id = var.public_subnets[0]
334 | tags = merge(var.tags, { Name = "Boundary Bastion" })
335 | vpc_security_group_ids = [one(aws_security_group.bastion[*].id)]
336 | }
337 |
--------------------------------------------------------------------------------