Skip to content

Commit

Permalink
Conditionally create EFS for ECS cluster
Browse files Browse the repository at this point in the history
* Conditionally creates an EFS file system. This can be used as a shared
  filesystem between the container instances.
* If the ECS cluster has been enabled, it will mount the EFS file system
  onto the instances at `/mnt/efs`
* A list of directories can be provided, which will be created within
  the EFS file system
* A security group is added that allows access from the ECS container
  instances security group. A rule is also added to the ECS container
  instances securit group to allow outbound to the EFS security group.
  • Loading branch information
Stretch96 committed Jan 2, 2024
1 parent a3ab5d8 commit 4fae06b
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 0 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_cloudwatch_log_group.infrastructure_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_default_network_acl.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_network_acl) | resource |
| [aws_ecs_cluster.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource |
| [aws_efs_file_system.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_file_system) | resource |
| [aws_efs_mount_target.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/efs_mount_target) | resource |
| [aws_eip.infrastructure_nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
| [aws_flow_log.infrastructure_vpc_flow_logs_cloudwatch](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
| [aws_flow_log.infrastructure_vpc_flow_logs_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
Expand Down Expand Up @@ -96,12 +98,15 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_s3_bucket_server_side_encryption_configuration.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
| [aws_s3_bucket_versioning.infrastructure_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | 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_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 |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_https_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_https_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_egress_nfs_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_ingress_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_container_instances_ingress_udp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_security_group_rule.infrastructure_ecs_cluster_efs_ingress_nfs_tcp](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource |
| [aws_sns_topic.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource |
| [aws_sns_topic_subscription.ecs_cluster_infrastructure_draining_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription) | resource |
| [aws_subnet.infrastructure_private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
Expand All @@ -118,7 +123,12 @@ This project creates and manages resources within an AWS account for infrastruct
|------|-------------|------|---------|:--------:|
| <a name="input_aws_profile_name_route53_root"></a> [aws\_profile\_name\_route53\_root](#input\_aws\_profile\_name\_route53\_root) | AWS Profile name which is configured for the account in which the root Route53 Hosted Zone exists. | `string` | n/a | yes |
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region in which to launch resources | `string` | n/a | yes |
| <a name="input_ecs_cluster_efs_directories"></a> [ecs\_cluster\_efs\_directories](#input\_ecs\_cluster\_efs\_directories) | ECS cluster EFS directories to create | `list(string)` | n/a | yes |
| <a name="input_ecs_cluster_efs_infrequent_access_transition"></a> [ecs\_cluster\_efs\_infrequent\_access\_transition](#input\_ecs\_cluster\_efs\_infrequent\_access\_transition) | ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition. | `number` | n/a | yes |
| <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_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_efs"></a> [enable\_infrastructure\_ecs\_cluster\_efs](#input\_enable\_infrastructure\_ecs\_cluster\_efs) | Conditionally create and mount EFS to the ECS cluster instances | `bool` | n/a | yes |
| <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_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_dockerhub_email"></a> [infrastructure\_dockerhub\_email](#input\_infrastructure\_dockerhub\_email) | Dockerhub email | `string` | n/a | yes |
Expand Down
11 changes: 11 additions & 0 deletions ec2-userdata/ecs-instance.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,14 @@ fi
sudo yum install -y \
jq \
rsync
%{~ if efs_id != ""}
# EFS
sudo mkdir -p /mnt/efs
sudo yum install -y nfs-utils
echo '${efs_id}.efs.${region}.amazonaws.com:/ /mnt/efs nfs4 nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 0 0' | sudo tee -a /etc/fstab
sudo mount -a
%{if efs_dirs != "" ~}
cd /mnt/efs
mkdir -p ${efs_dirs}
cd ..
%{~ endif}%{endif}
16 changes: 16 additions & 0 deletions ecs-cluster-infrastructure.tf
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,18 @@ resource "aws_security_group_rule" "infrastructure_ecs_cluster_container_instanc
security_group_id = aws_security_group.infrastructure_ecs_cluster_container_instances[0].id
}

resource "aws_security_group_rule" "infrastructure_ecs_cluster_container_instances_egress_nfs_tcp" {
count = local.enable_infrastructure_ecs_cluster && local.enable_infrastructure_ecs_cluster_efs ? 1 : 0

description = "Allow NFS tcp outbound to EFS security group"
type = "egress"
from_port = 2049
to_port = 2049
protocol = "tcp"
source_security_group_id = aws_security_group.infrastructure_ecs_cluster_efs[0].id
security_group_id = aws_security_group.infrastructure_ecs_cluster_container_instances[0].id
}

resource "aws_iam_role" "infrastructure_ecs_cluster" {
count = local.enable_infrastructure_ecs_cluster ? 1 : 0

Expand Down Expand Up @@ -192,6 +204,10 @@ resource "aws_launch_template" "infrastructure_ecs_cluster" {
instance_type = local.infrastructure_ecs_cluster_instance_type

user_data = local.infrastructure_ecs_cluster_user_data

depends_on = [
aws_efs_mount_target.infrastructure_ecs_cluster,
]
}

resource "aws_placement_group" "infrastructure_ecs_cluster" {
Expand Down
54 changes: 54 additions & 0 deletions efs-infrastructure.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
resource "aws_efs_file_system" "infrastructure_ecs_cluster" {
count = local.enable_infrastructure_ecs_cluster_efs ? 1 : 0

encrypted = local.infrastructure_kms_encryption
kms_key_id = local.infrastructure_kms_encryption ? aws_kms_key.infrastructure[0].arn : null
performance_mode = local.ecs_cluster_efs_performance_mode
throughput_mode = local.ecs_cluster_efs_throughput_mode

dynamic "lifecycle_policy" {
for_each = local.ecs_cluster_efs_infrequent_access_transition != 0 ? [1] : []
content {
transition_to_ia = "AFTER_${local.ecs_cluster_efs_infrequent_access_transition}_DAYS"
}
}

dynamic "lifecycle_policy" {
for_each = local.ecs_cluster_efs_infrequent_access_transition != 0 ? [1] : []
content {
transition_to_primary_storage_class = "AFTER_1_ACCESS"
}
}
}

resource "aws_efs_mount_target" "infrastructure_ecs_cluster" {
for_each = local.enable_infrastructure_ecs_cluster_efs ? local.infrastructure_vpc_network_enable_private ? toset([
for subnet in aws_subnet.infrastructure_private : subnet.id
]) : local.infrastructure_vpc_network_enable_public ? toset([
for subnet in aws_subnet.infrastructure_public : subnet.id
]) : [] : []

file_system_id = aws_efs_file_system.infrastructure_ecs_cluster[0].id
subnet_id = each.value
security_groups = local.enable_infrastructure_ecs_cluster ? [aws_security_group.infrastructure_ecs_cluster_efs[0].id] : []
}

resource "aws_security_group" "infrastructure_ecs_cluster_efs" {
count = local.enable_infrastructure_ecs_cluster_efs && local.enable_infrastructure_ecs_cluster ? 1 : 0

name = "${local.resource_prefix}-infrastructure-ecs-cluster-efs"
description = "Infrastructure ECS cluster EFS"
vpc_id = aws_vpc.infrastructure[0].id
}

resource "aws_security_group_rule" "infrastructure_ecs_cluster_efs_ingress_nfs_tcp" {
count = local.enable_infrastructure_ecs_cluster_efs && local.enable_infrastructure_ecs_cluster ? 1 : 0

description = "Allow ECS instances access to EFS (NFS) tcp"
type = "ingress"
from_port = 2049
to_port = 2049
protocol = "tcp"
source_security_group_id = aws_security_group.infrastructure_ecs_cluster_container_instances[0].id
security_group_id = aws_security_group.infrastructure_ecs_cluster_efs[0].id
}
11 changes: 11 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,20 @@ locals {
dockerhub_token = local.infrastructure_dockerhub_token,
dockerhub_email = local.infrastructure_dockerhub_email,
docker_storage_size = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_size
efs_id = local.enable_infrastructure_ecs_cluster_efs && (
local.infrastructure_vpc_network_enable_private || local.infrastructure_vpc_network_enable_public
) ? aws_efs_file_system.infrastructure_ecs_cluster[0].id : "",
region = local.aws_region,
efs_dirs = join(" ", local.ecs_cluster_efs_directories)
})
)

enable_infrastructure_ecs_cluster_efs = var.enable_infrastructure_ecs_cluster_efs && local.infrastructure_vpc
ecs_cluster_efs_performance_mode = var.ecs_cluster_efs_performance_mode
ecs_cluster_efs_throughput_mode = var.ecs_cluster_efs_throughput_mode
ecs_cluster_efs_infrequent_access_transition = var.ecs_cluster_efs_infrequent_access_transition
ecs_cluster_efs_directories = var.ecs_cluster_efs_directories

default_tags = {
Project = local.project_name,
Infrastructure = local.infrastructure_name,
Expand Down
25 changes: 25 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,28 @@ variable "infrastructure_ecs_cluster_autoscaling_time_based_custom" {
})
)
}

variable "enable_infrastructure_ecs_cluster_efs" {
description = "Conditionally create and mount EFS to the ECS cluster instances"
type = bool
}

variable "ecs_cluster_efs_performance_mode" {
description = "ECS cluser EFS performance mode"
type = string
}

variable "ecs_cluster_efs_throughput_mode" {
description = "ECS cluser EFS throughput mode"
type = string
}

variable "ecs_cluster_efs_infrequent_access_transition" {
description = "ECS cluser EFS IA transiton in days. Set to 0 to disable IA transition."
type = number
}

variable "ecs_cluster_efs_directories" {
description = "ECS cluster EFS directories to create"
type = list(string)
}

0 comments on commit 4fae06b

Please sign in to comment.