@digitraffic/common 2022.10.25-1 → 2022.10.31-1
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/.editorconfig +9 -0
- package/.eslintignore +4 -0
- package/.eslintrc.json +27 -0
- package/.github/CODEOWNERS +2 -0
- package/.github/workflows/build.yml +36 -0
- package/.github/workflows/eslint.yml +38 -0
- package/.github/workflows/mirror.yml +15 -0
- package/.gitignore +29 -0
- package/.husky/pre-commit +4 -0
- package/.prettierrc.json +10 -0
- package/dist/aws/infra/api/integration.js +52 -0
- package/dist/aws/infra/api/response.js +61 -0
- package/dist/aws/infra/api/responses.js +82 -0
- package/dist/aws/infra/api/static-integration.js +54 -0
- package/dist/aws/infra/canaries/canary-alarm.js +26 -0
- package/dist/aws/infra/canaries/canary-keys.js +7 -0
- package/dist/aws/infra/canaries/canary-parameters.js +3 -0
- package/dist/aws/infra/canaries/canary-role.js +46 -0
- package/dist/aws/infra/canaries/canary.js +32 -0
- package/dist/aws/infra/canaries/database-canary.js +70 -0
- package/dist/aws/infra/canaries/database-checker.js +103 -0
- package/dist/aws/infra/canaries/url-canary.js +47 -0
- package/dist/aws/infra/canaries/url-checker.js +252 -0
- package/dist/aws/infra/documentation.js +95 -0
- package/dist/aws/infra/scheduler.js +31 -0
- package/dist/aws/infra/security-rule.js +39 -0
- package/dist/aws/infra/sqs-integration.js +93 -0
- package/dist/aws/infra/sqs-queue.js +130 -0
- package/dist/aws/infra/stack/lambda-configs.js +105 -0
- package/dist/aws/infra/stack/monitoredfunction.js +143 -0
- package/dist/aws/infra/stack/rest_apis.js +185 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +174 -0
- package/dist/aws/infra/stack/stack.js +67 -0
- package/dist/aws/infra/stack/subscription.js +42 -0
- package/dist/aws/infra/usage-plans.js +42 -0
- package/dist/aws/runtime/apikey.js +13 -0
- package/dist/aws/runtime/digitraffic-integration-response.js +26 -0
- package/dist/aws/runtime/environment.js +12 -0
- package/dist/aws/runtime/messaging.js +31 -0
- package/dist/aws/runtime/s3.js +30 -0
- package/dist/aws/runtime/secrets/dbsecret.js +96 -0
- package/dist/aws/runtime/secrets/proxy-holder.js +27 -0
- package/dist/aws/runtime/secrets/rds-holder.js +27 -0
- package/dist/aws/runtime/secrets/secret-holder.js +76 -0
- package/dist/aws/runtime/secrets/secret.js +43 -0
- package/dist/aws/types/errors.js +16 -0
- package/dist/aws/types/lambda-response.js +33 -0
- package/dist/aws/types/mediatypes.js +16 -0
- package/dist/aws/types/model-with-reference.js +3 -0
- package/dist/aws/types/proxytypes.js +3 -0
- package/dist/aws/types/tags.js +7 -0
- package/dist/database/cached.js +32 -0
- package/dist/database/database.js +70 -0
- package/dist/database/last-updated.js +54 -0
- package/dist/database/models.js +3 -0
- package/dist/marine/id_utils.js +33 -0
- package/dist/marine/rtz.js +3 -0
- package/dist/test/asserter.js +45 -0
- package/dist/test/db-testutils.js +31 -0
- package/dist/test/httpserver.js +74 -0
- package/dist/test/secret.js +25 -0
- package/dist/test/secrets-manager.js +59 -0
- package/dist/test/testutils.js +44 -0
- package/dist/types/either.js +3 -0
- package/dist/types/input-error.js +7 -0
- package/dist/types/language.js +10 -0
- package/dist/types/traffictype.js +13 -0
- package/dist/types/validator.js +14 -0
- package/dist/utils/api-model.js +129 -0
- package/dist/utils/base64.js +21 -0
- package/dist/utils/date-utils.js +34 -0
- package/dist/utils/geojson-types.js +18 -0
- package/dist/utils/geometry.js +164 -0
- package/dist/utils/retry.js +50 -0
- package/dist/utils/slack.js +25 -0
- package/dist/utils/utils.js +75 -0
- package/jest.config.js +15 -0
- package/package.json +15 -13
- package/src/@types/geojson-validation/index.d.ts +4 -0
- package/src/aws/infra/api/integration.ts +73 -0
- package/src/aws/infra/api/response.ts +67 -0
- package/src/aws/infra/api/responses.ts +124 -0
- package/src/aws/infra/api/static-integration.ts +62 -0
- package/src/aws/infra/canaries/canary-alarm.ts +31 -0
- package/src/aws/infra/canaries/canary-keys.ts +3 -0
- package/{aws/infra/canaries/canary-parameters.d.ts → src/aws/infra/canaries/canary-parameters.ts} +7 -6
- package/src/aws/infra/canaries/canary-role.ts +47 -0
- package/src/aws/infra/canaries/canary.ts +46 -0
- package/src/aws/infra/canaries/database-canary.ts +98 -0
- package/src/aws/infra/canaries/database-checker.ts +155 -0
- package/src/aws/infra/canaries/url-canary.ts +74 -0
- package/src/aws/infra/canaries/url-checker.ts +366 -0
- package/src/aws/infra/documentation.ts +124 -0
- package/src/aws/infra/scheduler.ts +59 -0
- package/src/aws/infra/security-rule.ts +38 -0
- package/src/aws/infra/sqs-integration.ts +102 -0
- package/src/aws/infra/sqs-queue.ts +148 -0
- package/src/aws/infra/stack/lambda-configs.ts +207 -0
- package/src/aws/infra/stack/monitoredfunction.ts +342 -0
- package/src/aws/infra/stack/rest_apis.ts +223 -0
- package/src/aws/infra/stack/stack-checking-aspect.ts +279 -0
- package/src/aws/infra/stack/stack.ts +145 -0
- package/src/aws/infra/stack/subscription.ts +58 -0
- package/src/aws/infra/usage-plans.ts +41 -0
- package/src/aws/runtime/apikey.ts +9 -0
- package/src/aws/runtime/digitraffic-integration-response.ts +28 -0
- package/src/aws/runtime/environment.ts +9 -0
- package/src/aws/runtime/messaging.ts +26 -0
- package/src/aws/runtime/s3.ts +44 -0
- package/src/aws/runtime/secrets/dbsecret.ts +116 -0
- package/src/aws/runtime/secrets/proxy-holder.ts +37 -0
- package/src/aws/runtime/secrets/rds-holder.ts +33 -0
- package/src/aws/runtime/secrets/secret-holder.ts +116 -0
- package/src/aws/runtime/secrets/secret.ts +50 -0
- package/src/aws/types/errors.ts +14 -0
- package/src/aws/types/lambda-response.ts +43 -0
- package/{aws/types/mediatypes.d.ts → src/aws/types/mediatypes.ts} +4 -3
- package/{aws/types/model-with-reference.d.ts → src/aws/types/model-with-reference.ts} +2 -1
- package/src/aws/types/proxytypes.ts +27 -0
- package/src/aws/types/tags.ts +3 -0
- package/src/database/cached.ts +35 -0
- package/src/database/database.ts +96 -0
- package/src/database/last-updated.ts +59 -0
- package/{database/models.d.ts → src/database/models.ts} +1 -0
- package/src/marine/id_utils.ts +30 -0
- package/src/marine/rtz.ts +57 -0
- package/src/test/asserter.ts +48 -0
- package/src/test/db-testutils.ts +44 -0
- package/src/test/httpserver.ts +96 -0
- package/src/test/secret.ts +23 -0
- package/src/test/secrets-manager.ts +34 -0
- package/src/test/testutils.ts +39 -0
- package/src/types/either.ts +3 -0
- package/src/types/input-error.ts +2 -0
- package/src/types/language.ts +3 -0
- package/src/types/traffictype.ts +8 -0
- package/src/types/validator.ts +10 -0
- package/src/utils/api-model.ts +133 -0
- package/src/utils/base64.ts +16 -0
- package/src/utils/date-utils.ts +30 -0
- package/src/utils/geojson-types.ts +22 -0
- package/src/utils/geometry.ts +164 -0
- package/src/utils/retry.ts +49 -0
- package/src/utils/slack.ts +22 -0
- package/src/utils/utils.ts +105 -0
- package/test/marine/id_utils.test.ts +57 -0
- package/test/promise/promise.test.ts +143 -0
- package/test/secrets/dbsecret.test.ts +59 -0
- package/test/secrets/secret-holder.test.ts +143 -0
- package/test/secrets/secret.test.ts +49 -0
- package/test/test/httpserver.test.ts +128 -0
- package/test/utils/date-utils.test.ts +28 -0
- package/test/utils/geometry.test.ts +29 -0
- package/test/utils/utils.test.ts +64 -0
- package/tsconfig.eslint.json +4 -0
- package/tsconfig.json +22 -0
- package/yarn.lock +4060 -0
- package/aws/infra/api/integration.d.ts +0 -21
- package/aws/infra/api/integration.js +0 -52
- package/aws/infra/api/response.d.ts +0 -22
- package/aws/infra/api/response.js +0 -61
- package/aws/infra/api/responses.d.ts +0 -39
- package/aws/infra/api/responses.js +0 -79
- package/aws/infra/api/static-integration.d.ts +0 -15
- package/aws/infra/api/static-integration.js +0 -54
- package/aws/infra/canaries/canary-alarm.d.ts +0 -6
- package/aws/infra/canaries/canary-alarm.js +0 -26
- package/aws/infra/canaries/canary-parameters.js +0 -3
- package/aws/infra/canaries/canary-role.d.ts +0 -6
- package/aws/infra/canaries/canary-role.js +0 -46
- package/aws/infra/canaries/canary.d.ts +0 -8
- package/aws/infra/canaries/canary.js +0 -32
- package/aws/infra/canaries/database-canary.d.ts +0 -18
- package/aws/infra/canaries/database-canary.js +0 -55
- package/aws/infra/canaries/database-checker.d.ts +0 -21
- package/aws/infra/canaries/database-checker.js +0 -109
- package/aws/infra/canaries/url-canary.d.ts +0 -19
- package/aws/infra/canaries/url-canary.js +0 -46
- package/aws/infra/canaries/url-checker.d.ts +0 -46
- package/aws/infra/canaries/url-checker.js +0 -238
- package/aws/infra/documentation.d.ts +0 -56
- package/aws/infra/documentation.js +0 -95
- package/aws/infra/scheduler.d.ts +0 -12
- package/aws/infra/scheduler.js +0 -31
- package/aws/infra/security-rule.d.ts +0 -12
- package/aws/infra/security-rule.js +0 -39
- package/aws/infra/sqs-integration.d.ts +0 -7
- package/aws/infra/sqs-integration.js +0 -93
- package/aws/infra/sqs-queue.d.ts +0 -16
- package/aws/infra/sqs-queue.js +0 -130
- package/aws/infra/stack/lambda-configs.d.ts +0 -72
- package/aws/infra/stack/lambda-configs.js +0 -93
- package/aws/infra/stack/monitoredfunction.d.ts +0 -84
- package/aws/infra/stack/monitoredfunction.js +0 -135
- package/aws/infra/stack/rest_apis.d.ts +0 -41
- package/aws/infra/stack/rest_apis.js +0 -185
- package/aws/infra/stack/stack-checking-aspect.d.ts +0 -21
- package/aws/infra/stack/stack-checking-aspect.js +0 -174
- package/aws/infra/stack/stack.d.ts +0 -44
- package/aws/infra/stack/stack.js +0 -60
- package/aws/infra/stack/subscription.d.ts +0 -17
- package/aws/infra/stack/subscription.js +0 -41
- package/aws/infra/usage-plans.d.ts +0 -15
- package/aws/infra/usage-plans.js +0 -42
- package/aws/runtime/apikey.d.ts +0 -2
- package/aws/runtime/apikey.js +0 -13
- package/aws/runtime/digitraffic-integration-response.d.ts +0 -8
- package/aws/runtime/digitraffic-integration-response.js +0 -26
- package/aws/runtime/environment.d.ts +0 -1
- package/aws/runtime/environment.js +0 -12
- package/aws/runtime/messaging.d.ts +0 -10
- package/aws/runtime/messaging.js +0 -31
- package/aws/runtime/s3.d.ts +0 -2
- package/aws/runtime/s3.js +0 -30
- package/aws/runtime/secrets/dbsecret.d.ts +0 -54
- package/aws/runtime/secrets/dbsecret.js +0 -96
- package/aws/runtime/secrets/proxy-holder.d.ts +0 -9
- package/aws/runtime/secrets/proxy-holder.js +0 -26
- package/aws/runtime/secrets/rds-holder.d.ts +0 -9
- package/aws/runtime/secrets/rds-holder.js +0 -26
- package/aws/runtime/secrets/secret-holder.d.ts +0 -26
- package/aws/runtime/secrets/secret-holder.js +0 -73
- package/aws/runtime/secrets/secret.d.ts +0 -8
- package/aws/runtime/secrets/secret.js +0 -43
- package/aws/types/errors.d.ts +0 -4
- package/aws/types/errors.js +0 -9
- package/aws/types/lambda-response.d.ts +0 -12
- package/aws/types/lambda-response.js +0 -28
- package/aws/types/mediatypes.js +0 -15
- package/aws/types/model-with-reference.js +0 -3
- package/aws/types/proxytypes.d.ts +0 -26
- package/aws/types/proxytypes.js +0 -3
- package/aws/types/tags.d.ts +0 -2
- package/aws/types/tags.js +0 -7
- package/database/cached.d.ts +0 -7
- package/database/cached.js +0 -32
- package/database/database.d.ts +0 -19
- package/database/database.js +0 -62
- package/database/last-updated.d.ts +0 -16
- package/database/last-updated.js +0 -54
- package/database/models.js +0 -3
- package/index.d.ts +0 -1
- package/index.js +0 -18
- package/marine/id_utils.d.ts +0 -3
- package/marine/id_utils.js +0 -33
- package/marine/rtz.d.ts +0 -48
- package/marine/rtz.js +0 -3
- package/test/asserter.d.ts +0 -11
- package/test/asserter.js +0 -45
- package/test/db-testutils.d.ts +0 -2
- package/test/db-testutils.js +0 -31
- package/test/httpserver.d.ts +0 -18
- package/test/httpserver.js +0 -67
- package/test/secret.d.ts +0 -3
- package/test/secret.js +0 -25
- package/test/secrets-manager.d.ts +0 -9
- package/test/secrets-manager.js +0 -59
- package/test/testutils.d.ts +0 -12
- package/test/testutils.js +0 -44
- package/types/input-error.d.ts +0 -2
- package/types/input-error.js +0 -7
- package/types/language.d.ts +0 -5
- package/types/language.js +0 -10
- package/types/traffictype.d.ts +0 -8
- package/types/traffictype.js +0 -13
- package/types/validator.d.ts +0 -4
- package/types/validator.js +0 -14
- package/utils/api-model.d.ts +0 -87
- package/utils/api-model.js +0 -129
- package/utils/base64.d.ts +0 -12
- package/utils/base64.js +0 -21
- package/utils/date-utils.d.ts +0 -17
- package/utils/date-utils.js +0 -34
- package/utils/geojson-types.d.ts +0 -14
- package/utils/geojson-types.js +0 -18
- package/utils/geometry.d.ts +0 -36
- package/utils/geometry.js +0 -140
- package/utils/retry.d.ts +0 -13
- package/utils/retry.js +0 -50
- package/utils/slack.d.ts +0 -5
- package/utils/slack.js +0 -25
- package/utils/utils.d.ts +0 -30
- package/utils/utils.js +0 -64
@@ -0,0 +1,174 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.StackCheckingAspect = void 0;
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
5
|
+
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
|
6
|
+
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
|
7
|
+
const stack_1 = require("./stack");
|
8
|
+
const aws_apigateway_1 = require("aws-cdk-lib/aws-apigateway");
|
9
|
+
const change_case_1 = require("change-case");
|
10
|
+
const aws_sqs_1 = require("aws-cdk-lib/aws-sqs");
|
11
|
+
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
|
12
|
+
const MAX_CONCURRENCY_LIMIT = 100;
|
13
|
+
const NODE_RUNTIME = aws_lambda_1.Runtime.NODEJS_14_X.name;
|
14
|
+
var ResourceType;
|
15
|
+
(function (ResourceType) {
|
16
|
+
ResourceType["stackName"] = "STACK_NAME";
|
17
|
+
ResourceType["reservedConcurrentConcurrency"] = "RESERVED_CONCURRENT_CONCURRENCY";
|
18
|
+
ResourceType["functionTimeout"] = "FUNCTION_TIMEOUT";
|
19
|
+
ResourceType["functionMemorySize"] = "FUNCTION_MEMORY_SIZE";
|
20
|
+
ResourceType["functionRuntime"] = "FUNCTION_RUNTIME";
|
21
|
+
ResourceType["functionName"] = "FUNCTION_NAME";
|
22
|
+
ResourceType["tagSolution"] = "TAG_SOLUTION";
|
23
|
+
ResourceType["bucketPublicity"] = "BUCKET_PUBLICITY";
|
24
|
+
ResourceType["resourcePath"] = "RESOURCE_PATH";
|
25
|
+
ResourceType["queueEncryption"] = "QUEUE_ENCRYPTION";
|
26
|
+
ResourceType["logGroupRetention"] = "LOG_GROUP_RETENTION";
|
27
|
+
})(ResourceType || (ResourceType = {}));
|
28
|
+
class StackCheckingAspect {
|
29
|
+
constructor(stackShortName, whitelistedResources) {
|
30
|
+
this.stackShortName = stackShortName;
|
31
|
+
this.whitelistedResources = whitelistedResources;
|
32
|
+
}
|
33
|
+
static create(stack) {
|
34
|
+
return new StackCheckingAspect(stack.configuration.shortName, stack.configuration.whitelistedResources);
|
35
|
+
}
|
36
|
+
visit(node) {
|
37
|
+
//console.info("visiting class " + node.constructor.name);
|
38
|
+
this.checkStack(node);
|
39
|
+
this.checkFunction(node);
|
40
|
+
this.checkTags(node);
|
41
|
+
this.checkBucket(node);
|
42
|
+
this.checkResourceCasing(node);
|
43
|
+
this.checkQueueEncryption(node);
|
44
|
+
this.checkLogGroupRetention(node);
|
45
|
+
}
|
46
|
+
isWhitelisted(key) {
|
47
|
+
return this.whitelistedResources?.some((wl) => {
|
48
|
+
return key.matchAll(new RegExp(wl, "g"));
|
49
|
+
});
|
50
|
+
}
|
51
|
+
addAnnotation(node, key, message, isError = true) {
|
52
|
+
const resourceKey = `${node.node.path}/${key}`;
|
53
|
+
const isWhiteListed = this.isWhitelisted(resourceKey);
|
54
|
+
const annotationMessage = `${resourceKey}:${message}`;
|
55
|
+
// error && whitelisted -> warning
|
56
|
+
// warning && whitelisted -> nothing
|
57
|
+
if (isError && !isWhiteListed) {
|
58
|
+
aws_cdk_lib_1.Annotations.of(node).addError(annotationMessage);
|
59
|
+
}
|
60
|
+
else if ((!isError && !isWhiteListed) || (isError && isWhiteListed)) {
|
61
|
+
aws_cdk_lib_1.Annotations.of(node).addWarning(annotationMessage);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
checkStack(node) {
|
65
|
+
if (node instanceof stack_1.DigitrafficStack) {
|
66
|
+
if ((node.stackName.includes("Test") ||
|
67
|
+
node.stackName.includes("Tst")) &&
|
68
|
+
node.configuration.production) {
|
69
|
+
this.addAnnotation(node, ResourceType.stackName, "Production is set for Test-stack");
|
70
|
+
}
|
71
|
+
if ((node.stackName.includes("Prod") ||
|
72
|
+
node.stackName.includes("Prd")) &&
|
73
|
+
!node.configuration.production) {
|
74
|
+
this.addAnnotation(node, ResourceType.stackName, "Production is not set for Production-stack");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
checkFunction(node) {
|
79
|
+
if (node instanceof aws_lambda_1.CfnFunction) {
|
80
|
+
if (!node.reservedConcurrentExecutions) {
|
81
|
+
this.addAnnotation(node, ResourceType.reservedConcurrentConcurrency, "Function must have reservedConcurrentConcurrency");
|
82
|
+
}
|
83
|
+
else if (node.reservedConcurrentExecutions > MAX_CONCURRENCY_LIMIT) {
|
84
|
+
this.addAnnotation(node, ResourceType.reservedConcurrentConcurrency, "Function reservedConcurrentConcurrency too high!");
|
85
|
+
}
|
86
|
+
if (!node.timeout) {
|
87
|
+
this.addAnnotation(node, ResourceType.functionTimeout, "Function must have timeout");
|
88
|
+
}
|
89
|
+
if (!node.memorySize) {
|
90
|
+
this.addAnnotation(node, ResourceType.functionMemorySize, "Function must have memorySize");
|
91
|
+
}
|
92
|
+
if (node.runtime !== NODE_RUNTIME) {
|
93
|
+
this.addAnnotation(node, ResourceType.functionRuntime, `Function has wrong runtime ${node.runtime}!`);
|
94
|
+
}
|
95
|
+
if (this.stackShortName &&
|
96
|
+
node.functionName &&
|
97
|
+
!node.functionName.startsWith(this.stackShortName)) {
|
98
|
+
this.addAnnotation(node, ResourceType.functionName, `Function name does not begin with ${this.stackShortName}`);
|
99
|
+
}
|
100
|
+
}
|
101
|
+
}
|
102
|
+
checkTags(node) {
|
103
|
+
if (node instanceof aws_cdk_lib_1.Stack) {
|
104
|
+
if (!node.tags.tagValues()[stack_1.SOLUTION_KEY]) {
|
105
|
+
this.addAnnotation(node, ResourceType.tagSolution, "Solution tag is missing");
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
checkBucket(node) {
|
110
|
+
if (node instanceof aws_s3_1.CfnBucket) {
|
111
|
+
const c = node.publicAccessBlockConfiguration;
|
112
|
+
if (c) {
|
113
|
+
if (!c.blockPublicAcls ||
|
114
|
+
!c.blockPublicPolicy ||
|
115
|
+
!c.ignorePublicAcls ||
|
116
|
+
!c.restrictPublicBuckets) {
|
117
|
+
this.addAnnotation(node, ResourceType.bucketPublicity, "Check bucket publicity");
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
static isValidPath(path) {
|
123
|
+
// if path includes . or { check only the trailing part of path
|
124
|
+
if (path.includes(".")) {
|
125
|
+
return this.isValidPath(path.split(".")[0]);
|
126
|
+
}
|
127
|
+
if (path.includes("{")) {
|
128
|
+
return this.isValidPath(path.split("{")[0]);
|
129
|
+
}
|
130
|
+
return (0, change_case_1.paramCase)(path) === path;
|
131
|
+
}
|
132
|
+
static isValidQueryString(name) {
|
133
|
+
return (0, change_case_1.snakeCase)(name) === name;
|
134
|
+
}
|
135
|
+
checkResourceCasing(node) {
|
136
|
+
if (node instanceof aws_apigateway_1.CfnResource) {
|
137
|
+
if (!StackCheckingAspect.isValidPath(node.pathPart)) {
|
138
|
+
this.addAnnotation(node, ResourceType.resourcePath, "Path part should be in kebab-case");
|
139
|
+
}
|
140
|
+
}
|
141
|
+
else if (node instanceof aws_apigateway_1.CfnMethod) {
|
142
|
+
const integration = node.integration;
|
143
|
+
if (integration && integration.requestParameters) {
|
144
|
+
Object.keys(integration.requestParameters).forEach((key) => {
|
145
|
+
const split = key.split(".");
|
146
|
+
const type = split[2];
|
147
|
+
const name = split[3];
|
148
|
+
if (type === "querystring" &&
|
149
|
+
!StackCheckingAspect.isValidQueryString(name)) {
|
150
|
+
this.addAnnotation(node, name, "Querystring should be in snake_case");
|
151
|
+
}
|
152
|
+
});
|
153
|
+
}
|
154
|
+
}
|
155
|
+
}
|
156
|
+
checkQueueEncryption(node) {
|
157
|
+
if (node instanceof aws_sqs_1.CfnQueue) {
|
158
|
+
if (!node.kmsMasterKeyId) {
|
159
|
+
this.addAnnotation(node, ResourceType.queueEncryption, "Queue must have encryption enabled");
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
checkLogGroupRetention(node) {
|
164
|
+
if (node instanceof aws_logs_1.LogRetention) {
|
165
|
+
const child = node.node.defaultChild;
|
166
|
+
const retention = child._cfnProperties.RetentionInDays;
|
167
|
+
if (!retention) {
|
168
|
+
this.addAnnotation(node, ResourceType.logGroupRetention, "Log group must define log group retention");
|
169
|
+
}
|
170
|
+
}
|
171
|
+
}
|
172
|
+
}
|
173
|
+
exports.StackCheckingAspect = StackCheckingAspect;
|
174
|
+
//# sourceMappingURL=stack-checking-aspect.js.map
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.DigitrafficStack = exports.SSM_KEY_ALARM_TOPIC = exports.SSM_KEY_WARNING_TOPIC = exports.SOLUTION_KEY = void 0;
|
4
|
+
const aws_cdk_lib_1 = require("aws-cdk-lib");
|
5
|
+
const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
|
6
|
+
const aws_sns_1 = require("aws-cdk-lib/aws-sns");
|
7
|
+
const aws_ssm_1 = require("aws-cdk-lib/aws-ssm");
|
8
|
+
const aws_secretsmanager_1 = require("aws-cdk-lib/aws-secretsmanager");
|
9
|
+
const stack_checking_aspect_1 = require("./stack-checking-aspect");
|
10
|
+
const SSM_ROOT = "/digitraffic";
|
11
|
+
exports.SOLUTION_KEY = "Solution";
|
12
|
+
const MONITORING_ROOT = "/monitoring";
|
13
|
+
exports.SSM_KEY_WARNING_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/warning-topic`;
|
14
|
+
exports.SSM_KEY_ALARM_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/alarm-topic`;
|
15
|
+
class DigitrafficStack extends aws_cdk_lib_1.Stack {
|
16
|
+
constructor(scope, id, configuration) {
|
17
|
+
super(scope, id, configuration.stackProps);
|
18
|
+
this.configuration = configuration;
|
19
|
+
if (configuration.secretId) {
|
20
|
+
this.secret = aws_secretsmanager_1.Secret.fromSecretNameV2(this, "Secret", configuration.secretId);
|
21
|
+
}
|
22
|
+
// VPC reference construction requires vpcId and availability zones
|
23
|
+
// private subnets are used in Lambda configuration
|
24
|
+
if (configuration.vpcId) {
|
25
|
+
this.vpc = aws_ec2_1.Vpc.fromVpcAttributes(this, "vpc", {
|
26
|
+
vpcId: configuration.vpcId,
|
27
|
+
privateSubnetIds: configuration.privateSubnetIds,
|
28
|
+
availabilityZones: configuration.availabilityZones ?? [],
|
29
|
+
});
|
30
|
+
}
|
31
|
+
// security group that allows Lambda database access
|
32
|
+
if (configuration.lambdaDbSgId) {
|
33
|
+
this.lambdaDbSg = aws_ec2_1.SecurityGroup.fromSecurityGroupId(this, "LambdaDbSG", configuration.lambdaDbSgId);
|
34
|
+
}
|
35
|
+
this.alarmTopic = aws_sns_1.Topic.fromTopicArn(this, "AlarmTopic", aws_ssm_1.StringParameter.fromStringParameterName(this, "AlarmTopicParam", exports.SSM_KEY_ALARM_TOPIC).stringValue);
|
36
|
+
this.warningTopic = aws_sns_1.Topic.fromTopicArn(this, "WarningTopic", aws_ssm_1.StringParameter.fromStringParameterName(this, "WarningTopicParam", exports.SSM_KEY_WARNING_TOPIC).stringValue);
|
37
|
+
this.addAspects();
|
38
|
+
}
|
39
|
+
addAspects() {
|
40
|
+
aws_cdk_lib_1.Aspects.of(this).add(stack_checking_aspect_1.StackCheckingAspect.create(this));
|
41
|
+
}
|
42
|
+
createLambdaEnvironment() {
|
43
|
+
return this.createDefaultLambdaEnvironment(this.configuration.shortName);
|
44
|
+
}
|
45
|
+
createDefaultLambdaEnvironment(dbApplication) {
|
46
|
+
return this.configuration.secretId
|
47
|
+
? {
|
48
|
+
SECRET_ID: this.configuration.secretId,
|
49
|
+
DB_APPLICATION: dbApplication,
|
50
|
+
}
|
51
|
+
: {
|
52
|
+
DB_APPLICATION: dbApplication,
|
53
|
+
};
|
54
|
+
}
|
55
|
+
getSecret() {
|
56
|
+
if (this.secret === undefined) {
|
57
|
+
throw new Error("Secret is undefined");
|
58
|
+
}
|
59
|
+
return this.secret;
|
60
|
+
}
|
61
|
+
grantSecret(...lambdas) {
|
62
|
+
const secret = this.getSecret();
|
63
|
+
lambdas.forEach((l) => secret.grantRead(l));
|
64
|
+
}
|
65
|
+
}
|
66
|
+
exports.DigitrafficStack = DigitrafficStack;
|
67
|
+
//# sourceMappingURL=stack.js.map
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.DigitrafficLogSubscriptions = exports.createSubscription = void 0;
|
4
|
+
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
|
5
|
+
/**
|
6
|
+
* Creates a subscription filter that subscribes to a Lambda Log Group and delivers the logs to another destination.
|
7
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-subscriptionfilter.html
|
8
|
+
* @param lambda The Lambda function, needed to create a dependency
|
9
|
+
* @param lambdaName The Lambda name from which the Log Group name is derived
|
10
|
+
* @param logDestinationArn Destination for streamed logs
|
11
|
+
* @param stack CloudFormation stack
|
12
|
+
*/
|
13
|
+
function createSubscription(lambda, lambdaName, logDestinationArn, stack) {
|
14
|
+
if (logDestinationArn == undefined) {
|
15
|
+
return undefined;
|
16
|
+
}
|
17
|
+
const filter = new aws_logs_1.CfnSubscriptionFilter(stack, `${lambdaName}LogsSubscription`, {
|
18
|
+
logGroupName: `/aws/lambda/${lambdaName}`,
|
19
|
+
filterPattern: "",
|
20
|
+
destinationArn: logDestinationArn,
|
21
|
+
});
|
22
|
+
filter.node.addDependency(lambda);
|
23
|
+
return filter;
|
24
|
+
}
|
25
|
+
exports.createSubscription = createSubscription;
|
26
|
+
class DigitrafficLogSubscriptions {
|
27
|
+
constructor(stack, ...lambdas) {
|
28
|
+
const destinationArn = stack.configuration.logsDestinationArn;
|
29
|
+
if (destinationArn !== undefined) {
|
30
|
+
lambdas.forEach((lambda) => {
|
31
|
+
const filter = new aws_logs_1.CfnSubscriptionFilter(stack, `${lambda.givenName}LogsSubscription`, {
|
32
|
+
logGroupName: `/aws/lambda/${lambda.givenName}`,
|
33
|
+
filterPattern: "",
|
34
|
+
destinationArn,
|
35
|
+
});
|
36
|
+
filter.node.addDependency(lambda);
|
37
|
+
});
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
exports.DigitrafficLogSubscriptions = DigitrafficLogSubscriptions;
|
42
|
+
//# sourceMappingURL=subscription.js.map
|
@@ -0,0 +1,42 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.createDefaultUsagePlan = exports.createUsagePlan = void 0;
|
4
|
+
/**
|
5
|
+
* Creates an usage plan for a REST API with a single API key
|
6
|
+
* @param api The REST API
|
7
|
+
* @param apiKeyId Id for the API key, this is a surrogate id for CDK, not displayed anywhere
|
8
|
+
* @param apiKeyName Name for the API key, this is displayed in the AWS Console
|
9
|
+
* @deprecated Creates randomized API key names, use createDefaultUsagePlan instead
|
10
|
+
*/
|
11
|
+
function createUsagePlan(api, apiKeyId, apiKeyName) {
|
12
|
+
const apiKey = api.addApiKey(apiKeyId);
|
13
|
+
const plan = api.addUsagePlan(apiKeyName, {
|
14
|
+
name: apiKeyName,
|
15
|
+
});
|
16
|
+
plan.addApiStage({
|
17
|
+
stage: api.deploymentStage,
|
18
|
+
});
|
19
|
+
plan.addApiKey(apiKey);
|
20
|
+
return apiKey;
|
21
|
+
}
|
22
|
+
exports.createUsagePlan = createUsagePlan;
|
23
|
+
/**
|
24
|
+
* Creates a default usage plan for a REST API with a single API key
|
25
|
+
* @param api The REST API
|
26
|
+
* @param apiName Name of the api. Will generate key: apiName + ' API Key' and plan: apiName + ' API Usage Plan'
|
27
|
+
*/
|
28
|
+
function createDefaultUsagePlan(api, apiName) {
|
29
|
+
const apiKeyName = apiName + ' API Key';
|
30
|
+
const usagePlanName = apiName + ' API Usage Plan';
|
31
|
+
const apiKey = api.addApiKey(apiKeyName, { apiKeyName: apiKeyName });
|
32
|
+
const plan = api.addUsagePlan(usagePlanName, {
|
33
|
+
name: usagePlanName,
|
34
|
+
});
|
35
|
+
plan.addApiStage({
|
36
|
+
stage: api.deploymentStage,
|
37
|
+
});
|
38
|
+
plan.addApiKey(apiKey);
|
39
|
+
return apiKey;
|
40
|
+
}
|
41
|
+
exports.createDefaultUsagePlan = createDefaultUsagePlan;
|
42
|
+
//# sourceMappingURL=usage-plans.js.map
|
@@ -0,0 +1,13 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getApiKeyFromAPIGateway = void 0;
|
4
|
+
const aws_sdk_1 = require("aws-sdk");
|
5
|
+
function getApiKeyFromAPIGateway(keyId) {
|
6
|
+
const agw = new aws_sdk_1.APIGateway();
|
7
|
+
return agw.getApiKey({
|
8
|
+
apiKey: keyId,
|
9
|
+
includeValue: true,
|
10
|
+
}).promise();
|
11
|
+
}
|
12
|
+
exports.getApiKeyFromAPIGateway = getApiKeyFromAPIGateway;
|
13
|
+
//# sourceMappingURL=apikey.js.map
|
@@ -0,0 +1,26 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.DigitrafficIntegrationResponse = void 0;
|
4
|
+
const mediatypes_1 = require("../types/mediatypes");
|
5
|
+
const response_1 = require("../infra/api/response");
|
6
|
+
class DigitrafficIntegrationResponse {
|
7
|
+
static ok(mediaType) {
|
8
|
+
return this.create("200", mediaType);
|
9
|
+
}
|
10
|
+
static badRequest(mediaType) {
|
11
|
+
return this.create("400", mediaType ?? mediatypes_1.MediaType.TEXT_PLAIN);
|
12
|
+
}
|
13
|
+
static notImplemented(mediaType) {
|
14
|
+
return this.create("501", mediaType ?? mediatypes_1.MediaType.TEXT_PLAIN);
|
15
|
+
}
|
16
|
+
static create(statusCode, mediaType) {
|
17
|
+
return {
|
18
|
+
statusCode,
|
19
|
+
responseTemplates: {
|
20
|
+
[mediaType]: response_1.RESPONSE_DEFAULT_LAMBDA,
|
21
|
+
},
|
22
|
+
};
|
23
|
+
}
|
24
|
+
}
|
25
|
+
exports.DigitrafficIntegrationResponse = DigitrafficIntegrationResponse;
|
26
|
+
//# sourceMappingURL=digitraffic-integration-response.js.map
|
@@ -0,0 +1,12 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.envValue = void 0;
|
4
|
+
function envValue(key) {
|
5
|
+
const value = process.env[key];
|
6
|
+
if (value == null) {
|
7
|
+
throw new Error(`Missing environment value ${key}`);
|
8
|
+
}
|
9
|
+
return value;
|
10
|
+
}
|
11
|
+
exports.envValue = envValue;
|
12
|
+
//# sourceMappingURL=environment.js.map
|
@@ -0,0 +1,31 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.snsPublish = void 0;
|
4
|
+
/**
|
5
|
+
* Utility function for publishing SNS messages.
|
6
|
+
* Made because using *await* with AWS APIs doesn't require calling promise() but nothing works if it isn't called.
|
7
|
+
* Retries a single time in case of failure.
|
8
|
+
* @param message
|
9
|
+
* @param topicArn
|
10
|
+
* @param sns
|
11
|
+
*/
|
12
|
+
async function snsPublish(message, topicArn, sns) {
|
13
|
+
const publishParams = {
|
14
|
+
Message: message,
|
15
|
+
TopicArn: topicArn,
|
16
|
+
};
|
17
|
+
try {
|
18
|
+
await sns.publish(publishParams).promise();
|
19
|
+
}
|
20
|
+
catch (error) {
|
21
|
+
console.error('method=snsPublish error, retrying', error);
|
22
|
+
try {
|
23
|
+
await sns.publish(publishParams).promise();
|
24
|
+
}
|
25
|
+
catch (e2) {
|
26
|
+
console.error('method=snsPublish error after retry', e2);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
exports.snsPublish = snsPublish;
|
31
|
+
//# sourceMappingURL=messaging.js.map
|
@@ -0,0 +1,30 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.uploadToS3 = void 0;
|
4
|
+
const aws_sdk_1 = require("aws-sdk");
|
5
|
+
async function uploadToS3(bucketName, body, objectName, cannedAcl, contentType) {
|
6
|
+
const s3 = new aws_sdk_1.S3();
|
7
|
+
try {
|
8
|
+
await doUpload(s3, bucketName, body, objectName, cannedAcl, contentType);
|
9
|
+
}
|
10
|
+
catch (error) {
|
11
|
+
console.warn('method=uploadToS3 retrying upload to bucket %s', bucketName);
|
12
|
+
try {
|
13
|
+
await doUpload(s3, bucketName, body, objectName, cannedAcl, contentType);
|
14
|
+
}
|
15
|
+
catch (e2) {
|
16
|
+
console.error('method=uploadToS3 failed retrying upload to bucket %s', bucketName);
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
exports.uploadToS3 = uploadToS3;
|
21
|
+
function doUpload(s3, bucketName, body, filename, cannedAcl, contentType) {
|
22
|
+
return s3.upload({
|
23
|
+
Bucket: bucketName,
|
24
|
+
Body: body,
|
25
|
+
Key: filename,
|
26
|
+
ACL: cannedAcl,
|
27
|
+
ContentType: contentType,
|
28
|
+
}).promise();
|
29
|
+
}
|
30
|
+
//# sourceMappingURL=s3.js.map
|
@@ -0,0 +1,96 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.checkExpectedSecretKeys = exports.withDbSecret = exports.DatabaseEnvironmentKeys = exports.RdsSecretKey = exports.RdsProxySecretKey = void 0;
|
4
|
+
const secret_1 = require("./secret");
|
5
|
+
var RdsProxySecretKey;
|
6
|
+
(function (RdsProxySecretKey) {
|
7
|
+
RdsProxySecretKey["username"] = "username";
|
8
|
+
RdsProxySecretKey["password"] = "password";
|
9
|
+
RdsProxySecretKey["proxy_host"] = "proxy_host";
|
10
|
+
RdsProxySecretKey["proxy_ro_host"] = "proxy_ro_host";
|
11
|
+
})(RdsProxySecretKey = exports.RdsProxySecretKey || (exports.RdsProxySecretKey = {}));
|
12
|
+
var RdsSecretKey;
|
13
|
+
(function (RdsSecretKey) {
|
14
|
+
RdsSecretKey["username"] = "username";
|
15
|
+
RdsSecretKey["password"] = "password";
|
16
|
+
RdsSecretKey["host"] = "host";
|
17
|
+
RdsSecretKey["ro_host"] = "ro_host";
|
18
|
+
})(RdsSecretKey = exports.RdsSecretKey || (exports.RdsSecretKey = {}));
|
19
|
+
var DatabaseEnvironmentKeys;
|
20
|
+
(function (DatabaseEnvironmentKeys) {
|
21
|
+
DatabaseEnvironmentKeys["DB_USER"] = "DB_USER";
|
22
|
+
DatabaseEnvironmentKeys["DB_PASS"] = "DB_PASS";
|
23
|
+
DatabaseEnvironmentKeys["DB_URI"] = "DB_URI";
|
24
|
+
DatabaseEnvironmentKeys["DB_RO_URI"] = "DB_RO_URI";
|
25
|
+
DatabaseEnvironmentKeys["DB_APPLICATION"] = "DB_APPLICATION";
|
26
|
+
})(DatabaseEnvironmentKeys = exports.DatabaseEnvironmentKeys || (exports.DatabaseEnvironmentKeys = {}));
|
27
|
+
function setDbSecret(secret) {
|
28
|
+
process.env[DatabaseEnvironmentKeys.DB_USER] = secret.username;
|
29
|
+
process.env[DatabaseEnvironmentKeys.DB_PASS] = secret.password;
|
30
|
+
process.env[DatabaseEnvironmentKeys.DB_URI] = secret.host;
|
31
|
+
process.env[DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
|
32
|
+
}
|
33
|
+
// cached at Lambda container level
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
35
|
+
let cachedSecret;
|
36
|
+
const missingSecretErrorText = 'Missing or empty secretId';
|
37
|
+
/**
|
38
|
+
* Run the given function with secret retrieved from Secrets Manager. Also injects database-credentials into environment.
|
39
|
+
*
|
40
|
+
* @deprecated use SecretHolder & ProxyHolder
|
41
|
+
* @see SecretOptions
|
42
|
+
*
|
43
|
+
* @param {string} secretId
|
44
|
+
* @param {function} fn
|
45
|
+
* @param {SecretOptions} options
|
46
|
+
*/
|
47
|
+
async function withDbSecret(secretId, fn, options) {
|
48
|
+
if (!secretId) {
|
49
|
+
console.error(missingSecretErrorText);
|
50
|
+
return Promise.reject(missingSecretErrorText);
|
51
|
+
}
|
52
|
+
if (!cachedSecret) {
|
53
|
+
// if prefix is given, first set db values and then fetch secret
|
54
|
+
if (options?.prefix) {
|
55
|
+
// first set db values
|
56
|
+
await (0, secret_1.withSecret)(secretId, (fetchedSecret) => {
|
57
|
+
setDbSecret(fetchedSecret);
|
58
|
+
});
|
59
|
+
// then actual secret
|
60
|
+
await (0, secret_1.withSecretAndPrefix)(secretId, options.prefix, (fetchedSecret) => {
|
61
|
+
cachedSecret = fetchedSecret;
|
62
|
+
});
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
await (0, secret_1.withSecret)(secretId, (fetchedSecret) => {
|
66
|
+
setDbSecret(fetchedSecret);
|
67
|
+
cachedSecret = fetchedSecret;
|
68
|
+
});
|
69
|
+
}
|
70
|
+
}
|
71
|
+
try {
|
72
|
+
if (options?.expectedKeys?.length) {
|
73
|
+
checkExpectedSecretKeys(options.expectedKeys, cachedSecret);
|
74
|
+
}
|
75
|
+
return fn(cachedSecret);
|
76
|
+
}
|
77
|
+
catch (error) {
|
78
|
+
console.error('method=withDbSecret Caught an error, refreshing secret', error);
|
79
|
+
// try to refetch secret in case it has changed
|
80
|
+
await (0, secret_1.withSecret)(secretId, (fetchedSecret) => {
|
81
|
+
setDbSecret(fetchedSecret);
|
82
|
+
cachedSecret = fetchedSecret;
|
83
|
+
});
|
84
|
+
return fn(cachedSecret);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
exports.withDbSecret = withDbSecret;
|
88
|
+
function checkExpectedSecretKeys(keys, secret) {
|
89
|
+
const missingKeys = keys.filter(key => !(key in secret));
|
90
|
+
if (missingKeys.length) {
|
91
|
+
console.error(`method=checkExpectedSecretKeys secret didn't contain the key(s) ${missingKeys}`);
|
92
|
+
throw new Error('Expected keys were not found');
|
93
|
+
}
|
94
|
+
}
|
95
|
+
exports.checkExpectedSecretKeys = checkExpectedSecretKeys;
|
96
|
+
//# sourceMappingURL=dbsecret.js.map
|
@@ -0,0 +1,27 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ProxyHolder = void 0;
|
4
|
+
const secret_holder_1 = require("./secret-holder");
|
5
|
+
const dbsecret_1 = require("./dbsecret");
|
6
|
+
const utils_1 = require("../../../utils/utils");
|
7
|
+
const RDS_PROXY_SECRET_KEYS = Object.values(dbsecret_1.RdsProxySecretKey);
|
8
|
+
/**
|
9
|
+
* Holds credentials for RDS Proxy access.
|
10
|
+
*/
|
11
|
+
class ProxyHolder {
|
12
|
+
constructor(secretId) {
|
13
|
+
this.secretHolder = new secret_holder_1.SecretHolder(secretId, "", RDS_PROXY_SECRET_KEYS);
|
14
|
+
}
|
15
|
+
static create() {
|
16
|
+
return new ProxyHolder((0, utils_1.getEnvVariable)("SECRET_ID"));
|
17
|
+
}
|
18
|
+
async setCredentials() {
|
19
|
+
const secret = await this.secretHolder.get();
|
20
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_USER] = secret.username;
|
21
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_PASS] = secret.password;
|
22
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_URI] = secret.proxy_host;
|
23
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_RO_URI] = secret.proxy_ro_host;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
exports.ProxyHolder = ProxyHolder;
|
27
|
+
//# sourceMappingURL=proxy-holder.js.map
|
@@ -0,0 +1,27 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.RdsHolder = void 0;
|
4
|
+
const secret_holder_1 = require("./secret-holder");
|
5
|
+
const dbsecret_1 = require("./dbsecret");
|
6
|
+
const utils_1 = require("../../../utils/utils");
|
7
|
+
const RDS_SECRET_KEYS = Object.values(dbsecret_1.RdsSecretKey);
|
8
|
+
/**
|
9
|
+
* Holds credentials for RDS access.
|
10
|
+
*/
|
11
|
+
class RdsHolder {
|
12
|
+
constructor(secretId) {
|
13
|
+
this.secretHolder = new secret_holder_1.SecretHolder(secretId, "", RDS_SECRET_KEYS);
|
14
|
+
}
|
15
|
+
static create() {
|
16
|
+
return new RdsHolder((0, utils_1.getEnvVariable)("SECRET_ID"));
|
17
|
+
}
|
18
|
+
async setCredentials() {
|
19
|
+
const secret = await this.secretHolder.get();
|
20
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_USER] = secret.username;
|
21
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_PASS] = secret.password;
|
22
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_URI] = secret.host;
|
23
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
|
24
|
+
}
|
25
|
+
}
|
26
|
+
exports.RdsHolder = RdsHolder;
|
27
|
+
//# sourceMappingURL=rds-holder.js.map
|
@@ -0,0 +1,76 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SecretHolder = void 0;
|
4
|
+
const secret_1 = require("./secret");
|
5
|
+
const dbsecret_1 = require("./dbsecret");
|
6
|
+
const utils_1 = require("../../../utils/utils");
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
8
|
+
const NodeTtl = require("node-ttl");
|
9
|
+
const DEFAULT_PREFIX = "";
|
10
|
+
const DEFAULT_SECRET_KEY = "SECRET";
|
11
|
+
const DEFAULT_CONFIGURATION = {
|
12
|
+
ttl: 5 * 60, // timeout secrets in 5 minutes
|
13
|
+
};
|
14
|
+
/**
|
15
|
+
* Utility class for getting secrets from Secret Manager.
|
16
|
+
* Supports prefix for secrets, checking of expected keys and ttl-configuration.
|
17
|
+
*
|
18
|
+
* By default, secrets are cached for 5 minutes and then reread from the Secrets Manager(This can be overridden with configuration).
|
19
|
+
*
|
20
|
+
* Supports setting the database environment paramaters from the secret too.
|
21
|
+
*/
|
22
|
+
class SecretHolder {
|
23
|
+
constructor(secretId, prefix = "", expectedKeys = [], configuration = DEFAULT_CONFIGURATION) {
|
24
|
+
this.secretId = secretId;
|
25
|
+
this.prefix = prefix;
|
26
|
+
this.expectedKeys = expectedKeys;
|
27
|
+
this.secretCache = new NodeTtl(configuration);
|
28
|
+
}
|
29
|
+
async initSecret() {
|
30
|
+
const secretValue = await (0, secret_1.getSecret)(this.secretId);
|
31
|
+
console.info("refreshing secret " + this.secretId);
|
32
|
+
this.secretCache.push(DEFAULT_SECRET_KEY, secretValue);
|
33
|
+
}
|
34
|
+
static create(prefix = DEFAULT_PREFIX, expectedKeys = []) {
|
35
|
+
return new SecretHolder((0, utils_1.getEnvVariable)("SECRET_ID"), prefix, expectedKeys);
|
36
|
+
}
|
37
|
+
async get() {
|
38
|
+
const secret = await this.getSecret();
|
39
|
+
const parsedSecret = this.prefix === DEFAULT_PREFIX
|
40
|
+
? secret
|
41
|
+
: this.parseSecret(secret, `${this.prefix}.`);
|
42
|
+
if (this.expectedKeys.length > 0) {
|
43
|
+
(0, dbsecret_1.checkExpectedSecretKeys)(this.expectedKeys, parsedSecret);
|
44
|
+
}
|
45
|
+
return parsedSecret;
|
46
|
+
}
|
47
|
+
parseSecret(secret, prefix) {
|
48
|
+
const parsed = {};
|
49
|
+
const skip = prefix.length;
|
50
|
+
for (const key in secret) {
|
51
|
+
if (key.startsWith(prefix)) {
|
52
|
+
parsed[key.substring(skip)] = secret[key];
|
53
|
+
}
|
54
|
+
}
|
55
|
+
return parsed;
|
56
|
+
}
|
57
|
+
async getSecret() {
|
58
|
+
const secret = this.secretCache.get(DEFAULT_SECRET_KEY);
|
59
|
+
if (!secret) {
|
60
|
+
await this.initSecret();
|
61
|
+
}
|
62
|
+
return secret || this.secretCache.get(DEFAULT_SECRET_KEY);
|
63
|
+
}
|
64
|
+
/**
|
65
|
+
* @deprecated Use ProxyHolder
|
66
|
+
*/
|
67
|
+
async setDatabaseCredentials() {
|
68
|
+
const secret = await this.getSecret();
|
69
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_USER] = secret.username;
|
70
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_PASS] = secret.password;
|
71
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_URI] = secret.host;
|
72
|
+
process.env[dbsecret_1.DatabaseEnvironmentKeys.DB_RO_URI] = secret.ro_host;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
exports.SecretHolder = SecretHolder;
|
76
|
+
//# sourceMappingURL=secret-holder.js.map
|