Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(batch): add secrets props to job definition #19506

Closed
wants to merge 10 commits into from
23 changes: 23 additions & 0 deletions packages/@aws-cdk/aws-batch/lib/job-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,13 @@ export interface JobDefinitionContainer {
*/
readonly environment?: { [key: string]: string };

/**
* The environment variables from secrets manager or ssm parameter store
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ecs.Secret will not support SSM parameter store though.

Don't you want core.SecretValue ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well I guess not if you need the ARN. But in any case, the SSM comment here is inaccurate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my understanding, ecs.Secret supports SSM parameter store through fromSsmParameter method.
Is it correct?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I was thinking of ssm.Secret.

*
* @default none
*/
readonly secrets?: { [key: string]: ecs.Secret };

/**
* The image used to start a container.
*/
Expand Down Expand Up @@ -453,6 +460,14 @@ export class JobDefinition extends Resource implements IJobDefinition {
platformCapabilities: props.platformCapabilities ?? [PlatformCapabilities.EC2],
});

// add read secrets permission to execution role
if ( props.container.secrets && props.container.executionRole ) {
const executionRole = props.container.executionRole;
Object.values(props.container.secrets).forEach((secret) => {
secret.grantRead(executionRole);
});
}

this.jobDefinitionArn = this.getResourceArnAttribute(jobDef.ref, {
service: 'batch',
resource: 'job-definition',
Expand Down Expand Up @@ -507,6 +522,14 @@ export class JobDefinition extends Resource implements IJobDefinition {
return {
command: container.command,
environment: this.deserializeEnvVariables(container.environment),
secrets: container.secrets
? Object.entries(container.secrets).map(([key, value]) => {
return {
name: key,
valueFrom: value.arn,
};
})
: undefined,
image: this.imageConfig.imageName,
instanceType: container.instanceType && container.instanceType.toString(),
jobRoleArn: container.jobRole && container.jobRole.roleArn,
Expand Down
64 changes: 56 additions & 8 deletions packages/@aws-cdk/aws-batch/test/integ.batch.expected.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
"vpcPublicSubnet1Subnet2E65531E": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.0.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1a",
"CidrBlock": "10.0.0.0/19",
"MapPublicIpOnLaunch": true,
"Tags": [
{
Expand Down Expand Up @@ -115,11 +115,11 @@
"vpcPublicSubnet2Subnet009B674F": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.32.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1b",
"CidrBlock": "10.0.32.0/19",
"MapPublicIpOnLaunch": true,
"Tags": [
{
Expand Down Expand Up @@ -212,11 +212,11 @@
"vpcPublicSubnet3Subnet11B92D7C": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.64.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1c",
"CidrBlock": "10.0.64.0/19",
"MapPublicIpOnLaunch": true,
"Tags": [
{
Expand Down Expand Up @@ -309,11 +309,11 @@
"vpcPrivateSubnet1Subnet934893E8": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.96.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1a",
"CidrBlock": "10.0.96.0/19",
"MapPublicIpOnLaunch": false,
"Tags": [
{
Expand Down Expand Up @@ -371,11 +371,11 @@
"vpcPrivateSubnet2Subnet7031C2BA": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.128.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1b",
"CidrBlock": "10.0.128.0/19",
"MapPublicIpOnLaunch": false,
"Tags": [
{
Expand Down Expand Up @@ -433,11 +433,11 @@
"vpcPrivateSubnet3Subnet985AC459": {
"Type": "AWS::EC2::Subnet",
"Properties": {
"CidrBlock": "10.0.160.0/19",
"VpcId": {
"Ref": "vpcA2121C38"
},
"AvailabilityZone": "test-region-1c",
"CidrBlock": "10.0.160.0/19",
"MapPublicIpOnLaunch": false,
"Tags": [
{
Expand Down Expand Up @@ -1673,6 +1673,14 @@
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"batchsecret7CD5E4C6": {
"Type": "AWS::SecretsManager::Secret",
"Properties": {
"GenerateSecretString": {}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
},
"batchjobdeffromecrE0E30DAD": {
"Type": "AWS::Batch::JobDefinition",
"Properties": {
Expand Down Expand Up @@ -1758,8 +1766,14 @@
"Privileged": false,
"ReadonlyRootFilesystem": false,
"ResourceRequirements": [
{ "Type": "VCPU", "Value": "1" },
{ "Type": "MEMORY", "Value": "4" }
{
"Type": "VCPU",
"Value": "1"
},
{
"Type": "MEMORY",
"Value": "4"
}
]
},
"PlatformCapabilities": [
Expand Down Expand Up @@ -1788,6 +1802,32 @@
}
}
},
"executionroleDefaultPolicy497F11A3": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"secretsmanager:DescribeSecret",
"secretsmanager:GetSecretValue"
],
"Effect": "Allow",
"Resource": {
"Ref": "batchsecret7CD5E4C6"
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "executionroleDefaultPolicy497F11A3",
"Roles": [
{
"Ref": "executionroleD9A39BE6"
}
]
}
},
"batchjobdeffargate7FE30059": {
"Type": "AWS::Batch::JobDefinition",
"Properties": {
Expand All @@ -1811,6 +1851,14 @@
"Type": "MEMORY",
"Value": "512"
}
],
"Secrets": [
{
"Name": "SECRET",
"ValueFrom": {
"Ref": "batchsecret7CD5E4C6"
}
}
]
},
"PlatformCapabilities": [
Expand Down
5 changes: 5 additions & 0 deletions packages/@aws-cdk/aws-batch/test/integ.batch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
import * as ecr from '@aws-cdk/aws-ecr';
import * as ecs from '@aws-cdk/aws-ecs';
import * as iam from '@aws-cdk/aws-iam';
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
import * as cdk from '@aws-cdk/core';
import * as batch from '../lib/';

Expand Down Expand Up @@ -93,6 +94,7 @@ new batch.JobQueue(stack, 'batch-job-fargate-queue', {
});

const repo = new ecr.Repository(stack, 'batch-job-repo');
const secret = new secretsmanager.Secret(stack, 'batch-secret');

new batch.JobDefinition(stack, 'batch-job-def-from-ecr', {
container: {
Expand All @@ -115,5 +117,8 @@ new batch.JobDefinition(stack, 'batch-job-def-fargate', {
container: {
image: ecs.ContainerImage.fromRegistry('docker/whalesay'),
executionRole,
secrets: {
SECRET: ecs.Secret.fromSecretsManager(secret),
},
},
});
74 changes: 73 additions & 1 deletion packages/@aws-cdk/aws-batch/test/job-definition.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { throws } from 'assert';
import { Template } from '@aws-cdk/assertions';
import { Match, Template } from '@aws-cdk/assertions';
import * as ec2 from '@aws-cdk/aws-ec2';
import * as ecr from '@aws-cdk/aws-ecr';
import * as ecs from '@aws-cdk/aws-ecs';
Expand Down Expand Up @@ -31,13 +31,23 @@ describe('Batch Job Definition', () => {
options: { 'awslogs-region': 'us-east-1' },
};

const secret = new secretsmanager.Secret(stack, 'test-secret');
const parameter = ssm.StringParameter.fromSecureStringParameterAttributes(stack, 'test-parameter', {
parameterName: '/name',
version: 1,
});

jobDefProps = {
jobDefinitionName: 'test-job',
container: {
command: ['echo "Hello World"'],
environment: {
foo: 'bar',
},
secrets: {
SECRET: ecs.Secret.fromSecretsManager(secret),
PARAMETER: ecs.Secret.fromSsmParameter(parameter),
},
jobRole: role,
gpuCount: 1,
image: ecs.EcrImage.fromRegistry('docker/whalesay'),
Expand Down Expand Up @@ -82,6 +92,37 @@ describe('Batch Job Definition', () => {
Value: 'bar',
},
],
Secrets: [
{
Name: 'SECRET',
ValueFrom: {
Ref: Match.stringLikeRegexp('^testsecret[0-9A-Z]{8}$'),
},
},
{
Name: 'PARAMETER',
ValueFrom: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':ssm:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':parameter/name',
],
],
},
},
],
InstanceType: jobDefProps.container.instanceType ? jobDefProps.container.instanceType.toString() : '',
LinuxParameters: {},
LogConfiguration: {
Expand Down Expand Up @@ -144,6 +185,37 @@ describe('Batch Job Definition', () => {
Value: 'bar',
},
],
Secrets: [
{
Name: 'SECRET',
ValueFrom: {
Ref: Match.stringLikeRegexp('^testsecret[0-9A-Z]{8}$'),
},
},
{
Name: 'PARAMETER',
ValueFrom: {
'Fn::Join': [
'',
[
'arn:',
{
Ref: 'AWS::Partition',
},
':ssm:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':parameter/name',
],
],
},
},
],
ExecutionRoleArn: {
'Fn::GetAtt': [
'executionroleD9A39BE6',
Expand Down