diff --git a/smoke_tests/ecs_fargate/outputs.tf b/smoke_tests/ecs_fargate/outputs.tf index ebb4c85..05c5064 100644 --- a/smoke_tests/ecs_fargate/outputs.tf +++ b/smoke_tests/ecs_fargate/outputs.tf @@ -29,3 +29,11 @@ output "cws-only" { output "logging-only" { value = module.dd_task_logging_only } + +output "role-parsing-with-path" { + value = module.dd_task_role_parsing_with_path +} + +output "role-parsing-without-path" { + value = module.dd_task_role_parsing_without_path +} diff --git a/smoke_tests/ecs_fargate/role-parsing-with-path.tf b/smoke_tests/ecs_fargate/role-parsing-with-path.tf new file mode 100644 index 0000000..69f224d --- /dev/null +++ b/smoke_tests/ecs_fargate/role-parsing-with-path.tf @@ -0,0 +1,66 @@ +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2025-present Datadog, Inc. + +################################################################################ +# Task Definition: IAM Role with path in name +################################################################################ + +# Create IAM roles with paths to test the parsing logic +resource "aws_iam_role" "test_task_role_with_path" { + name = "${var.test_prefix}-task-role-with-path" + path = "/terraform-test/" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + Action = "sts:AssumeRole" + }] + }) +} + +resource "aws_iam_role" "test_execution_role_with_path" { + name = "${var.test_prefix}-execution-role-with-path" + path = "/terraform-test/" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + Action = "sts:AssumeRole" + }] + }) +} + +# Attach required policies to execution role +resource "aws_iam_role_policy_attachment" "test_execution_role_policy" { + role = aws_iam_role.test_execution_role_with_path.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +module "dd_task_role_parsing_with_path" { + source = "../../modules/ecs_fargate" + + # Use roles with paths to test parsing + task_role = aws_iam_role.test_task_role_with_path + execution_role = { arn = aws_iam_role.test_execution_role_with_path.arn } + + dd_api_key = var.dd_api_key + dd_site = var.dd_site + dd_service = var.dd_service + dd_essential = true + + # Configure Task Definition + family = "${var.test_prefix}-role-parsing-with-path" + container_definitions = jsonencode([]) + + requires_compatibilities = ["FARGATE"] +} diff --git a/smoke_tests/ecs_fargate/role-parsing-without-path.tf b/smoke_tests/ecs_fargate/role-parsing-without-path.tf new file mode 100644 index 0000000..30c3db5 --- /dev/null +++ b/smoke_tests/ecs_fargate/role-parsing-without-path.tf @@ -0,0 +1,66 @@ +# Unless explicitly stated otherwise all files in this repository are licensed +# under the Apache License Version 2.0. +# This product includes software developed at Datadog (https://www.datadoghq.com/). +# Copyright 2025-present Datadog, Inc. + +################################################################################ +# Task Definition: IAM Role without path in name +################################################################################ + +# Create IAM roles without paths to test the parsing logic +resource "aws_iam_role" "test_task_role_without_path" { + name = "${var.test_prefix}-task-role-without-path" + # No path specified - defaults to "/" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + Action = "sts:AssumeRole" + }] + }) +} + +resource "aws_iam_role" "test_execution_role_without_path" { + name = "${var.test_prefix}-execution-role-without-path" + # No path specified - defaults to "/" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [{ + Effect = "Allow" + Principal = { + Service = "ecs-tasks.amazonaws.com" + } + Action = "sts:AssumeRole" + }] + }) +} + +# Attach required policies to execution role +resource "aws_iam_role_policy_attachment" "test_execution_role_policy_no_path" { + role = aws_iam_role.test_execution_role_without_path.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" +} + +module "dd_task_role_parsing_without_path" { + source = "../../modules/ecs_fargate" + + # Use roles without paths to test parsing + task_role = aws_iam_role.test_task_role_without_path + execution_role = { arn = aws_iam_role.test_execution_role_without_path.arn } + + dd_api_key = var.dd_api_key + dd_site = var.dd_site + dd_service = var.dd_service + dd_essential = true + + # Configure Task Definition + family = "${var.test_prefix}-role-parsing-without-path" + container_definitions = jsonencode([]) + + requires_compatibilities = ["FARGATE"] +} diff --git a/tests/role_parsing_test.go b/tests/role_parsing_test.go new file mode 100644 index 0000000..e84e701 --- /dev/null +++ b/tests/role_parsing_test.go @@ -0,0 +1,73 @@ +// Unless explicitly stated otherwise all files in this repository are licensed +// under the Apache License Version 2.0. +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2025-present Datadog, Inc. + +package test + +import ( + "encoding/json" + "log" + "strings" + + "github.com/aws/aws-sdk-go-v2/service/ecs/types" + "github.com/gruntwork-io/terratest/modules/terraform" +) + +// TestRoleParsingWithPath tests that the module correctly parses role names from ARNs with paths +func (s *ECSFargateSuite) TestRoleParsingWithPath() { + log.Println("TestRoleParsingWithPath: Running test...") + + var containers []types.ContainerDefinition + task := terraform.OutputMap(s.T(), s.terraformOptions, "role-parsing-with-path") + + s.Equal(s.testPrefix+"-role-parsing-with-path", task["family"], "Unexpected task family name") + + err := json.Unmarshal([]byte(task["container_definitions"]), &containers) + s.NoError(err, "Failed to parse container definitions") + + s.NotEmpty(task["arn"], "Task definition ARN should not be empty") + s.NotEmpty(task["revision"], "Task definition revision should not be empty") + + taskRoleArn := task["task_role_arn"] + s.NotEmpty(taskRoleArn, "Task role ARN should not be empty") + s.Contains(taskRoleArn, "/terraform-test/", "Task role ARN should contain the path '/test-path/'") + s.Contains(taskRoleArn, s.testPrefix+"-task-role-with-path", "Task role ARN should contain the expected role name") + + executionRoleArn := task["execution_role_arn"] + s.NotEmpty(executionRoleArn, "Execution role ARN should not be empty") + s.Contains(executionRoleArn, "/terraform-test/", "Execution role ARN should contain the path '/terraform-test/'") + s.Contains(executionRoleArn, s.testPrefix+"-execution-role-with-path", "Execution role ARN should contain the expected role name") +} + +// TestRoleParsingWithoutPath tests that the module correctly parses role names from ARNs without paths +func (s *ECSFargateSuite) TestRoleParsingWithoutPath() { + log.Println("TestRoleParsingWithoutPath: Running test...") + + var containers []types.ContainerDefinition + task := terraform.OutputMap(s.T(), s.terraformOptions, "role-parsing-without-path") + + s.Equal(s.testPrefix+"-role-parsing-without-path", task["family"], "Unexpected task family name") + + err := json.Unmarshal([]byte(task["container_definitions"]), &containers) + s.NoError(err, "Failed to parse container definitions") + + s.NotEmpty(task["arn"], "Task definition ARN should not be empty") + s.NotEmpty(task["revision"], "Task definition revision should not be empty") + + taskRoleArn := task["task_role_arn"] + s.NotEmpty(taskRoleArn, "Task role ARN should not be empty") + s.Contains(taskRoleArn, s.testPrefix+"-task-role-without-path", "Task role ARN should contain the expected role name") + + roleArnParts := strings.Split(taskRoleArn, "/") + s.Equal(2, len(roleArnParts), "Role ARN without path should have exactly 2 parts when split by '/'") + s.Contains(roleArnParts[1], s.testPrefix+"-task-role-without-path", "Role name should be the second part after splitting by '/'") + + executionRoleArn := task["execution_role_arn"] + s.NotEmpty(executionRoleArn, "Execution role ARN should not be empty") + s.Contains(executionRoleArn, s.testPrefix+"-execution-role-without-path", "Execution role ARN should contain the expected role name") + + execRoleArnParts := strings.Split(executionRoleArn, "/") + s.Equal(2, len(execRoleArnParts), "Execution role ARN without path should have exactly 2 parts when split by '/'") + s.Contains(execRoleArnParts[1], s.testPrefix+"-execution-role-without-path", "Execution role name should be the second part after splitting by '/'") +}