diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl
index 3632b7b..0bde5bd 100644
--- a/.terraform.lock.hcl
+++ b/.terraform.lock.hcl
@@ -22,7 +22,7 @@ provider "registry.terraform.io/hashicorp/archive" {
provider "registry.terraform.io/hashicorp/aws" {
version = "5.31.0"
- constraints = ">= 5.24.0"
+ constraints = ">= 5.30.0"
hashes = [
"h1:2eauBmfftzGMpzFQn9aHSXiyaO3Ve5cnihmXcKGGpgU=",
"h1:5LaKSMz2FKj/QDz2a+06SHFRu59dMHrarLd1ODzhPMQ=",
@@ -55,3 +55,22 @@ provider "registry.terraform.io/hashicorp/aws" {
"zh:e3127ebd2cb0374cd1808f911e6bffe2f4ac4d84317061381242353f3a7bc27d",
]
}
+
+provider "registry.terraform.io/hashicorp/external" {
+ version = "2.3.2"
+ hashes = [
+ "h1:cy50n4q+Ir4GYppAfuYhQbBJVxMZbJUlIvM6FVK2axs=",
+ "zh:020bf652739ecd841d696e6c1b85ce7dd803e9177136df8fb03aa08b87365389",
+ "zh:0c7ea5a1cbf2e01a8627b8a84df69c93683f39fe947b288e958e72b9d12a827f",
+ "zh:25a68604c7d6aa736d6e99225051279eaac3a7cf4cab33b00ff7eae7096166f6",
+ "zh:34f46d82ca34604f6522de3b36eda19b7ad3be1e38947afc6ac31656eab58c8a",
+ "zh:6959f8f2f3de93e61e0abb90dbec41e28a66daec1607c46f43976bd6da50bcfd",
+ "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
+ "zh:a81e5d65a343da9caa6f1d17ae0aced9faecb36b4f8554bd445dbd4f8be21ab6",
+ "zh:b1d3f1557214d652c9120862ce27e9a7b61cb5aec5537a28240a5a37bf0b1413",
+ "zh:b71588d006471ae2d4a7eca2c51d69fd7c5dec9b088315599b794e2ad0cc5e90",
+ "zh:cfdaae4028b644dff3530c77b49d31f7e6f4c4e2a9e5c8ac6a88e383c80c9e9c",
+ "zh:dbde15154c2eb38a5f54d0e7646bc67510004179696f3cc2bc1d877cecacf83b",
+ "zh:fb681b363f83fb5f64dfa6afbf32d100d0facd2a766cf3493b8ddb0398e1b0f7",
+ ]
+}
diff --git a/README.md b/README.md
index 106087f..4b0ff43 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ This project creates and manages resources within an AWS account for infrastruct
| [terraform](#requirement\_terraform) | >= 1.6.5 |
| [archive](#requirement\_archive) | >= 2.4.1 |
| [aws](#requirement\_aws) | >= 5.30.0 |
+| [external](#requirement\_external) | >= 2.3.2 |
## Providers
@@ -21,6 +22,7 @@ This project creates and manages resources within an AWS account for infrastruct
| [archive](#provider\_archive) | 2.4.1 |
| [aws](#provider\_aws) | 5.31.0 |
| [aws.awsroute53root](#provider\_aws.awsroute53root) | 5.31.0 |
+| [external](#provider\_external) | 2.3.2 |
## Resources
@@ -51,6 +53,8 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_kms_encrypt](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_autoscaling_lifecycle_termination_sns_publish](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy.infrastructure_ecs_cluster_pass_role_ssm_dhmc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_policy.infrastructure_ecs_cluster_ssm_service_setting_rw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
| [aws_iam_role.ecs_cluster_infrastructure_draining_lambda](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.infrastructure_ecs_cluster](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role.infrastructure_ecs_cluster_autoscaling_lifecycle_termination](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
@@ -63,6 +67,8 @@ This project creates and manages resources within an AWS account for infrastruct
| [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 |
| [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 |
| [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 |
+| [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 |
+| [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 |
| [aws_internet_gateway.infrastructure_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
| [aws_kms_alias.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias) | resource |
| [aws_kms_key.infrastructure](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key) | resource |
@@ -116,6 +122,7 @@ This project creates and manages resources within an AWS account for infrastruct
| [aws_ami.ecs_cluster_ami](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami) | data source |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_route53_zone.root](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
+| [external_external.ssm_dhmc_setting](https://registry.terraform.io/providers/hashicorp/external/latest/docs/data-sources/external) | data source |
## Inputs
diff --git a/data.tf b/data.tf
index 921742f..5ecbf9b 100644
--- a/data.tf
+++ b/data.tf
@@ -26,3 +26,16 @@ data "aws_ami" "ecs_cluster_ami" {
]
}
}
+
+# aws_ssm_service_setting doesn't yet have a data source, so we need to use
+# a script to retrieve SSM service settings
+# https://github.com/hashicorp/terraform-provider-aws/issues/25170
+data "external" "ssm_dhmc_setting" {
+ count = local.enable_infrastructure_ecs_cluster ? 1 : 0
+
+ program = ["/bin/bash", "external-data-scripts/get-ssm-service-setting.sh"]
+
+ query = {
+ setting_id = "arn:aws:ssm:${local.aws_region}:${local.aws_account_id}:servicesetting/ssm/managed-instance/default-ec2-instance-management-role"
+ }
+}
diff --git a/ecs-cluster-infrastructure.tf b/ecs-cluster-infrastructure.tf
index 8a06833..d91e3c1 100644
--- a/ecs-cluster-infrastructure.tf
+++ b/ecs-cluster-infrastructure.tf
@@ -138,6 +138,43 @@ resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_ec2_ecs" {
policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ec2_ecs[0].arn
}
+resource "aws_iam_policy" "infrastructure_ecs_cluster_ssm_service_setting_rw" {
+ count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
+
+ name = "${local.resource_prefix}-ssm-service-setting-rw"
+ policy = templatefile(
+ "${path.root}/policies/ssm-service-setting-rw.json.tpl",
+ { ssm_service_setting_arn = data.external.ssm_dhmc_setting[0].result.arn }
+ )
+}
+
+resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_ssm_service_setting_rw" {
+ count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
+
+ role = aws_iam_role.infrastructure_ecs_cluster[0].name
+ policy_arn = aws_iam_policy.infrastructure_ecs_cluster_ssm_service_setting_rw[0].arn
+}
+
+resource "aws_iam_policy" "infrastructure_ecs_cluster_pass_role_ssm_dhmc" {
+ count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
+
+ name = "${local.resource_prefix}-pass-role-ssm-dhmc"
+ policy = templatefile(
+ "${path.root}/policies/pass-role.json.tpl",
+ {
+ role_arn = "arn:aws:iam::${local.aws_account_id}:role/${data.external.ssm_dhmc_setting[0].result.setting_value}",
+ service = "ssm.amazonaws.com"
+ }
+ )
+}
+
+resource "aws_iam_role_policy_attachment" "infrastructure_ecs_cluster_pass_role_ssm_dhmc" {
+ count = local.infrastructure_ecs_cluster_enable_ssm_dhmc ? 1 : 0
+
+ role = aws_iam_role.infrastructure_ecs_cluster[0].name
+ policy_arn = aws_iam_policy.infrastructure_ecs_cluster_pass_role_ssm_dhmc[0].arn
+}
+
resource "aws_iam_instance_profile" "infrastructure_ecs_cluster" {
count = local.enable_infrastructure_ecs_cluster ? 1 : 0
@@ -294,6 +331,12 @@ resource "aws_autoscaling_group" "infrastructure_ecs_cluster" {
"WarmPoolTotalCapacity",
"WarmPoolWarmedCapacity",
]
+
+ depends_on = [
+ aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ec2_ecs,
+ aws_iam_role_policy_attachment.infrastructure_ecs_cluster_ssm_service_setting_rw,
+ aws_iam_role_policy_attachment.infrastructure_ecs_cluster_pass_role_ssm_dhmc,
+ ]
}
resource "aws_sns_topic" "infrastructure_ecs_cluster_autoscaling_lifecycle_termination" {
diff --git a/external-data-scripts/get-ssm-service-setting.sh b/external-data-scripts/get-ssm-service-setting.sh
new file mode 100755
index 0000000..5bc6a77
--- /dev/null
+++ b/external-data-scripts/get-ssm-service-setting.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+set -o pipefail
+
+eval "$(jq -r '@sh "SSM_SERVICE_SETTING_ID=\(.setting_id)"')"
+
+SERVICE_SETTING="$(aws ssm get-service-setting --setting-id "$SSM_SERVICE_SETTING_ID" | jq -cr '.ServiceSetting')"
+
+jq -ncr --argjson service_setting "$SERVICE_SETTING" \
+ '$service_setting | {
+ setting_id: .SettingId,
+ setting_value: .SettingValue,
+ last_modified_date: .LastModifiedDate,
+ last_modified_user: .LastModifiedUser,
+ arn: .ARN,
+ status: .Status
+ }'
diff --git a/locals.tf b/locals.tf
index ca45ce5..d99f294 100644
--- a/locals.tf
+++ b/locals.tf
@@ -112,6 +112,7 @@ locals {
infrastructure_ecs_cluster_autoscaling_time_based_custom = {
for custom in toset(var.infrastructure_ecs_cluster_autoscaling_time_based_custom) : "${custom["min"]}-${custom["max"]} ${custom["cron"]}" => custom
}
+ infrastructure_ecs_cluster_enable_ssm_dhmc = local.enable_infrastructure_ecs_cluster ? data.external.ssm_dhmc_setting[0].result.setting_value != "$None" : ""
infrastructure_ecs_cluster_user_data = base64encode(
templatefile("ec2-userdata/ecs-instance.tpl", {
docker_storage_volume_device_name = local.infrastructure_ecs_cluster_ebs_docker_storage_volume_device_name,
diff --git a/policies/pass-role.json.tpl b/policies/pass-role.json.tpl
new file mode 100644
index 0000000..2d3d8f4
--- /dev/null
+++ b/policies/pass-role.json.tpl
@@ -0,0 +1,19 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "iam:PassRole"
+ ],
+ "Resource": "${role_arn}",
+ "Condition": {
+ "StringEquals": {
+ "iam:PassedToService": [
+ "${service}"
+ ]
+ }
+ }
+ }
+ ]
+}
diff --git a/policies/ssm-service-setting-rw.json.tpl b/policies/ssm-service-setting-rw.json.tpl
new file mode 100644
index 0000000..3d0547f
--- /dev/null
+++ b/policies/ssm-service-setting-rw.json.tpl
@@ -0,0 +1,14 @@
+{
+ "Version": "2012-10-17",
+ "Statement": [
+ {
+ "Effect": "Allow",
+ "Action": [
+ "ssm:GetServiceSetting",
+ "ssm:ResetServiceSetting",
+ "ssm:UpdateServiceSetting"
+ ],
+ "Resource": "${ssm_service_setting_arn}"
+ }
+ ]
+}
diff --git a/versions.tf b/versions.tf
index de5eeef..76f3905 100644
--- a/versions.tf
+++ b/versions.tf
@@ -9,5 +9,9 @@ terraform {
source = "hashicorp/archive"
version = ">= 2.4.1"
}
+ external = {
+ source = "hashicorp/external"
+ version = ">= 2.3.2"
+ }
}
}