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

fix(aws-custom-resource): switch off installLatestAwsSdk by default #23591

Merged
merged 9 commits into from
Jan 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ export class CustomLambdaDeploymentConfig extends Resource implements ILambdaDep
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});

this.node.addValidation({ validate: () => validateName('Deployment config', this.deploymentConfigName) });
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-cognito/lib/user-pool-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,8 @@ export class UserPoolClient extends Resource implements IUserPoolClient {
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: [this.userPool.userPoolArn],
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
},
).getResponseField('UserPoolClient.ClientSecret'));
}
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-cognito/lib/user-pool-domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ export class UserPoolDomain extends Resource implements IUserPoolDomain {
// https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazoncognitouserpools.html#amazoncognitouserpools-actions-as-permissions
resources: ['*'],
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});
}
return this.cloudFrontCustomResource.getResponseField('DomainDescription.CloudFrontDistribution');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export class AcceleratorSecurityGroupPeer implements ec2.IPeer {
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});

// We add a dependency on the endpoint group, guaranteeing that CloudFormation won't
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/aws-glue/lib/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,8 @@ export class Table extends Resource implements ITable {
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});
this.grantToUnderlyingResources(partitionIndexCustomResource, ['glue:UpdateTable']);

Expand Down
4 changes: 4 additions & 0 deletions packages/@aws-cdk/aws-msk/lib/cluster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ export class Cluster extends ClusterBase {
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: [this.clusterArn],
}),
installLatestAwsSdk: false,
});
}
return this._clusterDescription.getResponseField(`ClusterInfo.${responseField}`);
Expand Down Expand Up @@ -774,6 +775,8 @@ export class Cluster extends ClusterBase {
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: [this.clusterArn],
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});
}
return this._clusterBootstrapBrokers.getResponseField(responseField);
Expand Down Expand Up @@ -866,6 +869,7 @@ export class Cluster extends ClusterBase {
resources: [this.clusterArn],
}),
]),
installLatestAwsSdk: false,
});
} else {
throw Error(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ export class VpcEndpointServiceDomainName extends Construct {
]),
],
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});

// Look up the name/value pair if the domain changes, or the service changes,
Expand All @@ -154,6 +156,7 @@ export class VpcEndpointServiceDomainName extends Construct {
policy: AwsCustomResourcePolicy.fromSdkCalls({
resources: AwsCustomResourcePolicy.ANY_RESOURCE,
}),
installLatestAwsSdk: false,
});

// We only want to call and get the name/value pair after we've told AWS to enable Private DNS
Expand Down Expand Up @@ -206,6 +209,7 @@ export class VpcEndpointServiceDomainName extends Construct {
]),
],
}),
installLatestAwsSdk: false,
});
// Only verify after the record has been created
startVerification.node.addDependency(verificationRecord);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ export class EmrContainersStartJobRun extends sfn.TaskStateBase implements iam.I
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
// APIs are available in 2.1055.0
installLatestAwsSdk: false,
});
/* We make use of custom resources to call update-roll-trust-policy as this command is only available through
* aws cli because this is only used during the initial setup and is not available through the sdk.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import * as logs from '@aws-cdk/aws-logs';
import * as cdk from '@aws-cdk/core';
import { Annotations } from '@aws-cdk/core';
import * as cxapi from '@aws-cdk/cx-api';
import { Construct } from 'constructs';
import { PHYSICAL_RESOURCE_ID_REFERENCE } from './runtime';

Expand Down Expand Up @@ -298,12 +300,18 @@ export interface AwsCustomResourceProps {
readonly logRetention?: logs.RetentionDays;

/**
* Whether to install the latest AWS SDK v2. Allows to use the latest API
* calls documented at https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html.
* Whether to install the latest AWS SDK v2.
*
* The installation takes around 60 seconds.
* If not specified, this uses whatever JavaScript SDK version is the default in
* AWS Lambda at the time of execution.
*
* @default true
* Otherwise, installs the latest version from 'npmjs.com'. The installation takes
* around 60 seconds and requires internet connectivity.
*
* The default can be controlled using the context key
* `@aws-cdk/customresources:installLatestAwsSdkDefault` is.
*
* @default - The value of `@aws-cdk/customresources:installLatestAwsSdkDefault`, otherwise `true`
*/
readonly installLatestAwsSdk?: boolean;

Expand Down Expand Up @@ -407,6 +415,19 @@ export class AwsCustomResource extends Construct implements iam.IGrantable {
});
this.grantPrincipal = provider.grantPrincipal;

const installLatestAwsSdk = (props.installLatestAwsSdk
?? this.node.tryGetContext(cxapi.AWS_CUSTOM_RESOURCE_LATEST_SDK_DEFAULT)
?? true);

if (installLatestAwsSdk && props.installLatestAwsSdk === undefined) {
// This is dangerous. Add a warning.
Annotations.of(this).addWarning([
'installLatestAwsSdk was not specified, and defaults to true. You probably do not want this.',
`Set the global context flag \'${cxapi.AWS_CUSTOM_RESOURCE_LATEST_SDK_DEFAULT}\' to false to switch this behavior off project-wide,`,
'or set the property explicitly to true if you know you need to call APIs that are not in Lambda\'s built-in SDK version.',
].join(' '));
}

const create = props.onCreate || props.onUpdate;
this.customResource = new cdk.CustomResource(this, 'Resource', {
resourceType: props.resourceType || 'Custom::AWS',
Expand All @@ -416,7 +437,7 @@ export class AwsCustomResource extends Construct implements iam.IGrantable {
create: create && this.encodeJson(create),
update: props.onUpdate && this.encodeJson(props.onUpdate),
delete: props.onDelete && this.encodeJson(props.onDelete),
installLatestAwsSdk: props.installLatestAwsSdk ?? true,
installLatestAwsSdk,
},
});

Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/custom-resources/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
},
"dependencies": {
"@aws-cdk/aws-cloudformation": "0.0.0",
"@aws-cdk/cx-api": "0.0.0",
"@aws-cdk/aws-ec2": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/aws-lambda": "0.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as ec2 from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as logs from '@aws-cdk/aws-logs';
import * as cdk from '@aws-cdk/core';
import { App, Stack } from '@aws-cdk/core';
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId, PhysicalResourceIdReference } from '../../lib';

/* eslint-disable quote-props */
Expand Down Expand Up @@ -911,3 +912,37 @@ test('vpcSubnets without vpc results in an error', () => {
vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED },
})).toThrow('Cannot configure \'vpcSubnets\' without configuring a VPC');
});

test.each([
[undefined, true],
[true, true],
[false, false],
])('feature flag %p, installLatestAwsSdk %p', (flag, expected) => {
// GIVEN
const app = new App({
context: {
'@aws-cdk/customresources:installLatestAwsSdkDefault': flag,
},
});
const stack = new Stack(app, 'Stack');

// WHEN
new AwsCustomResource(stack, 'AwsSdk', {
resourceType: 'Custom::LogRetentionPolicy',
onCreate: {
service: 'CloudWatchLogs',
action: 'putRetentionPolicy',
parameters: {
logGroupName: '/aws/lambda/loggroup',
retentionInDays: 90,
},
physicalResourceId: PhysicalResourceId.of('loggroup'),
},
policy: AwsCustomResourcePolicy.fromSdkCalls({ resources: AwsCustomResourcePolicy.ANY_RESOURCE }),
});

// THEN
Template.fromStack(stack).hasResourceProperties('Custom::LogRetentionPolicy', {
'InstallLatestAwsSdk': expected,
});
});
24 changes: 23 additions & 1 deletion packages/@aws-cdk/cx-api/FEATURE_FLAGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ Flags come in three types:
| [@aws-cdk/aws-iam:standardizedServicePrincipals](#aws-cdkaws-iamstandardizedserviceprincipals) | Use standardized (global) service principals everywhere | 2.51.0 | (fix) |
| [@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy](#aws-cdkaws-s3serveraccesslogsusebucketpolicy) | Use S3 Bucket Policy instead of ACLs for Server Access Logging | 2.59.0 | (fix) |
| [@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName](#aws-cdkaws-iamimportedrolestacksafedefaultpolicyname) | Enable this feature to by default create default policy names for imported roles that depend on the stack the role is in. | V2NEXT | (fix) |
| [@aws-cdk/customresources:installLatestAwsSdkDefault](#aws-cdkcustomresourcesinstalllatestawssdkdefault) | Whether to install the latest SDK by default in AwsCustomResource | V2NEXT | (default) |

<!-- END table -->

Expand Down Expand Up @@ -72,7 +73,8 @@ The following json shows the current recommended set of flags, as `cdk init` wou
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false
}
}
```
Expand Down Expand Up @@ -736,4 +738,24 @@ This new implementation creates default policy names based on the constructs nod
| V2NEXT | `false` | `true` |


### @aws-cdk/customresources:installLatestAwsSdkDefault

*Whether to install the latest SDK by default in AwsCustomResource* (default)

This was originally introduced and enabled by default to not be limited by the SDK version
that's installed on AWS Lambda. However, it creates issues for Lambdas bound to VPCs that
do not have internet access, or in environments where 'npmjs.com' is not available.

The recommended setting is to disable the default installation behavior, and pass the
flag on a resource-by-resource basis to enable it if necessary.


| Since | Default | Recommended |
| ----- | ----- | ----- |
| (not in v1) | | |
| V2NEXT | `false` | `false` |

**Compatibility with old behavior:** Set installLatestAwsSdk: true on all resources that need it.


<!-- END details -->
18 changes: 18 additions & 0 deletions packages/@aws-cdk/cx-api/lib/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ export const EVENTS_TARGET_QUEUE_SAME_ACCOUNT = '@aws-cdk/aws-events:eventsTarge
export const IAM_STANDARDIZED_SERVICE_PRINCIPALS = '@aws-cdk/aws-iam:standardizedServicePrincipals';
export const ECS_DISABLE_EXPLICIT_DEPLOYMENT_CONTROLLER_FOR_CIRCUIT_BREAKER = '@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker';
export const S3_SERVER_ACCESS_LOGS_USE_BUCKET_POLICY = '@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy';
export const AWS_CUSTOM_RESOURCE_LATEST_SDK_DEFAULT = '@aws-cdk/customresources:installLatestAwsSdkDefault';

export const FLAGS: Record<string, FlagInfo> = {
//////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -593,6 +594,23 @@ export const FLAGS: Record<string, FlagInfo> = {
introducedIn: { v2: '2.59.0' },
recommendedValue: true,
},

//////////////////////////////////////////////////////////////////////
[AWS_CUSTOM_RESOURCE_LATEST_SDK_DEFAULT]: {
type: FlagType.ApiDefault,
summary: 'Whether to install the latest SDK by default in AwsCustomResource',
detailsMd: `
This was originally introduced and enabled by default to not be limited by the SDK version
that's installed on AWS Lambda. However, it creates issues for Lambdas bound to VPCs that
do not have internet access, or in environments where 'npmjs.com' is not available.

The recommended setting is to disable the default installation behavior, and pass the
flag on a resource-by-resource basis to enable it if necessary.
`,
compatibilityWithOldBehaviorMd: 'Set installLatestAwsSdk: true on all resources that need it.',
introducedIn: { v2: 'V2NEXT' },
recommendedValue: false,
},
};

const CURRENT_MV = 'v2';
Expand Down