Terraform启用ECS Exec遇错误:需配置有效taskRoleArn
ECS Exec启用失败的Terraform配置修复方案
启用ECS Exec时触发以下错误:
InvalidParameterException: The service couldn't be updated because a valid taskRoleArn is not being used
问题根源在于ECS Exec要求两个关键条件:
- 任务定义必须指定task_role_arn(原配置仅设置了execution_role_arn)
- 任务角色(Task Role)和执行角色(Execution Role)都需要具备ECS Exec相关权限
以下是修复后的完整Terraform配置,关键修改已标注:
provider "aws" { region = "us-east-1" } resource "aws_ecr_repository" "my_first_ecr_repo" { name = "my-first-ecr-repo" } resource "aws_ecs_cluster" "my_cluster" { name = "my-first-cluster" } # 新增:ECS任务角色(Task Role),用于容器内执行操作 resource "aws_iam_role" "ecsTaskRole" { name = "ecsTaskRole" assume_role_policy = data.aws_iam_policy_document.ecs_task_assume_role.json } data "aws_iam_policy_document" "ecs_task_assume_role" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ecs-tasks.amazonaws.com"] } } } # 新增:给任务角色附加ECS Exec所需权限 resource "aws_iam_role_policy_attachment" "ecs_task_exec_access" { role = aws_iam_role.ecsTaskRole.name policy_arn = "arn:aws:iam::aws:policy/AmazonECSContainerExecutionRolePolicy" } resource "aws_iam_role" "ecsTaskExecutionRole" { name = "ecsTaskExecutionRole" assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json } data "aws_iam_policy_document" "assume_role_policy" { statement { actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["ecs-tasks.amazonaws.com"] } } } resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_policy" { role = aws_iam_role.ecsTaskExecutionRole.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy" } # 新增:给执行角色补充ECS Exec所需的SSM权限 resource "aws_iam_role_policy" "ecs_execution_ssm_policy" { name = "ecs-execution-ssm-policy" role = aws_iam_role.ecsTaskExecutionRole.id policy = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = [ "ssmmessages:CreateControlChannel", "ssmmessages:CreateDataChannel", "ssmmessages:OpenControlChannel", "ssmmessages:OpenDataChannel" ] Resource = "*" } ] }) } resource "aws_default_vpc" "default_vpc" { } resource "aws_default_subnet" "default_subnet_a" { availability_zone = "us-east-1a" } resource "aws_default_subnet" "default_subnet_e" { availability_zone = "us-east-1b" } resource "aws_default_subnet" "default_subnet_f" { availability_zone = "us-east-1c" } resource "aws_ecs_task_definition" "my_first_task" { family = "my-first-task" container_definitions = <<DEFINITION [ { "name": "my-first-task", "image": "${aws_ecr_repository.my_first_ecr_repo.repository_url}", "essential": true, "portMappings": [ { "containerPort": 3000, "hostPort": 3000 } ], "memory": 512, "cpu": 256 } ] DEFINITION requires_compatibilities = ["FARGATE"] network_mode = "awsvpc" memory = 512 cpu = 256 execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn # 修改:新增任务角色ARN指定 task_role_arn = aws_iam_role.ecsTaskRole.arn } resource "aws_ecs_service" "my_first_service" { name = "my-first-service" enable_execute_command = true cluster = aws_ecs_cluster.my_cluster.id task_definition = aws_ecs_task_definition.my_first_task.arn launch_type = "FARGATE" desired_count = 3 load_balancer { target_group_arn = aws_lb_target_group.target_group.arn container_name = aws_ecs_task_definition.my_first_task.family container_port = 3000 } network_configuration { subnets = [aws_default_subnet.default_subnet_a.id, aws_default_subnet.default_subnet_e.id, aws_default_subnet.default_subnet_f.id] assign_public_ip = true security_groups = [aws_security_group.service_security_group.id] } } resource "aws_alb" "application_load_balancer" { name = "test-lb-tf" load_balancer_type = "application" subnets = [ aws_default_subnet.default_subnet_a.id, aws_default_subnet.default_subnet_e.id, aws_default_subnet.default_subnet_f.id ] security_groups = [aws_security_group.load_balancer_security_group.id] } resource "aws_security_group" "service_security_group" { ingress { from_port = 0 to_port = 0 protocol = "-1" security_groups = [aws_security_group.load_balancer_security_group.id] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } # 可选但建议:添加ECS Exec所需的SSM端口出站规则 egress { from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_security_group" "load_balancer_security_group" { ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } } resource "aws_lb_target_group" "target_group" { name = "target-group" port = 80 protocol = "HTTP" target_type = "ip" vpc_id = aws_default_vpc.default_vpc.id health_check { matcher = "200,301,302" path = "/" } } resource "aws_lb_listener" "listener" { load_balancer_arn = aws_alb.application_load_balancer.arn port = "80" protocol = "HTTP" default_action { type = "forward" target_group_arn = aws_lb_target_group.target_group.arn } }
关键修改说明
- 新增任务角色(ecsTaskRole):ECS Exec需要任务角色授予容器内操作权限,附加
AmazonECSContainerExecutionRolePolicy托管策略 - 补充执行角色权限:给ecsTaskExecutionRole添加自定义SSM权限,允许与SSM消息通道交互
- 任务定义指定task_role_arn:在
aws_ecs_task_definition中新增task_role_arn字段,关联创建的任务角色 - 安全组优化:可选添加443端口出站规则,确保容器能连接到SSM服务
部署完成后,可通过以下命令测试ECS Exec:
aws ecs execute-command --cluster my-first-cluster --task <TASK_ID> --container my-first-task --command "/bin/sh" --interactive
内容的提问来源于stack exchange,提问作者aspdev91
相关产品推荐
相关产品推荐

