Skip to content

Commit 76a56ad

Browse files
authored
fix: CDK does not work in FIPS-restricted environments (#22878)
In an environment where node is compiled with FIPS restrictions in mind, `crypto.createHash('md5')` does not work, for fear of MD5 being used for crypto purposes. We do not use it for crypto purposes, just to come up with unique identifiers for certain constructs. Nevertheless, CDK cannot work if `md5` is not available from the Node standard library. Fall back to a pure JavaScript implementation if the built-in MD5 hash does not work. This results in about a ~10x performance penalty, but the only thing we can do in order to produce the same templates. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent e4fdb02 commit 76a56ad

File tree

18 files changed

+287
-53
lines changed

18 files changed

+287
-53
lines changed

packages/@aws-cdk/aws-apigateway/lib/deployment.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import { Lazy, RemovalPolicy, Resource, CfnResource } from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33
import { Construct } from 'constructs';
44
import { CfnDeployment } from './apigateway.generated';
55
import { Method } from './method';
@@ -173,9 +173,7 @@ class LatestDeploymentResource extends CfnDeployment {
173173
// if hash components were added to the deployment, we use them to calculate
174174
// a logical ID for the deployment resource.
175175
if (hash.length > 0) {
176-
const md5 = crypto.createHash('md5');
177-
hash.map(x => this.stack.resolve(x)).forEach(c => md5.update(JSON.stringify(c)));
178-
lid += md5.digest('hex');
176+
lid += md5hash(hash.map(x => this.stack.resolve(x)).map(c => JSON.stringify(c)).join(''));
179177
}
180178

181179
return lid;

packages/@aws-cdk/aws-ec2/lib/instance.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as crypto from 'crypto';
21
import * as iam from '@aws-cdk/aws-iam';
32

43
import { Annotations, Aspects, Duration, Fn, IResource, Lazy, Resource, Stack, Tags } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
55
import { Construct } from 'constructs';
66
import { InstanceRequireImdsv2Aspect } from './aspects';
77
import { CloudFormationInit } from './cfn-init';
@@ -423,14 +423,14 @@ export class Instance extends Resource implements IInstance {
423423
if (recursing) { return originalLogicalId; }
424424
if (!(props.userDataCausesReplacement ?? props.initOptions)) { return originalLogicalId; }
425425

426-
const md5 = crypto.createHash('md5');
426+
const fragments = new Array<string>();
427427
recursing = true;
428428
try {
429-
md5.update(JSON.stringify(context.resolve(this.userData.render())));
429+
fragments.push(JSON.stringify(context.resolve(this.userData.render())));
430430
} finally {
431431
recursing = false;
432432
}
433-
const digest = md5.digest('hex').slice(0, 16);
433+
const digest = md5hash(fragments.join('')).slice(0, 16);
434434
return `${originalLogicalId}${digest}`;
435435
},
436436
}));

packages/@aws-cdk/aws-ec2/lib/volume.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import * as crypto from 'crypto';
2-
31
import { AccountRootPrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam';
42
import { IKey, ViaServicePrincipal } from '@aws-cdk/aws-kms';
53
import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names, RemovalPolicy } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
65
import { Construct } from 'constructs';
76
import { CfnVolume } from './ec2.generated';
87
import { IInstance } from './instance';
@@ -565,9 +564,7 @@ abstract class VolumeBase extends Resource implements IVolume {
565564
}
566565

567566
private calculateResourceTagValue(constructs: Construct[]): string {
568-
const md5 = crypto.createHash('md5');
569-
constructs.forEach(construct => md5.update(Names.uniqueId(construct)));
570-
return md5.digest('hex');
567+
return md5hash(constructs.map(c => Names.uniqueId(c)).join(''));
571568
}
572569
}
573570

packages/@aws-cdk/aws-glue/lib/code.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import * as crypto from 'crypto';
21
import * as fs from 'fs';
32
import * as iam from '@aws-cdk/aws-iam';
43
import * as s3 from '@aws-cdk/aws-s3';
54
import * as s3assets from '@aws-cdk/aws-s3-assets';
65
import * as cdk from '@aws-cdk/core';
6+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
77
import * as constructs from 'constructs';
88

99
/**
@@ -95,9 +95,7 @@ export class AssetCode extends Code {
9595
* Hash a string
9696
*/
9797
private hashcode(s: string): string {
98-
const hash = crypto.createHash('md5');
99-
hash.update(s);
100-
return hash.digest('hex');
98+
return md5hash(s);
10199
};
102100
}
103101

packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { ISecurityGroup, IVpc, SubnetSelection } from '@aws-cdk/aws-ec2';
33
import * as iam from '@aws-cdk/aws-iam';
44
import * as lambda from '@aws-cdk/aws-lambda';
@@ -219,9 +219,7 @@ export class SelfManagedKafkaEventSource extends StreamEventSource {
219219
}
220220

221221
private mappingId(target: lambda.IFunction) {
222-
let hash = crypto.createHash('md5');
223-
hash.update(JSON.stringify(Stack.of(target).resolve(this.innerProps.bootstrapServers)));
224-
const idHash = hash.digest('hex');
222+
const idHash = md5hash(JSON.stringify(Stack.of(target).resolve(this.innerProps.bootstrapServers)));
225223
return `KafkaEventSource:${idHash}:${this.innerProps.topic}`;
226224
}
227225

packages/@aws-cdk/aws-lambda/lib/function-hash.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import { CfnResource, FeatureFlags, Stack } from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33
import { LAMBDA_RECOGNIZE_LAYER_VERSION, LAMBDA_RECOGNIZE_VERSION_PROPS } from '@aws-cdk/cx-api';
44
import { Function as LambdaFunction } from './function';
55
import { ILayerVersion } from './layers';
@@ -34,9 +34,7 @@ export function calculateFunctionHash(fn: LambdaFunction) {
3434
stringifiedConfig = stringifiedConfig + calculateLayersHash(fn._layers);
3535
}
3636

37-
const hash = crypto.createHash('md5');
38-
hash.update(stringifiedConfig);
39-
return hash.digest('hex');
37+
return md5hash(stringifiedConfig);
4038
}
4139

4240
export function trimFromStart(s: string, maxLength: number) {
@@ -146,7 +144,5 @@ function calculateLayersHash(layers: ILayerVersion[]): string {
146144
layerConfig[layer.node.id] = properties;
147145
}
148146

149-
const hash = crypto.createHash('md5');
150-
hash.update(JSON.stringify(layerConfig));
151-
return hash.digest('hex');
147+
return md5hash(JSON.stringify(layerConfig));
152148
}

packages/@aws-cdk/aws-rds/lib/database-secret.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import * as crypto from 'crypto';
21
import * as kms from '@aws-cdk/aws-kms';
32
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
43
import { Aws, Names } from '@aws-cdk/core';
4+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
55
import { Construct } from 'constructs';
66
import { DEFAULT_PASSWORD_EXCLUDE_CHARS } from './private/util';
77

@@ -88,14 +88,13 @@ export class DatabaseSecret extends secretsmanager.Secret {
8888
});
8989

9090
if (props.replaceOnPasswordCriteriaChanges) {
91-
const hash = crypto.createHash('md5');
92-
hash.update(JSON.stringify({
91+
const hash = md5hash(JSON.stringify({
9392
// Use here the options that influence the password generation.
9493
// If at some point we add other password customization options
9594
// they sould be added here below (e.g. `passwordLength`).
9695
excludeCharacters,
9796
}));
98-
const logicalId = `${Names.uniqueId(this)}${hash.digest('hex')}`;
97+
const logicalId = `${Names.uniqueId(this)}${hash}`;
9998

10099
const secret = this.node.defaultChild as secretsmanager.CfnSecret;
101100
secret.overrideLogicalId(logicalId.slice(-255)); // Take last 255 chars

packages/@aws-cdk/aws-route53-patterns/lib/website-redirect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { DnsValidatedCertificate, ICertificate } from '@aws-cdk/aws-certificatemanager';
33
import { CloudFrontWebDistribution, OriginProtocolPolicy, PriceClass, ViewerCertificate, ViewerProtocolPolicy } from '@aws-cdk/aws-cloudfront';
44
import { ARecord, AaaaRecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
@@ -97,7 +97,7 @@ export class HttpsRedirect extends Construct {
9797
});
9898

9999
domainNames.forEach((domainName) => {
100-
const hash = crypto.createHash('md5').update(domainName).digest('hex').slice(0, 6);
100+
const hash = md5hash(domainName).slice(0, 6);
101101
const aliasProps = {
102102
recordName: domainName,
103103
zone: props.zone,

packages/@aws-cdk/aws-route53/lib/vpc-endpoint-service-domain-name.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as crypto from 'crypto';
1+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
22
import { IVpcEndpointService } from '@aws-cdk/aws-ec2';
33
import { Fn, Names, Stack } from '@aws-cdk/core';
44
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources';
@@ -225,7 +225,5 @@ interface PrivateDnsConfiguration {
225225
* Hash a string
226226
*/
227227
function hashcode(s: string): string {
228-
const hash = crypto.createHash('md5');
229-
hash.update(s);
230-
return hash.digest('hex');
228+
return md5hash(s);
231229
};

packages/@aws-cdk/aws-sagemaker/lib/private/util.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import * as crypto from 'crypto';
21
import * as cdk from '@aws-cdk/core';
2+
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
33

44
/**
55
* Generates a hash from the provided string for the purposes of avoiding construct ID collision
@@ -8,9 +8,7 @@ import * as cdk from '@aws-cdk/core';
88
* @returns A hex string representing the hash of the provided string
99
*/
1010
export function hashcode(s: string): string {
11-
const hash = crypto.createHash('md5');
12-
hash.update(s);
13-
return hash.digest('hex');
11+
return md5hash(s);
1412
}
1513

1614
/**
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export * from './cfn-parse';
2+
// Other libraries are going to need this as well
3+
export { md5hash } from '../private/md5';
24
export * from './customize-roles';

0 commit comments

Comments
 (0)