Skip to content

Commit

Permalink
Conditionally launch Bastion host
Browse files Browse the repository at this point in the history
* Launches a t3.micro AL2023 instance within the VPC, which can be
  accessed via Session Manager
  • Loading branch information
Stretch96 committed Sep 10, 2024
1 parent e17d364 commit e34f487
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_task_s3_list](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_role_policy_attachment.infrastructure_rds_s3_backups_task_s3_write](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
| [aws_iam_user.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
| [aws_instance.infrastructure_bastion](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance) | resource |
| [aws_internet_gateway.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
| [aws_kms_alias.custom_s3_buckets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
| [aws_kms_alias.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
Expand Down Expand Up @@ -375,12 +376,19 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_s3_object.infrastructure_ecs_cluster_service_build_pipeline_buildspec_store_files](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_secretsmanager_secret.infrastructure_rds_root_password](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret) | resource |
| [aws_secretsmanager_secret_version.infrastructure_rds_root_password](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version) | resource |
| [aws_security_group.infrastructure_ec2_bastion_host](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_ecs_cluster_container_instances](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_ecs_cluster_efs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_ecs_cluster_service_alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_elasticache](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group.infrastructure_rds_s3_backups_scheduled_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_https_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ec2_bastion_host_egress_rds](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_custom](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_dns_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_dns_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
Expand Down Expand Up @@ -425,6 +433,7 @@ This project creates and manages resources within an AWS account for infrastruct
| [archive_file.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [archive_file.ecs_cluster_infrastructure_ecs_asg_diff_metric_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [archive_file.ecs_cluster_infrastructure_pending_task_metric_lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [aws_ami.bastion_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
| [aws_ami.ecs_cluster_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_cloudfront_cache_policy.managed_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |
Expand Down Expand Up @@ -452,6 +461,7 @@ This project creates and manages resources within an AWS account for infrastruct
| <a name="input_ecs_cluster_efs_performance_mode"></a> [ecs\_cluster\_efs\_performance\_mode](#input\_ecs\_cluster\_efs\_performance\_mode) | ECS cluser EFS performance mode | `string` | n/a | yes |
| <a name="input_ecs_cluster_efs_throughput_mode"></a> [ecs\_cluster\_efs\_throughput\_mode](#input\_ecs\_cluster\_efs\_throughput\_mode) | ECS cluser EFS throughput mode | `string` | n/a | yes |
| <a name="input_enable_cloudformatian_s3_template_store"></a> [enable\_cloudformatian\_s3\_template\_store](#input\_enable\_cloudformatian\_s3\_template\_store) | Creates an S3 bucket to store custom CloudFormation templates, which can then be referenced in `custom_cloudformation_stacks`. A user with RW access to the bucket is also created. | `bool` | n/a | yes |
| <a name="input_enable_infrastructure_bastion_host"></a> [enable\_infrastructure\_bastion\_host](#input\_enable\_infrastructure\_bastion\_host) | Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager | `bool` | n/a | yes |
| <a name="input_enable_infrastructure_ecs_cluster"></a> [enable\_infrastructure\_ecs\_cluster](#input\_enable\_infrastructure\_ecs\_cluster) | Enable creation of infrastructure ECS cluster, to place ECS services | `bool` | n/a | yes |
| <a name="input_enable_infrastructure_ecs_cluster_asg_cpu_alert"></a> [enable\_infrastructure\_ecs\_cluster\_asg\_cpu\_alert](#input\_enable\_infrastructure\_ecs\_cluster\_asg\_cpu\_alert) | Enable a CPU alert for the ECS cluster's Autoscaling Group | `bool` | n/a | yes |
| <a name="input_enable_infrastructure_ecs_cluster_ecs_asg_diff_alert"></a> [enable\_infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_alert](#input\_enable\_infrastructure\_ecs\_cluster\_ecs\_asg\_diff\_alert) | Enable the ECS Cluster Container Instance / ASG instance diff alert | `bool` | n/a | yes |
Expand All @@ -462,6 +472,7 @@ This project creates and manages resources within an AWS account for infrastruct
| <a name="input_enable_infrastructure_route53_hosted_zone"></a> [enable\_infrastructure\_route53\_hosted\_zone](#input\_enable\_infrastructure\_route53\_hosted\_zone) | Creates a Route53 hosted zone, where DNS records will be created for resources launched within this module. | `bool` | n/a | yes |
| <a name="input_enable_infrastructure_vpc_transfer_s3_bucket"></a> [enable\_infrastructure\_vpc\_transfer\_s3\_bucket](#input\_enable\_infrastructure\_vpc\_transfer\_s3\_bucket) | Enable VPC transfer S3 bucket. This allows uploading/downloading files from resources within the infrastructure VPC | `bool` | n/a | yes |
| <a name="input_environment"></a> [environment](#input\_environment) | The environment name to be used as part of the resource prefix | `string` | n/a | yes |
| <a name="input_infrastructure_bastion_host_custom_security_group_rules"></a> [infrastructure\_bastion\_host\_custom\_security\_group\_rules](#input\_infrastructure\_bastion\_host\_custom\_security\_group\_rules) | Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = "egress", ... } }) | <pre>map(object({<br> description = string<br> type = string<br> from_port = number<br> to_port = number<br> protocol = string<br> source_security_group_id = optional(string, "")<br> cidr_blocks = optional(list(string), [])<br> }))</pre> | n/a | yes |
| <a name="input_infrastructure_dockerhub_email"></a> [infrastructure\_dockerhub\_email](#input\_infrastructure\_dockerhub\_email) | Dockerhub email | `string` | n/a | yes |
| <a name="input_infrastructure_dockerhub_token"></a> [infrastructure\_dockerhub\_token](#input\_infrastructure\_dockerhub\_token) | Dockerhub token which has permissions to pull images | `string` | n/a | yes |
| <a name="input_infrastructure_dockerhub_username"></a> [infrastructure\_dockerhub\_username](#input\_infrastructure\_dockerhub\_username) | Dockerhub username | `string` | n/a | yes |
Expand Down
21 changes: 21 additions & 0 deletions data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,27 @@ data "aws_ami" "ecs_cluster_ami" {
}
}

data "aws_ami" "bastion_ami" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

most_recent = true
owners = ["amazon"]

filter {
name = "name"
values = [
"al2023-ami-2023*"
]
}

filter {
name = "architecture"
values = [
"x86_64"
]
}
}

data "aws_sns_topic" "infrastructure_slack_sns_topic" {
count = local.infrastructure_slack_sns_topic_in_use ? 1 : 0

Expand Down
90 changes: 90 additions & 0 deletions ec2-infrastructure-bastion-host-security-group.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
resource "aws_security_group" "infrastructure_ec2_bastion_host" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

name = "${local.resource_prefix}-infrastructure-ec2-bastion-host"
description = "Infrastructure EC2 Bastion Host"
vpc_id = aws_vpc.infrastructure[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_egress_https_tcp" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

description = "Allow HTTPS tcp outbound"
type = "egress"
from_port = 443
to_port = 443
protocol = "tcp"
# tfsec:ignore:aws-ec2-no-public-egress-sgr
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_egress_https_udp" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

description = "Allow HTTPS udp outbound"
type = "egress"
from_port = 443
to_port = 443
protocol = "udp"
# tfsec:ignore:aws-ec2-no-public-egress-sgr
cidr_blocks = ["0.0.0.0/0"]
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_egress_dns_tcp" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

description = "Allow DNS tcp outbound to AWS"
type = "egress"
from_port = 53
to_port = 53
protocol = "tcp"
cidr_blocks = local.infrastructure_ecs_cluster_publicly_avaialble ? [
for subnet in aws_subnet.infrastructure_public : subnet.cidr_block
] : [
for subnet in aws_subnet.infrastructure_private : subnet.cidr_block
]
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_egress_dns_udp" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

description = "Allow DNS udp outbound to AWS"
type = "egress"
from_port = 53
to_port = 53
protocol = "udp"
cidr_blocks = local.infrastructure_ecs_cluster_publicly_avaialble ? [
for subnet in aws_subnet.infrastructure_public : subnet.cidr_block
] : [
for subnet in aws_subnet.infrastructure_private : subnet.cidr_block
]
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_egress_rds" {
for_each = local.enable_infrastructure_bastion_host ? local.infrastructure_rds : {}

description = "Allow ${each.value["engine"]} tcp outbound to RDS security group"
type = "egress"
from_port = local.rds_ports[each.value["engine"]]
to_port = local.rds_ports[each.value["engine"]]
protocol = "tcp"
source_security_group_id = aws_security_group.infrastructure_rds[each.key].id
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}

resource "aws_security_group_rule" "infrastructure_ec2_bastion_host_custom" {
for_each = local.enable_infrastructure_bastion_host ? local.infrastructure_bastion_host_custom_security_group_rules : {}

description = each.value["description"]
type = each.value["type"]
from_port = each.value["from_port"]
to_port = each.value["to_port"]
protocol = each.value["protocol"]
source_security_group_id = each.value["source_security_group_id"] != "" ? each.value["source_security_group_id"] : null
cidr_blocks = length(each.value["cidr_blocks"]) > 0 ? each.value["cidr_blocks"] : null
security_group_id = aws_security_group.infrastructure_ec2_bastion_host[0].id
}
22 changes: 22 additions & 0 deletions ec2-infrastructure-bastion-host.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
resource "aws_instance" "infrastructure_bastion" {
count = local.enable_infrastructure_bastion_host ? 1 : 0

ami = data.aws_ami.bastion_ami[0].id
instance_type = "t3.micro"
subnet_id = local.infrastructure_vpc_network_enable_private ? [for subnet in aws_subnet.infrastructure_private : subnet.id][0] : local.infrastructure_vpc_network_enable_public ? [for subnet in aws_subnet.infrastructure_public : subnet.id][0] : null
user_data_base64 = base64encode(templatefile("${path.root}/ec2-userdata/bastion.tpl", {}))
vpc_security_group_ids = [aws_security_group.infrastructure_ec2_bastion_host[0].id]

root_block_device {
encrypted = true
}

metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}

tags = {
Name = "${local.resource_prefix}-infrastructure-bastion"
}
}
14 changes: 14 additions & 0 deletions ec2-userdata/bastion.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

# Install useful packages
sudo yum update --security -y

if ! command -v aws &> /dev/null
then
sudo yum install -y aws-cli
fi

sudo yum install -y \
jq \
rsync \
vim
3 changes: 3 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ locals {
infrastructure_vpc_transfer_ssm_download_command = "aws s3 cp {{ Source }} {{ HostTarget }} {{ Recursive }}; if [ -n \\\"{{ TargetUID }}\\\" ] && [ -n \\\"{{ TargetGID }}\\\" ]; then chown {{ TargetUID }}:{{ TargetGID }} -R {{ HostTarget }}; fi"
infrastructure_vpc_transfer_ssm_upload_command = "aws s3 cp {{ Source }} {{ S3Target }} {{ Recursive }}"

enable_infrastructure_bastion_host = var.enable_infrastructure_bastion_host
infrastructure_bastion_host_custom_security_group_rules = var.infrastructure_bastion_host_custom_security_group_rules

infrastructure_dockerhub_email = var.infrastructure_dockerhub_email
infrastructure_dockerhub_username = var.infrastructure_dockerhub_username
infrastructure_dockerhub_token = var.infrastructure_dockerhub_token
Expand Down
18 changes: 18 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ variable "infrastructure_vpc_transfer_s3_bucket_access_vpc_ids" {
type = list(string)
}

variable "enable_infrastructure_bastion_host" {
description = "Enable Infrastructure Bastion host. This launches a t3.micro AL2023 instance within the VPC that can be accessed via Session Manager"
type = bool
}

variable "infrastructure_bastion_host_custom_security_group_rules" {
description = "Map of custom security group rules to add to the Infrastructure EC2 Bastion Host security group (eg. { rule-name = {type = \"egress\", ... } })"
type = map(object({
description = string
type = string
from_port = number
to_port = number
protocol = string
source_security_group_id = optional(string, "")
cidr_blocks = optional(list(string), [])
}))
}

variable "route53_root_hosted_zone_domain_name" {
description = "Route53 Hosted Zone in which to delegate Infrastructure Route53 Hosted Zones."
type = string
Expand Down

0 comments on commit e34f487

Please sign in to comment.