Skip to content

Commit 34c51b1

Browse files
authored
feat: support bastion host creation (#4)
This commit will create a bastion host if the user provides a value for the `key_name` input variable. The bastion host by default allows TCP traffic on port 22 from anywhere. However, the worker and controller instances only allow SSH access from the bastion host security group.
1 parent eb6418d commit 34c51b1

File tree

12 files changed

+135
-49
lines changed

12 files changed

+135
-49
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ As always, thanks for using this module!
105105
| controller\_instance\_type | Specifies the instance type of the controller EC2 instance | `string` | `"t3.small"` | no |
106106
| controller\_max\_size | The maximum size of the controller group | `number` | `3` | no |
107107
| controller\_min\_size | The minimum size of the controller group | `number` | `3` | no |
108+
| key\_name | The name of the key pair | `string` | `""` | no |
108109
| private\_subnets | List of private subnets | `list(string)` | `[]` | no |
109110
| public\_subnets | List of public subnets | `list(string)` | `[]` | no |
110111
| tags | One or more tags | `map(string)` | `{}` | no |

main.tf

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module "controllers" {
5252
desired_capacity = var.controller_desired_capacity
5353
image_id = local.image_id
5454
instance_type = var.controller_instance_type
55+
key_name = var.key_name
5556
max_size = var.controller_max_size
5657
min_size = var.controller_min_size
5758
private_subnets = local.private_subnets
@@ -63,19 +64,21 @@ module "controllers" {
6364
module "workers" {
6465
source = "./modules/worker"
6566

66-
boundary_release = var.boundary_release
67-
bucket_name = aws_s3_bucket.boundary.id
68-
desired_capacity = var.worker_desired_capacity
69-
image_id = local.image_id
70-
instance_type = var.worker_instance_type
71-
ip_addresses = module.controllers.ip_addresses
72-
kms_key_id = module.controllers.kms_key_id
73-
max_size = var.worker_max_size
74-
min_size = var.worker_min_size
75-
public_subnets = local.public_subnets
76-
security_group_id = module.controllers.security_group_id
77-
tags = local.tags
78-
vpc_id = local.vpc_id
67+
bastion_security_group = module.controllers.bastion_security_group
68+
boundary_release = var.boundary_release
69+
bucket_name = aws_s3_bucket.boundary.id
70+
desired_capacity = var.worker_desired_capacity
71+
image_id = local.image_id
72+
instance_type = var.worker_instance_type
73+
ip_addresses = module.controllers.ip_addresses
74+
key_name = var.key_name
75+
kms_key_id = module.controllers.kms_key_id
76+
max_size = var.worker_max_size
77+
min_size = var.worker_min_size
78+
public_subnets = local.public_subnets
79+
security_group_id = module.controllers.security_group_id
80+
tags = local.tags
81+
vpc_id = local.vpc_id
7982
}
8083

8184
module "vpc" {

modules/boundary/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ No provider.
1111

1212
| Name | Description | Type | Default | Required |
1313
|------|-------------|------|---------|:--------:|
14+
| after\_start | Run arbitrary commands after starting the Boundary service | `list(string)` | `[]` | no |
1415
| auto\_scaling\_group\_name | The name of the Auto Scaling group | `string` | n/a | yes |
16+
| before\_start | Run arbitrary commands before starting the Boundary service | `list(string)` | `[]` | no |
1517
| boundary\_release | The version of Boundary to install | `string` | n/a | yes |
1618
| bucket\_name | The name of the bucket to upload the contents of the<br>cloud-init-output.log file | `string` | n/a | yes |
1719
| desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group<br>at the time of its creation and the capacity it attempts to maintain. | `number` | `0` | no |
@@ -21,7 +23,6 @@ No provider.
2123
| key\_name | The name of the key pair | `string` | `""` | no |
2224
| max\_size | The maximum size of the group | `number` | n/a | yes |
2325
| min\_size | The minimum size of the group | `number` | n/a | yes |
24-
| runcmd | Run arbitrary commands at a rc.local like level with output to the<br>console. Each item can be either a list or a string. | `list(string)` | `[]` | no |
2526
| security\_groups | A list that contains the security groups to assign to the instances in the Auto<br>Scaling group | `list(string)` | `[]` | no |
2627
| tags | One or more tags. You can tag your Auto Scaling group and propagate the tags to<br>the Amazon EC2 instances it launches. | `map(string)` | `{}` | no |
2728
| target\_group\_arns | The Amazon Resource Names (ARN) of the target groups to associate with the Auto<br>Scaling group | `list(string)` | `[]` | no |

modules/boundary/main.tf

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,15 @@ locals {
1313

1414
runcmd = concat(
1515
[
16-
"curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip",
17-
"unzip awscliv2.zip",
18-
"./aws/install",
1916
"wget -O boundary.zip ${local.download_url}",
2017
"unzip boundary.zip -d /usr/local/bin"
2118
],
22-
var.runcmd,
19+
var.before_start,
2320
[
2421
"systemctl enable boundary",
2522
"systemctl start boundary",
26-
"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"
27-
]
23+
],
24+
var.after_start
2825
)
2926

3027
write_files = concat(

modules/boundary/variables.tf

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,20 @@
1+
variable "after_start" {
2+
default = []
3+
description = "Run arbitrary commands after starting the Boundary service"
4+
type = list(string)
5+
}
6+
17
variable "auto_scaling_group_name" {
28
description = "The name of the Auto Scaling group"
39
type = string
410
}
511

12+
variable "before_start" {
13+
default = []
14+
description = "Run arbitrary commands before starting the Boundary service"
15+
type = list(string)
16+
}
17+
618
variable "boundary_release" {
719
description = "The version of Boundary to install"
820
type = string
@@ -67,17 +79,6 @@ variable "min_size" {
6779
type = number
6880
}
6981

70-
variable "runcmd" {
71-
default = []
72-
73-
description = <<EOF
74-
Run arbitrary commands at a rc.local like level with output to the
75-
console. Each item can be either a list or a string.
76-
EOF
77-
78-
type = list(string)
79-
}
80-
8182
variable "security_groups" {
8283
default = []
8384

modules/controller/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ No requirements.
3131

3232
| Name | Description |
3333
|------|-------------|
34+
| bastion\_security\_group | The ID of the bastion security group |
3435
| dns\_name | The public DNS name of the load balancer |
3536
| ip\_addresses | One or more private IPv4 addresses associated with the controllers |
3637
| kms\_key\_id | The unique identifier for the worker-auth key |

modules/controller/main.tf

Lines changed: 70 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,17 @@ resource "aws_security_group" "controller" {
7474
vpc_id = var.vpc_id
7575
}
7676

77+
resource "aws_security_group_rule" "ssh" {
78+
count = var.key_name != "" ? 1 : 0
79+
80+
from_port = 22
81+
protocol = "TCP"
82+
security_group_id = aws_security_group.controller.id
83+
source_security_group_id = join("", aws_security_group.bastion[*].id)
84+
to_port = 22
85+
type = "ingress"
86+
}
87+
7788
resource "aws_security_group_rule" "ingress" {
7889
from_port = 9200
7990
protocol = "TCP"
@@ -162,26 +173,34 @@ module "postgresql" {
162173
module "controllers" {
163174
source = "../boundary"
164175

165-
auto_scaling_group_name = "boundary-controller"
166-
boundary_release = var.boundary_release
167-
bucket_name = var.bucket_name
168-
desired_capacity = var.desired_capacity
169-
iam_instance_profile = aws_iam_instance_profile.controller.name
170-
image_id = var.image_id
171-
instance_type = var.instance_type
172-
key_name = var.key_name
173-
max_size = var.max_size
174-
min_size = var.min_size
175-
176-
# Initialize the DB before starting the service
177-
runcmd = [
176+
after_start = [
177+
"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"
178+
]
179+
180+
auto_scaling_group_name = "Boundary Controller"
181+
182+
# Initialize the DB before starting the service and install the AWS
183+
# CLI.
184+
before_start = [
185+
"curl https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip",
186+
"unzip awscliv2.zip",
187+
"./aws/install",
178188
"boundary database init -config /etc/boundary/configuration.hcl -log-format json"
179189
]
180190

181-
security_groups = [aws_security_group.controller.id]
182-
tags = var.tags
183-
target_group_arns = module.alb.target_group_arns
184-
vpc_zone_identifier = var.private_subnets
191+
boundary_release = var.boundary_release
192+
bucket_name = var.bucket_name
193+
desired_capacity = var.desired_capacity
194+
iam_instance_profile = aws_iam_instance_profile.controller.name
195+
image_id = var.image_id
196+
instance_type = var.instance_type
197+
key_name = var.key_name
198+
max_size = var.max_size
199+
min_size = var.min_size
200+
security_groups = [aws_security_group.controller.id]
201+
tags = var.tags
202+
target_group_arns = module.alb.target_group_arns
203+
vpc_zone_identifier = var.private_subnets
185204

186205
write_files = [
187206
{
@@ -270,3 +289,37 @@ resource "aws_kms_key" "auth" {
270289
key_usage = "ENCRYPT_DECRYPT"
271290
tags = merge(var.tags, { Purpose = "worker-auth" })
272291
}
292+
293+
resource "aws_security_group" "bastion" {
294+
count = var.key_name != "" ? 1 : 0
295+
296+
egress {
297+
cidr_blocks = ["0.0.0.0/0"]
298+
from_port = 0
299+
protocol = "-1"
300+
to_port = 0
301+
}
302+
303+
ingress {
304+
cidr_blocks = ["0.0.0.0/0"]
305+
from_port = 22
306+
protocol = "TCP"
307+
to_port = 22
308+
}
309+
310+
name = "Boundary Bastion"
311+
tags = var.tags
312+
vpc_id = var.vpc_id
313+
}
314+
315+
resource "aws_instance" "bastion" {
316+
count = var.key_name != "" ? 1 : 0
317+
318+
ami = var.image_id
319+
associate_public_ip_address = true
320+
instance_type = "t3.micro"
321+
key_name = var.key_name
322+
subnet_id = var.public_subnets[0]
323+
tags = merge(var.tags, { Name = "Boundary Bastion" })
324+
vpc_security_group_ids = [join("", aws_security_group.bastion[*].id)]
325+
}

modules/controller/outputs.tf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
output "bastion_security_group" {
2+
description = "The ID of the bastion security group"
3+
value = join("", aws_security_group.bastion[*].id)
4+
}
5+
16
output "dns_name" {
27
description = "The public DNS name of the load balancer"
38
value = module.alb.this_lb_dns_name

modules/worker/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ No requirements.
1313

1414
| Name | Description | Type | Default | Required |
1515
|------|-------------|------|---------|:--------:|
16+
| bastion\_security\_group | The ID of the bastion security group | `string` | `""` | no |
1617
| boundary\_release | The version of Boundary to install | `string` | `"0.1.0"` | no |
1718
| bucket\_name | The name of the bucket to upload the contents of the<br>cloud-init-output.log file | `string` | n/a | yes |
1819
| desired\_capacity | The desired capacity is the initial capacity of the Auto Scaling group<br>at the time of its creation and the capacity it attempts to maintain. | `number` | `3` | no |

modules/worker/main.tf

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ resource "aws_security_group" "worker" {
4747
to_port = 9202
4848
}
4949

50+
dynamic "ingress" {
51+
for_each = var.key_name != "" ? [22] : []
52+
53+
content {
54+
from_port = 22
55+
protocol = "TCP"
56+
security_groups = [var.bastion_security_group]
57+
to_port = 22
58+
}
59+
}
60+
5061
name = "Boundary worker"
5162
tags = var.tags
5263
vpc_id = var.vpc_id
@@ -55,7 +66,7 @@ resource "aws_security_group" "worker" {
5566
module "workers" {
5667
source = "../boundary"
5768

58-
auto_scaling_group_name = "boundary-worker"
69+
auto_scaling_group_name = "Boundary Worker"
5970
boundary_release = var.boundary_release
6071
bucket_name = var.bucket_name
6172
desired_capacity = var.desired_capacity

modules/worker/variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
variable "bastion_security_group" {
2+
default = ""
3+
description = "The ID of the bastion security group"
4+
type = string
5+
}
6+
17
variable "boundary_release" {
28
default = "0.1.0"
39
description = "The version of Boundary to install"

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,12 @@ variable "controller_min_size" {
3434
type = number
3535
}
3636

37+
variable "key_name" {
38+
default = ""
39+
description = "The name of the key pair"
40+
type = string
41+
}
42+
3743
variable "private_subnets" {
3844
default = []
3945
description = "List of private subnets"

0 commit comments

Comments
 (0)