Skip to content

Commit cf20e81

Browse files
authored
adds secrets-sidecar module (#40)
1 parent 4e70b16 commit cf20e81

File tree

4 files changed

+201
-7
lines changed

4 files changed

+201
-7
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ that is needed.
4040
| [autoscale-time.tf][edat] | Time-based auto scaling | Yes |
4141
| [logs-logzio.tf][edll] | Ship container logs to logz.io | Yes |
4242
| [secretsmanager.tf][edsm] | Add a Secrets Manager secret with a CMK KMS key. Also gives app role and ECS task definition role access to read secrets from Secrets Manager | Yes |
43+
| [secrets-sidecar.tf][ssc] | Adds a task definition configuration for deploying your app along with a sidecar container that writes your secrets manager secret to a file. Note that this is dependent upon opting in to `secretsmanager.tf`. | Yes |
4344
| [ssm-parameters.tf][ssm] | Add a CMK KMS key for use with SSM Parameter Store. Also gives ECS task definition role access to read secrets from parameter store. | Yes |
4445
| [ecs-event-stream.tf][ees] | Add an ECS event log dashboard | Yes |
4546

@@ -141,3 +142,4 @@ $ fargate-create -f terraform.tfvars
141142
[ees]: ./env/dev/ecs-event-stream.tf
142143
[base]: ./base/README.md
143144
[env-dev]: ./env/dev/README.md
145+
[ssc]: secrets-sidecar.tf

env/dev/README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ The optional components can be removed by simply deleting the `.tf` file.
2121
| [autoscale-time.tf][edat] | Time-based auto scaling | Yes |
2222
| [logs-logzio.tf][edll] | Ship container logs to logz.io | Yes |
2323
| [secretsmanager.tf][edsm] | Add a Secrets Manager secret with a CMK KMS key. Also gives app role and ECS task definition role access to read secrets from Secrets Manager | Yes |
24+
| [secrets-sidecar.tf][ssc] | Adds a task definition configuration for deploying your app along with a sidecar container that writes your secrets manager secret to a file. Note that this is dependent upon opting in to `secretsmanager.tf`. | Yes |
2425
| [ssm-parameters.tf][ssm] | Add a CMK KMS key for use with SSM Parameter Store. Also gives ECS task definition role access to read secrets from parameter store. | Yes |
2526

2627

@@ -72,6 +73,8 @@ $ terraform apply
7273
| scale_down_max_capacity | The maximum number of containers to scale down to. | string | `0` | no |
7374
| scale_down_min_capacity | The mimimum number of containers to scale down to. Set this and `scale_down_max_capacity` to 0 to turn off service on the `scale_down_cron` schedule. | string | `0` | no |
7475
| scale_up_cron | Default scale up at 7 am weekdays, this is UTC so it doesn't adjust to daylight savings https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html | string | `cron(0 11 ? * MON-FRI *)` | no |
76+
| secret_dir | directory where secret is written | string | `/var/secret` | yes |
77+
| secret_sidecar_image | sidecar container that writes the secret to a file accessible by app container | string | `quay.io/turner/secretsmanager-sidecar` | yes |
7578
| secrets_saml_users | The users (email addresses) from the saml role to give access | list | - | yes |
7679
| tags | Tags for the infrastructure | map | - | yes |
7780
| vpc | The VPC to use for the Fargate cluster | string | - | yes |
@@ -106,4 +109,5 @@ $ terraform apply
106109
[edsm]: secretsmanager.tf
107110
[alb-docs]: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/application-load-balancers.html
108111
[up]: https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/ScheduledEvents.html
109-
[ssm]: ssm-parameters.tf
112+
[ssm]: ssm-parameters.tf
113+
[ssc]: secrets-sidecar.tf

env/dev/fargate-create.yml

+10-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
# this file is used by fargate-create (https://github.com/turnerlabs/fargate-create)
32
# if not using fargate-create, this file can be ignored/deleted
43

@@ -30,17 +29,22 @@ prompts:
3029
- "logs-logzio.tf"
3130
- "logs-logzio.zip"
3231

32+
- question: "Would you like an ECS event log dashboard?"
33+
default: "yes"
34+
filesToDeleteIfNo:
35+
- "ecs-event-stream.tf"
36+
3337
- question: "Would you like to use Secrets Manager for secrets?"
3438
default: "no"
3539
filesToDeleteIfNo:
3640
- "secretsmanager.tf"
41+
42+
- question: "Would you like a sidecar container that makes your secrets manager secret available as a file?"
43+
default: "no"
44+
filesToDeleteIfNo:
45+
- "secrets-sidecar.tf"
3746

3847
- question: "Would you like to use SSM Parameter Store for secrets?"
3948
default: "no"
4049
filesToDeleteIfNo:
4150
- "ssm-parameters.tf"
42-
43-
- question: "Would you like an ECS event log dashboard?"
44-
default: "yes"
45-
filesToDeleteIfNo:
46-
- "ecs-event-stream.tf"

env/dev/secrets-sidecar.tf

+184
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* This module adds a task definition configuration for deploying your app along with
3+
* a sidecar container that writes your secrets manager secret to an ephemeral file
4+
* that gets bind mounted into your app container. Note that this module is
5+
* dependent upon opting in to the secretsmanager.tf module.
6+
*
7+
* You can deploy this configuration using Fargate CLI:
8+
* fargate service deploy -r x
9+
* where "x" is the revision number that this module outputs (see terraform output)
10+
*
11+
* Note that if you deploy this configuration on top of your existing app,
12+
* you will need to re-deploy your app (image and envvars) afterwards.
13+
* If using fargate-create CLI you can run ./deploy.sh
14+
*
15+
*/
16+
17+
variable "secret_dir" {
18+
type = string
19+
default = "/var/secret"
20+
description = "directory where secret is written"
21+
}
22+
23+
variable "secret_sidecar_image" {
24+
type = string
25+
default = "quay.io/turner/secretsmanager-sidecar"
26+
description = "sidecar container that writes the secret to a file accessible by app container"
27+
}
28+
29+
locals {
30+
secret_file = "${var.secret_dir}/${aws_secretsmanager_secret.sm_secret.name}"
31+
logs_group = "/fargate/service/${var.app}-${var.environment}"
32+
}
33+
34+
resource "aws_ecs_task_definition" "secrets_sidecar" {
35+
family = "${var.app}-${var.environment}"
36+
requires_compatibilities = ["FARGATE"]
37+
network_mode = "awsvpc"
38+
cpu = "256"
39+
memory = "512"
40+
execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn
41+
task_role_arn = aws_iam_role.app_role.arn
42+
43+
volume {
44+
name = "secret"
45+
}
46+
47+
container_definitions = <<DEFINITION
48+
[
49+
{
50+
"name": "${var.container_name}",
51+
"image": "${var.default_backend_image}",
52+
"essential": true,
53+
"dependsOn": [
54+
{
55+
"containerName": "secrets",
56+
"condition": "SUCCESS"
57+
}
58+
],
59+
"portMappings": [
60+
{
61+
"protocol": "tcp",
62+
"containerPort": ${var.container_port},
63+
"hostPort": ${var.container_port}
64+
}
65+
],
66+
"environment": [
67+
{
68+
"name": "PORT",
69+
"value": "${var.container_port}"
70+
},
71+
{
72+
"name": "HEALTHCHECK",
73+
"value": "${var.health_check}"
74+
},
75+
{
76+
"name": "ENABLE_LOGGING",
77+
"value": "false"
78+
},
79+
{
80+
"name": "PRODUCT",
81+
"value": "${var.app}"
82+
},
83+
{
84+
"name": "ENVIRONMENT",
85+
"value": "${var.environment}"
86+
},
87+
{
88+
"name": "SECRET",
89+
"value": "${local.secret_file}"
90+
}
91+
],
92+
"mountPoints": [
93+
{
94+
"readOnly": true,
95+
"containerPath": "${var.secret_dir}",
96+
"sourceVolume": "secret"
97+
}
98+
],
99+
"logConfiguration": {
100+
"logDriver": "awslogs",
101+
"options": {
102+
"awslogs-group": "${local.logs_group}",
103+
"awslogs-region": "us-east-1",
104+
"awslogs-stream-prefix": "ecs"
105+
}
106+
}
107+
},
108+
{
109+
"name": "secrets",
110+
"image": "${var.secret_sidecar_image}",
111+
"essential": false,
112+
"environment": [
113+
{
114+
"name": "SECRET_ID",
115+
"value": "${aws_secretsmanager_secret.sm_secret.arn}"
116+
},
117+
{
118+
"name": "SECRET_FILE",
119+
"value": "${local.secret_file}"
120+
}
121+
],
122+
"mountPoints": [
123+
{
124+
"readOnly": false,
125+
"containerPath": "${var.secret_dir}",
126+
"sourceVolume": "secret"
127+
}
128+
],
129+
"logConfiguration": {
130+
"logDriver": "awslogs",
131+
"options": {
132+
"awslogs-group": "${local.logs_group}",
133+
"awslogs-region": "us-east-1",
134+
"awslogs-stream-prefix": "ecs"
135+
}
136+
}
137+
}
138+
]
139+
DEFINITION
140+
141+
tags = var.tags
142+
143+
# avoid race condition:
144+
#"Too many concurrent attempts to create a new revision of the specified family"
145+
depends_on = [aws_ecs_task_definition.app]
146+
}
147+
148+
data "template_file" "secrets_sidecar_deploy" {
149+
template = <<EOF
150+
#!/bin/bash
151+
set -e
152+
153+
AWS_PROFILE=$${aws_profile}
154+
AWS_DEFAULT_REGION=$${region}
155+
156+
echo "backing up running container configuration"
157+
fargate task describe -t $${current_taskdefinition} > backup.yml
158+
159+
echo "deploying new sidecar configuration"
160+
fargate service deploy -r $${sidecar_revision}
161+
162+
echo "re-deploying app configuration"
163+
fargate service deploy -f backup.yml
164+
fargate service env set -e SECRET=$${secret}
165+
EOF
166+
167+
vars = {
168+
aws_profile = var.aws_profile
169+
region = var.region
170+
current_taskdefinition = aws_ecs_service.app.task_definition
171+
sidecar_revision = split(":", aws_ecs_task_definition.secrets_sidecar.arn)[6]
172+
secret = local.secret_file
173+
}
174+
}
175+
176+
resource "local_file" "secrets_sidecar" {
177+
filename = "secrets-sidecar-deploy.sh"
178+
content = "${data.template_file.secrets_sidecar_deploy.rendered}"
179+
}
180+
181+
# command to deploy the secrets sidecar configuration
182+
output "deploy_secrets_sidecar" {
183+
value = "fargate service deploy --revision ${split(":", aws_ecs_task_definition.secrets_sidecar.arn)[6]}"
184+
}

0 commit comments

Comments
 (0)