Skip to content

Commit 5dc6053

Browse files
committed
Conditionally add ECS cluster SSM policies
* This conditionally adds the policies with permissions required to use SSM default host management configuration. * It checks for the value of the service setting to ensure dhcm has been enabled to decide wether to add the policies. `aws_ssm_service_setting` doesn't yet have a data source (hashicorp/terraform-provider-aws#25170), so it uses a script along with the `external` provider instead, to get the service setting parameters.
1 parent 8bceca6 commit 5dc6053

9 files changed

+157
-1
lines changed

.terraform.lock.hcl

+20-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This project creates and manages resources within an AWS account for infrastruct
1313
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.6.5 |
1414
| <a name="requirement_archive"></a> [archive](#requirement\_archive) | >= 2.4.1 |
1515
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | >= 5.30.0 |
16+
| <a name="requirement_external"></a> [external](#requirement\_external) | >= 2.3.2 |
1617

1718
## Providers
1819

@@ -21,6 +22,7 @@ This project creates and manages resources within an AWS account for infrastruct
2122
| <a name="provider_archive"></a> [archive](#provider\_archive) | 2.4.1 |
2223
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.31.0 |
2324
| <a name="provider_aws.awsroute53root"></a> [aws.awsroute53root](#provider\_aws.awsroute53root) | 5.31.0 |
25+
| <a name="provider_external"></a> [external](#provider\_external) | 2.3.2 |
2426

2527
## Resources
2628

@@ -46,6 +48,8 @@ This project creates and manages resources within an AWS account for infrastruct
4648
| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
4749
| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
4850
| [aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
51+
| [aws_iam_policy.infrastructure_ecs_cluster_pass_role_ssm_dhmc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
52+
| [aws_iam_policy.infrastructure_ecs_cluster_ssm_service_setting_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
4953
| [aws_iam_role.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
5054
| [aws_iam_role.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
5155
| [aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
@@ -58,6 +62,8 @@ This project creates and manages resources within an AWS account for infrastruct
5862
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
5963
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
6064
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
65+
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_pass_role_ssm_dhmc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
66+
| [aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ssm_service_setting_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource |
6167
| [aws_internet_gateway.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
6268
| [aws_kms_alias.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
6369
| [aws_kms_key.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
@@ -108,6 +114,7 @@ This project creates and manages resources within an AWS account for infrastruct
108114
| [aws_ami.ecs_cluster_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
109115
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
110116
| [aws_route53_zone.root](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
117+
| [external_external.ssm_dhmc_setting](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source |
111118

112119
## Inputs
113120

data.tf

+13
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,16 @@ data "aws_ami" "ecs_cluster_ami" {
2626
]
2727
}
2828
}
29+
30+
# aws_ssm_service_setting doesn't yet have a data source, so we need to use
31+
# a script to retrieve SSM service settings
32+
# https://github.com/hashicorp/terraform-provider-aws/issues/25170
33+
data "external" "ssm_dhmc_setting" {
34+
count = local.enable_infrastructure_ecs_cluster ? 1 : 0
35+
36+
program = ["/bin/bash", "external-data-scripts/get-ssm-service-setting.sh"]
37+
38+
query = {
39+
setting_id = "arn:aws:ssm:${local.aws_region}:${local.aws_account_id}:servicesetting/ssm/managed-instance/default-ec2-instance-management-role"
40+
}
41+
}

ecs-cluster-infrastructure.tf

+43
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,43 @@ resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_ec2_ecs" {
126126
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn
127127
}
128128

129+
resource "aws_iam_policy" "infrastructure_ecs_cluster_ssm_service_setting_rw" {
130+
count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
131+
132+
name = "${local.resource_prefix}-ssm-service-setting-rw"
133+
policy = templatefile(
134+
"${path.root}/policies/ssm-service-setting-rw.json.tpl",
135+
{ ssm_service_setting_arn = data.external.ssm_dhmc_setting[0].result.arn }
136+
)
137+
}
138+
139+
resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_ssm_service_setting_rw" {
140+
count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
141+
142+
role = aws_iam_role.infrastructure_ecs_cluster[0].name
143+
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ssm_service_setting_rw[0].arn
144+
}
145+
146+
resource "aws_iam_policy" "infrastructure_ecs_cluster_pass_role_ssm_dhmc" {
147+
count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
148+
149+
name = "${local.resource_prefix}-pass-role-ssm-dhmc"
150+
policy = templatefile(
151+
"${path.root}/policies/pass-role.json.tpl",
152+
{
153+
role_arn = "arn:aws:iam::${local.aws_account_id}:role/${data.external.ssm_dhmc_setting[0].result.setting_value}",
154+
service = "ssm.amazonaws.com"
155+
}
156+
)
157+
}
158+
159+
resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_pass_role_ssm_dhmc" {
160+
count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
161+
162+
role = aws_iam_role.infrastructure_ecs_cluster[0].name
163+
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_pass_role_ssm_dhmc[0].arn
164+
}
165+
129166
resource "aws_iam_instance_profile" "infrastructure_ecs_cluster" {
130167
count = local.enable_infrastructure_ecs_cluster ? 1 : 0
131168

@@ -254,6 +291,12 @@ resource "aws_autoscaling_group" "infrastructure_ecs_cluster" {
254291
timeouts {
255292
delete = "15m"
256293
}
294+
295+
depends_on = [
296+
aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,
297+
aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ssm_service_setting_rw,
298+
aws_iam_role_policy_attachment.infrastructure_ecs_cluster_pass_role_ssm_dhmc,
299+
]
257300
}
258301

259302
resource "aws_sns_topic" "infrastructure_ecs_cluster_autoscaling_lifecycle_termination" {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/bash
2+
3+
set -e
4+
set -o pipefail
5+
6+
eval "$(jq -r '@sh "SSM_SERVICE_SETTING_ID=\(.setting_id)"')"
7+
8+
SERVICE_SETTING="$(aws ssm get-service-setting --setting-id "$SSM_SERVICE_SETTING_ID" | jq -cr '.ServiceSetting')"
9+
10+
#SETTING_ID="$(echo "$SERVICE_SETTING" | jq -cr '.SettingId')"
11+
#SETTING_VALUE="$(echo "$SERVICE_SETTING" | jq -cr 'SettingValue')"
12+
#LAST_MODIFIED_DATE="$(echo "$SERVICE_SETTING" | jq -cr '.LastModifiedDate')"
13+
#LAST_MODIFIED_USER="$(echo "$SERVICE_SETTING" | jq -cr '.LastModifiedUser')"
14+
#ARN="$(echo "$SERVICE_SETTING" | jq -cr '.ARN')"
15+
#STATUS="$(echo "$SERVICE_SETTING" | jq -cr '.Status')"
16+
#
17+
#jq -n \
18+
# --arg setting_id "$SETTING_ID" \
19+
# --arg setting_value "$SETTING_VALUE" \
20+
# --arg last_modified_date "$LAST_MODIFIED_DATE" \
21+
# --arg last_modified_user "$LAST_MODIFIED_USER" \
22+
# --arg arn "$ARN" \
23+
# --arg status "$STATUS" \
24+
# '{
25+
# setting_id =
26+
# }'
27+
28+
jq -ncr --argjson service_setting "$SERVICE_SETTING" \
29+
'$service_setting | {
30+
setting_id: .SettingId,
31+
setting_value: .SettingValue,
32+
last_modified_date: .LastModifiedDate,
33+
last_modified_user: .LastModifiedUser,
34+
arn: .ARN,
35+
status: .Status
36+
}'

locals.tf

+1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ locals {
107107
infrastructure_ecs_cluster_min_size = var.infrastructure_ecs_cluster_min_size
108108
infrastructure_ecs_cluster_max_size = var.infrastructure_ecs_cluster_max_size
109109
infrastructure_ecs_cluster_max_instance_lifetime = var.infrastructure_ecs_cluster_max_instance_lifetime
110+
infrastructure_ecs_cluster_enable_ssm_dhmc = local.enable_infrastructure_ecs_cluster ? data.external.ssm_dhmc_setting[0].result.setting_value != "$None" : ""
110111
infrastructure_ecs_cluster_user_data = base64encode(
111112
templatefile("ec2-userdata/ecs-instance.tpl", {
112113
docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,

policies/pass-role.json.tpl

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Effect": "Allow",
6+
"Action": [
7+
"iam:PassRole"
8+
],
9+
"Resource": "${role_arn}",
10+
"Condition": {
11+
"StringEquals": {
12+
"iam:PassedToService": [
13+
"${service}"
14+
]
15+
}
16+
}
17+
}
18+
]
19+
}
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"Version": "2012-10-17",
3+
"Statement": [
4+
{
5+
"Effect": "Allow",
6+
"Action": [
7+
"ssm:GetServiceSetting",
8+
"ssm:ResetServiceSetting",
9+
"ssm:UpdateServiceSetting"
10+
],
11+
"Resource": "${ssm_service_setting_arn}"
12+
}
13+
]
14+
}

versions.tf

+4
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ terraform {
99
source = "hashicorp/archive"
1010
version = ">= 2.4.1"
1111
}
12+
external = {
13+
source = "hashicorp/external"
14+
version = ">= 2.3.2"
15+
}
1216
}
1317
}

0 commit comments

Comments
 (0)