Skip to content

ecs.ExternalService: enableExecuteCommand is shown as not supported (while in fact it is supported) #31181

@hrko

Description

@hrko

Describe the bug

When creating an ExternalService, specifying the enableExecuteCommand: true option for the property will result in the following error when running cdk synth.

Error: Enable Execute Command options are not supported for External service

However, the enableExecuteCommand option is actually supported by the ExternalService as well, and can be manually enabled using the AWS CLI.

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Version

No response

Expected Behavior

When creating an ExternalService, the enableExecuteCommand: true option can be set for the property.

Current Behavior

When creating an ExternalService, setting the enableExecuteCommand: true option to the property causes an error when executing cdk synth.

Reproduction Steps

A code snippet that reproduces the problem is like as follows:

    const ecsService = new ecs.ExternalService(this, 'ExternalService', {
      serviceName: "EcsAnywhereService",
      cluster: EcsAnywhereCluster,
      taskDefinition,
      desiredCount: 1,
      enableExecuteCommand: true,
    });
Click here to show entire stack code

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as ecs from 'aws-cdk-lib/aws-ecs';
import * as iam from "aws-cdk-lib/aws-iam";
import { CfnOutput } from 'aws-cdk-lib/core';

export class PocEcsAnywhereStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // VPC
    const vpc = new ec2.Vpc(this, "EcsAnywhereVPC", {
      ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16'),
      natGateways: 0,
      maxAzs: 2,
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: "EcsAnywherePublic",
          subnetType: ec2.SubnetType.PUBLIC,
        },
        {
          cidrMask: 24,
          name: "EcsAnywherePrivate",
          subnetType: ec2.SubnetType.PRIVATE_ISOLATED,
        }
      ]
    }
    )

    // ECS Cluster
    const EcsAnywhereCluster = new ecs.Cluster(this, "EcsAnywhereCluster", {
      vpc: vpc,
      clusterName: "EcsAnywhereCluster",

    })

    // Task role
    const taskRole = new iam.Role(this, 'TaskRole', {
      assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'),
    });
    taskRole.addToPolicy(new iam.PolicyStatement({
      actions: [
        // for ECS Exec
        'ssmmessages:CreateControlChannel',
        'ssmmessages:CreateDataChannel',
        'ssmmessages:OpenControlChannel',
        'ssmmessages:OpenDataChannel',
      ],
      resources: ['*'],
    }));

    // ECS task definition
    const taskDefinition = new ecs.ExternalTaskDefinition(this, 'ExternalTaskDefinition', {
      // executionRole: taskExecutionRole,
      taskRole: taskRole,
    });

    taskDefinition.addContainer('NginxContainer', {
      image: ecs.ContainerImage.fromRegistry(
        "public.ecr.aws/nginx/nginx:latest"
      ),
      cpu: 256,
      memoryLimitMiB: 512,
      containerName: "EcsAnywhereContainer",
      // for ECS Exec
      linuxParameters: new ecs.LinuxParameters(this, 'LinuxParameters', {
        initProcessEnabled: true,
      }),
    })

    // ECS service
    const ecsService = new ecs.ExternalService(this, 'ExternalService', {
      serviceName: "EcsAnywhereService",
      cluster: EcsAnywhereCluster,
      taskDefinition,
      desiredCount: 1,
      enableExecuteCommand: true, // for ECS Exec
    });

    // Instance role for ECS Anywhere
    const instance_iam_role = new iam.Role(this, 'EcsAnywhereInstanceRole', {
      roleName: "EcsAnywhereInstanceRole",
      assumedBy: new iam.ServicePrincipal("ssm.amazonaws.com"),
      managedPolicies: [
        iam.ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"),
        iam.ManagedPolicy.fromManagedPolicyArn(this, "EcsAnywhereEC2Policy", "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"),
      ]
    })

    // Output
    new CfnOutput(this, "Step1RegisterExternalInstance", {
      description: "Create an Systems Manager activation pair",
      value: `aws ssm create-activation --iam-role ${instance_iam_role.roleName}`,
      exportName: "1-RegisterExternalInstance",
    })

    const ecsAnywhereInstallScriptUrl = "https://amazon-ecs-agent.s3.amazonaws.com/ecs-anywhere-install-latest.sh"
    new CfnOutput(this, "Step2DownloadInstallationScript", {
      description: "On your VM, download installation script",
      value: `curl -o "ecs-anywhere-install.sh" "${ecsAnywhereInstallScriptUrl}" && sudo chmod +x ecs-anywhere-install.sh`,
      exportName: "2-DownloadInstallationScript",
    });

    new CfnOutput(this, "Step3ExecuteScript", {
      description: "Run installation script on VM",
      value: `sudo ./ecs-anywhere-install.sh  --region ${this.region} --cluster ${EcsAnywhereCluster.clusterName} --activation-id $ACTIVATION_ID --activation-code $ACTIVATION_CODE`,
      exportName: "3-ExecuteInstallationScript",
    });
  }
}

Possible Solution

No response

Additional Information/Context

No response

CDK CLI Version

2.154.0 (build 0fc07f3)

Framework Version

No response

Node.js Version

v20.17.0

OS

Debian GNU/Linux 11 (bullseye)

Language

TypeScript

Language Version

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    @aws-cdk/aws-ecsRelated to Amazon Elastic ContainerbugThis issue is a bug.effort/smallSmall work item – less than a day of effortp2

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions