quidproquo-deploy-awscdk 0.1.2 → 0.1.3
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/lib/commonjs/constructs/basic/Function.d.ts +1 -0
- package/lib/commonjs/constructs/basic/Function.js +27 -2
- package/lib/commonjs/constructs/basic/LambdaLayers.js +4 -2
- package/lib/commonjs/constructs/basic/WebserverRoll.js +82 -24
- package/lib/commonjs/constructs/feature/account/QpqAccountBudgetConstruct.d.ts +9 -0
- package/lib/commonjs/constructs/feature/account/QpqAccountBudgetConstruct.js +71 -0
- package/lib/commonjs/constructs/feature/account/QpqAccountCloudTrailConstruct.d.ts +11 -0
- package/lib/commonjs/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.js → account/QpqAccountCloudTrailConstruct.js} +9 -33
- package/lib/commonjs/constructs/feature/account/QpqAccountSecurityServicesConstruct.d.ts +12 -0
- package/lib/commonjs/constructs/feature/account/QpqAccountSecurityServicesConstruct.js +61 -0
- package/lib/commonjs/constructs/feature/account/index.d.ts +3 -0
- package/lib/commonjs/constructs/feature/account/index.js +19 -0
- package/lib/commonjs/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.d.ts +9 -0
- package/lib/commonjs/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.js +218 -0
- package/lib/commonjs/constructs/feature/config/dashboard/index.d.ts +1 -0
- package/lib/commonjs/constructs/feature/config/{cloudTrail → dashboard}/index.js +1 -1
- package/lib/commonjs/constructs/feature/config/index.d.ts +2 -1
- package/lib/commonjs/constructs/feature/config/index.js +2 -1
- package/lib/commonjs/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.d.ts +9 -0
- package/lib/commonjs/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.js +35 -0
- package/lib/commonjs/constructs/feature/config/waf/index.d.ts +2 -0
- package/lib/commonjs/constructs/feature/config/waf/index.js +18 -0
- package/lib/commonjs/constructs/feature/config/waf/wafRules.d.ts +3 -0
- package/lib/commonjs/constructs/feature/config/waf/wafRules.js +64 -0
- package/lib/commonjs/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.js +6 -1
- package/lib/commonjs/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.js +10 -2
- package/lib/commonjs/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +5 -1
- package/lib/commonjs/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.js +1 -0
- package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +6 -0
- package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +22 -16
- package/lib/commonjs/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.d.ts +3 -0
- package/lib/commonjs/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.js +88 -2
- package/lib/commonjs/constructs/feature/index.d.ts +1 -0
- package/lib/commonjs/constructs/feature/index.js +1 -0
- package/lib/commonjs/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.js +49 -0
- package/lib/commonjs/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.js +2 -0
- package/lib/commonjs/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.js +5 -0
- package/lib/commonjs/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.js +10 -0
- package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +15 -0
- package/lib/commonjs/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.js +1 -0
- package/lib/commonjs/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.d.ts +5 -0
- package/lib/commonjs/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.js +52 -2
- package/lib/commonjs/stacks/AccountQpqStack.d.ts +7 -0
- package/lib/commonjs/stacks/AccountQpqStack.js +36 -0
- package/lib/commonjs/stacks/ApiQpqServiceStack.js +10 -0
- package/lib/commonjs/stacks/BootstrapQpqServiceStack.js +18 -4
- package/lib/commonjs/stacks/InfQpqServiceStack.js +2 -0
- package/lib/commonjs/stacks/WafCloudFrontWebAclStack.d.ts +12 -0
- package/lib/commonjs/stacks/WafCloudFrontWebAclStack.js +81 -0
- package/lib/commonjs/stacks/index.d.ts +2 -0
- package/lib/commonjs/stacks/index.js +2 -0
- package/lib/commonjs/utils/index.d.ts +2 -0
- package/lib/commonjs/utils/index.js +2 -0
- package/lib/commonjs/utils/javascriptRuntimeUtils.d.ts +4 -0
- package/lib/commonjs/utils/javascriptRuntimeUtils.js +24 -0
- package/lib/commonjs/utils/logRetentionUtils.d.ts +3 -0
- package/lib/commonjs/utils/logRetentionUtils.js +32 -0
- package/lib/commonjs/utils/qpqAwsCdkNamingUtils.d.ts +9 -6
- package/lib/commonjs/utils/qpqAwsCdkNamingUtils.js +8 -1
- package/lib/esm/constructs/basic/Function.d.ts +1 -0
- package/lib/esm/constructs/basic/Function.js +33 -2
- package/lib/esm/constructs/basic/LambdaLayers.js +4 -2
- package/lib/esm/constructs/basic/WebserverRoll.js +50 -24
- package/lib/esm/constructs/feature/account/QpqAccountBudgetConstruct.d.ts +9 -0
- package/lib/esm/constructs/feature/account/QpqAccountBudgetConstruct.js +66 -0
- package/lib/esm/constructs/feature/account/QpqAccountCloudTrailConstruct.d.ts +11 -0
- package/lib/esm/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.js → account/QpqAccountCloudTrailConstruct.js} +9 -29
- package/lib/esm/constructs/feature/account/QpqAccountSecurityServicesConstruct.d.ts +12 -0
- package/lib/esm/constructs/feature/account/QpqAccountSecurityServicesConstruct.js +56 -0
- package/lib/esm/constructs/feature/account/index.d.ts +3 -0
- package/lib/esm/constructs/feature/account/index.js +3 -0
- package/lib/esm/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.d.ts +9 -0
- package/lib/esm/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.js +214 -0
- package/lib/esm/constructs/feature/config/dashboard/index.d.ts +1 -0
- package/lib/esm/constructs/feature/config/dashboard/index.js +1 -0
- package/lib/esm/constructs/feature/config/index.d.ts +2 -1
- package/lib/esm/constructs/feature/config/index.js +2 -1
- package/lib/esm/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.d.ts +9 -0
- package/lib/esm/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.js +31 -0
- package/lib/esm/constructs/feature/config/waf/index.d.ts +2 -0
- package/lib/esm/constructs/feature/config/waf/index.js +2 -0
- package/lib/esm/constructs/feature/config/waf/wafRules.d.ts +3 -0
- package/lib/esm/constructs/feature/config/waf/wafRules.js +60 -0
- package/lib/esm/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.js +7 -2
- package/lib/esm/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.js +11 -3
- package/lib/esm/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +6 -2
- package/lib/esm/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.js +1 -0
- package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +6 -0
- package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +23 -17
- package/lib/esm/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.d.ts +3 -0
- package/lib/esm/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.js +58 -3
- package/lib/esm/constructs/feature/index.d.ts +1 -0
- package/lib/esm/constructs/feature/index.js +1 -0
- package/lib/esm/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.js +50 -1
- package/lib/esm/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.js +2 -0
- package/lib/esm/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.js +6 -1
- package/lib/esm/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.js +10 -0
- package/lib/esm/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +16 -1
- package/lib/esm/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.js +1 -0
- package/lib/esm/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.d.ts +5 -0
- package/lib/esm/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.js +54 -3
- package/lib/esm/stacks/AccountQpqStack.d.ts +7 -0
- package/lib/esm/stacks/AccountQpqStack.js +31 -0
- package/lib/esm/stacks/ApiQpqServiceStack.js +11 -1
- package/lib/esm/stacks/BootstrapQpqServiceStack.js +19 -5
- package/lib/esm/stacks/InfQpqServiceStack.js +2 -0
- package/lib/esm/stacks/WafCloudFrontWebAclStack.d.ts +12 -0
- package/lib/esm/stacks/WafCloudFrontWebAclStack.js +77 -0
- package/lib/esm/stacks/index.d.ts +2 -0
- package/lib/esm/stacks/index.js +2 -0
- package/lib/esm/utils/index.d.ts +2 -0
- package/lib/esm/utils/index.js +2 -0
- package/lib/esm/utils/javascriptRuntimeUtils.d.ts +4 -0
- package/lib/esm/utils/javascriptRuntimeUtils.js +19 -0
- package/lib/esm/utils/logRetentionUtils.d.ts +3 -0
- package/lib/esm/utils/logRetentionUtils.js +27 -0
- package/lib/esm/utils/qpqAwsCdkNamingUtils.d.ts +9 -6
- package/lib/esm/utils/qpqAwsCdkNamingUtils.js +6 -0
- package/package.json +7 -7
- package/src/constructs/basic/Function.ts +45 -2
- package/src/constructs/basic/LambdaLayers.ts +4 -2
- package/src/constructs/basic/WebserverRoll.ts +66 -27
- package/src/constructs/feature/account/QpqAccountBudgetConstruct.ts +81 -0
- package/src/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.ts → account/QpqAccountCloudTrailConstruct.ts} +13 -33
- package/src/constructs/feature/account/QpqAccountSecurityServicesConstruct.ts +86 -0
- package/src/constructs/feature/account/index.ts +3 -0
- package/src/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.ts +263 -0
- package/src/constructs/feature/config/dashboard/index.ts +1 -0
- package/src/constructs/feature/config/index.ts +2 -1
- package/src/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.ts +42 -0
- package/src/constructs/feature/config/waf/index.ts +2 -0
- package/src/constructs/feature/config/waf/wafRules.ts +72 -0
- package/src/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.ts +8 -2
- package/src/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.ts +17 -3
- package/src/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.ts +7 -2
- package/src/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.ts +2 -0
- package/src/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.ts +33 -19
- package/src/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.ts +68 -3
- package/src/constructs/feature/index.ts +1 -0
- package/src/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.ts +65 -1
- package/src/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.ts +3 -0
- package/src/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.ts +7 -1
- package/src/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.ts +18 -0
- package/src/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.ts +30 -1
- package/src/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.ts +2 -0
- package/src/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.ts +79 -3
- package/src/stacks/AccountQpqStack.ts +50 -0
- package/src/stacks/ApiQpqServiceStack.ts +14 -0
- package/src/stacks/BootstrapQpqServiceStack.ts +22 -13
- package/src/stacks/InfQpqServiceStack.ts +2 -0
- package/src/stacks/WafCloudFrontWebAclStack.ts +93 -0
- package/src/stacks/index.ts +2 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/javascriptRuntimeUtils.ts +24 -0
- package/src/utils/logRetentionUtils.test.ts +22 -0
- package/src/utils/logRetentionUtils.ts +28 -0
- package/src/utils/qpqAwsCdkNamingUtils.test.ts +19 -0
- package/src/utils/qpqAwsCdkNamingUtils.ts +9 -0
- package/lib/commonjs/constructs/feature/config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.d.ts +0 -9
- package/lib/commonjs/constructs/feature/config/cloudTrail/index.d.ts +0 -1
- package/lib/esm/constructs/feature/config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.d.ts +0 -9
- package/lib/esm/constructs/feature/config/cloudTrail/index.d.ts +0 -1
- package/lib/esm/constructs/feature/config/cloudTrail/index.js +0 -1
- package/src/constructs/feature/config/cloudTrail/index.ts +0 -1
|
@@ -16,6 +16,7 @@ export interface FunctionProps extends QpqConstructBlockProps {
|
|
|
16
16
|
role?: aws_iam.IRole;
|
|
17
17
|
reacreateOnFunctionNameChange?: boolean;
|
|
18
18
|
vpc?: aws_ec2.IVpc;
|
|
19
|
+
securityGroups?: aws_ec2.ISecurityGroup[];
|
|
19
20
|
}
|
|
20
21
|
export declare class Function extends QpqConstructBlock {
|
|
21
22
|
readonly lambdaFunction: aws_lambda.Function;
|
|
@@ -34,14 +34,36 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.Function = void 0;
|
|
37
|
+
const quidproquo_actionprocessor_awslambda_1 = require("quidproquo-actionprocessor-awslambda");
|
|
37
38
|
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
38
39
|
const quidproquo_config_aws_2 = require("quidproquo-config-aws");
|
|
40
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
39
41
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
42
|
const cdk = __importStar(require("aws-cdk-lib"));
|
|
41
43
|
const upath_1 = require("upath");
|
|
42
44
|
const constants_1 = require("../../constants");
|
|
43
45
|
const utils_1 = require("../../utils");
|
|
46
|
+
const qpqDeployAwsCdkUtils = __importStar(require("../../utils/qpqDeployAwsCdkUtils"));
|
|
44
47
|
const QpqConstructBlock_1 = require("../base/QpqConstructBlock");
|
|
48
|
+
// Resolves the federated code store location for this service, if it opted in via
|
|
49
|
+
// defineFederatedModuleStore. Points the lambda at the referenced storage drive's
|
|
50
|
+
// bucket, namespaced by service (s3://<bucket>/<service>), so many services can share
|
|
51
|
+
// one bucket. Read access comes from the storage drive's own grants. Returns {} when
|
|
52
|
+
// federation isn't configured, so the lambda runs only its bundled code.
|
|
53
|
+
const getFederatedCodeStoreEnv = (qpqConfig) => {
|
|
54
|
+
var _a;
|
|
55
|
+
const federatedStore = quidproquo_core_1.qpqCoreUtils.getFederatedModuleStore(qpqConfig);
|
|
56
|
+
if (!federatedStore) {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
const storageDrive = quidproquo_core_1.qpqCoreUtils.getStorageDriveByName(federatedStore.storageDrive, qpqConfig);
|
|
60
|
+
if (!storageDrive) {
|
|
61
|
+
throw new Error(`defineFederatedModuleStore references storage drive [${federatedStore.storageDrive}] which is not defined - add a matching defineStorageDrive`);
|
|
62
|
+
}
|
|
63
|
+
const bucketName = quidproquo_actionprocessor_awslambda_1.awsNamingUtils.resolveConfigRuntimeResourceNameFromConfig(((_a = storageDrive.owner) === null || _a === void 0 ? void 0 : _a.resourceNameOverride) || storageDrive.storageDrive, qpqConfig, storageDrive.owner);
|
|
64
|
+
const serviceName = quidproquo_core_1.qpqCoreUtils.getApplicationModuleName(qpqConfig);
|
|
65
|
+
return Object.assign({ federatedCodeStoreUrl: `s3://${bucketName}/${serviceName}` }, (federatedStore.recheckMs !== undefined ? { federatedCodeStoreRecheckMs: `${federatedStore.recheckMs}` } : {}));
|
|
66
|
+
};
|
|
45
67
|
class Function extends QpqConstructBlock_1.QpqConstructBlock {
|
|
46
68
|
constructor(scope, id, props) {
|
|
47
69
|
var _a;
|
|
@@ -53,12 +75,13 @@ class Function extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
53
75
|
this.lambdaFunction = new aws_cdk_lib_1.aws_lambda.Function(this, functionId, {
|
|
54
76
|
functionName: props.functionName,
|
|
55
77
|
timeout: cdk.Duration.seconds(props.timeoutInSeconds || 25),
|
|
56
|
-
runtime:
|
|
78
|
+
runtime: (0, utils_1.getLambdaRuntime)(props.qpqConfig),
|
|
79
|
+
architecture: (0, utils_1.getLambdaArchitecture)(props.qpqConfig),
|
|
57
80
|
memorySize: props.memoryInBytes || serviceInfo.lambdaMaxMemoryInMiB || 1024,
|
|
58
81
|
layers: props.apiLayerVersions,
|
|
59
82
|
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset((0, upath_1.join)(utils_1.qpqAwsCdkPathUtils.getApiBuildPathFullPath(props.qpqConfig), props.functionType)),
|
|
60
83
|
handler: `${handlerFile}.${props.executorName}`,
|
|
61
|
-
environment: Object.assign({ AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1' }, (props.environment || {})),
|
|
84
|
+
environment: Object.assign(Object.assign({ AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1' }, getFederatedCodeStoreEnv(props.qpqConfig)), (props.environment || {})),
|
|
62
85
|
reservedConcurrentExecutions: quidproquo_config_aws_2.qpqConfigAwsUtils.isReservedConcurrencyDisabled(props.qpqConfig) ? undefined : props.reservedConcurrentExecutions,
|
|
63
86
|
tracing: quidproquo_config_aws_2.qpqConfigAwsUtils.isTracingDisabled(props.qpqConfig) ? aws_cdk_lib_1.aws_lambda.Tracing.DISABLED : aws_cdk_lib_1.aws_lambda.Tracing.ACTIVE,
|
|
64
87
|
logGroup: new aws_cdk_lib_1.aws_logs.LogGroup(this, 'LogGroup', {
|
|
@@ -72,7 +95,9 @@ class Function extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
72
95
|
subnetType: aws_cdk_lib_1.aws_ec2.SubnetType.PRIVATE_WITH_EGRESS,
|
|
73
96
|
}
|
|
74
97
|
: undefined,
|
|
98
|
+
securityGroups: props.securityGroups,
|
|
75
99
|
});
|
|
100
|
+
qpqDeployAwsCdkUtils.applyEnvironmentTags(this.lambdaFunction, props.qpqConfig);
|
|
76
101
|
if (!quidproquo_config_aws_2.qpqConfigAwsUtils.isLambdaWarmingDisabled(props.qpqConfig)) {
|
|
77
102
|
const region = quidproquo_config_aws_2.qpqConfigAwsUtils.getApplicationModuleDeployRegion(props.qpqConfig);
|
|
78
103
|
const accountId = quidproquo_config_aws_2.qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);
|
|
@@ -9,6 +9,7 @@ const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
|
9
9
|
const quidproquo_core_1 = require("quidproquo-core");
|
|
10
10
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const utils_1 = require("../../utils");
|
|
12
13
|
const QpqConstructBlock_1 = require("../base/QpqConstructBlock");
|
|
13
14
|
const getLambdaLayersWithFullPaths = (qpqConfig) => {
|
|
14
15
|
const awsServiceAccountInfoConfig = (0, quidproquo_config_aws_1.getAwsServiceAccountInfoConfig)(qpqConfig);
|
|
@@ -23,12 +24,13 @@ class LambdaLayers extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
23
24
|
constructor(scope, id, props) {
|
|
24
25
|
super(scope, id, props);
|
|
25
26
|
const apiLayers = (0, exports.getLambdaLayersWithFullPaths)(props.qpqConfig);
|
|
27
|
+
const lambdaRuntime = (0, utils_1.getLambdaRuntime)(props.qpqConfig);
|
|
26
28
|
const userLayers = apiLayers.map((layer) => {
|
|
27
29
|
return layer.buildPath
|
|
28
30
|
? new aws_cdk_lib_1.aws_lambda.LayerVersion(this, `${layer.name}-layer`, {
|
|
29
31
|
layerVersionName: quidproquo_actionprocessor_awslambda_1.awsNamingUtils.getQpqRuntimeResourceNameFromConfig(layer.name, props.qpqConfig),
|
|
30
32
|
code: new aws_cdk_lib_1.aws_lambda.AssetCode(layer.buildPath),
|
|
31
|
-
compatibleRuntimes: [
|
|
33
|
+
compatibleRuntimes: [lambdaRuntime],
|
|
32
34
|
})
|
|
33
35
|
: aws_cdk_lib_1.aws_lambda.LayerVersion.fromLayerVersionArn(this, `${layer.name}-layer-ref`, layer.layerArn);
|
|
34
36
|
});
|
|
@@ -37,7 +39,7 @@ class LambdaLayers extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
37
39
|
const logExtensionLayer = new aws_cdk_lib_1.aws_lambda.LayerVersion(this, 'qpq-log-extension-layer', {
|
|
38
40
|
layerVersionName: quidproquo_actionprocessor_awslambda_1.awsNamingUtils.getQpqRuntimeResourceNameFromConfig('qpq-log-extension', props.qpqConfig),
|
|
39
41
|
code: new aws_cdk_lib_1.aws_lambda.AssetCode((0, quidproquo_actionprocessor_awslambda_1.getLogExtensionLayerPath)()),
|
|
40
|
-
compatibleRuntimes: [
|
|
42
|
+
compatibleRuntimes: [lambdaRuntime],
|
|
41
43
|
});
|
|
42
44
|
this.layers = [...userLayers, logExtensionLayer];
|
|
43
45
|
}
|
|
@@ -1,7 +1,44 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
36
|
exports.WebserverRoll = void 0;
|
|
37
|
+
const quidproquo_actionprocessor_awslambda_1 = require("quidproquo-actionprocessor-awslambda");
|
|
38
|
+
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
39
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
4
40
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
41
|
+
const qpqDeployAwsCdkUtils = __importStar(require("../../utils/qpqDeployAwsCdkUtils"));
|
|
5
42
|
const QpqConstructBlock_1 = require("../base/QpqConstructBlock");
|
|
6
43
|
class WebserverRoll extends QpqConstructBlock_1.QpqConstructBlock {
|
|
7
44
|
constructor(scope, id, props) {
|
|
@@ -10,6 +47,22 @@ class WebserverRoll extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
10
47
|
roleName: this.resourceName('service-role'),
|
|
11
48
|
assumedBy: new aws_cdk_lib_1.aws_iam.CompositePrincipal(new aws_cdk_lib_1.aws_iam.ServicePrincipal('lambda.amazonaws.com'), new aws_cdk_lib_1.aws_iam.ServicePrincipal('transfer.amazonaws.com'), new aws_cdk_lib_1.aws_iam.ServicePrincipal('edgelambda.amazonaws.com')),
|
|
12
49
|
});
|
|
50
|
+
qpqDeployAwsCdkUtils.applyEnvironmentTags(role, props.qpqConfig);
|
|
51
|
+
const region = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployRegion(props.qpqConfig);
|
|
52
|
+
const accountId = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);
|
|
53
|
+
const applicationName = quidproquo_core_1.qpqCoreUtils.getApplicationName(props.qpqConfig);
|
|
54
|
+
const environment = quidproquo_core_1.qpqCoreUtils.getApplicationModuleEnvironment(props.qpqConfig);
|
|
55
|
+
const feature = quidproquo_core_1.qpqCoreUtils.getApplicationModuleFeature(props.qpqConfig);
|
|
56
|
+
// This deployment's identity tags, as applied to every qpq resource by applyEnvironmentTags.
|
|
57
|
+
// Used for tag-based conditions where the target resource's id is unknowable at synth
|
|
58
|
+
// (later deploy phase / AWS-generated) but the resource is still owned by this deployment.
|
|
59
|
+
const applicationResourceTagConditions = Object.assign({ 'aws:ResourceTag/application': quidproquo_core_1.qpqCoreUtils.getApplicationName(props.qpqConfig), 'aws:ResourceTag/environment': quidproquo_core_1.qpqCoreUtils.getApplicationModuleEnvironment(props.qpqConfig) }, (feature ? { 'aws:ResourceTag/feature': feature } : {}));
|
|
60
|
+
// Every event-bus topic this service can publish to (owned + referenced cross-module) -
|
|
61
|
+
// the same owner-fallback derivation the runtime send processor uses to build the ARN.
|
|
62
|
+
const eventBusTopicArns = quidproquo_core_1.qpqCoreUtils.getAllEventBusConfigs(props.qpqConfig).map((eventBusConfig) => {
|
|
63
|
+
var _a, _b, _c, _d, _e;
|
|
64
|
+
return quidproquo_actionprocessor_awslambda_1.awsNamingUtils.getEventBusSnsTopicArn(((_a = eventBusConfig.owner) === null || _a === void 0 ? void 0 : _a.resourceNameOverride) || eventBusConfig.name, props.qpqConfig, ((_b = eventBusConfig.owner) === null || _b === void 0 ? void 0 : _b.module) || quidproquo_core_1.qpqCoreUtils.getApplicationModuleName(props.qpqConfig), ((_c = eventBusConfig.owner) === null || _c === void 0 ? void 0 : _c.environment) || quidproquo_core_1.qpqCoreUtils.getApplicationModuleEnvironment(props.qpqConfig), ((_d = eventBusConfig.owner) === null || _d === void 0 ? void 0 : _d.application) || quidproquo_core_1.qpqCoreUtils.getApplicationName(props.qpqConfig), ((_e = eventBusConfig.owner) === null || _e === void 0 ? void 0 : _e.feature) || quidproquo_core_1.qpqCoreUtils.getApplicationModuleFeature(props.qpqConfig));
|
|
65
|
+
});
|
|
13
66
|
const policies = [
|
|
14
67
|
// Resolve cross-stack resource names at runtime via CloudFormation exports.
|
|
15
68
|
{
|
|
@@ -17,35 +70,39 @@ class WebserverRoll extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
17
70
|
actions: ['cloudformation:ListExports'],
|
|
18
71
|
resources: ['*'],
|
|
19
72
|
},
|
|
20
|
-
//
|
|
73
|
+
// Read api-key values at runtime for api-key validation - keys are fetched individually
|
|
74
|
+
// by id (never listed), so the grant is per-key, pinned to this application's tags.
|
|
75
|
+
// Module is deliberately NOT pinned: routes may reference another service's key
|
|
76
|
+
// (ApiKeyReference.serviceName) within the same application + environment.
|
|
21
77
|
{
|
|
22
78
|
sid: 'APIGatewayGetOperations',
|
|
23
79
|
actions: ['apigateway:GET'],
|
|
24
|
-
resources: [
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
sid: 'CloudFrontCreateInvalidation',
|
|
29
|
-
actions: ['cloudfront:CreateInvalidation'],
|
|
30
|
-
resources: ['*'],
|
|
31
|
-
},
|
|
32
|
-
// Publish to event-bus SNS topics (the framework's pub/sub layer).
|
|
33
|
-
{
|
|
34
|
-
sid: 'SNSPublishMessages',
|
|
35
|
-
actions: ['sns:Publish'],
|
|
36
|
-
resources: ['*'],
|
|
80
|
+
resources: [`arn:aws:apigateway:${region}::/apikeys/*`],
|
|
81
|
+
conditions: {
|
|
82
|
+
StringEquals: applicationResourceTagConditions,
|
|
83
|
+
},
|
|
37
84
|
},
|
|
38
|
-
//
|
|
85
|
+
// Publish to event-bus SNS topics (the framework's pub/sub layer), scoped to the
|
|
86
|
+
// buses this service declares. Omitted entirely when no event buses are configured.
|
|
87
|
+
...(eventBusTopicArns.length > 0
|
|
88
|
+
? [
|
|
89
|
+
{
|
|
90
|
+
sid: 'SNSPublishMessages',
|
|
91
|
+
actions: ['sns:Publish'],
|
|
92
|
+
resources: eventBusTopicArns,
|
|
93
|
+
},
|
|
94
|
+
]
|
|
95
|
+
: []),
|
|
96
|
+
// Invoke QPQ service functions from other lambdas. The runtime derives target names
|
|
97
|
+
// with getConfigRuntimeResourceName from its own app/env/feature (only the target
|
|
98
|
+
// service varies), so the same helper builds this pattern with the function and
|
|
99
|
+
// service segments wildcarded - cross-app/env invocation is not possible.
|
|
39
100
|
{
|
|
40
101
|
sid: 'LambdaInvokeFunction',
|
|
41
102
|
actions: ['lambda:InvokeFunction'],
|
|
42
|
-
resources: [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
{
|
|
46
|
-
sid: 'APIGatewayManageConnections',
|
|
47
|
-
actions: ['execute-api:ManageConnections'],
|
|
48
|
-
resources: ['*'],
|
|
103
|
+
resources: [
|
|
104
|
+
`arn:aws:lambda:${region}:${accountId}:function:${quidproquo_actionprocessor_awslambda_1.awsNamingUtils.getConfigRuntimeResourceName('*-sfunc', applicationName, '*', environment, feature)}`,
|
|
105
|
+
],
|
|
49
106
|
},
|
|
50
107
|
// Look up ACM certs when wiring up custom domains at runtime.
|
|
51
108
|
{
|
|
@@ -53,7 +110,8 @@ class WebserverRoll extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
53
110
|
actions: ['acm:DescribeCertificate', 'acm:ListCertificates'],
|
|
54
111
|
resources: ['*'],
|
|
55
112
|
},
|
|
56
|
-
// Standard Lambda logging + log retrieval for the `askGetLogs` flow.
|
|
113
|
+
// Standard Lambda logging + log retrieval for the `askGetLogs` flow. Account-pinned;
|
|
114
|
+
// region is left open because edge lambdas write logs in their execution region.
|
|
57
115
|
{
|
|
58
116
|
sid: 'CloudWatchLogsManagement',
|
|
59
117
|
actions: [
|
|
@@ -65,7 +123,7 @@ class WebserverRoll extends QpqConstructBlock_1.QpqConstructBlock {
|
|
|
65
123
|
'logs:GetLogEvents',
|
|
66
124
|
'logs:FilterLogEvents',
|
|
67
125
|
],
|
|
68
|
-
resources: [
|
|
126
|
+
resources: [`arn:aws:logs:*:${accountId}:log-group:*`],
|
|
69
127
|
},
|
|
70
128
|
// Required for VPC-attached Lambdas to manage their ENIs.
|
|
71
129
|
{
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AccountBudgetQPQConfigSetting } from 'quidproquo-config-aws';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
import { QpqConstructBlock, QpqConstructBlockProps } from '../../base/QpqConstructBlock';
|
|
4
|
+
export interface QpqAccountBudgetConstructProps extends QpqConstructBlockProps {
|
|
5
|
+
budgetConfig: AccountBudgetQPQConfigSetting;
|
|
6
|
+
}
|
|
7
|
+
export declare class QpqAccountBudgetConstruct extends QpqConstructBlock {
|
|
8
|
+
constructor(scope: Construct, id: string, props: QpqAccountBudgetConstructProps);
|
|
9
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QpqAccountBudgetConstruct = void 0;
|
|
4
|
+
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
5
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
6
|
+
const QpqConstructBlock_1 = require("../../base/QpqConstructBlock");
|
|
7
|
+
const defaultThresholds = [
|
|
8
|
+
{ thresholdPercent: 80, type: quidproquo_config_aws_1.BudgetThresholdType.actual },
|
|
9
|
+
{ thresholdPercent: 100, type: quidproquo_config_aws_1.BudgetThresholdType.forecasted },
|
|
10
|
+
{ thresholdPercent: 100, type: quidproquo_config_aws_1.BudgetThresholdType.actual },
|
|
11
|
+
{ thresholdPercent: 150, type: quidproquo_config_aws_1.BudgetThresholdType.actual },
|
|
12
|
+
];
|
|
13
|
+
class QpqAccountBudgetConstruct extends QpqConstructBlock_1.QpqConstructBlock {
|
|
14
|
+
constructor(scope, id, props) {
|
|
15
|
+
var _a;
|
|
16
|
+
super(scope, id, props);
|
|
17
|
+
const { name, monthlyLimitUsd, subscriberEmails, thresholds = defaultThresholds, anomalyDetection } = props.budgetConfig;
|
|
18
|
+
const accountId = quidproquo_config_aws_1.qpqConfigAwsUtils.getApplicationModuleDeployAccountId(props.qpqConfig);
|
|
19
|
+
const emailSubscribers = subscriberEmails.map((email) => ({
|
|
20
|
+
subscriptionType: 'EMAIL',
|
|
21
|
+
address: email,
|
|
22
|
+
}));
|
|
23
|
+
new aws_cdk_lib_1.aws_budgets.CfnBudget(this, 'budget', {
|
|
24
|
+
budget: {
|
|
25
|
+
budgetName: `qpq-budget-${accountId}-${name}`,
|
|
26
|
+
budgetType: 'COST',
|
|
27
|
+
timeUnit: 'MONTHLY',
|
|
28
|
+
budgetLimit: {
|
|
29
|
+
amount: monthlyLimitUsd,
|
|
30
|
+
unit: 'USD',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
notificationsWithSubscribers: thresholds.map((threshold) => ({
|
|
34
|
+
notification: {
|
|
35
|
+
notificationType: threshold.type === quidproquo_config_aws_1.BudgetThresholdType.forecasted ? 'FORECASTED' : 'ACTUAL',
|
|
36
|
+
comparisonOperator: 'GREATER_THAN',
|
|
37
|
+
threshold: threshold.thresholdPercent,
|
|
38
|
+
thresholdType: 'PERCENTAGE',
|
|
39
|
+
},
|
|
40
|
+
subscribers: emailSubscribers,
|
|
41
|
+
})),
|
|
42
|
+
});
|
|
43
|
+
if (!(anomalyDetection === null || anomalyDetection === void 0 ? void 0 : anomalyDetection.disabled)) {
|
|
44
|
+
// AWS allows only one DIMENSIONAL(SERVICE) anomaly monitor per account - declare a
|
|
45
|
+
// single defineAccountBudget per account (or disable anomalyDetection on extras)
|
|
46
|
+
const anomalyMonitor = new aws_cdk_lib_1.aws_ce.CfnAnomalyMonitor(this, 'anomaly-monitor', {
|
|
47
|
+
monitorName: `qpq-anomaly-monitor-${accountId}-${name}`,
|
|
48
|
+
monitorType: 'DIMENSIONAL',
|
|
49
|
+
monitorDimension: 'SERVICE',
|
|
50
|
+
});
|
|
51
|
+
new aws_cdk_lib_1.aws_ce.CfnAnomalySubscription(this, 'anomaly-subscription', {
|
|
52
|
+
subscriptionName: `qpq-anomaly-subscription-${accountId}-${name}`,
|
|
53
|
+
monitorArnList: [anomalyMonitor.attrMonitorArn],
|
|
54
|
+
// DAILY is required for EMAIL subscribers (IMMEDIATE is SNS-only)
|
|
55
|
+
frequency: 'DAILY',
|
|
56
|
+
subscribers: subscriberEmails.map((email) => ({
|
|
57
|
+
type: 'EMAIL',
|
|
58
|
+
address: email,
|
|
59
|
+
})),
|
|
60
|
+
thresholdExpression: JSON.stringify({
|
|
61
|
+
Dimensions: {
|
|
62
|
+
Key: 'ANOMALY_TOTAL_IMPACT_ABSOLUTE',
|
|
63
|
+
MatchOptions: ['GREATER_THAN_OR_EQUAL'],
|
|
64
|
+
Values: [`${(_a = anomalyDetection === null || anomalyDetection === void 0 ? void 0 : anomalyDetection.minimumImpactUsd) !== null && _a !== void 0 ? _a : 10}`],
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.QpqAccountBudgetConstruct = QpqAccountBudgetConstruct;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AccountCloudTrailQPQConfigSetting } from 'quidproquo-config-aws';
|
|
2
|
+
import { aws_logs } from 'aws-cdk-lib';
|
|
3
|
+
import { Construct } from 'constructs';
|
|
4
|
+
import { QpqConstructBlock, QpqConstructBlockProps } from '../../base/QpqConstructBlock';
|
|
5
|
+
export interface QpqAccountCloudTrailConstructProps extends QpqConstructBlockProps {
|
|
6
|
+
cloudTrailConfig: AccountCloudTrailQPQConfigSetting;
|
|
7
|
+
}
|
|
8
|
+
export declare class QpqAccountCloudTrailConstruct extends QpqConstructBlock {
|
|
9
|
+
readonly logGroup?: aws_logs.LogGroup;
|
|
10
|
+
constructor(scope: Construct, id: string, props: QpqAccountCloudTrailConstructProps);
|
|
11
|
+
}
|
|
@@ -33,37 +33,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
-
exports.
|
|
36
|
+
exports.QpqAccountCloudTrailConstruct = void 0;
|
|
37
37
|
const quidproquo_config_aws_1 = require("quidproquo-config-aws");
|
|
38
38
|
const cdk = __importStar(require("aws-cdk-lib"));
|
|
39
39
|
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
40
|
-
const
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.THREE_DAYS,
|
|
44
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.FIVE_DAYS,
|
|
45
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.ONE_WEEK,
|
|
46
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.TWO_WEEKS,
|
|
47
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.ONE_MONTH,
|
|
48
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.TWO_MONTHS,
|
|
49
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.THREE_MONTHS,
|
|
50
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.FOUR_MONTHS,
|
|
51
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.FIVE_MONTHS,
|
|
52
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.SIX_MONTHS,
|
|
53
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.ONE_YEAR,
|
|
54
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.THIRTEEN_MONTHS,
|
|
55
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.EIGHTEEN_MONTHS,
|
|
56
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.TWO_YEARS,
|
|
57
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.FIVE_YEARS,
|
|
58
|
-
aws_cdk_lib_1.aws_logs.RetentionDays.TEN_YEARS,
|
|
59
|
-
];
|
|
60
|
-
const resolveLogRetention = (days) => {
|
|
61
|
-
var _a;
|
|
62
|
-
if (!days)
|
|
63
|
-
return aws_cdk_lib_1.aws_logs.RetentionDays.ONE_MONTH;
|
|
64
|
-
return (_a = SUPPORTED_RETENTION_DAYS.find((v) => v >= days)) !== null && _a !== void 0 ? _a : aws_cdk_lib_1.aws_logs.RetentionDays.TEN_YEARS;
|
|
65
|
-
};
|
|
66
|
-
class QpqBootstrapConfigCloudTrailConstruct extends QpqConstructBlock_1.QpqConstructBlock {
|
|
40
|
+
const utils_1 = require("../../../utils");
|
|
41
|
+
const QpqConstructBlock_1 = require("../../base/QpqConstructBlock");
|
|
42
|
+
class QpqAccountCloudTrailConstruct extends QpqConstructBlock_1.QpqConstructBlock {
|
|
67
43
|
constructor(scope, id, props) {
|
|
68
44
|
super(scope, id, props);
|
|
69
45
|
const { name, retentionDays = 365, enableLogFileValidation = true, multiRegion = true, includeGlobalServiceEvents = true, cloudWatchLogs, } = props.cloudTrailConfig;
|
|
@@ -77,10 +53,10 @@ class QpqBootstrapConfigCloudTrailConstruct extends QpqConstructBlock_1.QpqConst
|
|
|
77
53
|
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
78
54
|
lifecycleRules: [{ expiration: cdk.Duration.days(retentionDays) }],
|
|
79
55
|
});
|
|
80
|
-
|
|
56
|
+
this.logGroup = cloudWatchLogs
|
|
81
57
|
? new aws_cdk_lib_1.aws_logs.LogGroup(this, 'log-group', {
|
|
82
58
|
logGroupName: `/qpq/cloudtrail/${name}`,
|
|
83
|
-
retention: resolveLogRetention(cloudWatchLogs.retentionDays),
|
|
59
|
+
retention: (0, utils_1.resolveLogRetention)(cloudWatchLogs.retentionDays),
|
|
84
60
|
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
85
61
|
})
|
|
86
62
|
: undefined;
|
|
@@ -90,9 +66,9 @@ class QpqBootstrapConfigCloudTrailConstruct extends QpqConstructBlock_1.QpqConst
|
|
|
90
66
|
enableFileValidation: enableLogFileValidation,
|
|
91
67
|
isMultiRegionTrail: multiRegion,
|
|
92
68
|
includeGlobalServiceEvents,
|
|
93
|
-
sendToCloudWatchLogs: !!logGroup,
|
|
94
|
-
cloudWatchLogGroup: logGroup,
|
|
69
|
+
sendToCloudWatchLogs: !!this.logGroup,
|
|
70
|
+
cloudWatchLogGroup: this.logGroup,
|
|
95
71
|
});
|
|
96
72
|
}
|
|
97
73
|
}
|
|
98
|
-
exports.
|
|
74
|
+
exports.QpqAccountCloudTrailConstruct = QpqAccountCloudTrailConstruct;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AccountSecurityServicesQPQConfigSetting } from 'quidproquo-config-aws';
|
|
2
|
+
import { aws_logs } from 'aws-cdk-lib';
|
|
3
|
+
import { Construct } from 'constructs';
|
|
4
|
+
import { QpqConstructBlock, QpqConstructBlockProps } from '../../base/QpqConstructBlock';
|
|
5
|
+
export interface QpqAccountSecurityServicesConstructProps extends QpqConstructBlockProps {
|
|
6
|
+
securityServicesConfig: AccountSecurityServicesQPQConfigSetting;
|
|
7
|
+
/** The account CloudTrail's CloudWatch log group - required for cognitoAuthFailureAlert. */
|
|
8
|
+
cloudTrailLogGroup?: aws_logs.ILogGroup;
|
|
9
|
+
}
|
|
10
|
+
export declare class QpqAccountSecurityServicesConstruct extends QpqConstructBlock {
|
|
11
|
+
constructor(scope: Construct, id: string, props: QpqAccountSecurityServicesConstructProps);
|
|
12
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.QpqAccountSecurityServicesConstruct = void 0;
|
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
|
5
|
+
const QpqConstructBlock_1 = require("../../base/QpqConstructBlock");
|
|
6
|
+
// GuardDuty detectors and Security Hub hubs are one-per-account+region, which is exactly
|
|
7
|
+
// why they live in the account stack rather than any app's bootstrap - an app teardown
|
|
8
|
+
// must not take the account's threat detection with it.
|
|
9
|
+
class QpqAccountSecurityServicesConstruct extends QpqConstructBlock_1.QpqConstructBlock {
|
|
10
|
+
constructor(scope, id, props) {
|
|
11
|
+
var _a;
|
|
12
|
+
super(scope, id, props);
|
|
13
|
+
if (props.securityServicesConfig.enableGuardDuty) {
|
|
14
|
+
new aws_cdk_lib_1.aws_guardduty.CfnDetector(this, 'guardduty-detector', {
|
|
15
|
+
enable: true,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (props.securityServicesConfig.enableSecurityHub) {
|
|
19
|
+
// Security Hub's compliance standards require AWS Config recording, which bills per
|
|
20
|
+
// configuration item recorded - enabling this is a deliberate cost decision
|
|
21
|
+
new aws_cdk_lib_1.aws_securityhub.CfnHub(this, 'security-hub');
|
|
22
|
+
}
|
|
23
|
+
// Credential stuffing hitting Cognito directly (bypassing the apis) shows up as
|
|
24
|
+
// cognito-idp NotAuthorizedException events in CloudTrail - alert by email when the
|
|
25
|
+
// failure rate spikes. (Failed logins through qpq routes are covered separately by
|
|
26
|
+
// the per-api 401-rate alarms.)
|
|
27
|
+
const cognitoAuthFailureAlert = props.securityServicesConfig.cognitoAuthFailureAlert;
|
|
28
|
+
if (cognitoAuthFailureAlert) {
|
|
29
|
+
if (!props.cloudTrailLogGroup) {
|
|
30
|
+
throw new Error('cognitoAuthFailureAlert requires a defineAccountCloudTrail with cloudWatchLogs enabled');
|
|
31
|
+
}
|
|
32
|
+
const metricFilter = new aws_cdk_lib_1.aws_logs.MetricFilter(this, 'cognito-auth-failure-filter', {
|
|
33
|
+
logGroup: props.cloudTrailLogGroup,
|
|
34
|
+
filterPattern: aws_cdk_lib_1.aws_logs.FilterPattern.all(aws_cdk_lib_1.aws_logs.FilterPattern.stringValue('$.eventSource', '=', 'cognito-idp.amazonaws.com'), aws_cdk_lib_1.aws_logs.FilterPattern.stringValue('$.errorCode', '=', 'NotAuthorizedException')),
|
|
35
|
+
metricNamespace: 'qpq/security',
|
|
36
|
+
metricName: 'cognito-auth-failures',
|
|
37
|
+
metricValue: '1',
|
|
38
|
+
});
|
|
39
|
+
const alertTopic = new aws_cdk_lib_1.aws_sns.Topic(this, 'security-alerts-topic', {
|
|
40
|
+
topicName: 'qpq-account-security-alerts',
|
|
41
|
+
});
|
|
42
|
+
cognitoAuthFailureAlert.emails.forEach((email) => {
|
|
43
|
+
alertTopic.addSubscription(new aws_cdk_lib_1.aws_sns_subscriptions.EmailSubscription(email));
|
|
44
|
+
});
|
|
45
|
+
const alarm = new aws_cdk_lib_1.aws_cloudwatch.Alarm(this, 'cognito-auth-failure-alarm', {
|
|
46
|
+
alarmName: 'qpq-account-cognito-auth-failures',
|
|
47
|
+
metric: metricFilter.metric({
|
|
48
|
+
statistic: 'Sum',
|
|
49
|
+
period: aws_cdk_lib_1.Duration.minutes(5),
|
|
50
|
+
}),
|
|
51
|
+
threshold: (_a = cognitoAuthFailureAlert.thresholdPer5Minutes) !== null && _a !== void 0 ? _a : 10,
|
|
52
|
+
comparisonOperator: aws_cdk_lib_1.aws_cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
|
|
53
|
+
evaluationPeriods: 1,
|
|
54
|
+
// No sign-in attempts = no datapoints - that is not an alarm state
|
|
55
|
+
treatMissingData: aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.NOT_BREACHING,
|
|
56
|
+
});
|
|
57
|
+
alarm.addAlarmAction(new aws_cdk_lib_1.aws_cloudwatch_actions.SnsAction(alertTopic));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
exports.QpqAccountSecurityServicesConstruct = QpqAccountSecurityServicesConstruct;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./QpqAccountBudgetConstruct"), exports);
|
|
18
|
+
__exportStar(require("./QpqAccountCloudTrailConstruct"), exports);
|
|
19
|
+
__exportStar(require("./QpqAccountSecurityServicesConstruct"), exports);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AwsServiceDashboardQPQConfigSetting } from 'quidproquo-config-aws';
|
|
2
|
+
import { Construct } from 'constructs';
|
|
3
|
+
import { QpqConstructBlock, QpqConstructBlockProps } from '../../../base/QpqConstructBlock';
|
|
4
|
+
export interface QpqConfigAwsDashboardConstructProps extends QpqConstructBlockProps {
|
|
5
|
+
dashboardConfig: AwsServiceDashboardQPQConfigSetting;
|
|
6
|
+
}
|
|
7
|
+
export declare class QpqConfigAwsDashboardConstruct extends QpqConstructBlock {
|
|
8
|
+
constructor(scope: Construct, id: string, props: QpqConfigAwsDashboardConstructProps);
|
|
9
|
+
}
|