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.
Files changed (164) hide show
  1. package/lib/commonjs/constructs/basic/Function.d.ts +1 -0
  2. package/lib/commonjs/constructs/basic/Function.js +27 -2
  3. package/lib/commonjs/constructs/basic/LambdaLayers.js +4 -2
  4. package/lib/commonjs/constructs/basic/WebserverRoll.js +82 -24
  5. package/lib/commonjs/constructs/feature/account/QpqAccountBudgetConstruct.d.ts +9 -0
  6. package/lib/commonjs/constructs/feature/account/QpqAccountBudgetConstruct.js +71 -0
  7. package/lib/commonjs/constructs/feature/account/QpqAccountCloudTrailConstruct.d.ts +11 -0
  8. package/lib/commonjs/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.js → account/QpqAccountCloudTrailConstruct.js} +9 -33
  9. package/lib/commonjs/constructs/feature/account/QpqAccountSecurityServicesConstruct.d.ts +12 -0
  10. package/lib/commonjs/constructs/feature/account/QpqAccountSecurityServicesConstruct.js +61 -0
  11. package/lib/commonjs/constructs/feature/account/index.d.ts +3 -0
  12. package/lib/commonjs/constructs/feature/account/index.js +19 -0
  13. package/lib/commonjs/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.d.ts +9 -0
  14. package/lib/commonjs/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.js +218 -0
  15. package/lib/commonjs/constructs/feature/config/dashboard/index.d.ts +1 -0
  16. package/lib/commonjs/constructs/feature/config/{cloudTrail → dashboard}/index.js +1 -1
  17. package/lib/commonjs/constructs/feature/config/index.d.ts +2 -1
  18. package/lib/commonjs/constructs/feature/config/index.js +2 -1
  19. package/lib/commonjs/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.d.ts +9 -0
  20. package/lib/commonjs/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.js +35 -0
  21. package/lib/commonjs/constructs/feature/config/waf/index.d.ts +2 -0
  22. package/lib/commonjs/constructs/feature/config/waf/index.js +18 -0
  23. package/lib/commonjs/constructs/feature/config/waf/wafRules.d.ts +3 -0
  24. package/lib/commonjs/constructs/feature/config/waf/wafRules.js +64 -0
  25. package/lib/commonjs/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.js +6 -1
  26. package/lib/commonjs/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.js +10 -2
  27. package/lib/commonjs/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +5 -1
  28. package/lib/commonjs/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.js +1 -0
  29. package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +6 -0
  30. package/lib/commonjs/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +22 -16
  31. package/lib/commonjs/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.d.ts +3 -0
  32. package/lib/commonjs/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.js +88 -2
  33. package/lib/commonjs/constructs/feature/index.d.ts +1 -0
  34. package/lib/commonjs/constructs/feature/index.js +1 -0
  35. package/lib/commonjs/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.js +49 -0
  36. package/lib/commonjs/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.js +2 -0
  37. package/lib/commonjs/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.js +5 -0
  38. package/lib/commonjs/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.js +10 -0
  39. package/lib/commonjs/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +15 -0
  40. package/lib/commonjs/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.js +1 -0
  41. package/lib/commonjs/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.d.ts +5 -0
  42. package/lib/commonjs/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.js +52 -2
  43. package/lib/commonjs/stacks/AccountQpqStack.d.ts +7 -0
  44. package/lib/commonjs/stacks/AccountQpqStack.js +36 -0
  45. package/lib/commonjs/stacks/ApiQpqServiceStack.js +10 -0
  46. package/lib/commonjs/stacks/BootstrapQpqServiceStack.js +18 -4
  47. package/lib/commonjs/stacks/InfQpqServiceStack.js +2 -0
  48. package/lib/commonjs/stacks/WafCloudFrontWebAclStack.d.ts +12 -0
  49. package/lib/commonjs/stacks/WafCloudFrontWebAclStack.js +81 -0
  50. package/lib/commonjs/stacks/index.d.ts +2 -0
  51. package/lib/commonjs/stacks/index.js +2 -0
  52. package/lib/commonjs/utils/index.d.ts +2 -0
  53. package/lib/commonjs/utils/index.js +2 -0
  54. package/lib/commonjs/utils/javascriptRuntimeUtils.d.ts +4 -0
  55. package/lib/commonjs/utils/javascriptRuntimeUtils.js +24 -0
  56. package/lib/commonjs/utils/logRetentionUtils.d.ts +3 -0
  57. package/lib/commonjs/utils/logRetentionUtils.js +32 -0
  58. package/lib/commonjs/utils/qpqAwsCdkNamingUtils.d.ts +9 -6
  59. package/lib/commonjs/utils/qpqAwsCdkNamingUtils.js +8 -1
  60. package/lib/esm/constructs/basic/Function.d.ts +1 -0
  61. package/lib/esm/constructs/basic/Function.js +33 -2
  62. package/lib/esm/constructs/basic/LambdaLayers.js +4 -2
  63. package/lib/esm/constructs/basic/WebserverRoll.js +50 -24
  64. package/lib/esm/constructs/feature/account/QpqAccountBudgetConstruct.d.ts +9 -0
  65. package/lib/esm/constructs/feature/account/QpqAccountBudgetConstruct.js +66 -0
  66. package/lib/esm/constructs/feature/account/QpqAccountCloudTrailConstruct.d.ts +11 -0
  67. package/lib/esm/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.js → account/QpqAccountCloudTrailConstruct.js} +9 -29
  68. package/lib/esm/constructs/feature/account/QpqAccountSecurityServicesConstruct.d.ts +12 -0
  69. package/lib/esm/constructs/feature/account/QpqAccountSecurityServicesConstruct.js +56 -0
  70. package/lib/esm/constructs/feature/account/index.d.ts +3 -0
  71. package/lib/esm/constructs/feature/account/index.js +3 -0
  72. package/lib/esm/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.d.ts +9 -0
  73. package/lib/esm/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.js +214 -0
  74. package/lib/esm/constructs/feature/config/dashboard/index.d.ts +1 -0
  75. package/lib/esm/constructs/feature/config/dashboard/index.js +1 -0
  76. package/lib/esm/constructs/feature/config/index.d.ts +2 -1
  77. package/lib/esm/constructs/feature/config/index.js +2 -1
  78. package/lib/esm/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.d.ts +9 -0
  79. package/lib/esm/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.js +31 -0
  80. package/lib/esm/constructs/feature/config/waf/index.d.ts +2 -0
  81. package/lib/esm/constructs/feature/config/waf/index.js +2 -0
  82. package/lib/esm/constructs/feature/config/waf/wafRules.d.ts +3 -0
  83. package/lib/esm/constructs/feature/config/waf/wafRules.js +60 -0
  84. package/lib/esm/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.js +7 -2
  85. package/lib/esm/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.js +11 -3
  86. package/lib/esm/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.js +6 -2
  87. package/lib/esm/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.js +1 -0
  88. package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.d.ts +6 -0
  89. package/lib/esm/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.js +23 -17
  90. package/lib/esm/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.d.ts +3 -0
  91. package/lib/esm/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.js +58 -3
  92. package/lib/esm/constructs/feature/index.d.ts +1 -0
  93. package/lib/esm/constructs/feature/index.js +1 -0
  94. package/lib/esm/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.js +50 -1
  95. package/lib/esm/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.js +2 -0
  96. package/lib/esm/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.js +6 -1
  97. package/lib/esm/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.js +10 -0
  98. package/lib/esm/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.js +16 -1
  99. package/lib/esm/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.js +1 -0
  100. package/lib/esm/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.d.ts +5 -0
  101. package/lib/esm/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.js +54 -3
  102. package/lib/esm/stacks/AccountQpqStack.d.ts +7 -0
  103. package/lib/esm/stacks/AccountQpqStack.js +31 -0
  104. package/lib/esm/stacks/ApiQpqServiceStack.js +11 -1
  105. package/lib/esm/stacks/BootstrapQpqServiceStack.js +19 -5
  106. package/lib/esm/stacks/InfQpqServiceStack.js +2 -0
  107. package/lib/esm/stacks/WafCloudFrontWebAclStack.d.ts +12 -0
  108. package/lib/esm/stacks/WafCloudFrontWebAclStack.js +77 -0
  109. package/lib/esm/stacks/index.d.ts +2 -0
  110. package/lib/esm/stacks/index.js +2 -0
  111. package/lib/esm/utils/index.d.ts +2 -0
  112. package/lib/esm/utils/index.js +2 -0
  113. package/lib/esm/utils/javascriptRuntimeUtils.d.ts +4 -0
  114. package/lib/esm/utils/javascriptRuntimeUtils.js +19 -0
  115. package/lib/esm/utils/logRetentionUtils.d.ts +3 -0
  116. package/lib/esm/utils/logRetentionUtils.js +27 -0
  117. package/lib/esm/utils/qpqAwsCdkNamingUtils.d.ts +9 -6
  118. package/lib/esm/utils/qpqAwsCdkNamingUtils.js +6 -0
  119. package/package.json +7 -7
  120. package/src/constructs/basic/Function.ts +45 -2
  121. package/src/constructs/basic/LambdaLayers.ts +4 -2
  122. package/src/constructs/basic/WebserverRoll.ts +66 -27
  123. package/src/constructs/feature/account/QpqAccountBudgetConstruct.ts +81 -0
  124. package/src/constructs/feature/{config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.ts → account/QpqAccountCloudTrailConstruct.ts} +13 -33
  125. package/src/constructs/feature/account/QpqAccountSecurityServicesConstruct.ts +86 -0
  126. package/src/constructs/feature/account/index.ts +3 -0
  127. package/src/constructs/feature/config/dashboard/QpqConfigAwsDashboardConstruct.ts +263 -0
  128. package/src/constructs/feature/config/dashboard/index.ts +1 -0
  129. package/src/constructs/feature/config/index.ts +2 -1
  130. package/src/constructs/feature/config/waf/QpqBootstrapConfigWafConstruct.ts +42 -0
  131. package/src/constructs/feature/config/waf/index.ts +2 -0
  132. package/src/constructs/feature/config/waf/wafRules.ts +72 -0
  133. package/src/constructs/feature/core/auth/QpqInfCoreUserDirectoryConstruct.ts +8 -2
  134. package/src/constructs/feature/core/graphDatabase/QpqCoreApiGraphDatabaseConstruct.ts +17 -3
  135. package/src/constructs/feature/core/keyValueStore/QpqCoreKeyValueStoreConstruct.ts +7 -2
  136. package/src/constructs/feature/core/schedule/QpqCoreRecurringScheduleConstruct.ts +2 -0
  137. package/src/constructs/feature/core/storageDrive/QpqCoreStorageDriveConstruct.ts +33 -19
  138. package/src/constructs/feature/core/virtualNetwork/BootstrapQpqCoreVirtualNetworkConstruct.ts +68 -3
  139. package/src/constructs/feature/index.ts +1 -0
  140. package/src/constructs/feature/webserver/api/ApiQpqWebserverApiConstruct.ts +65 -1
  141. package/src/constructs/feature/webserver/apiKey/QpqWebserverApiKeyConstruct.ts +3 -0
  142. package/src/constructs/feature/webserver/domainProxy/WebQpqWebserverDomainProxyConstruct.ts +7 -1
  143. package/src/constructs/feature/webserver/serviceFunction/QpqWebserverServiceFunctionConstruct.ts +18 -0
  144. package/src/constructs/feature/webserver/webEntry/WebQpqWebserverWebEntryConstruct.ts +30 -1
  145. package/src/constructs/feature/webserver/websocket/QpqApiWebserverWebsocketConstruct.ts +2 -0
  146. package/src/constructs/feature/webserver/websocket/QpqWebserverWebsocketConstruct.ts +79 -3
  147. package/src/stacks/AccountQpqStack.ts +50 -0
  148. package/src/stacks/ApiQpqServiceStack.ts +14 -0
  149. package/src/stacks/BootstrapQpqServiceStack.ts +22 -13
  150. package/src/stacks/InfQpqServiceStack.ts +2 -0
  151. package/src/stacks/WafCloudFrontWebAclStack.ts +93 -0
  152. package/src/stacks/index.ts +2 -0
  153. package/src/utils/index.ts +2 -0
  154. package/src/utils/javascriptRuntimeUtils.ts +24 -0
  155. package/src/utils/logRetentionUtils.test.ts +22 -0
  156. package/src/utils/logRetentionUtils.ts +28 -0
  157. package/src/utils/qpqAwsCdkNamingUtils.test.ts +19 -0
  158. package/src/utils/qpqAwsCdkNamingUtils.ts +9 -0
  159. package/lib/commonjs/constructs/feature/config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.d.ts +0 -9
  160. package/lib/commonjs/constructs/feature/config/cloudTrail/index.d.ts +0 -1
  161. package/lib/esm/constructs/feature/config/cloudTrail/QpqBootstrapConfigCloudTrailConstruct.d.ts +0 -9
  162. package/lib/esm/constructs/feature/config/cloudTrail/index.d.ts +0 -1
  163. package/lib/esm/constructs/feature/config/cloudTrail/index.js +0 -1
  164. 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: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_22_X,
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: [aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_22_X],
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: [aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_22_X],
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
- // Look up API Gateway metadata (stages, deployments) from within Lambdas.
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
- // Invalidate CloudFront caches after web-entry static asset deploys.
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
- // Invoke QPQ service functions (`*sfunc*`) from other Lambdas.
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: ['arn:aws:lambda:*:*:function:*sfunc*'],
43
- },
44
- // Push messages to websocket clients via API Gateway Management API.
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.QpqBootstrapConfigCloudTrailConstruct = void 0;
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 QpqConstructBlock_1 = require("../../../base/QpqConstructBlock");
41
- const SUPPORTED_RETENTION_DAYS = [
42
- aws_cdk_lib_1.aws_logs.RetentionDays.ONE_DAY,
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
- const logGroup = cloudWatchLogs
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.QpqBootstrapConfigCloudTrailConstruct = QpqBootstrapConfigCloudTrailConstruct;
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,3 @@
1
+ export * from './QpqAccountBudgetConstruct';
2
+ export * from './QpqAccountCloudTrailConstruct';
3
+ export * from './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
+ }