@gradientedge/cdk-utils 8.97.0 → 8.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/lib/construct/site-with-ecs-backend/constants.d.ts +4 -0
- package/dist/src/lib/construct/site-with-ecs-backend/constants.js +8 -0
- package/dist/src/lib/construct/site-with-ecs-backend/index.d.ts +1 -0
- package/dist/src/lib/construct/site-with-ecs-backend/index.js +1 -0
- package/dist/src/lib/construct/site-with-ecs-backend/main.d.ts +7 -1
- package/dist/src/lib/construct/site-with-ecs-backend/main.js +43 -0
- package/dist/src/lib/construct/site-with-ecs-backend/types.d.ts +14 -0
- package/dist/src/lib/services/aws/secrets-manager/main.d.ts +8 -22
- package/dist/src/lib/services/aws/secrets-manager/main.js +20 -28
- package/dist/src/lib/utils/aws/index.d.ts +2 -0
- package/dist/src/lib/utils/aws/index.js +8 -1
- package/package.json +12 -10
- package/src/lib/construct/site-with-ecs-backend/constants.ts +4 -0
- package/src/lib/construct/site-with-ecs-backend/index.ts +1 -0
- package/src/lib/construct/site-with-ecs-backend/main.ts +47 -1
- package/src/lib/construct/site-with-ecs-backend/types.ts +22 -0
- package/src/lib/services/aws/secrets-manager/main.ts +22 -36
- package/src/lib/utils/aws/index.ts +7 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SiteResponseHeaderPolicyType = void 0;
|
|
4
|
+
var SiteResponseHeaderPolicyType;
|
|
5
|
+
(function (SiteResponseHeaderPolicyType) {
|
|
6
|
+
SiteResponseHeaderPolicyType["ORIGIN"] = "origin";
|
|
7
|
+
SiteResponseHeaderPolicyType["STATIC"] = "static";
|
|
8
|
+
})(SiteResponseHeaderPolicyType || (exports.SiteResponseHeaderPolicyType = SiteResponseHeaderPolicyType = {}));
|
|
@@ -14,5 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./constants"), exports);
|
|
17
18
|
__exportStar(require("./main"), exports);
|
|
18
19
|
__exportStar(require("./types"), exports);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as cdk from 'aws-cdk-lib';
|
|
1
2
|
import * as certificateManager from 'aws-cdk-lib/aws-certificatemanager';
|
|
2
3
|
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
|
|
3
4
|
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
@@ -11,7 +12,7 @@ import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
|
11
12
|
import * as efs from 'aws-cdk-lib/aws-efs';
|
|
12
13
|
import { Construct } from 'constructs';
|
|
13
14
|
import { CommonConstruct } from '../../common';
|
|
14
|
-
import { SiteWithEcsBackendProps } from './types';
|
|
15
|
+
import { SiteWithEcsBackendProps, SiteResponseHeadersPolicyProps } from './types';
|
|
15
16
|
/**
|
|
16
17
|
* @classdesc Provides a construct to create and deploy a site hosted with an clustered ECS/ELB backend
|
|
17
18
|
* @example
|
|
@@ -58,6 +59,8 @@ export declare class SiteWithEcsBackend extends CommonConstruct {
|
|
|
58
59
|
siteDomainNames: string[];
|
|
59
60
|
siteCloudfrontFunction: cloudfront.Function;
|
|
60
61
|
siteFunctionAssociations: cloudfront.FunctionAssociation[];
|
|
62
|
+
siteOriginRequestPolicy: cloudfront.OriginRequestPolicy;
|
|
63
|
+
siteOriginResponseHeadersPolicy?: cloudfront.ResponseHeadersPolicy;
|
|
61
64
|
constructor(parent: Construct, id: string, props: SiteWithEcsBackendProps);
|
|
62
65
|
/**
|
|
63
66
|
* @summary Initialise and provision resources
|
|
@@ -122,6 +125,9 @@ export declare class SiteWithEcsBackend extends CommonConstruct {
|
|
|
122
125
|
* Method to create log bucket for site distribution
|
|
123
126
|
*/
|
|
124
127
|
protected createSiteLogBucket(): void;
|
|
128
|
+
protected createSiteOriginRequestPolicy(): void;
|
|
129
|
+
protected createResponseHeaderPolicy(props: SiteResponseHeadersPolicyProps): cdk.aws_cloudfront.ResponseHeadersPolicy | undefined;
|
|
130
|
+
protected createSiteOriginResponseHeadersPolicy(): void;
|
|
125
131
|
protected createSiteOrigin(): void;
|
|
126
132
|
/**
|
|
127
133
|
* @summary Method to create a site cloudfront function
|
|
@@ -24,6 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.SiteWithEcsBackend = void 0;
|
|
27
|
+
const _ = __importStar(require("lodash"));
|
|
27
28
|
const cdk = __importStar(require("aws-cdk-lib"));
|
|
28
29
|
const cloudfront = __importStar(require("aws-cdk-lib/aws-cloudfront"));
|
|
29
30
|
const origins = __importStar(require("aws-cdk-lib/aws-cloudfront-origins"));
|
|
@@ -77,6 +78,8 @@ class SiteWithEcsBackend extends common_1.CommonConstruct {
|
|
|
77
78
|
siteDomainNames;
|
|
78
79
|
siteCloudfrontFunction;
|
|
79
80
|
siteFunctionAssociations;
|
|
81
|
+
siteOriginRequestPolicy;
|
|
82
|
+
siteOriginResponseHeadersPolicy;
|
|
80
83
|
constructor(parent, id, props) {
|
|
81
84
|
super(parent, id, props);
|
|
82
85
|
this.props = props;
|
|
@@ -100,6 +103,8 @@ class SiteWithEcsBackend extends common_1.CommonConstruct {
|
|
|
100
103
|
this.createEcsBuildArgs();
|
|
101
104
|
this.createEcsContainerImage();
|
|
102
105
|
this.createEcsService();
|
|
106
|
+
this.createSiteOriginRequestPolicy();
|
|
107
|
+
this.createSiteOriginResponseHeadersPolicy();
|
|
103
108
|
this.createSiteOrigin();
|
|
104
109
|
this.createSiteCloudfrontFunction();
|
|
105
110
|
this.resolveSiteFunctionAssociations();
|
|
@@ -340,9 +345,47 @@ class SiteWithEcsBackend extends common_1.CommonConstruct {
|
|
|
340
345
|
createSiteLogBucket() {
|
|
341
346
|
this.siteLogBucket = this.s3Manager.createS3Bucket(`${this.id}-site-logs`, this, this.props.siteLogBucket);
|
|
342
347
|
}
|
|
348
|
+
createSiteOriginRequestPolicy() {
|
|
349
|
+
if (!this.props.siteOriginRequestPolicy)
|
|
350
|
+
return;
|
|
351
|
+
this.siteOriginRequestPolicy = new cloudfront.OriginRequestPolicy(this, `${this.id}-sorp`, {
|
|
352
|
+
comment: `Request Policy for ${this.id}-distribution - ${this.props.stage} stage`,
|
|
353
|
+
cookieBehavior: this.props.siteOriginRequestPolicy.cookieBehavior,
|
|
354
|
+
headerBehavior: this.props.siteOriginRequestPolicy.headerBehavior,
|
|
355
|
+
originRequestPolicyName: `${this.id}-origin-request`,
|
|
356
|
+
queryStringBehavior: this.props.siteOriginRequestPolicy.queryStringBehavior,
|
|
357
|
+
});
|
|
358
|
+
_.assign(this.props.siteDistribution.defaultBehavior, {
|
|
359
|
+
originRequestPolicy: this.siteOriginRequestPolicy,
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
createResponseHeaderPolicy(props) {
|
|
363
|
+
if (!props)
|
|
364
|
+
return undefined;
|
|
365
|
+
return new cloudfront.ResponseHeadersPolicy(this, `${this.id}-${props.type}-srhp`, {
|
|
366
|
+
...props,
|
|
367
|
+
comment: `Response Header Policy for ${props.type} for ${this.id}-distribution - ${this.props.stage} stage`,
|
|
368
|
+
responseHeadersPolicyName: `${this.id}-${props.type}-response`,
|
|
369
|
+
securityHeadersBehavior: {
|
|
370
|
+
strictTransportSecurity: {
|
|
371
|
+
...props.securityHeadersBehavior?.strictTransportSecurity,
|
|
372
|
+
accessControlMaxAge: cdk.Duration.seconds(props.securityHeadersBehavior?.strictTransportSecurity?.accessControlMaxAgeInSeconds),
|
|
373
|
+
},
|
|
374
|
+
},
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
createSiteOriginResponseHeadersPolicy() {
|
|
378
|
+
if (!this.props.siteOriginResponseHeadersPolicy)
|
|
379
|
+
return;
|
|
380
|
+
this.siteOriginResponseHeadersPolicy = this.createResponseHeaderPolicy(this.props.siteOriginResponseHeadersPolicy);
|
|
381
|
+
_.assign(this.props.siteDistribution.defaultBehavior, {
|
|
382
|
+
responseHeadersPolicy: this.siteOriginResponseHeadersPolicy,
|
|
383
|
+
});
|
|
384
|
+
}
|
|
343
385
|
createSiteOrigin() {
|
|
344
386
|
this.siteOrigin = new origins.HttpOrigin(this.siteInternalDomainName, {
|
|
345
387
|
httpPort: this.props.siteTask.listenerPort,
|
|
388
|
+
originId: `${this.id}-server`,
|
|
346
389
|
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY,
|
|
347
390
|
});
|
|
348
391
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { CommonStackProps } from '../../common';
|
|
2
2
|
import { AcmProps, CloudfrontFunctionProps, DistributionProps, EcsApplicationLoadBalancedFargateServiceProps, EcsClusterProps, EfsAccessPointOptions, EfsFileSystemProps, HealthCheck, LogProps, S3BucketProps } from '../../services';
|
|
3
3
|
import { VpcProps } from 'aws-cdk-lib/aws-ec2';
|
|
4
|
+
import { OriginRequestPolicyProps, ResponseHeadersStrictTransportSecurity, ResponseSecurityHeadersBehavior, ResponseHeadersPolicyProps } from 'aws-cdk-lib/aws-cloudfront';
|
|
5
|
+
import { SiteResponseHeaderPolicyType } from './constants';
|
|
4
6
|
/**
|
|
5
7
|
*/
|
|
6
8
|
export interface SiteWithEcsBackendProps extends CommonStackProps {
|
|
@@ -18,6 +20,8 @@ export interface SiteWithEcsBackendProps extends CommonStackProps {
|
|
|
18
20
|
siteHealthCheck: HealthCheck;
|
|
19
21
|
siteLog: LogProps;
|
|
20
22
|
siteLogBucket: S3BucketProps;
|
|
23
|
+
siteOriginRequestPolicy: OriginRequestPolicyProps;
|
|
24
|
+
siteOriginResponseHeadersPolicy: SiteResponseHeadersPolicyProps;
|
|
21
25
|
siteRecordName?: string;
|
|
22
26
|
siteRegionalCertificate: AcmProps;
|
|
23
27
|
siteSubDomain: string;
|
|
@@ -27,3 +31,13 @@ export interface SiteWithEcsBackendProps extends CommonStackProps {
|
|
|
27
31
|
useExistingHostedZone: boolean;
|
|
28
32
|
useExistingVpc: boolean;
|
|
29
33
|
}
|
|
34
|
+
export interface SiteResponseHeadersStrictTransportSecurity extends ResponseHeadersStrictTransportSecurity {
|
|
35
|
+
accessControlMaxAgeInSeconds: number;
|
|
36
|
+
}
|
|
37
|
+
export interface SiteSecurityHeadersBehavior extends ResponseSecurityHeadersBehavior {
|
|
38
|
+
strictTransportSecurity: SiteResponseHeadersStrictTransportSecurity;
|
|
39
|
+
}
|
|
40
|
+
export interface SiteResponseHeadersPolicyProps extends ResponseHeadersPolicyProps {
|
|
41
|
+
securityHeadersBehavior: SiteSecurityHeadersBehavior;
|
|
42
|
+
type: SiteResponseHeaderPolicyType;
|
|
43
|
+
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { SecretsManager as SM } from '@aws-sdk/client-secrets-manager';
|
|
2
|
-
import * as cdk from 'aws-cdk-lib';
|
|
3
1
|
import * as secretsManager from 'aws-cdk-lib/aws-secretsmanager';
|
|
4
2
|
import { CommonConstruct } from '../../../common';
|
|
5
3
|
/**
|
|
@@ -19,30 +17,18 @@ import { CommonConstruct } from '../../../common';
|
|
|
19
17
|
* @see [CDK Secrets Manager Module]{@link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_secretsmanager-readme.html}
|
|
20
18
|
*/
|
|
21
19
|
export declare class SecretsManager {
|
|
22
|
-
/**
|
|
23
|
-
*
|
|
24
|
-
* @param region
|
|
25
|
-
*/
|
|
26
|
-
getAwsSecretsManager(region: string): SM;
|
|
27
|
-
/**
|
|
28
|
-
* @summary Method to load a secret from secrets manager
|
|
29
|
-
* @param secretName
|
|
30
|
-
* @param region
|
|
31
|
-
*/
|
|
32
|
-
loadSecret(secretName: string, region: string): Promise<any>;
|
|
33
|
-
/**
|
|
34
|
-
* @summary Method to retrieve a secret from secrets manager with a cloudformation export
|
|
35
|
-
* @param id
|
|
36
|
-
* @param scope
|
|
37
|
-
* @param stackName
|
|
38
|
-
* @param exportName
|
|
39
|
-
*/
|
|
40
|
-
retrieveSecretFromSecretsManager(id: string, scope: CommonConstruct, stackName: string, exportName: string): cdk.aws_secretsmanager.ISecret;
|
|
41
20
|
/**
|
|
42
21
|
* @summary Method to create a secret
|
|
43
22
|
* @param id scoped id of the resource
|
|
44
23
|
* @param scope scope in which this resource is defined
|
|
45
24
|
* @param props the secret properties
|
|
46
25
|
*/
|
|
47
|
-
createSecret(id: string, scope: CommonConstruct, props: secretsManager.SecretProps):
|
|
26
|
+
createSecret(id: string, scope: CommonConstruct, props: secretsManager.SecretProps): secretsManager.Secret;
|
|
27
|
+
/**
|
|
28
|
+
* @summary Method to resolve secret value from a secret using AWS SDK
|
|
29
|
+
* @param scope scope in which this resource is defined
|
|
30
|
+
* @param secretId the secret name/ARN
|
|
31
|
+
* @param secretKey the secret key to resolve the value for
|
|
32
|
+
*/
|
|
33
|
+
resolveSecretValue(scope: CommonConstruct, secretId: string, secretKey: string): Promise<any>;
|
|
48
34
|
}
|
|
@@ -25,7 +25,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.SecretsManager = void 0;
|
|
27
27
|
const client_secrets_manager_1 = require("@aws-sdk/client-secrets-manager");
|
|
28
|
-
const cdk = __importStar(require("aws-cdk-lib"));
|
|
29
28
|
const secretsManager = __importStar(require("aws-cdk-lib/aws-secretsmanager"));
|
|
30
29
|
const utils = __importStar(require("../../../utils"));
|
|
31
30
|
/**
|
|
@@ -45,33 +44,6 @@ const utils = __importStar(require("../../../utils"));
|
|
|
45
44
|
* @see [CDK Secrets Manager Module]{@link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_secretsmanager-readme.html}
|
|
46
45
|
*/
|
|
47
46
|
class SecretsManager {
|
|
48
|
-
/**
|
|
49
|
-
*
|
|
50
|
-
* @param region
|
|
51
|
-
*/
|
|
52
|
-
getAwsSecretsManager(region) {
|
|
53
|
-
return new client_secrets_manager_1.SecretsManager({ region: region });
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* @summary Method to load a secret from secrets manager
|
|
57
|
-
* @param secretName
|
|
58
|
-
* @param region
|
|
59
|
-
*/
|
|
60
|
-
async loadSecret(secretName, region) {
|
|
61
|
-
const secretsManager = this.getAwsSecretsManager(region);
|
|
62
|
-
const secret = await Promise.all([secretsManager.getSecretValue({ SecretId: secretName })]);
|
|
63
|
-
return secret ? JSON.parse(secret[0].SecretString) : {};
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* @summary Method to retrieve a secret from secrets manager with a cloudformation export
|
|
67
|
-
* @param id
|
|
68
|
-
* @param scope
|
|
69
|
-
* @param stackName
|
|
70
|
-
* @param exportName
|
|
71
|
-
*/
|
|
72
|
-
retrieveSecretFromSecretsManager(id, scope, stackName, exportName) {
|
|
73
|
-
return secretsManager.Secret.fromSecretNameV2(scope, `${id}`, cdk.Fn.importValue(`${stackName}-${scope.props.stage}-${exportName}`));
|
|
74
|
-
}
|
|
75
47
|
/**
|
|
76
48
|
* @summary Method to create a secret
|
|
77
49
|
* @param id scoped id of the resource
|
|
@@ -87,5 +59,25 @@ class SecretsManager {
|
|
|
87
59
|
utils.createCfnOutput(`${id}-secretArn`, scope, secret.secretArn);
|
|
88
60
|
return secret;
|
|
89
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* @summary Method to resolve secret value from a secret using AWS SDK
|
|
64
|
+
* @param scope scope in which this resource is defined
|
|
65
|
+
* @param secretId the secret name/ARN
|
|
66
|
+
* @param secretKey the secret key to resolve the value for
|
|
67
|
+
*/
|
|
68
|
+
async resolveSecretValue(scope, secretId, secretKey) {
|
|
69
|
+
const client = new client_secrets_manager_1.SecretsManagerClient({
|
|
70
|
+
credentials: utils.determineCredentials(),
|
|
71
|
+
region: scope.props.region,
|
|
72
|
+
});
|
|
73
|
+
const command = new client_secrets_manager_1.GetSecretValueCommand({
|
|
74
|
+
SecretId: secretId,
|
|
75
|
+
});
|
|
76
|
+
const response = await client.send(command);
|
|
77
|
+
if (!response.SecretString)
|
|
78
|
+
throw `Unable to resolve secret for ${secretId}`;
|
|
79
|
+
const secretString = JSON.parse(response.SecretString);
|
|
80
|
+
return secretString[secretKey];
|
|
81
|
+
}
|
|
90
82
|
}
|
|
91
83
|
exports.SecretsManager = SecretsManager;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as cdk from 'aws-cdk-lib';
|
|
2
2
|
import { CommonConstruct } from '../../common';
|
|
3
|
+
import { AwsCredentialIdentityProvider } from '@aws-sdk/types';
|
|
3
4
|
/**
|
|
4
5
|
* @summary Helper method to add CloudFormation outputs from the construct
|
|
5
6
|
* @param id scoped id of the resource
|
|
@@ -10,3 +11,4 @@ import { CommonConstruct } from '../../common';
|
|
|
10
11
|
* @returns The CloudFormation output
|
|
11
12
|
*/
|
|
12
13
|
export declare function createCfnOutput(id: string, scope: CommonConstruct, value?: string, description?: string, overrideId?: boolean): cdk.CfnOutput;
|
|
14
|
+
export declare function determineCredentials(): AwsCredentialIdentityProvider;
|
|
@@ -23,9 +23,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.createCfnOutput = void 0;
|
|
26
|
+
exports.determineCredentials = exports.createCfnOutput = void 0;
|
|
27
27
|
const cdk = __importStar(require("aws-cdk-lib"));
|
|
28
28
|
const _ = __importStar(require("lodash"));
|
|
29
|
+
const credential_providers_1 = require("@aws-sdk/credential-providers");
|
|
29
30
|
/**
|
|
30
31
|
* @summary Helper method to add CloudFormation outputs from the construct
|
|
31
32
|
* @param id scoped id of the resource
|
|
@@ -48,3 +49,9 @@ function createCfnOutput(id, scope, value, description, overrideId = true) {
|
|
|
48
49
|
return output;
|
|
49
50
|
}
|
|
50
51
|
exports.createCfnOutput = createCfnOutput;
|
|
52
|
+
function determineCredentials() {
|
|
53
|
+
if (process.env.AWS_PROFILE)
|
|
54
|
+
return (0, credential_providers_1.fromIni)();
|
|
55
|
+
return (0, credential_providers_1.fromEnv)();
|
|
56
|
+
}
|
|
57
|
+
exports.determineCredentials = determineCredentials;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradientedge/cdk-utils",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.99.0",
|
|
4
4
|
"description": "Utilities for AWS CDK provisioning",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"engines": {
|
|
@@ -30,10 +30,10 @@
|
|
|
30
30
|
"build:production": "rimraf dist/ && npx tsc -p tsconfig.prd.json && pnpm -r build",
|
|
31
31
|
"ci": "pnpm install --frozen-lockfile && pnpm build && pnpm validate && pnpm run docs",
|
|
32
32
|
"cz": "npx cz",
|
|
33
|
-
"override:plugin:docs": "cp theme/type-converter.js node_modules/better-docs/typescript",
|
|
34
33
|
"docs": "npx rimraf api-docs && pnpm override:plugin:docs && npx jsdoc --pedantic -c jsdoc.json .",
|
|
35
|
-
"lint": "pnpm prettify && eslint **/*.ts --cache --max-warnings=0",
|
|
36
34
|
"fix": "pnpm prettify && eslint --fix **/*.ts",
|
|
35
|
+
"lint": "pnpm prettify && eslint **/*.ts --cache --max-warnings=0",
|
|
36
|
+
"override:plugin:docs": "cp theme/type-converter.js node_modules/better-docs/typescript",
|
|
37
37
|
"prettier": "npx prettier --cache --check \"**/*.{ts,json,md}\"",
|
|
38
38
|
"prettify": "npx prettier --cache --write \"**/*.{ts,json,md}\"",
|
|
39
39
|
"test": "npx rimraf coverage && npx jest --ci --maxWorkers=100%",
|
|
@@ -46,13 +46,15 @@
|
|
|
46
46
|
}
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@aws-sdk/client-secrets-manager": "^3.
|
|
49
|
+
"@aws-sdk/client-secrets-manager": "^3.357.0",
|
|
50
|
+
"@aws-sdk/credential-providers": "^3.357.0",
|
|
51
|
+
"@aws-sdk/types": "^3.357.0",
|
|
50
52
|
"@types/lodash": "^4.14.195",
|
|
51
53
|
"@types/node": "^20.3.1",
|
|
52
54
|
"@types/uuid": "^9.0.2",
|
|
53
55
|
"app-root-path": "^3.1.0",
|
|
54
|
-
"aws-cdk-lib": "^2.
|
|
55
|
-
"constructs": "^10.2.
|
|
56
|
+
"aws-cdk-lib": "^2.85.0",
|
|
57
|
+
"constructs": "^10.2.56",
|
|
56
58
|
"lodash": "^4.17.21",
|
|
57
59
|
"moment": "^2.29.4",
|
|
58
60
|
"nconf": "^0.12.0",
|
|
@@ -65,9 +67,9 @@
|
|
|
65
67
|
"@babel/eslint-parser": "^7.22.5",
|
|
66
68
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
|
67
69
|
"@types/jest": "^29.5.2",
|
|
68
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
69
|
-
"@typescript-eslint/parser": "^5.
|
|
70
|
-
"aws-cdk": "^2.
|
|
70
|
+
"@typescript-eslint/eslint-plugin": "^5.60.0",
|
|
71
|
+
"@typescript-eslint/parser": "^5.60.0",
|
|
72
|
+
"aws-cdk": "^2.85.0",
|
|
71
73
|
"better-docs": "^2.7.2",
|
|
72
74
|
"codecov": "^3.8.3",
|
|
73
75
|
"commitizen": "^4.3.0",
|
|
@@ -84,8 +86,8 @@
|
|
|
84
86
|
"jsdoc": "^4.0.2",
|
|
85
87
|
"jsdoc-babel": "^0.5.0",
|
|
86
88
|
"jsdoc-mermaid": "^1.0.0",
|
|
87
|
-
"jsdoc-to-markdown": "^8.0.0",
|
|
88
89
|
"jsdoc-plugin-typescript": "^2.2.1",
|
|
90
|
+
"jsdoc-to-markdown": "^8.0.0",
|
|
89
91
|
"prettier": "^2.8.8",
|
|
90
92
|
"prettier-plugin-organize-imports": "^3.2.2",
|
|
91
93
|
"rimraf": "^5.0.1",
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as _ from 'lodash'
|
|
1
2
|
import * as cdk from 'aws-cdk-lib'
|
|
2
3
|
import * as certificateManager from 'aws-cdk-lib/aws-certificatemanager'
|
|
3
4
|
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'
|
|
@@ -13,7 +14,7 @@ import * as s3 from 'aws-cdk-lib/aws-s3'
|
|
|
13
14
|
import * as efs from 'aws-cdk-lib/aws-efs'
|
|
14
15
|
import { Construct } from 'constructs'
|
|
15
16
|
import { CommonConstruct } from '../../common'
|
|
16
|
-
import { SiteWithEcsBackendProps } from './types'
|
|
17
|
+
import { SiteWithEcsBackendProps, SiteResponseHeadersPolicyProps } from './types'
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* @classdesc Provides a construct to create and deploy a site hosted with an clustered ECS/ELB backend
|
|
@@ -62,6 +63,8 @@ export class SiteWithEcsBackend extends CommonConstruct {
|
|
|
62
63
|
siteDomainNames: string[]
|
|
63
64
|
siteCloudfrontFunction: cloudfront.Function
|
|
64
65
|
siteFunctionAssociations: cloudfront.FunctionAssociation[]
|
|
66
|
+
siteOriginRequestPolicy: cloudfront.OriginRequestPolicy
|
|
67
|
+
siteOriginResponseHeadersPolicy?: cloudfront.ResponseHeadersPolicy
|
|
65
68
|
|
|
66
69
|
constructor(parent: Construct, id: string, props: SiteWithEcsBackendProps) {
|
|
67
70
|
super(parent, id, props)
|
|
@@ -88,6 +91,8 @@ export class SiteWithEcsBackend extends CommonConstruct {
|
|
|
88
91
|
this.createEcsBuildArgs()
|
|
89
92
|
this.createEcsContainerImage()
|
|
90
93
|
this.createEcsService()
|
|
94
|
+
this.createSiteOriginRequestPolicy()
|
|
95
|
+
this.createSiteOriginResponseHeadersPolicy()
|
|
91
96
|
this.createSiteOrigin()
|
|
92
97
|
this.createSiteCloudfrontFunction()
|
|
93
98
|
this.resolveSiteFunctionAssociations()
|
|
@@ -402,9 +407,50 @@ export class SiteWithEcsBackend extends CommonConstruct {
|
|
|
402
407
|
this.siteLogBucket = this.s3Manager.createS3Bucket(`${this.id}-site-logs`, this, this.props.siteLogBucket)
|
|
403
408
|
}
|
|
404
409
|
|
|
410
|
+
protected createSiteOriginRequestPolicy() {
|
|
411
|
+
if (!this.props.siteOriginRequestPolicy) return
|
|
412
|
+
this.siteOriginRequestPolicy = new cloudfront.OriginRequestPolicy(this, `${this.id}-sorp`, {
|
|
413
|
+
comment: `Request Policy for ${this.id}-distribution - ${this.props.stage} stage`,
|
|
414
|
+
cookieBehavior: this.props.siteOriginRequestPolicy.cookieBehavior,
|
|
415
|
+
headerBehavior: this.props.siteOriginRequestPolicy.headerBehavior,
|
|
416
|
+
originRequestPolicyName: `${this.id}-origin-request`,
|
|
417
|
+
queryStringBehavior: this.props.siteOriginRequestPolicy.queryStringBehavior,
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
_.assign(this.props.siteDistribution.defaultBehavior, {
|
|
421
|
+
originRequestPolicy: this.siteOriginRequestPolicy,
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
protected createResponseHeaderPolicy(props: SiteResponseHeadersPolicyProps) {
|
|
426
|
+
if (!props) return undefined
|
|
427
|
+
return new cloudfront.ResponseHeadersPolicy(this, `${this.id}-${props.type}-srhp`, {
|
|
428
|
+
...props,
|
|
429
|
+
comment: `Response Header Policy for ${props.type} for ${this.id}-distribution - ${this.props.stage} stage`,
|
|
430
|
+
responseHeadersPolicyName: `${this.id}-${props.type}-response`,
|
|
431
|
+
securityHeadersBehavior: {
|
|
432
|
+
strictTransportSecurity: {
|
|
433
|
+
...props.securityHeadersBehavior?.strictTransportSecurity,
|
|
434
|
+
accessControlMaxAge: cdk.Duration.seconds(
|
|
435
|
+
props.securityHeadersBehavior?.strictTransportSecurity?.accessControlMaxAgeInSeconds
|
|
436
|
+
),
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
})
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
protected createSiteOriginResponseHeadersPolicy() {
|
|
443
|
+
if (!this.props.siteOriginResponseHeadersPolicy) return
|
|
444
|
+
this.siteOriginResponseHeadersPolicy = this.createResponseHeaderPolicy(this.props.siteOriginResponseHeadersPolicy)
|
|
445
|
+
_.assign(this.props.siteDistribution.defaultBehavior, {
|
|
446
|
+
responseHeadersPolicy: this.siteOriginResponseHeadersPolicy,
|
|
447
|
+
})
|
|
448
|
+
}
|
|
449
|
+
|
|
405
450
|
protected createSiteOrigin() {
|
|
406
451
|
this.siteOrigin = new origins.HttpOrigin(this.siteInternalDomainName, {
|
|
407
452
|
httpPort: this.props.siteTask.listenerPort,
|
|
453
|
+
originId: `${this.id}-server`,
|
|
408
454
|
protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY,
|
|
409
455
|
})
|
|
410
456
|
}
|
|
@@ -12,6 +12,13 @@ import {
|
|
|
12
12
|
S3BucketProps,
|
|
13
13
|
} from '../../services'
|
|
14
14
|
import { VpcProps } from 'aws-cdk-lib/aws-ec2'
|
|
15
|
+
import {
|
|
16
|
+
OriginRequestPolicyProps,
|
|
17
|
+
ResponseHeadersStrictTransportSecurity,
|
|
18
|
+
ResponseSecurityHeadersBehavior,
|
|
19
|
+
ResponseHeadersPolicyProps,
|
|
20
|
+
} from 'aws-cdk-lib/aws-cloudfront'
|
|
21
|
+
import { SiteResponseHeaderPolicyType } from './constants'
|
|
15
22
|
|
|
16
23
|
/**
|
|
17
24
|
*/
|
|
@@ -30,6 +37,8 @@ export interface SiteWithEcsBackendProps extends CommonStackProps {
|
|
|
30
37
|
siteHealthCheck: HealthCheck
|
|
31
38
|
siteLog: LogProps
|
|
32
39
|
siteLogBucket: S3BucketProps
|
|
40
|
+
siteOriginRequestPolicy: OriginRequestPolicyProps
|
|
41
|
+
siteOriginResponseHeadersPolicy: SiteResponseHeadersPolicyProps
|
|
33
42
|
siteRecordName?: string
|
|
34
43
|
siteRegionalCertificate: AcmProps
|
|
35
44
|
siteSubDomain: string
|
|
@@ -39,3 +48,16 @@ export interface SiteWithEcsBackendProps extends CommonStackProps {
|
|
|
39
48
|
useExistingHostedZone: boolean
|
|
40
49
|
useExistingVpc: boolean
|
|
41
50
|
}
|
|
51
|
+
|
|
52
|
+
export interface SiteResponseHeadersStrictTransportSecurity extends ResponseHeadersStrictTransportSecurity {
|
|
53
|
+
accessControlMaxAgeInSeconds: number
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface SiteSecurityHeadersBehavior extends ResponseSecurityHeadersBehavior {
|
|
57
|
+
strictTransportSecurity: SiteResponseHeadersStrictTransportSecurity
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export interface SiteResponseHeadersPolicyProps extends ResponseHeadersPolicyProps {
|
|
61
|
+
securityHeadersBehavior: SiteSecurityHeadersBehavior
|
|
62
|
+
type: SiteResponseHeaderPolicyType
|
|
63
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as cdk from 'aws-cdk-lib'
|
|
1
|
+
import { GetSecretValueCommand, SecretsManagerClient } from '@aws-sdk/client-secrets-manager'
|
|
3
2
|
import * as secretsManager from 'aws-cdk-lib/aws-secretsmanager'
|
|
4
3
|
import * as utils from '../../../utils'
|
|
5
4
|
import { CommonConstruct } from '../../../common'
|
|
@@ -21,40 +20,6 @@ import { CommonConstruct } from '../../../common'
|
|
|
21
20
|
* @see [CDK Secrets Manager Module]{@link https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_secretsmanager-readme.html}
|
|
22
21
|
*/
|
|
23
22
|
export class SecretsManager {
|
|
24
|
-
/**
|
|
25
|
-
*
|
|
26
|
-
* @param region
|
|
27
|
-
*/
|
|
28
|
-
public getAwsSecretsManager(region: string) {
|
|
29
|
-
return new SM({ region: region })
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @summary Method to load a secret from secrets manager
|
|
34
|
-
* @param secretName
|
|
35
|
-
* @param region
|
|
36
|
-
*/
|
|
37
|
-
public async loadSecret(secretName: string, region: string) {
|
|
38
|
-
const secretsManager = this.getAwsSecretsManager(region)
|
|
39
|
-
const secret: any = await Promise.all([secretsManager.getSecretValue({ SecretId: secretName })])
|
|
40
|
-
return secret ? JSON.parse(secret[0].SecretString) : {}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* @summary Method to retrieve a secret from secrets manager with a cloudformation export
|
|
45
|
-
* @param id
|
|
46
|
-
* @param scope
|
|
47
|
-
* @param stackName
|
|
48
|
-
* @param exportName
|
|
49
|
-
*/
|
|
50
|
-
public retrieveSecretFromSecretsManager(id: string, scope: CommonConstruct, stackName: string, exportName: string) {
|
|
51
|
-
return secretsManager.Secret.fromSecretNameV2(
|
|
52
|
-
scope,
|
|
53
|
-
`${id}`,
|
|
54
|
-
cdk.Fn.importValue(`${stackName}-${scope.props.stage}-${exportName}`)
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
23
|
/**
|
|
59
24
|
* @summary Method to create a secret
|
|
60
25
|
* @param id scoped id of the resource
|
|
@@ -72,4 +37,25 @@ export class SecretsManager {
|
|
|
72
37
|
|
|
73
38
|
return secret
|
|
74
39
|
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @summary Method to resolve secret value from a secret using AWS SDK
|
|
43
|
+
* @param scope scope in which this resource is defined
|
|
44
|
+
* @param secretId the secret name/ARN
|
|
45
|
+
* @param secretKey the secret key to resolve the value for
|
|
46
|
+
*/
|
|
47
|
+
public async resolveSecretValue(scope: CommonConstruct, secretId: string, secretKey: string) {
|
|
48
|
+
const client = new SecretsManagerClient({
|
|
49
|
+
credentials: utils.determineCredentials(),
|
|
50
|
+
region: scope.props.region,
|
|
51
|
+
})
|
|
52
|
+
const command = new GetSecretValueCommand({
|
|
53
|
+
SecretId: secretId,
|
|
54
|
+
})
|
|
55
|
+
const response = await client.send(command)
|
|
56
|
+
if (!response.SecretString) throw `Unable to resolve secret for ${secretId}`
|
|
57
|
+
const secretString = JSON.parse(response.SecretString)
|
|
58
|
+
|
|
59
|
+
return secretString[secretKey]
|
|
60
|
+
}
|
|
75
61
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as cdk from 'aws-cdk-lib'
|
|
2
2
|
import * as _ from 'lodash'
|
|
3
3
|
import { CommonConstruct } from '../../common'
|
|
4
|
+
import { fromEnv, fromIni } from '@aws-sdk/credential-providers'
|
|
5
|
+
import { AwsCredentialIdentityProvider } from '@aws-sdk/types'
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* @summary Helper method to add CloudFormation outputs from the construct
|
|
@@ -29,3 +31,8 @@ export function createCfnOutput(
|
|
|
29
31
|
}
|
|
30
32
|
return output
|
|
31
33
|
}
|
|
34
|
+
|
|
35
|
+
export function determineCredentials(): AwsCredentialIdentityProvider {
|
|
36
|
+
if (process.env.AWS_PROFILE) return fromIni()
|
|
37
|
+
return fromEnv()
|
|
38
|
+
}
|