diff --git a/packages/@aws-cdk/aws-ecs/README.md b/packages/@aws-cdk/aws-ecs/README.md index 6a27855e031f5..2c4f04e64b257 100644 --- a/packages/@aws-cdk/aws-ecs/README.md +++ b/packages/@aws-cdk/aws-ecs/README.md @@ -427,6 +427,25 @@ The task execution role is automatically granted read permissions on the secrets files is restricted to the EC2 launch type for files hosted on S3. Further details provided in the AWS documentation about [specifying environment variables](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/taskdef-envfiles.html). +### System controls + +To set system controls (kernel parameters) on the container, use the `systemControls` prop: + +```ts +declare const taskDefinition: ecs.TaskDefinition; + +taskDefinition.addContainer('container', { + image: ecs.ContainerImage.fromRegistry("amazon/amazon-ecs-sample"), + memoryLimitMiB: 1024, + systemControls: [ + { + namespace: 'net', + value: 'ipv4.tcp_tw_recycle', + }, + ], +}); +``` + ## Service A `Service` instantiates a `TaskDefinition` on a `Cluster` a given number of diff --git a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts index f817a5280315e..625041468a0a4 100644 --- a/packages/@aws-cdk/aws-ecs/lib/container-definition.ts +++ b/packages/@aws-cdk/aws-ecs/lib/container-definition.ts @@ -307,6 +307,15 @@ export interface ContainerDefinitionOptions { * @default - No inference accelerators assigned. */ readonly inferenceAcceleratorResources?: string[]; + + /** + * A list of namespaced kernel parameters to set in the container. + * + * @default - No system controls are set. + * @see https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-ecs-taskdefinition-systemcontrol.html + * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#container_definition_systemcontrols + */ + readonly systemControls?: SystemControl[]; } /** @@ -669,6 +678,7 @@ export class ContainerDefinition extends CoreConstruct { linuxParameters: this.linuxParameters && this.linuxParameters.renderLinuxParameters(), resourceRequirements: (!this.props.gpuCount && this.inferenceAcceleratorResources.length == 0 ) ? undefined : renderResourceRequirements(this.props.gpuCount, this.inferenceAcceleratorResources), + systemControls: this.props.systemControls && renderSystemControls(this.props.systemControls), }; } } @@ -1040,3 +1050,25 @@ function renderVolumeFrom(vf: VolumeFrom): CfnTaskDefinition.VolumeFromProperty readOnly: vf.readOnly, }; } + +/** + * Kernel parameters to set in the container + */ +export interface SystemControl { + /** + * The namespaced kernel parameter for which to set a value. + */ + readonly namespace: string; + + /** + * The value for the namespaced kernel parameter specified in namespace. + */ + readonly value: string; +} + +function renderSystemControls(systemControls: SystemControl[]): CfnTaskDefinition.SystemControlProperty[] { + return systemControls.map(sc => ({ + namespace: sc.namespace, + value: sc.value, + })); +} diff --git a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts index a5153b82d331a..a384294900342 100644 --- a/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts +++ b/packages/@aws-cdk/aws-ecs/test/container-definition.test.ts @@ -85,6 +85,9 @@ describe('container definition', () => { secrets: { SECRET: ecs.Secret.fromSecretsManager(secret), }, + systemControls: [ + { namespace: 'SomeNamespace', value: 'SomeValue' }, + ], }); // THEN @@ -218,6 +221,12 @@ describe('container definition', () => { ], StartTimeout: 2, StopTimeout: 5, + SystemControls: [ + { + Namespace: 'SomeNamespace', + Value: 'SomeValue', + }, + ], User: 'rootUser', WorkingDirectory: 'a/b/c', }, @@ -753,6 +762,40 @@ describe('container definition', () => { }); }); + test('can specify system controls', () => { + // GIVEN + const stack = new cdk.Stack(); + const taskDefinition = new ecs.Ec2TaskDefinition(stack, 'TaskDef'); + + // WHEN + taskDefinition.addContainer('cont', { + image: ecs.ContainerImage.fromRegistry('test'), + memoryLimitMiB: 1024, + systemControls: [ + { namespace: 'SomeNamespace1', value: 'SomeValue1' }, + { namespace: 'SomeNamespace2', value: 'SomeValue2' }, + ], + }); + + // THEN + expect(stack).toHaveResourceLike('AWS::ECS::TaskDefinition', { + ContainerDefinitions: [ + { + SystemControls: [ + { + Namespace: 'SomeNamespace1', + Value: 'SomeValue1', + }, + { + Namespace: 'SomeNamespace2', + Value: 'SomeValue2', + }, + ], + }, + ], + }); + }); + describe('Environment Files', () => { describe('with EC2 task definitions', () => { test('can add asset environment file to the container definition', () => {