Repository: cdklabs/cdk-ecs-service-extensions (language: python)

Issue:
chore(deps): upgrade dependencies
Upgrades project dependencies. See details in [workflow run].

[Workflow Run]: https://github.com/cdklabs/cdk-ecs-service-extensions/actions/runs/2145572044

------

*Automatically created by projen via the "upgrade-main" workflow*


Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 25b0457b..a05e1391 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,3 +51,12 @@ junit.xml
 .jsii
 tsconfig.json
 !/API.md
+test/.tmp
+test/aliased-port.integ.snapshot/asset.*
+test/aliased-port.integ.snapshot/**/asset.*
+test/aliased-port.integ.snapshot/cdk.out
+test/aliased-port.integ.snapshot/**/cdk.out
+test/aliased-port.integ.snapshot/manifest.json
+test/aliased-port.integ.snapshot/**/manifest.json
+test/aliased-port.integ.snapshot/tree.json
+test/aliased-port.integ.snapshot/**/tree.json
diff --git a/.npmignore b/.npmignore
index 2b909372..e5390cbf 100644
--- a/.npmignore
+++ b/.npmignore
@@ -22,3 +22,5 @@ dist
 tsconfig.tsbuildinfo
 /.eslintrc.json
 !.jsii
+test/.tmp
+test/aliased-port.integ.snapshot
diff --git a/.projen/deps.json b/.projen/deps.json
index 55ea8df4..e69ecf10 100644
--- a/.projen/deps.json
+++ b/.projen/deps.json
@@ -22,7 +22,12 @@
     },
     {
       "name": "aws-cdk-lib",
-      "version": "2.8.0",
+      "version": "2.52.0",
+      "type": "build"
+    },
+    {
+      "name": "aws-cdk",
+      "version": "^2",
       "type": "build"
     },
     {
@@ -96,6 +101,10 @@
       "version": "^27",
       "type": "build"
     },
+    {
+      "name": "ts-node",
+      "type": "build"
+    },
     {
       "name": "typescript",
       "type": "build"
@@ -107,7 +116,7 @@
     },
     {
       "name": "aws-cdk-lib",
-      "version": "^2.8.0",
+      "version": "^2.52.0",
       "type": "peer"
     },
     {
diff --git a/.projen/tasks.json b/.projen/tasks.json
index d7c72c22..94e5bece 100644
--- a/.projen/tasks.json
+++ b/.projen/tasks.json
@@ -130,6 +130,78 @@
         }
       ]
     },
+    "integ:aliased-port:assert": {
+      "name": "integ:aliased-port:assert",
+      "description": "assert the snapshot of integration test 'aliased-port'",
+      "steps": [
+        {
+          "exec": "[ -d \"test/aliased-port.integ.snapshot\" ] || (echo \"No snapshot available for integration test 'aliased-port'. Run 'projen integ:aliased-port:deploy' to capture.\" && exit 1)"
+        },
+        {
+          "exec": "cdk synth --app \"ts-node -P tsconfig.dev.json test/aliased-port.integ.ts\" --no-notices --no-version-reporting --no-asset-metadata --no-path-metadata -o test/.tmp/aliased-port.integ/assert.cdk.out > /dev/null"
+        },
+        {
+          "exec": "diff -r -x asset.* -x cdk.out -x manifest.json -x tree.json test/aliased-port.integ.snapshot/ test/.tmp/aliased-port.integ/assert.cdk.out/"
+        }
+      ]
+    },
+    "integ:aliased-port:deploy": {
+      "name": "integ:aliased-port:deploy",
+      "description": "deploy integration test 'aliased-port' and capture snapshot",
+      "steps": [
+        {
+          "exec": "rm -fr test/.tmp/aliased-port.integ/deploy.cdk.out"
+        },
+        {
+          "exec": "cdk deploy --app \"ts-node -P tsconfig.dev.json test/aliased-port.integ.ts\" --no-notices --no-version-reporting --no-asset-metadata --no-path-metadata '**' --require-approval=never -o test/.tmp/aliased-port.integ/deploy.cdk.out"
+        },
+        {
+          "exec": "rm -fr test/aliased-port.integ.snapshot"
+        },
+        {
+          "exec": "mv test/.tmp/aliased-port.integ/deploy.cdk.out test/aliased-port.integ.snapshot"
+        },
+        {
+          "spawn": "integ:aliased-port:destroy"
+        }
+      ]
+    },
+    "integ:aliased-port:destroy": {
+      "name": "integ:aliased-port:destroy",
+      "description": "destroy integration test 'aliased-port'",
+      "steps": [
+        {
+          "exec": "cdk destroy --app test/aliased-port.integ.snapshot '**' --no-version-reporting"
+        }
+      ]
+    },
+    "integ:aliased-port:snapshot": {
+      "name": "integ:aliased-port:snapshot",
+      "description": "update snapshot for integration test \"aliased-port\"",
+      "steps": [
+        {
+          "exec": "cdk synth --app \"ts-node -P tsconfig.dev.json test/aliased-port.integ.ts\" --no-notices --no-version-reporting --no-asset-metadata --no-path-metadata -o test/aliased-port.integ.snapshot > /dev/null"
+        }
+      ]
+    },
+    "integ:aliased-port:watch": {
+      "name": "integ:aliased-port:watch",
+      "description": "watch integration test 'aliased-port' (without updating snapshots)",
+      "steps": [
+        {
+          "exec": "cdk watch --app \"ts-node -P tsconfig.dev.json test/aliased-port.integ.ts\" --no-notices --no-version-reporting --no-asset-metadata --no-path-metadata '**' -o test/.tmp/aliased-port.integ/deploy.cdk.out"
+        }
+      ]
+    },
+    "integ:snapshot-all": {
+      "name": "integ:snapshot-all",
+      "description": "update snapshot for all integration tests",
+      "steps": [
+        {
+          "spawn": "integ:aliased-port:snapshot"
+        }
+      ]
+    },
     "package": {
       "name": "package",
       "description": "Creates the distribution package",
@@ -246,6 +318,9 @@
         },
         {
           "spawn": "eslint"
+        },
+        {
+          "spawn": "integ:aliased-port:assert"
         }
       ]
     },
diff --git a/.projenrc.js b/.projenrc.js
index e363f701..16eca77f 100644
--- a/.projenrc.js
+++ b/.projenrc.js
@@ -5,7 +5,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
   author: 'Amazon Web Services',
   authorAddress: 'https://aws.amazon.com',
   authorOrganization: true,
-  cdkVersion: '2.8.0',
+  cdkVersion: '2.52.0',
   defaultReleaseBranch: 'main',
   description: 'The CDK Construct Library that helps you build ECS services using simple extensions',
   name: 'cdklabs/cdk-ecs-service-extensions',
diff --git a/API.md b/API.md
index 407b382a..4dc1721e 100644
--- a/API.md
+++ b/API.md
@@ -670,6 +670,127 @@ The underlying ECS service that was created.
 
 ## Structs <a name="Structs" id="Structs"></a>
 
+### AliasedPortMutatingHookProps <a name="AliasedPortMutatingHookProps" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps"></a>
+
+#### Initializer <a name="Initializer" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.Initializer"></a>
+
+```typescript
+import { AliasedPortMutatingHookProps } from '@aws-cdk-containers/ecs-service-extensions'
+
+const aliasedPortMutatingHookProps: AliasedPortMutatingHookProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.aliasPort">aliasPort</a></code> | <code>number</code> | The port on the container which receives traffic. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.portMappingName">portMappingName</a></code> | <code>string</code> | The name by which to refer to this port mapping. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.protocol">protocol</a></code> | <code>aws-cdk-lib.aws_ecs.AppProtocol</code> | The protocol which this port mapping expects to receive. |
+
+---
+
+##### `aliasPort`<sup>Required</sup> <a name="aliasPort" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.aliasPort"></a>
+
+```typescript
+public readonly aliasPort: number;
+```
+
+- *Type:* number
+
+The port on the container which receives traffic.
+
+This is the same as the `containerPort` property of port mapping.
+
+---
+
+##### `portMappingName`<sup>Required</sup> <a name="portMappingName" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.portMappingName"></a>
+
+```typescript
+public readonly portMappingName: string;
+```
+
+- *Type:* string
+
+The name by which to refer to this port mapping.
+
+---
+
+##### `protocol`<sup>Optional</sup> <a name="protocol" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps.property.protocol"></a>
+
+```typescript
+public readonly protocol: AppProtocol;
+```
+
+- *Type:* aws-cdk-lib.aws_ecs.AppProtocol
+- *Default:* none
+
+The protocol which this port mapping expects to receive.
+
+---
+
+### AliasedPortProps <a name="AliasedPortProps" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortProps"></a>
+
+AliasedPortProps defines the properties of an aliased port extension.
+
+#### Initializer <a name="Initializer" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.Initializer"></a>
+
+```typescript
+import { AliasedPortProps } from '@aws-cdk-containers/ecs-service-extensions'
+
+const aliasedPortProps: AliasedPortProps = { ... }
+```
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.alias">alias</a></code> | <code>string</code> | The DNS alias to advertise for downstream clients. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.aliasPort">aliasPort</a></code> | <code>number</code> | The traffic port for clients to use to connect to the DNS alias. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.appProtocol">appProtocol</a></code> | <code>aws-cdk-lib.aws_ecs.AppProtocol</code> | The protocol to use over the specified port. |
+
+---
+
+##### `alias`<sup>Required</sup> <a name="alias" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.alias"></a>
+
+```typescript
+public readonly alias: string;
+```
+
+- *Type:* string
+
+The DNS alias to advertise for downstream clients.
+
+---
+
+##### `aliasPort`<sup>Optional</sup> <a name="aliasPort" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.aliasPort"></a>
+
+```typescript
+public readonly aliasPort: number;
+```
+
+- *Type:* number
+- *Default:* same as containerPort.
+
+The traffic port for clients to use to connect to the DNS alias.
+
+---
+
+##### `appProtocol`<sup>Optional</sup> <a name="appProtocol" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortProps.property.appProtocol"></a>
+
+```typescript
+public readonly appProtocol: AppProtocol;
+```
+
+- *Type:* aws-cdk-lib.aws_ecs.AppProtocol
+- *Default:* none
+
+The protocol to use over the specified port.
+
+May be one of HTTP, HTTP2, or GRPC.
+
+---
+
 ### AssignPublicIpDnsOptions <a name="AssignPublicIpDnsOptions" id="@aws-cdk-containers/ecs-service-extensions.AssignPublicIpDnsOptions"></a>
 
 #### Initializer <a name="Initializer" id="@aws-cdk-containers/ecs-service-extensions.AssignPublicIpDnsOptions.Initializer"></a>
@@ -1540,6 +1661,7 @@ const serviceBuild: ServiceBuild = { ... }
 | <code><a href="#@aws-cdk-containers/ecs-service-extensions.ServiceBuild.property.healthCheckGracePeriod">healthCheckGracePeriod</a></code> | <code>aws-cdk-lib.Duration</code> | How long the healthcheck can fail during initial task startup before the task is considered unhealthy. |
 | <code><a href="#@aws-cdk-containers/ecs-service-extensions.ServiceBuild.property.maxHealthyPercent">maxHealthyPercent</a></code> | <code>number</code> | Maximum percentage of tasks that can be launched. |
 | <code><a href="#@aws-cdk-containers/ecs-service-extensions.ServiceBuild.property.minHealthyPercent">minHealthyPercent</a></code> | <code>number</code> | Minimum healthy task percentage. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.ServiceBuild.property.serviceConnectConfiguration">serviceConnectConfiguration</a></code> | <code>aws-cdk-lib.aws_ecs.ServiceConnectProps</code> | Configuration for service connect for this service. |
 
 ---
 
@@ -1650,6 +1772,19 @@ Minimum healthy task percentage.
 
 ---
 
+##### `serviceConnectConfiguration`<sup>Optional</sup> <a name="serviceConnectConfiguration" id="@aws-cdk-containers/ecs-service-extensions.ServiceBuild.property.serviceConnectConfiguration"></a>
+
+```typescript
+public readonly serviceConnectConfiguration: ServiceConnectProps;
+```
+
+- *Type:* aws-cdk-lib.aws_ecs.ServiceConnectProps
+- *Default:* No Service Connect configured.
+
+Configuration for service connect for this service.
+
+---
+
 ### ServiceProps <a name="ServiceProps" id="@aws-cdk-containers/ecs-service-extensions.ServiceProps"></a>
 
 The settings for an ECS Service.
@@ -1849,6 +1984,288 @@ If not provided, the default `eventsQueue` will subscribe to the given topic.
 
 ## Classes <a name="Classes" id="Classes"></a>
 
+### AliasedPortExtension <a name="AliasedPortExtension" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension"></a>
+
+#### Initializers <a name="Initializers" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.Initializer"></a>
+
+```typescript
+import { AliasedPortExtension } from '@aws-cdk-containers/ecs-service-extensions'
+
+new AliasedPortExtension(props: AliasedPortProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.Initializer.parameter.props">props</a></code> | <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortProps">AliasedPortProps</a></code> | *No description.* |
+
+---
+
+##### `props`<sup>Required</sup> <a name="props" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortProps">AliasedPortProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.addContainerMutatingHook">addContainerMutatingHook</a></code> | This hook allows another service extension to register a mutating hook for changing the primary container of this extension. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.addHooks">addHooks</a></code> | A hook that allows the extension to add hooks to other extensions that are registered. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.connectToService">connectToService</a></code> | This hook allows the extension to establish a connection to extensions from another service. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyServiceProps">modifyServiceProps</a></code> | Prior to launching the task definition as a service, this hook is called on each extension to give it a chance to mutate the properties of the service to be created. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyTaskDefinitionProps">modifyTaskDefinitionProps</a></code> | This is a hook which allows extensions to modify the settings of the task definition prior to it being created. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.prehook">prehook</a></code> | A hook that is called for each extension ahead of time to allow for any initial setup, such as creating resources in advance. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.resolveContainerDependencies">resolveContainerDependencies</a></code> | Once all containers are added to the task definition, this hook is called for each extension to give it a chance to resolve its dependency graph so that its container starts in the right order based on the other extensions that were enabled. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useService">useService</a></code> | When this hook is implemented by extension, it allows the extension to use the service which has been created. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useTaskDefinition">useTaskDefinition</a></code> | Once the task definition is created, this hook is called for each extension to give it a chance to add containers to the task definition, change the task definition's role to add permissions, etc. |
+
+---
+
+##### `addContainerMutatingHook` <a name="addContainerMutatingHook" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.addContainerMutatingHook"></a>
+
+```typescript
+public addContainerMutatingHook(hook: ContainerMutatingHook): void
+```
+
+This hook allows another service extension to register a mutating hook for changing the primary container of this extension.
+
+This is primarily used
+for the application extension. For example, the Firelens extension wants to
+be able to modify the settings of the application container to
+route logs through Firelens.
+
+###### `hook`<sup>Required</sup> <a name="hook" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.addContainerMutatingHook.parameter.hook"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.ContainerMutatingHook">ContainerMutatingHook</a>
+
+---
+
+##### `addHooks` <a name="addHooks" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.addHooks"></a>
+
+```typescript
+public addHooks(): void
+```
+
+A hook that allows the extension to add hooks to other extensions that are registered.
+
+##### `connectToService` <a name="connectToService" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.connectToService"></a>
+
+```typescript
+public connectToService(service: Service, connectToProps?: ConnectToProps): void
+```
+
+This hook allows the extension to establish a connection to extensions from another service.
+
+Usually used for things like
+allowing one service to talk to the load balancer or service mesh
+proxy for another service.
+
+###### `service`<sup>Required</sup> <a name="service" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.connectToService.parameter.service"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.Service">Service</a>
+
+The other service to connect to.
+
+---
+
+###### `connectToProps`<sup>Optional</sup> <a name="connectToProps" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.connectToService.parameter.connectToProps"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.ConnectToProps">ConnectToProps</a>
+
+---
+
+##### `modifyServiceProps` <a name="modifyServiceProps" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyServiceProps"></a>
+
+```typescript
+public modifyServiceProps(props: ServiceBuild): ServiceBuild
+```
+
+Prior to launching the task definition as a service, this hook is called on each extension to give it a chance to mutate the properties of the service to be created.
+
+###### `props`<sup>Required</sup> <a name="props" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyServiceProps.parameter.props"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.ServiceBuild">ServiceBuild</a>
+
+---
+
+##### `modifyTaskDefinitionProps` <a name="modifyTaskDefinitionProps" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyTaskDefinitionProps"></a>
+
+```typescript
+public modifyTaskDefinitionProps(props: TaskDefinitionProps): TaskDefinitionProps
+```
+
+This is a hook which allows extensions to modify the settings of the task definition prior to it being created.
+
+For example, the App Mesh
+extension needs to configure an Envoy proxy in the task definition,
+or the Application extension wants to set the overall resource for
+the task.
+
+###### `props`<sup>Required</sup> <a name="props" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.modifyTaskDefinitionProps.parameter.props"></a>
+
+- *Type:* aws-cdk-lib.aws_ecs.TaskDefinitionProps
+
+Properties of the task definition to be created.
+
+---
+
+##### `prehook` <a name="prehook" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.prehook"></a>
+
+```typescript
+public prehook(service: Service, scope: Construct): void
+```
+
+A hook that is called for each extension ahead of time to allow for any initial setup, such as creating resources in advance.
+
+###### `service`<sup>Required</sup> <a name="service" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.prehook.parameter.service"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.Service">Service</a>
+
+---
+
+###### `scope`<sup>Required</sup> <a name="scope" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.prehook.parameter.scope"></a>
+
+- *Type:* constructs.Construct
+
+---
+
+##### `resolveContainerDependencies` <a name="resolveContainerDependencies" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.resolveContainerDependencies"></a>
+
+```typescript
+public resolveContainerDependencies(): void
+```
+
+Once all containers are added to the task definition, this hook is called for each extension to give it a chance to resolve its dependency graph so that its container starts in the right order based on the other extensions that were enabled.
+
+##### `useService` <a name="useService" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useService"></a>
+
+```typescript
+public useService(service: Ec2Service | FargateService): void
+```
+
+When this hook is implemented by extension, it allows the extension to use the service which has been created.
+
+It is generally used to
+create any final resources which might depend on the service itself.
+
+###### `service`<sup>Required</sup> <a name="service" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useService.parameter.service"></a>
+
+- *Type:* aws-cdk-lib.aws_ecs.Ec2Service | aws-cdk-lib.aws_ecs.FargateService
+
+The generated service.
+
+---
+
+##### `useTaskDefinition` <a name="useTaskDefinition" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useTaskDefinition"></a>
+
+```typescript
+public useTaskDefinition(taskDefinition: TaskDefinition): void
+```
+
+Once the task definition is created, this hook is called for each extension to give it a chance to add containers to the task definition, change the task definition's role to add permissions, etc.
+
+###### `taskDefinition`<sup>Required</sup> <a name="taskDefinition" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.useTaskDefinition.parameter.taskDefinition"></a>
+
+- *Type:* aws-cdk-lib.aws_ecs.TaskDefinition
+
+The created task definition to add containers to.
+
+---
+
+
+#### Properties <a name="Properties" id="Properties"></a>
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.property.name">name</a></code> | <code>string</code> | The name of the extension. |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.property.container">container</a></code> | <code>aws-cdk-lib.aws_ecs.ContainerDefinition</code> | The container for this extension. |
+
+---
+
+##### `name`<sup>Required</sup> <a name="name" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.property.name"></a>
+
+```typescript
+public readonly name: string;
+```
+
+- *Type:* string
+
+The name of the extension.
+
+---
+
+##### `container`<sup>Optional</sup> <a name="container" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortExtension.property.container"></a>
+
+```typescript
+public readonly container: ContainerDefinition;
+```
+
+- *Type:* aws-cdk-lib.aws_ecs.ContainerDefinition
+
+The container for this extension.
+
+Most extensions have a container, but not
+every extension is required to have a container. Some extensions may just
+modify the properties of the service, or create external resources
+connected to the service.
+
+---
+
+
+### AliasedPortMutatingHook <a name="AliasedPortMutatingHook" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook"></a>
+
+This hook modifies the application container's settings so that its primary port mapping has a name.
+
+#### Initializers <a name="Initializers" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.Initializer"></a>
+
+```typescript
+import { AliasedPortMutatingHook } from '@aws-cdk-containers/ecs-service-extensions'
+
+new AliasedPortMutatingHook(props: AliasedPortMutatingHookProps)
+```
+
+| **Name** | **Type** | **Description** |
+| --- | --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.Initializer.parameter.props">props</a></code> | <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps">AliasedPortMutatingHookProps</a></code> | *No description.* |
+
+---
+
+##### `props`<sup>Required</sup> <a name="props" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.Initializer.parameter.props"></a>
+
+- *Type:* <a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHookProps">AliasedPortMutatingHookProps</a>
+
+---
+
+#### Methods <a name="Methods" id="Methods"></a>
+
+| **Name** | **Description** |
+| --- | --- |
+| <code><a href="#@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.mutateContainerDefinition">mutateContainerDefinition</a></code> | This is a hook for modifying the container definition of any upstream containers. |
+
+---
+
+##### `mutateContainerDefinition` <a name="mutateContainerDefinition" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.mutateContainerDefinition"></a>
+
+```typescript
+public mutateContainerDefinition(props: ContainerDefinitionOptions): ContainerDefinitionOptions
+```
+
+This is a hook for modifying the container definition of any upstream containers.
+
+This is primarily used for the main application container.
+For example, the Firelens extension wants to be able to modify the logging
+settings of the application container.
+
+###### `props`<sup>Required</sup> <a name="props" id="@aws-cdk-containers/ecs-service-extensions.AliasedPortMutatingHook.mutateContainerDefinition.parameter.props"></a>
+
+- *Type:* aws-cdk-lib.aws_ecs.ContainerDefinitionOptions
+
+---
+
+
+
+
 ### AppMeshExtension <a name="AppMeshExtension" id="@aws-cdk-containers/ecs-service-extensions.AppMeshExtension"></a>
 
 This extension adds an Envoy sidecar to the task definition and creates the App Mesh resources required to route network traffic to the container in a service mesh.
diff --git a/package.json b/package.json
index ecf8d1e8..360c34bc 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,12 @@
     "docgen": "npx projen docgen",
     "eject": "npx projen eject",
     "eslint": "npx projen eslint",
+    "integ:aliased-port:assert": "npx projen integ:aliased-port:assert",
+    "integ:aliased-port:deploy": "npx projen integ:aliased-port:deploy",
+    "integ:aliased-port:destroy": "npx projen integ:aliased-port:destroy",
+    "integ:aliased-port:snapshot": "npx projen integ:aliased-port:snapshot",
+    "integ:aliased-port:watch": "npx projen integ:aliased-port:watch",
+    "integ:snapshot-all": "npx projen integ:snapshot-all",
     "package": "npx projen package",
     "package-all": "npx projen package-all",
     "package:dotnet": "npx projen package:dotnet",
@@ -42,7 +48,8 @@
     "@types/node": "^14",
     "@typescript-eslint/eslint-plugin": "^5",
     "@typescript-eslint/parser": "^5",
-    "aws-cdk-lib": "2.8.0",
+    "aws-cdk": "^2",
+    "aws-cdk-lib": "2.52.0",
     "constructs": "10.0.5",
     "eslint": "^8",
     "eslint-import-resolver-node": "^0.3.6",
@@ -56,13 +63,14 @@
     "jsii-pacmak": "^1.71.0",
     "json-schema": "^0.4.0",
     "npm-check-updates": "^16",
-    "projen": "^0.65.36",
+    "projen": "0.65.33",
     "standard-version": "^9",
     "ts-jest": "^27",
-    "typescript": "^4.9.3"
+    "ts-node": "^10.9.1",
+    "typescript": "^4.8.4"
   },
   "peerDependencies": {
-    "aws-cdk-lib": "^2.8.0",
+    "aws-cdk-lib": "^2.52.0",
     "constructs": "^10.0.5"
   },
   "keywords": [
diff --git a/src/extensions/aliased-port.ts b/src/extensions/aliased-port.ts
new file mode 100644
index 00000000..1f9def11
--- /dev/null
+++ b/src/extensions/aliased-port.ts
@@ -0,0 +1,169 @@
+import * as ecs from 'aws-cdk-lib/aws-ecs';
+import { Construct } from 'constructs';
+import { Service } from '../service';
+import { Container } from './container';
+import { ContainerMutatingHook, ServiceBuild, ServiceExtension } from './extension-interfaces';
+
+
+/**
+ * AliasedPortProps defines the properties of an aliased port extension
+ */
+export interface AliasedPortProps {
+  /**
+   * The DNS alias to advertise for downstream clients.
+   */
+  readonly alias: string;
+  /**
+   * The protocol to use over the specified port.
+   *
+   * May be one of HTTP, HTTP2, or GRPC.
+   *
+   * @default - none
+   */
+  readonly appProtocol?: ecs.AppProtocol;
+
+  /**
+   * The traffic port for clients to use to connect to the DNS alias.
+   *
+   * @default - same as containerPort.
+   */
+  readonly aliasPort?: number;
+}
+
+export class AliasedPortExtension extends ServiceExtension {
+  protected alias: string;
+  protected aliasPort?: number;
+  protected appProtocol?: ecs.AppProtocol;
+  protected namespace?: string;
+
+  constructor(props: AliasedPortProps) {
+    super('aliasedPort');
+
+    this.aliasPort = props.aliasPort;
+    this.alias = props.alias;
+    this.appProtocol = props.appProtocol;
+  }
+
+  public prehook(service: Service, scope: Construct) {
+    this.parentService = service;
+    this.scope = scope;
+
+    // If there isn't a default cloudmap namespace on the cluster, create a private HTTP namespace for SC.
+    if (!this.parentService.cluster.defaultCloudMapNamespace) {
+      this.parentService.environment.addDefaultCloudMapNamespace({
+        name: this.parentService.environment.id,
+      });
+    }
+    this.namespace = this.parentService.environment.cluster.defaultCloudMapNamespace?.namespaceName;
+  }
+
+  public addHooks(): void {
+    const containerextension = this.parentService.serviceDescription.get('service-container') as Container;
+    if (!containerextension) {
+      throw new Error('Aliased Port extension requires a Container extension to already exist.');
+    }
+
+    containerextension.addContainerMutatingHook(new AliasedPortMutatingHook({
+      portMappingName: this.alias,
+      aliasPort: containerextension.trafficPort,
+      protocol: this.appProtocol,
+    }));
+  }
+
+  public modifyServiceProps(props: ServiceBuild): ServiceBuild {
+    if (props.serviceConnectConfiguration && props.serviceConnectConfiguration.namespace !== this.namespace) {
+      throw new Error('Service connect cannot be enabled with two different namespaces.');
+    }
+
+    const containerextension = this.parentService.serviceDescription.get('service-container') as Container;
+
+    if (!containerextension.container) {
+      throw new Error('Parent service must have a container to enable an Aliased Port Extension.');
+    }
+    if (!containerextension.trafficPort && !this.aliasPort) {
+      throw new Error('Cannot infer port: container has no traffic port and aliasPort was not specified.');
+    }
+
+    // If there is already a service connect config, we need to modify the existing properties instead of creating new ones.
+    // Push a new service to the list of services.
+    let services: ecs.ServiceConnectService[] = [];
+    if (props.serviceConnectConfiguration) {
+      services = props.serviceConnectConfiguration.services ? props.serviceConnectConfiguration.services : [];
+    }
+    services.push({
+      portMappingName: this.alias,
+      port: this.aliasPort || containerextension.trafficPort,
+      dnsName: this.alias,
+    });
+    if (!this.parentService.cluster.defaultCloudMapNamespace) {
+      throw new Error('Cluster must have a default CloudMap namespace.');
+    }
+    if (!props.serviceConnectConfiguration) {
+      return {
+        ...props,
+
+        serviceConnectConfiguration: {
+          namespace: this.parentService.cluster.defaultCloudMapNamespace.namespaceName,
+          services,
+        },
+      };
+    }
+
+    return {
+      ...props,
+
+      serviceConnectConfiguration: {
+        ...props.serviceConnectConfiguration,
+        services,
+      },
+    };
+  }
+}
+
+export interface AliasedPortMutatingHookProps {
+  /**
+   * The name by which to refer to this port mapping.
+   */
+  readonly portMappingName: string;
+  /**
+   * The port on the container which receives traffic. This is the same as the `containerPort` property of port mapping.
+   */
+  readonly aliasPort: number;
+  /**
+   * The protocol which this port mapping expects to receive.
+   *
+   * @default - none
+   */
+  readonly protocol?: ecs.AppProtocol;
+}
+
+/**
+ * This hook modifies the application container's settings so that
+ * its primary port mapping has a name.
+ */
+export class AliasedPortMutatingHook extends ContainerMutatingHook {
+  private portMappingName: string;
+  private portMappingProtocol?: ecs.AppProtocol;
+  private aliasPort: number;
+
+  constructor(props: AliasedPortMutatingHookProps) {
+    super();
+    this.portMappingName = props.portMappingName;
+    this.aliasPort = props.aliasPort;
+    this.portMappingProtocol = props.protocol;
+  }
+
+  public mutateContainerDefinition(props: ecs.ContainerDefinitionOptions): ecs.ContainerDefinitionOptions {
+    return {
+      ...props,
+
+      portMappings: [
+        {
+          containerPort: this.aliasPort,
+          name: this.portMappingName,
+          appProtocol: this.portMappingProtocol,
+        },
+      ],
+    } as ecs.ContainerDefinitionOptions;
+  }
+}
diff --git a/src/extensions/container.ts b/src/extensions/container.ts
index 802aa157..603b2795 100644
--- a/src/extensions/container.ts
+++ b/src/extensions/container.ts
@@ -154,10 +154,12 @@ export class Container extends ServiceExtension {
     }
     this.container = taskDefinition.addContainer('app', containerProps);
 
-    // Create a port mapping for the container
-    this.container.addPortMappings({
-      containerPort: this.trafficPort,
-    });
+    // Create a port mapping for the container if not already created by another extension.
+    if (!this.container.findPortMapping(this.trafficPort, ecs.Protocol.TCP)) {
+      this.container.addPortMappings({
+        containerPort: this.trafficPort,
+      });
+    }
 
     // Raise the ulimits for this main application container
     // so that it can handle more concurrent requests
diff --git a/src/extensions/extension-interfaces.ts b/src/extensions/extension-interfaces.ts
index 0fc8c09d..5cfcc901 100644
--- a/src/extensions/extension-interfaces.ts
+++ b/src/extensions/extension-interfaces.ts
@@ -55,6 +55,13 @@ export interface ServiceBuild {
    */
   readonly cloudMapOptions?: ecs.CloudMapOptions;
 
+  /**
+   * Configuration for service connect for this service.
+   *
+   * @default - No Service Connect configured.
+   */
+  readonly serviceConnectConfiguration?: ecs.ServiceConnectProps;
+
   /**
    * How long the healthcheck can fail during initial task startup before
    * the task is considered unhealthy. This is used to give the task more
diff --git a/src/extensions/index.ts b/src/extensions/index.ts
index 2a7a55bb..612464d3 100644
--- a/src/extensions/index.ts
+++ b/src/extensions/index.ts
@@ -8,3 +8,4 @@ export * from './xray';
 export * from './assign-public-ip';
 export * from './queue/queue';
 export * from './injecter';
+export * from './aliased-port';
diff --git a/yarn.lock b/yarn.lock
index 0e50c64f..64f9c583 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10,6 +10,21 @@
     "@jridgewell/gen-mapping" "^0.1.0"
     "@jridgewell/trace-mapping" "^0.3.9"
 
+"@aws-cdk/asset-awscli-v1@^2.2.9":
+  version "2.2.20"
+  resolved "https://registry.yarnpkg.com/@aws-cdk/asset-awscli-v1/-/asset-awscli-v1-2.2.20.tgz#d821c02e316d57cb7432e2e62cef11782647f14b"
+  integrity sha512-ZKrUu3nYWdJt2so6gaOn9aS5ttb/ScDHRe9RBRgCp1DRqtUByL5m++2c7QQrTSIiMjkDHSkB5OO2k+tizACrCQ==
+
+"@aws-cdk/asset-kubectl-v20@^2.1.1":
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/@aws-cdk/asset-kubectl-v20/-/asset-kubectl-v20-2.1.1.tgz#d01c1efb867fb7f2cfd8c8b230b8eae16447e156"
+  integrity sha512-U1ntiX8XiMRRRH5J1IdC+1t5CE89015cwyt5U63Cpk0GnMlN5+h9WsWMlKlPXZR4rdq/m806JRlBMRpBUB2Dhw==
+
+"@aws-cdk/asset-node-proxy-agent-v5@^2.0.15":
+  version "2.0.26"
+  resolved "https://registry.yarnpkg.com/@aws-cdk/asset-node-proxy-agent-v5/-/asset-node-proxy-agent-v5-2.0.26.tgz#73a734ecd72d6582338de42c93b3930e12507d16"
+  integrity sha512-c+5R41bZhMUVnM4t4fqOwV2J9hUqEALuavvM7+JdmLWhvhf/MsW7zxJnF27Krvptubxj8V6pw6rNhiVkUx1nqw==
+
 "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
@@ -295,6 +310,13 @@
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
   integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
 
+"@cspotcode/source-map-support@^0.8.0":
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1"
+  integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==
+  dependencies:
+    "@jridgewell/trace-mapping" "0.3.9"
+
 "@eslint/eslintrc@^1.3.3":
   version "1.3.3"
   resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.3.tgz#2b044ab39fdfa75b4688184f9e573ce3c5b0ff95"
@@ -546,7 +568,7 @@
     "@jridgewell/sourcemap-codec" "^1.4.10"
     "@jridgewell/trace-mapping" "^0.3.9"
 
-"@jridgewell/resolve-uri@3.1.0":
+"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
   integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
@@ -561,6 +583,14 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
+"@jridgewell/trace-mapping@0.3.9":
+  version "0.3.9"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
+  integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.0.3"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+
 "@jridgewell/trace-mapping@^0.3.9":
   version "0.3.17"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
@@ -754,6 +784,26 @@
   resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf"
   integrity sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==
 
+"@tsconfig/node10@^1.0.7":
+  version "1.0.9"
+  resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
+  integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==
+
+"@tsconfig/node12@^1.0.7":
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d"
+  integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==
+
+"@tsconfig/node14@^1.0.0":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1"
+  integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==
+
+"@tsconfig/node16@^1.0.2":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e"
+  integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==
+
 "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
   version "7.1.20"
   resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.20.tgz#e168cdd612c92a2d335029ed62ac94c95b362359"
@@ -787,6 +837,16 @@
   dependencies:
     "@babel/types" "^7.3.0"
 
+"@types/cacheable-request@^6.0.2":
+  version "6.0.3"
+  resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
+  integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
+  dependencies:
+    "@types/http-cache-semantics" "*"
+    "@types/keyv" "^3.1.4"
+    "@types/node" "*"
+    "@types/responselike" "^1.0.0"
+
 "@types/glob@*":
   version "8.0.0"
   resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.0.0.tgz#321607e9cbaec54f687a0792b2d1d370739455d2"
@@ -802,7 +862,7 @@
   dependencies:
     "@types/node" "*"
 
-"@types/http-cache-semantics@^4.0.1":
+"@types/http-cache-semantics@*":
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812"
   integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==
@@ -844,6 +904,13 @@
   resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
   integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
 
+"@types/keyv@^3.1.4":
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
+  integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
+  dependencies:
+    "@types/node" "*"
+
 "@types/minimatch@*":
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
@@ -874,6 +941,13 @@
   resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.0.tgz#efcbd41937f9ae7434c714ab698604822d890759"
   integrity sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==
 
+"@types/responselike@^1.0.0":
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.0.tgz#251f4fe7d154d2bad125abe1b429b23afd262e29"
+  integrity sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==
+  dependencies:
+    "@types/node" "*"
+
 "@types/semver@^7.3.12":
   version "7.3.13"
   resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91"
@@ -1020,12 +1094,17 @@ acorn-walk@^7.1.1:
   resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
   integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
 
+acorn-walk@^8.1.1:
+  version "8.2.0"
+  resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
+  integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
+
 acorn@^7.1.1:
   version "7.4.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
   integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
 
-acorn@^8.2.4, acorn@^8.8.0:
+acorn@^8.2.4, acorn@^8.4.1, acorn@^8.8.0:
   version "8.8.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
   integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==
@@ -1148,6 +1227,11 @@ are-we-there-yet@^3.0.0:
     delegates "^1.0.0"
     readable-stream "^3.6.0"
 
+arg@^4.1.0:
+  version "4.1.3"
+  resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
+  integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
+
 argparse@^1.0.7:
   version "1.0.10"
   resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
@@ -1206,21 +1290,31 @@ at-least-node@^1.0.0:
   resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
   integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
 
-aws-cdk-lib@2.8.0:
-  version "2.8.0"
-  resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.8.0.tgz#11e1d21705bd7b60bd9fdd4e230ddd9202863fd0"
-  integrity sha512-i6vys7oGc77a6LpXuBF3434wyx6X7WUS/BPaRFAf52LWb8PPlq/pSOVP5kkKPgqCElvAzQatqMZuoeT6tbincQ==
+aws-cdk-lib@2.52.0:
+  version "2.52.0"
+  resolved "https://registry.yarnpkg.com/aws-cdk-lib/-/aws-cdk-lib-2.52.0.tgz#6467144aba3ba5db21d127519984b8ab426960ca"
+  integrity sha512-6pIPiDiSsyPAmRxf/EzIHoHkTEfkhr9GPhQgIWAUmlTnQ2hirvdSPpOzqyNUcE9DOEzrir9Kg3kjVqVa0my13Q==
   dependencies:
+    "@aws-cdk/asset-awscli-v1" "^2.2.9"
+    "@aws-cdk/asset-kubectl-v20" "^2.1.1"
+    "@aws-cdk/asset-node-proxy-agent-v5" "^2.0.15"
     "@balena/dockerignore" "^1.0.2"
     case "1.6.3"
     fs-extra "^9.1.0"
     ignore "^5.2.0"
-    jsonschema "^1.4.0"
-    minimatch "^3.0.4"
+    jsonschema "^1.4.1"
+    minimatch "^3.1.2"
     punycode "^2.1.1"
-    semver "^7.3.5"
+    semver "^7.3.8"
     yaml "1.10.2"
 
+aws-cdk@^2:
+  version "2.51.1"
+  resolved "https://registry.yarnpkg.com/aws-cdk/-/aws-cdk-2.51.1.tgz#f836e97b27b3493c2c9c3e36b62f2df6a7d3b946"
+  integrity sha512-c60bIcMfe/gn4qkw/TZvqw+DxVGFn25D624RcciLxIAI/t9v2taaPfIdlCVXDSr3qfy0Oc7GpEh3jL9I/RpVFw==
+  optionalDependencies:
+    fsevents "2.3.2"
+
 babel-jest@^27.5.1:
   version "27.5.1"
   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
@@ -1407,23 +1501,23 @@ cacache@^17.0.0:
     tar "^6.1.11"
     unique-filename "^3.0.0"
 
-cacheable-lookup@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27"
-  integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==
+cacheable-lookup@^6.0.4:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-6.1.0.tgz#0330a543471c61faa4e9035db583aad753b36385"
+  integrity sha512-KJ/Dmo1lDDhmW2XDPMo+9oiy/CeqosPguPCrgcVzKyZrL6pM1gU2GmPY/xo6OQPTUaA/c0kwHuywB4E6nmT9ww==
 
-cacheable-request@^10.2.1:
-  version "10.2.3"
-  resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.3.tgz#25277efe121308ab722c28b4164e51382b4adeb1"
-  integrity sha512-6BehRBOs7iurNjAYN9iPazTwFDaMQavJO8W1MEm3s2pH8q/tkPTtLDRUZaweWK87WFGf2Y5wLAlaCJlR5kOz3w==
+cacheable-request@^7.0.2:
+  version "7.0.2"
+  resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27"
+  integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==
   dependencies:
-    "@types/http-cache-semantics" "^4.0.1"
-    get-stream "^6.0.1"
-    http-cache-semantics "^4.1.0"
-    keyv "^4.5.2"
-    mimic-response "^4.0.0"
-    normalize-url "^8.0.0"
-    responselike "^3.0.0"
+    clone-response "^1.0.2"
+    get-stream "^5.1.0"
+    http-cache-semantics "^4.0.0"
+    keyv "^4.0.0"
+    lowercase-keys "^2.0.0"
+    normalize-url "^6.0.1"
+    responselike "^2.0.0"
 
 call-bind@^1.0.0, call-bind@^1.0.2:
   version "1.0.2"
@@ -1505,9 +1599,9 @@ chownr@^2.0.0:
   integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
 
 ci-info@^3.2.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.7.0.tgz#6d01b3696c59915b6ce057e4aa4adfc2fa25f5ef"
-  integrity sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==
+  version "3.6.2"
+  resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.6.2.tgz#362ea15378f1c39378ba786affbc1c9ef015ecfd"
+  integrity sha512-lVZdhvbEudris15CLytp2u6Y0p5EKfztae9Fqa189MfNmln9F33XuH69v5fvNfiRN5/0eAUz2yJL3mo+nhaRKg==
 
 cjs-module-lexer@^1.0.0:
   version "1.2.2"
@@ -1540,6 +1634,13 @@ cliui@^7.0.2:
     strip-ansi "^6.0.0"
     wrap-ansi "^7.0.0"
 
+clone-response@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
+  integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
+  dependencies:
+    mimic-response "^1.0.0"
+
 clone@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
@@ -1845,6 +1946,11 @@ core-util-is@~1.0.0:
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
   integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
 
+create-require@^1.1.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
+  integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
+
 cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -2026,6 +2132,11 @@ diff-sequences@^27.5.1:
   resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
   integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
 
+diff@^4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
+  integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
+
 dir-glob@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -2108,6 +2219,13 @@ encoding@^0.1.13:
   dependencies:
     iconv-lite "^0.6.2"
 
+end-of-stream@^1.1.0:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+  integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+  dependencies:
+    once "^1.4.0"
+
 entities@~2.0:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f"
@@ -2523,7 +2641,7 @@ flatted@^3.1.0, flatted@^3.2.7:
   resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787"
   integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==
 
-form-data-encoder@^2.1.2:
+form-data-encoder@^2.0.1:
   version "2.1.4"
   resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5"
   integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==
@@ -2582,7 +2700,7 @@ fs.realpath@^1.0.0:
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
   integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
 
-fsevents@^2.3.2:
+fsevents@2.3.2, fsevents@^2.3.2:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
   integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
@@ -2660,6 +2778,13 @@ get-stdin@^8.0.0:
   resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53"
   integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==
 
+get-stream@^5.1.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+  integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+  dependencies:
+    pump "^3.0.0"
+
 get-stream@^6.0.0, get-stream@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
@@ -2783,21 +2908,23 @@ globby@^11.0.4, globby@^11.1.0:
     slash "^3.0.0"
 
 got@^12.1.0:
-  version "12.5.3"
-  resolved "https://registry.yarnpkg.com/got/-/got-12.5.3.tgz#82bdca2dd61258a02e24d668ea6e7abb70ac3598"
-  integrity sha512-8wKnb9MGU8IPGRIo+/ukTy9XLJBwDiCpIf5TVzQ9Cpol50eMTpBq2GAuDsuDIz7hTYmZgMgC1e9ydr6kSDWs3w==
+  version "12.3.1"
+  resolved "https://registry.yarnpkg.com/got/-/got-12.3.1.tgz#79d6ebc0cb8358c424165698ddb828be56e74684"
+  integrity sha512-tS6+JMhBh4iXMSXF6KkIsRxmloPln31QHDlcb6Ec3bzxjjFJFr/8aXdpyuLmVc9I4i2HyBHYw1QU5K1ruUdpkw==
   dependencies:
     "@sindresorhus/is" "^5.2.0"
     "@szmarczak/http-timer" "^5.0.1"
-    cacheable-lookup "^7.0.0"
-    cacheable-request "^10.2.1"
+    "@types/cacheable-request" "^6.0.2"
+    "@types/responselike" "^1.0.0"
+    cacheable-lookup "^6.0.4"
+    cacheable-request "^7.0.2"
     decompress-response "^6.0.0"
-    form-data-encoder "^2.1.2"
+    form-data-encoder "^2.0.1"
     get-stream "^6.0.1"
     http2-wrapper "^2.1.10"
     lowercase-keys "^3.0.0"
     p-cancelable "^3.0.0"
-    responselike "^3.0.0"
+    responselike "^2.0.0"
 
 graceful-fs@4.2.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
   version "4.2.10"
@@ -2915,7 +3042,7 @@ html-escaper@^2.0.0:
   resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
   integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
 
-http-cache-semantics@^4.1.0:
+http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
   integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
@@ -3983,12 +4110,12 @@ jsonparse@^1.2.0, jsonparse@^1.3.1:
   resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
   integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
 
-jsonschema@^1.4.0:
+jsonschema@^1.4.1:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.1.tgz#cc4c3f0077fb4542982973d8a083b6b34f482dab"
   integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==
 
-keyv@^4.5.2:
+keyv@^4.0.0:
   version "4.5.2"
   resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.2.tgz#0e310ce73bf7851ec702f2eaf46ec4e3805cce56"
   integrity sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==
@@ -4114,6 +4241,11 @@ log4js@^6.7.0:
     rfdc "^1.3.0"
     streamroller "^3.1.3"
 
+lowercase-keys@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+  integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
 lowercase-keys@^3.0.0:
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2"
@@ -4138,7 +4270,7 @@ make-dir@^3.0.0:
   dependencies:
     semver "^6.0.0"
 
-make-error@1.x:
+make-error@1.x, make-error@^1.1.1:
   version "1.3.6"
   resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
   integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
@@ -4261,16 +4393,16 @@ mimic-fn@^2.1.0:
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
 
+mimic-response@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+  integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
 mimic-response@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
   integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
 
-mimic-response@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f"
-  integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==
-
 min-indent@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
@@ -4490,10 +4622,10 @@ normalize-path@^3.0.0:
   resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
   integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
 
-normalize-url@^8.0.0:
-  version "8.0.0"
-  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.0.tgz#593dbd284f743e8dcf6a5ddf8fadff149c82701a"
-  integrity sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==
+normalize-url@^6.0.1:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+  integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
 
 npm-bundled@^3.0.0:
   version "3.0.0"
@@ -4640,7 +4772,7 @@ object.values@^1.1.5:
     define-properties "^1.1.4"
     es-abstract "^1.20.4"
 
-once@^1.3.0:
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
   integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
@@ -4925,10 +5057,10 @@ progress@^2.0.3:
   resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
   integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
 
-projen@^0.65.36:
-  version "0.65.36"
-  resolved "https://registry.yarnpkg.com/projen/-/projen-0.65.36.tgz#572ef2d03ecbddaa4f92de13fb35459dc5a05a8e"
-  integrity sha512-veSMieTJYJ43CS7xOLdDnDy4QCkHZpOSmaR9en58rsfoNFqWpF6+ee/ezu8/bl3PoBbutVIRc/wzQjW2uyNCbA==
+projen@0.65.33:
+  version "0.65.33"
+  resolved "https://registry.yarnpkg.com/projen/-/projen-0.65.33.tgz#f2bbcfb85d3601660e36ee8899aaaf96b94b6da5"
+  integrity sha512-i7t7E5kyztGoCXR2BSWRYnREJ7vd1vMeREx7/BH8wZnOm5DF0HSZx/rk2X+bysJfWvPU92iu6kkGTQCGAgLlvw==
   dependencies:
     "@iarna/toml" "^2.2.5"
     case "^1.6.3"
@@ -4984,6 +5116,14 @@ psl@^1.1.33:
   resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
   integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
 
+pump@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
 punycode@^2.1.0, punycode@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
@@ -5221,12 +5361,12 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.0:
     path-parse "^1.0.7"
     supports-preserve-symlinks-flag "^1.0.0"
 
-responselike@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626"
-  integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==
+responselike@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
+  integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
   dependencies:
-    lowercase-keys "^3.0.0"
+    lowercase-keys "^2.0.0"
 
 retry@^0.12.0:
   version "0.12.0"
@@ -5808,6 +5948,25 @@ ts-jest@^27:
     semver "7.x"
     yargs-parser "20.x"
 
+ts-node@^10.9.1:
+  version "10.9.1"
+  resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b"
+  integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
+  dependencies:
+    "@cspotcode/source-map-support" "^0.8.0"
+    "@tsconfig/node10" "^1.0.7"
+    "@tsconfig/node12" "^1.0.7"
+    "@tsconfig/node14" "^1.0.0"
+    "@tsconfig/node16" "^1.0.2"
+    acorn "^8.4.1"
+    acorn-walk "^8.1.1"
+    arg "^4.1.0"
+    create-require "^1.1.0"
+    diff "^4.0.1"
+    make-error "^1.1.1"
+    v8-compile-cache-lib "^3.0.1"
+    yn "3.1.1"
+
 tsconfig-paths@^3.14.1:
   version "3.14.1"
   resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
@@ -5896,7 +6055,7 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==
 
-typescript@^4.9.3:
+typescript@^4.8.4:
   version "4.9.3"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db"
   integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==
@@ -6029,6 +6188,11 @@ uuid@^8.3.2:
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
   integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
 
+v8-compile-cache-lib@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
+  integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==
+
 v8-to-istanbul@^8.1.0:
   version "8.1.1"
   resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"
@@ -6281,6 +6445,11 @@ yargs@^16.0.0, yargs@^16.2.0:
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
+yn@3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
+  integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
+
 yocto-queue@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"


Test patch:
diff --git a/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json b/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json
new file mode 100644
index 00000000..86cbed3e
--- /dev/null
+++ b/test/aliased-port.integ.snapshot/aws-ecs-integ.assets.json
@@ -0,0 +1,19 @@
+{
+  "version": "21.0.0",
+  "files": {
+    "008fd6f37d1eb1900674e08594b06958fad8cce9adf9fc4256765219a4131c01": {
+      "source": {
+        "path": "aws-ecs-integ.template.json",
+        "packaging": "file"
+      },
+      "destinations": {
+        "current_account-current_region": {
+          "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
+          "objectKey": "008fd6f37d1eb1900674e08594b06958fad8cce9adf9fc4256765219a4131c01.json",
+          "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
+        }
+      }
+    }
+  },
+  "dockerImages": {}
+}
\ No newline at end of file
diff --git a/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json b/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json
new file mode 100644
index 00000000..e9da4e54
--- /dev/null
+++ b/test/aliased-port.integ.snapshot/aws-ecs-integ.template.json
@@ -0,0 +1,583 @@
+{
+ "Resources": {
+  "productionenvironmentvpcAEB47DF7": {
+   "Type": "AWS::EC2::VPC",
+   "Properties": {
+    "CidrBlock": "10.0.0.0/16",
+    "EnableDnsHostnames": true,
+    "EnableDnsSupport": true,
+    "InstanceTenancy": "default",
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet1Subnet8D92C089": {
+   "Type": "AWS::EC2::Subnet",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "AvailabilityZone": {
+     "Fn::Select": [
+      0,
+      {
+       "Fn::GetAZs": ""
+      }
+     ]
+    },
+    "CidrBlock": "10.0.0.0/18",
+    "MapPublicIpOnLaunch": true,
+    "Tags": [
+     {
+      "Key": "aws-cdk:subnet-name",
+      "Value": "Public"
+     },
+     {
+      "Key": "aws-cdk:subnet-type",
+      "Value": "Public"
+     },
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet1"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet1RouteTable6E9ABC21": {
+   "Type": "AWS::EC2::RouteTable",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet1"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet1RouteTableAssociationA8117374": {
+   "Type": "AWS::EC2::SubnetRouteTableAssociation",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPublicSubnet1RouteTable6E9ABC21"
+    },
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089"
+    }
+   }
+  },
+  "productionenvironmentvpcPublicSubnet1DefaultRoute524C894D": {
+   "Type": "AWS::EC2::Route",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPublicSubnet1RouteTable6E9ABC21"
+    },
+    "DestinationCidrBlock": "0.0.0.0/0",
+    "GatewayId": {
+     "Ref": "productionenvironmentvpcIGWE7C39890"
+    }
+   },
+   "DependsOn": [
+    "productionenvironmentvpcVPCGW1B428D07"
+   ]
+  },
+  "productionenvironmentvpcPublicSubnet1EIP54BA88DB": {
+   "Type": "AWS::EC2::EIP",
+   "Properties": {
+    "Domain": "vpc",
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet1"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet1NATGateway6075E4CA": {
+   "Type": "AWS::EC2::NatGateway",
+   "Properties": {
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPublicSubnet1Subnet8D92C089"
+    },
+    "AllocationId": {
+     "Fn::GetAtt": [
+      "productionenvironmentvpcPublicSubnet1EIP54BA88DB",
+      "AllocationId"
+     ]
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet1"
+     }
+    ]
+   },
+   "DependsOn": [
+    "productionenvironmentvpcPublicSubnet1DefaultRoute524C894D",
+    "productionenvironmentvpcPublicSubnet1RouteTableAssociationA8117374"
+   ]
+  },
+  "productionenvironmentvpcPublicSubnet2Subnet298E6C31": {
+   "Type": "AWS::EC2::Subnet",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "AvailabilityZone": {
+     "Fn::Select": [
+      1,
+      {
+       "Fn::GetAZs": ""
+      }
+     ]
+    },
+    "CidrBlock": "10.0.64.0/18",
+    "MapPublicIpOnLaunch": true,
+    "Tags": [
+     {
+      "Key": "aws-cdk:subnet-name",
+      "Value": "Public"
+     },
+     {
+      "Key": "aws-cdk:subnet-type",
+      "Value": "Public"
+     },
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet2"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet2RouteTable842A68D7": {
+   "Type": "AWS::EC2::RouteTable",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet2"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet2RouteTableAssociation0A7549F3": {
+   "Type": "AWS::EC2::SubnetRouteTableAssociation",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPublicSubnet2RouteTable842A68D7"
+    },
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31"
+    }
+   }
+  },
+  "productionenvironmentvpcPublicSubnet2DefaultRoute92CD697D": {
+   "Type": "AWS::EC2::Route",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPublicSubnet2RouteTable842A68D7"
+    },
+    "DestinationCidrBlock": "0.0.0.0/0",
+    "GatewayId": {
+     "Ref": "productionenvironmentvpcIGWE7C39890"
+    }
+   },
+   "DependsOn": [
+    "productionenvironmentvpcVPCGW1B428D07"
+   ]
+  },
+  "productionenvironmentvpcPublicSubnet2EIP14CA46AA": {
+   "Type": "AWS::EC2::EIP",
+   "Properties": {
+    "Domain": "vpc",
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet2"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPublicSubnet2NATGatewayE1850FCC": {
+   "Type": "AWS::EC2::NatGateway",
+   "Properties": {
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPublicSubnet2Subnet298E6C31"
+    },
+    "AllocationId": {
+     "Fn::GetAtt": [
+      "productionenvironmentvpcPublicSubnet2EIP14CA46AA",
+      "AllocationId"
+     ]
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PublicSubnet2"
+     }
+    ]
+   },
+   "DependsOn": [
+    "productionenvironmentvpcPublicSubnet2DefaultRoute92CD697D",
+    "productionenvironmentvpcPublicSubnet2RouteTableAssociation0A7549F3"
+   ]
+  },
+  "productionenvironmentvpcPrivateSubnet1Subnet53F632E6": {
+   "Type": "AWS::EC2::Subnet",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "AvailabilityZone": {
+     "Fn::Select": [
+      0,
+      {
+       "Fn::GetAZs": ""
+      }
+     ]
+    },
+    "CidrBlock": "10.0.128.0/18",
+    "MapPublicIpOnLaunch": false,
+    "Tags": [
+     {
+      "Key": "aws-cdk:subnet-name",
+      "Value": "Private"
+     },
+     {
+      "Key": "aws-cdk:subnet-type",
+      "Value": "Private"
+     },
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PrivateSubnet1"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet1RouteTable2C6DFF0C": {
+   "Type": "AWS::EC2::RouteTable",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PrivateSubnet1"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet1RouteTableAssociation8BA32463": {
+   "Type": "AWS::EC2::SubnetRouteTableAssociation",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet1RouteTable2C6DFF0C"
+    },
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet1Subnet53F632E6"
+    }
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet1DefaultRouteFBB3DE6C": {
+   "Type": "AWS::EC2::Route",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet1RouteTable2C6DFF0C"
+    },
+    "DestinationCidrBlock": "0.0.0.0/0",
+    "NatGatewayId": {
+     "Ref": "productionenvironmentvpcPublicSubnet1NATGateway6075E4CA"
+    }
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet2Subnet756FB93C": {
+   "Type": "AWS::EC2::Subnet",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "AvailabilityZone": {
+     "Fn::Select": [
+      1,
+      {
+       "Fn::GetAZs": ""
+      }
+     ]
+    },
+    "CidrBlock": "10.0.192.0/18",
+    "MapPublicIpOnLaunch": false,
+    "Tags": [
+     {
+      "Key": "aws-cdk:subnet-name",
+      "Value": "Private"
+     },
+     {
+      "Key": "aws-cdk:subnet-type",
+      "Value": "Private"
+     },
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PrivateSubnet2"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet2RouteTable2F77D0D2": {
+   "Type": "AWS::EC2::RouteTable",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc/PrivateSubnet2"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet2RouteTableAssociation09188261": {
+   "Type": "AWS::EC2::SubnetRouteTableAssociation",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet2RouteTable2F77D0D2"
+    },
+    "SubnetId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet2Subnet756FB93C"
+    }
+   }
+  },
+  "productionenvironmentvpcPrivateSubnet2DefaultRoute5F9AB6C1": {
+   "Type": "AWS::EC2::Route",
+   "Properties": {
+    "RouteTableId": {
+     "Ref": "productionenvironmentvpcPrivateSubnet2RouteTable2F77D0D2"
+    },
+    "DestinationCidrBlock": "0.0.0.0/0",
+    "NatGatewayId": {
+     "Ref": "productionenvironmentvpcPublicSubnet2NATGatewayE1850FCC"
+    }
+   }
+  },
+  "productionenvironmentvpcIGWE7C39890": {
+   "Type": "AWS::EC2::InternetGateway",
+   "Properties": {
+    "Tags": [
+     {
+      "Key": "Name",
+      "Value": "aws-ecs-integ/production-environment-vpc"
+     }
+    ]
+   }
+  },
+  "productionenvironmentvpcVPCGW1B428D07": {
+   "Type": "AWS::EC2::VPCGatewayAttachment",
+   "Properties": {
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    },
+    "InternetGatewayId": {
+     "Ref": "productionenvironmentvpcIGWE7C39890"
+    }
+   }
+  },
+  "productionenvironmentclusterC6599D2D": {
+   "Type": "AWS::ECS::Cluster"
+  },
+  "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D": {
+   "Type": "AWS::ServiceDiscovery::PrivateDnsNamespace",
+   "Properties": {
+    "Name": "production",
+    "Vpc": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    }
+   }
+  },
+  "ServiceConnecttaskdefinitionTaskRole9F4C55FD": {
+   "Type": "AWS::IAM::Role",
+   "Properties": {
+    "AssumeRolePolicyDocument": {
+     "Statement": [
+      {
+       "Action": "sts:AssumeRole",
+       "Effect": "Allow",
+       "Principal": {
+        "Service": "ecs-tasks.amazonaws.com"
+       }
+      }
+     ],
+     "Version": "2012-10-17"
+    }
+   }
+  },
+  "ServiceConnecttaskdefinitionB19E0536": {
+   "Type": "AWS::ECS::TaskDefinition",
+   "Properties": {
+    "ContainerDefinitions": [
+     {
+      "Cpu": 256,
+      "Environment": [
+       {
+        "Name": "PORT",
+        "Value": "80"
+       }
+      ],
+      "Essential": true,
+      "Image": "nathanpeck/name",
+      "Memory": 512,
+      "Name": "app",
+      "PortMappings": [
+       {
+        "AppProtocol": "grpc",
+        "ContainerPort": 80,
+        "Name": "name",
+        "Protocol": "tcp"
+       }
+      ],
+      "Ulimits": [
+       {
+        "HardLimit": 1024000,
+        "Name": "nofile",
+        "SoftLimit": 1024000
+       }
+      ]
+     }
+    ],
+    "Cpu": "256",
+    "Family": "awsecsintegServiceConnecttaskdefinitionCE44FAD5",
+    "Memory": "512",
+    "NetworkMode": "awsvpc",
+    "RequiresCompatibilities": [
+     "EC2",
+     "FARGATE"
+    ],
+    "TaskRoleArn": {
+     "Fn::GetAtt": [
+      "ServiceConnecttaskdefinitionTaskRole9F4C55FD",
+      "Arn"
+     ]
+    }
+   }
+  },
+  "ServiceConnectserviceService9DF17EC6": {
+   "Type": "AWS::ECS::Service",
+   "Properties": {
+    "Cluster": {
+     "Ref": "productionenvironmentclusterC6599D2D"
+    },
+    "DeploymentConfiguration": {
+     "MaximumPercent": 200,
+     "MinimumHealthyPercent": 100
+    },
+    "DesiredCount": 1,
+    "EnableECSManagedTags": false,
+    "LaunchType": "FARGATE",
+    "NetworkConfiguration": {
+     "AwsvpcConfiguration": {
+      "AssignPublicIp": "DISABLED",
+      "SecurityGroups": [
+       {
+        "Fn::GetAtt": [
+         "ServiceConnectserviceSecurityGroup0D1FCAE3",
+         "GroupId"
+        ]
+       }
+      ],
+      "Subnets": [
+       {
+        "Ref": "productionenvironmentvpcPrivateSubnet1Subnet53F632E6"
+       },
+       {
+        "Ref": "productionenvironmentvpcPrivateSubnet2Subnet756FB93C"
+       }
+      ]
+     }
+    },
+    "ServiceConnectConfiguration": {
+     "Enabled": true,
+     "Namespace": "production",
+     "Services": [
+      {
+       "ClientAliases": [
+        {
+         "DnsName": "name",
+         "Port": 1000
+        }
+       ],
+       "PortName": "name"
+      }
+     ]
+    },
+    "TaskDefinition": {
+     "Ref": "ServiceConnecttaskdefinitionB19E0536"
+    }
+   },
+   "DependsOn": [
+    "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D"
+   ]
+  },
+  "ServiceConnectserviceSecurityGroup0D1FCAE3": {
+   "Type": "AWS::EC2::SecurityGroup",
+   "Properties": {
+    "GroupDescription": "aws-ecs-integ/ServiceConnect-service/SecurityGroup",
+    "SecurityGroupEgress": [
+     {
+      "CidrIp": "0.0.0.0/0",
+      "Description": "Allow all outbound traffic by default",
+      "IpProtocol": "-1"
+     }
+    ],
+    "VpcId": {
+     "Ref": "productionenvironmentvpcAEB47DF7"
+    }
+   },
+   "DependsOn": [
+    "productionenvironmentclusterDefaultServiceDiscoveryNamespaceBE74D64D"
+   ]
+  }
+ },
+ "Parameters": {
+  "BootstrapVersion": {
+   "Type": "AWS::SSM::Parameter::Value<String>",
+   "Default": "/cdk-bootstrap/hnb659fds/version",
+   "Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]"
+  }
+ },
+ "Rules": {
+  "CheckBootstrapVersion": {
+   "Assertions": [
+    {
+     "Assert": {
+      "Fn::Not": [
+       {
+        "Fn::Contains": [
+         [
+          "1",
+          "2",
+          "3",
+          "4",
+          "5"
+         ],
+         {
+          "Ref": "BootstrapVersion"
+         }
+        ]
+       }
+      ]
+     },
+     "AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI."
+    }
+   ]
+  }
+ }
+}
\ No newline at end of file
diff --git a/test/aliased-port.integ.ts b/test/aliased-port.integ.ts
new file mode 100644
index 00000000..f3d74614
--- /dev/null
+++ b/test/aliased-port.integ.ts
@@ -0,0 +1,37 @@
+import { App, Stack } from 'aws-cdk-lib';
+import * as ecs from 'aws-cdk-lib/aws-ecs';
+import { AliasedPortExtension, Container, Environment, EnvironmentCapacityType, Service, ServiceDescription } from '../lib';
+
+const app = new App();
+const stack = new Stack(app, 'aws-ecs-integ');
+
+const environment = new Environment(stack, 'production', {
+  capacityType: EnvironmentCapacityType.FARGATE,
+});
+
+const aliasedPortServiceDescription = new ServiceDescription();
+
+aliasedPortServiceDescription.add(new Container({
+  cpu: 256,
+  memoryMiB: 512,
+  trafficPort: 80,
+  image: ecs.ContainerImage.fromRegistry('nathanpeck/name'),
+  environment: {
+    PORT: '80',
+  },
+}));
+
+aliasedPortServiceDescription.add(new AliasedPortExtension({
+  alias: 'name',
+  aliasPort: 1000,
+  appProtocol: ecs.AppProtocol.grpc,
+}));
+
+const svc = new Service(stack, 'ServiceConnect', {
+  environment: environment,
+  serviceDescription: aliasedPortServiceDescription,
+  desiredCount: 1,
+});
+
+const ns = environment.cluster.defaultCloudMapNamespace!;
+svc.ecsService.node.addDependency(ns);
diff --git a/test/aliased-port.test.ts b/test/aliased-port.test.ts
new file mode 100644
index 00000000..af6b111c
--- /dev/null
+++ b/test/aliased-port.test.ts
@@ -0,0 +1,120 @@
+import { Stack } from 'aws-cdk-lib';
+import { Template } from 'aws-cdk-lib/assertions';
+import * as ecs from 'aws-cdk-lib/aws-ecs';
+import { AliasedPortExtension, Container, Environment, ServiceDescription, Service } from '../lib';
+
+describe('aliased port', () => {
+  let stack: Stack;
+  let environment: Environment;
+  let serviceDescription: ServiceDescription;
+  beforeEach(() => {
+    stack = new Stack();
+    environment = new Environment(stack, 'production');
+    serviceDescription = new ServiceDescription();
+  });
+
+  test('aliased port extension throws error when no container extension exists', () => {
+
+    serviceDescription.add(new AliasedPortExtension({
+      alias: 'name',
+    }));
+
+    expect(() => {
+      new Service(stack, 'my-service', {
+        environment,
+        serviceDescription,
+      });
+    }).toThrow('Service \'my-service\' must have a Container extension');
+  });
+
+  test('when adding all options', () => {
+    serviceDescription.add(new Container({
+      cpu: 256,
+      memoryMiB: 512,
+      trafficPort: 80,
+      image: ecs.ContainerImage.fromRegistry('nathanpeck/name'),
+    }));
+
+    serviceDescription.add(new AliasedPortExtension({
+      alias: 'name',
+      aliasPort: 1000,
+      appProtocol: ecs.AppProtocol.grpc,
+    }));
+
+    new Service(stack, 'my-service', {
+      environment,
+      serviceDescription,
+    });
+
+    // THEN
+    Template.fromStack(stack).hasResourceProperties('AWS::ECS::TaskDefinition', {
+      ContainerDefinitions: [
+        {
+          PortMappings: [
+            {
+              Name: 'name',
+              Protocol: 'tcp',
+              AppProtocol: 'grpc',
+              ContainerPort: 80,
+            },
+          ],
+        },
+      ],
+    });
+
+    Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
+      ServiceConnectConfiguration: {
+        Enabled: true,
+        Namespace: 'production',
+        Services: [
+          {
+            PortName: 'name',
+            ClientAliases: [
+              {
+                Port: 1000,
+                DnsName: 'name',
+              },
+            ],
+          },
+        ],
+      },
+    });
+  });
+
+  test('when adding an aliased port with minimal config', () => {
+    serviceDescription.add(new Container({
+      cpu: 256,
+      memoryMiB: 512,
+      trafficPort: 80,
+      image: ecs.ContainerImage.fromRegistry('nathanpeck/name'),
+    }));
+
+    serviceDescription.add(new AliasedPortExtension({
+      alias: 'name',
+    }));
+
+    new Service(stack, 'my-service', {
+      environment,
+      serviceDescription,
+    });
+
+    // THEN
+    Template.fromStack(stack).hasResourceProperties('AWS::ECS::Service', {
+      ServiceConnectConfiguration: {
+        Enabled: true,
+        Namespace: 'production',
+        Services: [
+          {
+            PortName: 'name',
+            ClientAliases: [
+              {
+                Port: 80,
+                DnsName: 'name',
+              },
+            ],
+          },
+        ],
+      },
+    });
+  });
+});
\ No newline at end of file