Skip to content

Commit

Permalink
fix: CDK does not work in FIPS-restricted environments (#22878)
Browse files Browse the repository at this point in the history
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*
  • Loading branch information
rix0rrr authored Nov 15, 2022
1 parent e4fdb02 commit 76a56ad
Show file tree
Hide file tree
Showing 18 changed files with 287 additions and 53 deletions.
6 changes: 2 additions & 4 deletions packages/@aws-cdk/aws-apigateway/lib/deployment.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as crypto from 'crypto';
import { Lazy, RemovalPolicy, Resource, CfnResource } from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { Construct } from 'constructs';
import { CfnDeployment } from './apigateway.generated';
import { Method } from './method';
Expand Down Expand Up @@ -173,9 +173,7 @@ class LatestDeploymentResource extends CfnDeployment {
// if hash components were added to the deployment, we use them to calculate
// a logical ID for the deployment resource.
if (hash.length > 0) {
const md5 = crypto.createHash('md5');
hash.map(x => this.stack.resolve(x)).forEach(c => md5.update(JSON.stringify(c)));
lid += md5.digest('hex');
lid += md5hash(hash.map(x => this.stack.resolve(x)).map(c => JSON.stringify(c)).join(''));
}

return lid;
Expand Down
8 changes: 4 additions & 4 deletions packages/@aws-cdk/aws-ec2/lib/instance.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as crypto from 'crypto';
import * as iam from '@aws-cdk/aws-iam';

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

const md5 = crypto.createHash('md5');
const fragments = new Array<string>();
recursing = true;
try {
md5.update(JSON.stringify(context.resolve(this.userData.render())));
fragments.push(JSON.stringify(context.resolve(this.userData.render())));
} finally {
recursing = false;
}
const digest = md5.digest('hex').slice(0, 16);
const digest = md5hash(fragments.join('')).slice(0, 16);
return `${originalLogicalId}${digest}`;
},
}));
Expand Down
7 changes: 2 additions & 5 deletions packages/@aws-cdk/aws-ec2/lib/volume.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import * as crypto from 'crypto';

import { AccountRootPrincipal, Grant, IGrantable } from '@aws-cdk/aws-iam';
import { IKey, ViaServicePrincipal } from '@aws-cdk/aws-kms';
import { IResource, Resource, Size, SizeRoundingBehavior, Stack, Token, Tags, Names, RemovalPolicy } from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { Construct } from 'constructs';
import { CfnVolume } from './ec2.generated';
import { IInstance } from './instance';
Expand Down Expand Up @@ -565,9 +564,7 @@ abstract class VolumeBase extends Resource implements IVolume {
}

private calculateResourceTagValue(constructs: Construct[]): string {
const md5 = crypto.createHash('md5');
constructs.forEach(construct => md5.update(Names.uniqueId(construct)));
return md5.digest('hex');
return md5hash(constructs.map(c => Names.uniqueId(c)).join(''));
}
}

Expand Down
6 changes: 2 additions & 4 deletions packages/@aws-cdk/aws-glue/lib/code.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as iam from '@aws-cdk/aws-iam';
import * as s3 from '@aws-cdk/aws-s3';
import * as s3assets from '@aws-cdk/aws-s3-assets';
import * as cdk from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import * as constructs from 'constructs';

/**
Expand Down Expand Up @@ -95,9 +95,7 @@ export class AssetCode extends Code {
* Hash a string
*/
private hashcode(s: string): string {
const hash = crypto.createHash('md5');
hash.update(s);
return hash.digest('hex');
return md5hash(s);
};
}

Expand Down
6 changes: 2 additions & 4 deletions packages/@aws-cdk/aws-lambda-event-sources/lib/kafka.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as crypto from 'crypto';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { ISecurityGroup, IVpc, SubnetSelection } from '@aws-cdk/aws-ec2';
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
Expand Down Expand Up @@ -219,9 +219,7 @@ export class SelfManagedKafkaEventSource extends StreamEventSource {
}

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

Expand Down
10 changes: 3 additions & 7 deletions packages/@aws-cdk/aws-lambda/lib/function-hash.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as crypto from 'crypto';
import { CfnResource, FeatureFlags, Stack } from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { LAMBDA_RECOGNIZE_LAYER_VERSION, LAMBDA_RECOGNIZE_VERSION_PROPS } from '@aws-cdk/cx-api';
import { Function as LambdaFunction } from './function';
import { ILayerVersion } from './layers';
Expand Down Expand Up @@ -34,9 +34,7 @@ export function calculateFunctionHash(fn: LambdaFunction) {
stringifiedConfig = stringifiedConfig + calculateLayersHash(fn._layers);
}

const hash = crypto.createHash('md5');
hash.update(stringifiedConfig);
return hash.digest('hex');
return md5hash(stringifiedConfig);
}

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

const hash = crypto.createHash('md5');
hash.update(JSON.stringify(layerConfig));
return hash.digest('hex');
return md5hash(JSON.stringify(layerConfig));
}
7 changes: 3 additions & 4 deletions packages/@aws-cdk/aws-rds/lib/database-secret.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as crypto from 'crypto';
import * as kms from '@aws-cdk/aws-kms';
import * as secretsmanager from '@aws-cdk/aws-secretsmanager';
import { Aws, Names } from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { Construct } from 'constructs';
import { DEFAULT_PASSWORD_EXCLUDE_CHARS } from './private/util';

Expand Down Expand Up @@ -88,14 +88,13 @@ export class DatabaseSecret extends secretsmanager.Secret {
});

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

const secret = this.node.defaultChild as secretsmanager.CfnSecret;
secret.overrideLogicalId(logicalId.slice(-255)); // Take last 255 chars
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as crypto from 'crypto';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { DnsValidatedCertificate, ICertificate } from '@aws-cdk/aws-certificatemanager';
import { CloudFrontWebDistribution, OriginProtocolPolicy, PriceClass, ViewerCertificate, ViewerProtocolPolicy } from '@aws-cdk/aws-cloudfront';
import { ARecord, AaaaRecord, IHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
Expand Down Expand Up @@ -97,7 +97,7 @@ export class HttpsRedirect extends Construct {
});

domainNames.forEach((domainName) => {
const hash = crypto.createHash('md5').update(domainName).digest('hex').slice(0, 6);
const hash = md5hash(domainName).slice(0, 6);
const aliasProps = {
recordName: domainName,
zone: props.zone,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as crypto from 'crypto';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';
import { IVpcEndpointService } from '@aws-cdk/aws-ec2';
import { Fn, Names, Stack } from '@aws-cdk/core';
import { AwsCustomResource, AwsCustomResourcePolicy, PhysicalResourceId } from '@aws-cdk/custom-resources';
Expand Down Expand Up @@ -225,7 +225,5 @@ interface PrivateDnsConfiguration {
* Hash a string
*/
function hashcode(s: string): string {
const hash = crypto.createHash('md5');
hash.update(s);
return hash.digest('hex');
return md5hash(s);
};
6 changes: 2 additions & 4 deletions packages/@aws-cdk/aws-sagemaker/lib/private/util.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as crypto from 'crypto';
import * as cdk from '@aws-cdk/core';
import { md5hash } from '@aws-cdk/core/lib/helpers-internal';

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

/**
Expand Down
2 changes: 2 additions & 0 deletions packages/@aws-cdk/core/lib/helpers-internal/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './cfn-parse';
// Other libraries are going to need this as well
export { md5hash } from '../private/md5';
export * from './customize-roles';
Loading

0 comments on commit 76a56ad

Please sign in to comment.