diff --git a/examples/secrets/README.md b/examples/secrets/README.md new file mode 100644 index 0000000..0749cdd --- /dev/null +++ b/examples/secrets/README.md @@ -0,0 +1,3 @@ +## examples/secrets + +An example which shows how to inject secrets with of the module. diff --git a/examples/secrets/main.tf b/examples/secrets/main.tf new file mode 100644 index 0000000..59977c8 --- /dev/null +++ b/examples/secrets/main.tf @@ -0,0 +1,128 @@ +# ---------------------------------------- +# Create a ecs service using fargate +# ---------------------------------------- +terraform { + required_version = ">= 0.12" +} + +provider "aws" { + version = ">= 2.17" + region = var.region +} + +data "aws_vpc" "main" { + default = true +} + +data "aws_subnet_ids" "main" { + vpc_id = data.aws_vpc.main.id +} + + +module "fargate_alb" { + source = "telia-oss/loadbalancer/aws" + version = "3.0.0" + + name_prefix = var.name_prefix + type = "application" + internal = false + vpc_id = data.aws_vpc.main.id + subnet_ids = data.aws_subnet_ids.main.ids + + tags = { + environment = "dev" + terraform = "True" + } +} + +resource "aws_lb_listener" "alb" { + load_balancer_arn = module.fargate_alb.arn + port = 80 + protocol = "HTTP" + + default_action { + target_group_arn = module.fargate.target_group_arn + type = "forward" + } +} + +resource "aws_security_group_rule" "task_ingress_8000" { + security_group_id = module.fargate.service_sg_id + type = "ingress" + protocol = "tcp" + from_port = 8000 + to_port = 8000 + source_security_group_id = module.fargate_alb.security_group_id +} + +resource "aws_security_group_rule" "alb_ingress_80" { + security_group_id = module.fargate_alb.security_group_id + type = "ingress" + protocol = "tcp" + from_port = 80 + to_port = 80 + cidr_blocks = ["0.0.0.0/0"] + ipv6_cidr_blocks = ["::/0"] +} + +resource "aws_ecs_cluster" "cluster" { + name = "${var.name_prefix}-cluster" +} + +resource "aws_secretsmanager_secret" "task_container_secrets" { + name = var.name_prefix + kms_key_id = var.task_container_secrets_kms_key +} + +resource "aws_secretsmanager_secret_version" "task_container_secrets" { + secret_id = aws_secretsmanager_secret.task_container_secrets.id + secret_string = "Super secret and important string" +} + +data "aws_secretsmanager_secret" "task_container_secrets" { + arn = aws_secretsmanager_secret.task_container_secrets.arn +} + +data "aws_kms_key" "task_container_secrets" { + key_id = data.aws_secretsmanager_secret.task_container_secrets.kms_key_id +} + +module "fargate" { + source = "../../" + + name_prefix = var.name_prefix + vpc_id = data.aws_vpc.main.id + private_subnet_ids = data.aws_subnet_ids.main.ids + lb_arn = module.fargate_alb.arn + cluster_id = aws_ecs_cluster.cluster.id + task_container_image = "crccheck/hello-world:latest" + + // public ip is needed for default vpc, default is false + task_container_assign_public_ip = true + + // port, default protocol is HTTP + task_container_port = 8000 + + task_container_environment = { + TEST_VARIABLE = "TEST_VALUE" + } + + task_container_secrets_kms_key = data.aws_kms_key.task_container_secrets.key_id + + task_container_secrets = [ + { + name = "TASK_SECRET" + valueFrom = aws_secretsmanager_secret_version.task_container_secrets.arn + } + ] + + health_check = { + port = "traffic-port" + path = "/" + } + + tags = { + environment = "dev" + terraform = "True" + } +} diff --git a/examples/secrets/outputs.tf b/examples/secrets/outputs.tf new file mode 100644 index 0000000..08b6235 --- /dev/null +++ b/examples/secrets/outputs.tf @@ -0,0 +1,11 @@ +output "cluster_arn" { + value = aws_ecs_cluster.cluster.arn +} + +output "service_arn" { + value = module.fargate.service_arn +} + +output "endpoint" { + value = module.fargate_alb.dns_name +} diff --git a/examples/secrets/variables.tf b/examples/secrets/variables.tf new file mode 100644 index 0000000..769ac34 --- /dev/null +++ b/examples/secrets/variables.tf @@ -0,0 +1,15 @@ +variable "name_prefix" { + type = string + default = "fargate-task-secrets-example" +} + +variable "region" { + type = string + default = "eu-west-1" +} + +variable "task_container_secrets_kms_key" { + type = string + description = "" + default = "alias/aws/secretsmanager" +} diff --git a/main.tf b/main.tf index b771a90..aabb2bd 100644 --- a/main.tf +++ b/main.tf @@ -33,6 +33,12 @@ resource "aws_iam_role_policy" "read_repository_credentials" { policy = data.aws_iam_policy_document.read_repository_credentials.json } +resource "aws_iam_role_policy" "read_task_container_secrets" { + name = "${var.name_prefix}-read-task-container-secrets" + role = aws_iam_role.execution.id + policy = data.aws_iam_policy_document.task_container_secrets.json +} + # ------------------------------------------------------------------------------ # IAM - Task role, basic. Users of the module will append policies to this role # when they use the module. S3, Dynamo permissions etc etc. @@ -141,6 +147,9 @@ resource "aws_ecs_task_definition" "task" { "credentialsParameter": "${var.repository_credentials}" }, %{~endif} + %{if length(var.task_container_secrets) > 0~} + "secrets": ${jsonencode(var.task_container_secrets)}, + %{~endif} "essential": true, "portMappings": [ { diff --git a/policies.tf b/policies.tf index e8bf08a..0a9ab1f 100644 --- a/policies.tf +++ b/policies.tf @@ -67,3 +67,22 @@ data "aws_iam_policy_document" "read_repository_credentials" { } } +data "aws_kms_key" "task_container_secrets_key" { + key_id = var.task_container_secrets_kms_key +} + +data "aws_iam_policy_document" "task_container_secrets" { + statement { + effect = "Allow" + + resources = concat( + [data.aws_kms_key.task_container_secrets_key.arn], + [for i in var.task_container_secrets : i["valueFrom"]] + ) + actions = [ + "secretsmanager:GetSecretValue", + "kms:Decrypt", + ] + } +} + diff --git a/test/module_test.go b/test/module_test.go index 90c1683..b27b1af 100644 --- a/test/module_test.go +++ b/test/module_test.go @@ -39,6 +39,27 @@ func TestModule(t *testing.T) { }, }, }, + { + description: "task secrets example", + directory: "../examples/secrets", + name: fmt.Sprintf("fargate-secrets-test-%s", random.UniqueId()), + region: "eu-west-1", + expected: ecs.Expectations{ + DesiredTaskCount: 1, + TaskCPU: 256, + TaskMemory: 512, + NetworkMode: "awsvpc", + ContainerImage: "crccheck/hello-world:latest", + ContainerEnvironment: map[string]string{ + "TEST_VARIABLE": "TEST_VALUE", + }, + HTTPGetResponse: []string{ + `Hello World`, + `~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~`, + `\______ o _,/`, + }, + }, + }, } for _, tc := range tests { diff --git a/variables.tf b/variables.tf index 0c62190..3bb90c7 100644 --- a/variables.tf +++ b/variables.tf @@ -12,6 +12,17 @@ variable "container_name" { type = string } +variable "task_container_secrets" { + type = list(object({ name = string, valueFrom = string })) + default = [] +} + +variable "task_container_secrets_kms_key" { + type = string + description = "" + default = "alias/aws/secretsmanager" +} + variable "vpc_id" { description = "The VPC ID." type = string @@ -133,6 +144,7 @@ variable "repository_credentials" { type = string } + variable "repository_credentials_kms_key" { default = "alias/aws/secretsmanager" description = "key id, key ARN, alias name or alias ARN of the key that encrypted the repository credentials"