From 6918848f1dab99c67e49d21bdc839d907ff8b647 Mon Sep 17 00:00:00 2001 From: Michael Barrientos Date: Wed, 25 Sep 2019 09:47:44 -0700 Subject: [PATCH] [feature] Add ECS modules to cztack (#132) --- aws-ecs-job-fargate/README.md | 45 ++++++ aws-ecs-job-fargate/iam.tf | 58 ++++++++ aws-ecs-job-fargate/main.tf | 87 ++++++++++++ aws-ecs-job-fargate/outputs.tf | 17 +++ aws-ecs-job-fargate/variables.tf | 91 +++++++++++++ aws-ecs-job/README.md | 40 ++++++ aws-ecs-job/iam.tf | 58 ++++++++ aws-ecs-job/main.tf | 72 ++++++++++ aws-ecs-job/outputs.tf | 12 ++ aws-ecs-job/variables.tf | 72 ++++++++++ aws-ecs-service-fargate/README.md | 196 +++++++++++++++++++++++++++ aws-ecs-service-fargate/alb.tf | 112 +++++++++++++++ aws-ecs-service-fargate/discovery.tf | 25 ++++ aws-ecs-service-fargate/domain.tf | 62 +++++++++ aws-ecs-service-fargate/iam.tf | 57 ++++++++ aws-ecs-service-fargate/main.tf | 14 ++ aws-ecs-service-fargate/outputs.tf | 27 ++++ aws-ecs-service-fargate/service.tf | 145 ++++++++++++++++++++ aws-ecs-service-fargate/variables.tf | 192 ++++++++++++++++++++++++++ aws-ecs-service/README.md | 186 +++++++++++++++++++++++++ aws-ecs-service/alb.tf | 119 ++++++++++++++++ aws-ecs-service/discovery.tf | 25 ++++ aws-ecs-service/domain.tf | 62 +++++++++ aws-ecs-service/iam.tf | 57 ++++++++ aws-ecs-service/main.tf | 14 ++ aws-ecs-service/outputs.tf | 27 ++++ aws-ecs-service/service.tf | 147 ++++++++++++++++++++ aws-ecs-service/variables.tf | 186 +++++++++++++++++++++++++ 28 files changed, 2205 insertions(+) create mode 100644 aws-ecs-job-fargate/README.md create mode 100644 aws-ecs-job-fargate/iam.tf create mode 100755 aws-ecs-job-fargate/main.tf create mode 100755 aws-ecs-job-fargate/outputs.tf create mode 100755 aws-ecs-job-fargate/variables.tf create mode 100644 aws-ecs-job/README.md create mode 100644 aws-ecs-job/iam.tf create mode 100755 aws-ecs-job/main.tf create mode 100755 aws-ecs-job/outputs.tf create mode 100755 aws-ecs-job/variables.tf create mode 100644 aws-ecs-service-fargate/README.md create mode 100644 aws-ecs-service-fargate/alb.tf create mode 100644 aws-ecs-service-fargate/discovery.tf create mode 100644 aws-ecs-service-fargate/domain.tf create mode 100644 aws-ecs-service-fargate/iam.tf create mode 100755 aws-ecs-service-fargate/main.tf create mode 100755 aws-ecs-service-fargate/outputs.tf create mode 100644 aws-ecs-service-fargate/service.tf create mode 100755 aws-ecs-service-fargate/variables.tf create mode 100644 aws-ecs-service/README.md create mode 100644 aws-ecs-service/alb.tf create mode 100644 aws-ecs-service/discovery.tf create mode 100644 aws-ecs-service/domain.tf create mode 100644 aws-ecs-service/iam.tf create mode 100755 aws-ecs-service/main.tf create mode 100755 aws-ecs-service/outputs.tf create mode 100644 aws-ecs-service/service.tf create mode 100755 aws-ecs-service/variables.tf diff --git a/aws-ecs-job-fargate/README.md b/aws-ecs-job-fargate/README.md new file mode 100644 index 00000000..b9fd44c9 --- /dev/null +++ b/aws-ecs-job-fargate/README.md @@ -0,0 +1,45 @@ +# ECS Job on Fargate + +This creates an ECS service running on Fargate with no load balancer in front of it. Good for +background worker daemon sort of things. + +## Terraform managed task definition vs czecs + +If the user sets `var.manage_task_definition = true`, Terraform will manage the lifecycle +of the container definition; any external changes are reset on the next Terraform run. + +If var.manage_task_definition = false, the user is expected to manage the +container definition external to Terraform (e.g. using [czecs](https://github.com/chanzuckerberg/czecs)). Upon creation, +Terraform will use a stub definition, but from that point forward will ignore any +changes to the definition, allowing external task definition management. + + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| cluster\_id | | string | n/a | yes | +| container\_name | Name of the container. Must match name in task definition. If omitted, defaults to name derived from project/env/service. | string | `null` | no | +| cpu | CPU units for Fargate task. Used if task_definition provided, or for initial stub task if externally managed. | number | `256` | no | +| deployment\_maximum\_percent | (Optional) The upper limit (as a percentage of the service's desiredCount) of the number of running tasks that can be running in a service during a deployment. Not valid when using the DAEMON scheduling strategy. | number | `200` | no | +| deployment\_minimum\_healthy\_percent | (Optional) The lower limit (as a percentage of the service's desiredCount) of the number of running tasks that must remain running and healthy in a service during a deployment. | number | `100` | no | +| desired\_count | | number | n/a | yes | +| env | Env for tagging and naming. See [doc](../README.md#consistent-tagging). | string | n/a | yes | +| memory | Memory in megabytes for Fargate task. Used if task_definition provided, or for initial stub task if externally managed. | number | `512` | no | +| project | Project for tagging and naming. See [doc](../README.md#consistent-tagging) | string | n/a | yes | +| registry\_secretsmanager\_arn | ARN for AWS Secrets Manager secret for credentials to private registry | string | `null` | no | +| security\_group\_ids | Security group to use for the Fargate task. | list | `` | no | +| service | Service for tagging and naming. See [doc](../README.md#consistent-tagging). | string | n/a | yes | +| task\_definition | JSON to describe task. If omitted, defaults to a stub task that is expected to be managed outside of Terraform. | string | `null` | no | +| task\_role\_arn | | string | n/a | yes | +| task\_subnets | Subnets to launch Fargate task in. | list | `` | no | + +## Outputs + +| Name | Description | +|------|-------------| +| ecs\_service\_arn | ARN for the ECS service. | +| ecs\_task\_definition\_family | The family of the task definition defined for the given/generated container definition. | +| task\_execution\_role\_arn | Task execution role for Fargate task. | + + diff --git a/aws-ecs-job-fargate/iam.tf b/aws-ecs-job-fargate/iam.tf new file mode 100644 index 00000000..4647df90 --- /dev/null +++ b/aws-ecs-job-fargate/iam.tf @@ -0,0 +1,58 @@ +data "aws_iam_policy_document" "execution_role" { + statement { + principals { + type = "Service" + identifiers = ["ecs-tasks.amazonaws.com"] + } + + actions = ["sts:AssumeRole"] + } +} + +# Always create and attach, Fargate requires task definition to have execution role ARN to support log driver awslogs. +resource "aws_iam_role" "task_execution_role" { + name = "${local.name}-execution-role" + assume_role_policy = data.aws_iam_policy_document.execution_role.json +} + +# TODO(mbarrien): We can probably narrow this down to allowing access to only +# the specific ECR arn if applicable, and the specific cloudwatch log group. +# Either pass both identifiers in, or pass the entire role ARN as an argument +resource "aws_iam_role_policy_attachment" "task_execution_role" { + count = var.registry_secretsmanager_arn != null ? 1 : 0 + role = aws_iam_role.task_execution_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +data "aws_iam_policy_document" "registry_secretsmanager" { + count = var.registry_secretsmanager_arn != null ? 1 : 0 + + statement { + actions = [ + "kms:Decrypt", + ] + + resources = [var.registry_secretsmanager_arn] + } + + statement { + actions = [ + "secretsmanager:GetSecretValue", + ] + + # Limit to only current version of the secret + condition { + test = "ForAnyValue:StringEquals" + variable = "secretsmanager:VersionStage" + values = ["AWSCURRENT"] + } + + resources = [var.registry_secretsmanager_arn] + } +} + +resource "aws_iam_role_policy" "task_execution_role_secretsmanager" { + count = var.registry_secretsmanager_arn != null ? 1 : 0 + role = aws_iam_role.task_execution_role.name + policy = data.aws_iam_policy_document.registry_secretsmanager[0].json +} diff --git a/aws-ecs-job-fargate/main.tf b/aws-ecs-job-fargate/main.tf new file mode 100755 index 00000000..89bfb521 --- /dev/null +++ b/aws-ecs-job-fargate/main.tf @@ -0,0 +1,87 @@ +locals { + name = "${var.project}-${var.env}-${var.service}" + + container_name = var.container_name == null ? local.name : var.container_name + + task_definition = "${aws_ecs_task_definition.job.family}:${aws_ecs_task_definition.job.revision}" + + tags = { + managedBy = "terraform" + Name = local.name + project = var.project + env = var.env + service = var.service + owner = var.owner + } +} + +# Only one of the following is active at a time, depending on var.manage_task_definition +resource "aws_ecs_service" "job" { + name = local.name + cluster = var.cluster_id + count = var.manage_task_definition ? 1 : 0 + launch_type = "FARGATE" + + task_definition = local.task_definition + desired_count = var.desired_count + deployment_maximum_percent = var.deployment_maximum_percent + deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent + scheduling_strategy = "REPLICA" + + network_configuration { + subnets = var.task_subnets + security_groups = var.security_group_ids + } + + tags = local.tags +} + +resource "aws_ecs_service" "unmanaged-job" { + name = local.name + cluster = var.cluster_id + count = var.manage_task_definition ? 0 : 1 + launch_type = "FARGATE" + + task_definition = local.task_definition + desired_count = var.desired_count + deployment_maximum_percent = var.deployment_maximum_percent + deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent + scheduling_strategy = "REPLICA" + + network_configuration { + subnets = var.task_subnets + security_groups = var.security_group_ids + } + + lifecycle { + ignore_changes = [task_definition] + } + + tags = local.tags +} + +# Default container definition if var.manage_task_definition == false +# Defaults to a minimal hello-world implementation; should be updated separately from +# Terraform, e.g. using ecs deploy or czecs +locals { + template = <