@digitraffic/common 2026.3.17-1 → 2026.3.26-1-beta
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/README.md +18 -1
- package/dist/__test__/asserter.d.ts +13 -0
- package/dist/__test__/asserter.js +39 -0
- package/dist/__test__/db-testutils.d.ts +3 -0
- package/dist/__test__/db-testutils.js +38 -0
- package/dist/__test__/dependencies.test.d.ts +1 -0
- package/dist/__test__/dependencies.test.js +21 -0
- package/dist/__test__/imports.test.d.ts +1 -0
- package/dist/__test__/imports.test.js +318 -0
- package/dist/__test__/infra/acl-builder.test.d.ts +1 -0
- package/dist/__test__/infra/acl-builder.test.js +72 -0
- package/dist/__test__/infra/api/handler-factory.test.d.ts +1 -0
- package/dist/__test__/infra/api/handler-factory.test.js +42 -0
- package/dist/__test__/infra/api/integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/integration.test.js +162 -0
- package/dist/__test__/infra/api/response.test.d.ts +1 -0
- package/dist/__test__/infra/api/response.test.js +77 -0
- package/dist/__test__/infra/api/static-integration.test.d.ts +1 -0
- package/dist/__test__/infra/api/static-integration.test.js +35 -0
- package/dist/__test__/infra/documentation.test.d.ts +1 -0
- package/dist/__test__/infra/documentation.test.js +38 -0
- package/dist/__test__/infra/scheduler.test.d.ts +1 -0
- package/dist/__test__/infra/scheduler.test.js +23 -0
- package/dist/__test__/infra/security-rule.test.d.ts +1 -0
- package/dist/__test__/infra/security-rule.test.js +21 -0
- package/dist/__test__/infra/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/infra/stack/rest-apis.test.js +47 -0
- package/dist/__test__/marine/id_utils.test.d.ts +1 -0
- package/dist/__test__/marine/id_utils.test.js +45 -0
- package/dist/__test__/mock-ky.d.ts +2 -0
- package/dist/__test__/mock-ky.js +15 -0
- package/dist/__test__/promise/promise.test.d.ts +1 -0
- package/dist/__test__/promise/promise.test.js +126 -0
- package/dist/__test__/runtime/dt-logger.test.d.ts +1 -0
- package/dist/__test__/runtime/dt-logger.test.js +193 -0
- package/dist/__test__/secrets/secret-holder.test.d.ts +1 -0
- package/dist/__test__/secrets/secret-holder.test.js +96 -0
- package/dist/__test__/secrets/secret.test.d.ts +1 -0
- package/dist/__test__/secrets/secret.test.js +57 -0
- package/dist/__test__/stack/dt-function.test.d.ts +1 -0
- package/dist/__test__/stack/dt-function.test.js +340 -0
- package/dist/__test__/stack/rest-apis.test.d.ts +1 -0
- package/dist/__test__/stack/rest-apis.test.js +45 -0
- package/dist/__test__/test/mock-ky.test.d.ts +1 -0
- package/dist/__test__/test/mock-ky.test.js +46 -0
- package/dist/__test__/testutils.d.ts +12 -0
- package/dist/__test__/testutils.js +32 -0
- package/dist/__test__/types/lambda-proxy-types.test.d.ts +8 -0
- package/dist/__test__/types/lambda-proxy-types.test.js +155 -0
- package/dist/__test__/types/lambda-response-builder.test.d.ts +1 -0
- package/dist/__test__/types/lambda-response-builder.test.js +81 -0
- package/dist/__test__/types/lambda-response.test.d.ts +9 -0
- package/dist/__test__/types/lambda-response.test.js +73 -0
- package/dist/__test__/utils/base64.test.d.ts +1 -0
- package/dist/__test__/utils/base64.test.js +38 -0
- package/dist/__test__/utils/date-utils.test.d.ts +1 -0
- package/dist/__test__/utils/date-utils.test.js +32 -0
- package/dist/__test__/utils/geometry.test.d.ts +1 -0
- package/dist/__test__/utils/geometry.test.js +25 -0
- package/dist/__test__/utils/lambda-proxy-event.test.d.ts +1 -0
- package/dist/__test__/utils/lambda-proxy-event.test.js +45 -0
- package/dist/__test__/utils/logging.test.d.ts +1 -0
- package/dist/__test__/utils/logging.test.js +75 -0
- package/dist/__test__/utils/stop-watch.test.d.ts +1 -0
- package/dist/__test__/utils/stop-watch.test.js +118 -0
- package/dist/__test__/utils/utils.test.d.ts +1 -0
- package/dist/__test__/utils/utils.test.js +48 -0
- package/dist/aws/infra/acl-builder.d.ts +53 -0
- package/dist/aws/infra/acl-builder.js +407 -0
- package/dist/aws/infra/api/handler-factory.d.ts +22 -0
- package/dist/aws/infra/api/handler-factory.js +68 -0
- package/dist/aws/infra/api/integration.d.ts +49 -0
- package/dist/aws/infra/api/integration.js +162 -0
- package/dist/aws/infra/api/response.d.ts +62 -0
- package/dist/aws/infra/api/response.js +132 -0
- package/dist/aws/infra/api/responses.d.ts +60 -0
- package/dist/aws/infra/api/responses.js +90 -0
- package/dist/aws/infra/api/static-integration.d.ts +16 -0
- package/dist/aws/infra/api/static-integration.js +76 -0
- package/dist/aws/infra/bucket-policy.d.ts +38 -0
- package/dist/aws/infra/bucket-policy.js +30 -0
- package/dist/aws/infra/canaries/canary-alarm.d.ts +6 -0
- package/dist/aws/infra/canaries/canary-alarm.js +20 -0
- package/dist/aws/infra/canaries/canary-keys.d.ts +3 -0
- package/dist/aws/infra/canaries/canary-keys.js +4 -0
- package/dist/aws/infra/canaries/canary-parameters.d.ts +19 -0
- package/dist/aws/infra/canaries/canary-parameters.js +2 -0
- package/dist/aws/infra/canaries/canary-role.d.ts +14 -0
- package/dist/aws/infra/canaries/canary-role.js +51 -0
- package/dist/aws/infra/canaries/canary.d.ts +8 -0
- package/dist/aws/infra/canaries/canary.js +26 -0
- package/dist/aws/infra/canaries/database-canary.d.ts +17 -0
- package/dist/aws/infra/canaries/database-canary.js +65 -0
- package/dist/aws/infra/canaries/database-checker.d.ts +33 -0
- package/dist/aws/infra/canaries/database-checker.js +119 -0
- package/dist/aws/infra/canaries/url-canary.d.ts +16 -0
- package/dist/aws/infra/canaries/url-canary.js +55 -0
- package/dist/aws/infra/canaries/url-checker.d.ts +45 -0
- package/dist/aws/infra/canaries/url-checker.js +256 -0
- package/dist/aws/infra/documentation.d.ts +56 -0
- package/dist/aws/infra/documentation.js +90 -0
- package/dist/aws/infra/import-util.d.ts +17 -0
- package/dist/aws/infra/import-util.js +41 -0
- package/dist/aws/infra/scheduler.d.ts +12 -0
- package/dist/aws/infra/scheduler.js +27 -0
- package/dist/aws/infra/security-rule.d.ts +12 -0
- package/dist/aws/infra/security-rule.js +35 -0
- package/dist/aws/infra/sqs-integration.d.ts +4 -0
- package/dist/aws/infra/sqs-integration.js +85 -0
- package/dist/aws/infra/sqs-queue.d.ts +19 -0
- package/dist/aws/infra/sqs-queue.js +145 -0
- package/dist/aws/infra/stack/dt-function-alarms.d.ts +29 -0
- package/dist/aws/infra/stack/dt-function-alarms.js +54 -0
- package/dist/aws/infra/stack/dt-function.d.ts +124 -0
- package/dist/aws/infra/stack/dt-function.js +315 -0
- package/dist/aws/infra/stack/lambda-configs.d.ts +44 -0
- package/dist/aws/infra/stack/lambda-configs.js +71 -0
- package/dist/aws/infra/stack/lambda-log-group.d.ts +15 -0
- package/dist/aws/infra/stack/lambda-log-group.js +24 -0
- package/dist/aws/infra/stack/monitoredfunction.d.ts +85 -0
- package/dist/aws/infra/stack/monitoredfunction.js +147 -0
- package/dist/aws/infra/stack/parameters.d.ts +40 -0
- package/dist/aws/infra/stack/parameters.js +50 -0
- package/dist/aws/infra/stack/rest-api.d.ts +74 -0
- package/dist/aws/infra/stack/rest-api.js +235 -0
- package/dist/aws/infra/stack/stack-checking-aspect.d.ts +20 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +183 -0
- package/dist/aws/infra/stack/stack.d.ts +56 -0
- package/dist/aws/infra/stack/stack.js +71 -0
- package/dist/aws/infra/stack/subscription.d.ts +17 -0
- package/dist/aws/infra/stack/subscription.js +37 -0
- package/dist/aws/infra/stacks/db-dns-stack.d.ts +13 -0
- package/dist/aws/infra/stacks/db-dns-stack.js +60 -0
- package/dist/aws/infra/stacks/db-proxy-stack.d.ts +24 -0
- package/dist/aws/infra/stacks/db-proxy-stack.js +74 -0
- package/dist/aws/infra/stacks/db-stack.d.ts +65 -0
- package/dist/aws/infra/stacks/db-stack.js +189 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.d.ts +5 -0
- package/dist/aws/infra/stacks/intra-stack-configuration.js +2 -0
- package/dist/aws/infra/stacks/network-stack.d.ts +14 -0
- package/dist/aws/infra/stacks/network-stack.js +45 -0
- package/dist/aws/infra/usage-plans.d.ts +16 -0
- package/dist/aws/infra/usage-plans.js +38 -0
- package/dist/aws/runtime/apikey.d.ts +2 -0
- package/dist/aws/runtime/apikey.js +13 -0
- package/dist/aws/runtime/digitraffic-integration-response.d.ts +8 -0
- package/dist/aws/runtime/digitraffic-integration-response.js +25 -0
- package/dist/aws/runtime/dt-logger-default.d.ts +9 -0
- package/dist/aws/runtime/dt-logger-default.js +6 -0
- package/dist/aws/runtime/dt-logger.d.ts +117 -0
- package/dist/aws/runtime/dt-logger.js +159 -0
- package/dist/aws/runtime/environment.d.ts +5 -0
- package/dist/aws/runtime/environment.js +7 -0
- package/dist/aws/runtime/s3.d.ts +3 -0
- package/dist/aws/runtime/s3.js +21 -0
- package/dist/aws/runtime/secrets/dbsecret.d.ts +16 -0
- package/dist/aws/runtime/secrets/dbsecret.js +26 -0
- package/dist/aws/runtime/secrets/proxy-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/proxy-holder.js +25 -0
- package/dist/aws/runtime/secrets/rds-holder.d.ts +9 -0
- package/dist/aws/runtime/secrets/rds-holder.js +25 -0
- package/dist/aws/runtime/secrets/secret-holder.d.ts +30 -0
- package/dist/aws/runtime/secrets/secret-holder.js +81 -0
- package/dist/aws/runtime/secrets/secret.d.ts +8 -0
- package/dist/aws/runtime/secrets/secret.js +61 -0
- package/dist/aws/types/errors.d.ts +8 -0
- package/dist/aws/types/errors.js +13 -0
- package/dist/aws/types/lambda-proxy-types.d.ts +59 -0
- package/dist/aws/types/lambda-proxy-types.js +210 -0
- package/dist/aws/types/lambda-response.d.ts +89 -0
- package/dist/aws/types/lambda-response.js +204 -0
- package/dist/aws/types/mediatypes.d.ts +11 -0
- package/dist/aws/types/mediatypes.js +14 -0
- package/dist/aws/types/model-with-reference.d.ts +7 -0
- package/dist/aws/types/model-with-reference.js +2 -0
- package/dist/aws/types/tags.d.ts +2 -0
- package/dist/aws/types/tags.js +4 -0
- package/dist/database/database.d.ts +27 -0
- package/dist/database/database.js +95 -0
- package/dist/database/last-updated.d.ts +15 -0
- package/dist/database/last-updated.js +46 -0
- package/dist/database/models.d.ts +6 -0
- package/dist/database/models.js +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/marine/id_utils.d.ts +3 -0
- package/dist/marine/id_utils.js +36 -0
- package/dist/marine/rtz.d.ts +48 -0
- package/dist/marine/rtz.js +2 -0
- package/dist/types/async-timeout-error.d.ts +3 -0
- package/dist/types/async-timeout-error.js +6 -0
- package/dist/types/either.d.ts +9 -0
- package/dist/types/either.js +2 -0
- package/dist/types/geojson.d.ts +47 -0
- package/dist/types/geojson.js +51 -0
- package/dist/types/http-error.d.ts +4 -0
- package/dist/types/http-error.js +8 -0
- package/dist/types/input-error.d.ts +2 -0
- package/dist/types/input-error.js +3 -0
- package/dist/types/language.d.ts +5 -0
- package/dist/types/language.js +7 -0
- package/dist/types/nullable.d.ts +24 -0
- package/dist/types/nullable.js +2 -0
- package/dist/types/openapi-schema.d.ts +932 -0
- package/dist/types/openapi-schema.js +151 -0
- package/dist/types/traffictype.d.ts +11 -0
- package/dist/types/traffictype.js +13 -0
- package/dist/types/urn.d.ts +1 -0
- package/dist/types/urn.js +2 -0
- package/dist/types/util-types.d.ts +11 -0
- package/dist/types/util-types.js +2 -0
- package/dist/types/validator.d.ts +4 -0
- package/dist/types/validator.js +9 -0
- package/dist/utils/api-model.d.ts +51 -0
- package/dist/utils/api-model.js +118 -0
- package/dist/utils/base64.d.ts +34 -0
- package/dist/utils/base64.js +53 -0
- package/dist/utils/date-utils.d.ts +27 -0
- package/dist/utils/date-utils.js +45 -0
- package/dist/utils/geojson-types.d.ts +14 -0
- package/dist/utils/geojson-types.js +15 -0
- package/dist/utils/geometry.d.ts +44 -0
- package/dist/utils/geometry.js +154 -0
- package/dist/utils/lambda-proxy-event.d.ts +9 -0
- package/dist/utils/lambda-proxy-event.js +31 -0
- package/dist/utils/logging.d.ts +40 -0
- package/dist/utils/logging.js +88 -0
- package/dist/utils/retry.d.ts +33 -0
- package/dist/utils/retry.js +135 -0
- package/dist/utils/slack.d.ts +5 -0
- package/dist/utils/slack.js +24 -0
- package/dist/utils/stop-watch.d.ts +46 -0
- package/dist/utils/stop-watch.js +114 -0
- package/dist/utils/utils.d.ts +95 -0
- package/dist/utils/utils.js +178 -0
- package/dist/utils/zod-utils.d.ts +27 -0
- package/dist/utils/zod-utils.js +57 -0
- package/package.json +30 -28
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { CfnDocumentationPart, Cors, EndpointType, GatewayResponse, MethodLoggingLevel, ResponseType, RestApi, } from "aws-cdk-lib/aws-apigateway";
|
|
2
|
+
import { AnyPrincipal, Effect, PolicyDocument, PolicyStatement, } from "aws-cdk-lib/aws-iam";
|
|
3
|
+
import { StringParameter } from "aws-cdk-lib/aws-ssm";
|
|
4
|
+
import { set } from "es-toolkit/compat";
|
|
5
|
+
import { getModelReference } from "../../../utils/api-model.js";
|
|
6
|
+
import { MediaType } from "../../types/mediatypes.js";
|
|
7
|
+
import { createDefaultUsagePlan, createUsagePlan } from "../usage-plans.js";
|
|
8
|
+
export const PUBLIC_REST_API_CORS_CONFIG = {
|
|
9
|
+
defaultCorsPreflightOptions: {
|
|
10
|
+
allowOrigins: Cors.ALL_ORIGINS,
|
|
11
|
+
allowHeaders: [
|
|
12
|
+
"Content-Type",
|
|
13
|
+
"X-Amz-Date",
|
|
14
|
+
"Authorization",
|
|
15
|
+
"X-Api-Key",
|
|
16
|
+
"X-Amz-Security-Token",
|
|
17
|
+
"Digitraffic-User",
|
|
18
|
+
],
|
|
19
|
+
allowMethods: ["OPTIONS", "GET", "HEAD"],
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
export class DigitrafficRestApi extends RestApi {
|
|
23
|
+
apiKeyIds;
|
|
24
|
+
enableDocumentation;
|
|
25
|
+
_stack;
|
|
26
|
+
constructor(stack, apiId, apiName, allowFromIpAddresses, config) {
|
|
27
|
+
const policyDocument = allowFromIpAddresses === null || allowFromIpAddresses === undefined
|
|
28
|
+
? createDefaultPolicyDocument()
|
|
29
|
+
: createIpRestrictionPolicyDocument(allowFromIpAddresses);
|
|
30
|
+
// override default config with given extra config
|
|
31
|
+
const apiConfig = {
|
|
32
|
+
...{
|
|
33
|
+
deployOptions: {
|
|
34
|
+
loggingLevel: MethodLoggingLevel.ERROR,
|
|
35
|
+
},
|
|
36
|
+
restApiName: apiName,
|
|
37
|
+
endpointTypes: [EndpointType.REGIONAL],
|
|
38
|
+
policy: policyDocument,
|
|
39
|
+
},
|
|
40
|
+
...config,
|
|
41
|
+
};
|
|
42
|
+
super(stack, apiId, apiConfig);
|
|
43
|
+
this._stack = stack;
|
|
44
|
+
this.apiKeyIds = [];
|
|
45
|
+
this.enableDocumentation =
|
|
46
|
+
stack.configuration.stackFeatures?.enableDocumentation ?? true;
|
|
47
|
+
add404Support(this, stack);
|
|
48
|
+
}
|
|
49
|
+
hostname() {
|
|
50
|
+
return `${this.restApiId}.execute-api.${this.stack.region}.amazonaws.com`;
|
|
51
|
+
}
|
|
52
|
+
exportEndpoint(params) {
|
|
53
|
+
const firstKey = this.apiKeyIds[0];
|
|
54
|
+
var apiKeyId = params?.apiKeyId;
|
|
55
|
+
if (!apiKeyId) {
|
|
56
|
+
if (this.apiKeyIds.length > 1) {
|
|
57
|
+
throw new Error("Multiple apikeys, configure which to export");
|
|
58
|
+
}
|
|
59
|
+
if (!firstKey) {
|
|
60
|
+
throw new Error("No apikeys to export");
|
|
61
|
+
}
|
|
62
|
+
apiKeyId = firstKey;
|
|
63
|
+
}
|
|
64
|
+
const exportName = params?.exportName ?? this._stack.configuration.shortName;
|
|
65
|
+
const sp1 = new StringParameter(this._stack, `export.endpoint.${exportName}`, {
|
|
66
|
+
parameterName: `/digitraffic/${exportName}/endpointUrl`,
|
|
67
|
+
stringValue: this.url,
|
|
68
|
+
});
|
|
69
|
+
const sp2 = new StringParameter(this._stack, `export.apiKeyId.${exportName}`, {
|
|
70
|
+
parameterName: `/digitraffic/${exportName}/apiKeyId`,
|
|
71
|
+
stringValue: apiKeyId,
|
|
72
|
+
});
|
|
73
|
+
return [sp1, sp2];
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* @param apiKeyId
|
|
77
|
+
* @param apiKeyName
|
|
78
|
+
* @deprecated Uses deprecated createUsagePlan that creates randomized API key names, use createUsagePlanV2 instead
|
|
79
|
+
*/
|
|
80
|
+
createUsagePlan(apiKeyId, apiKeyName) {
|
|
81
|
+
const newKeyId = createUsagePlan(this, apiKeyId, apiKeyName).keyId;
|
|
82
|
+
this.apiKeyIds.push(newKeyId);
|
|
83
|
+
return newKeyId;
|
|
84
|
+
}
|
|
85
|
+
createUsagePlanV2(apiName, apiKey) {
|
|
86
|
+
const newKeyId = createDefaultUsagePlan(this, apiName, apiKey).keyId;
|
|
87
|
+
this.apiKeyIds.push(newKeyId);
|
|
88
|
+
return newKeyId;
|
|
89
|
+
}
|
|
90
|
+
addJsonModel(modelName, schema) {
|
|
91
|
+
return this.getModelWithReference(this.addModel(modelName, {
|
|
92
|
+
contentType: MediaType.APPLICATION_JSON,
|
|
93
|
+
modelName,
|
|
94
|
+
schema,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
addCSVModel(modelName) {
|
|
98
|
+
return this.getModelWithReference(this.addModel(modelName, {
|
|
99
|
+
contentType: MediaType.TEXT_CSV,
|
|
100
|
+
modelName,
|
|
101
|
+
schema: {},
|
|
102
|
+
}));
|
|
103
|
+
}
|
|
104
|
+
getModelWithReference(model) {
|
|
105
|
+
return set(model, "modelReference", getModelReference(model.modelId, this.restApiId));
|
|
106
|
+
}
|
|
107
|
+
addDocumentationPart(resource, parameterName, resourceName, type, properties) {
|
|
108
|
+
const location = {
|
|
109
|
+
type,
|
|
110
|
+
path: resource.path,
|
|
111
|
+
name: type !== "METHOD" ? parameterName : undefined,
|
|
112
|
+
};
|
|
113
|
+
new CfnDocumentationPart(this.stack, resourceName, {
|
|
114
|
+
restApiId: resource.api.restApiId,
|
|
115
|
+
location,
|
|
116
|
+
properties: JSON.stringify(properties),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
documentResource(resource, ...documentationPart) {
|
|
120
|
+
if (this.enableDocumentation) {
|
|
121
|
+
documentationPart.forEach((dp) => {
|
|
122
|
+
this.addDocumentationPart(resource, dp.parameterName, `${resource.path}.${dp.parameterName}.Documentation`, dp.type, dp.documentationProperties);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
console.info("Skipping documentation for %s", resource.path);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
addResourceWithCorsOptionsSubTree(resource, pathPart, config) {
|
|
130
|
+
const mergedConfig = {
|
|
131
|
+
...PUBLIC_REST_API_CORS_CONFIG,
|
|
132
|
+
...config,
|
|
133
|
+
};
|
|
134
|
+
return resource.addResource(pathPart, mergedConfig);
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Add support for HTTP OPTIONS to an API GW resource,
|
|
138
|
+
* this is required for preflight CORS requests made by browsers.
|
|
139
|
+
* @param apiResource
|
|
140
|
+
*/
|
|
141
|
+
addCorsOptions(apiResource) {
|
|
142
|
+
apiResource.addCorsPreflight(PUBLIC_REST_API_CORS_CONFIG.defaultCorsPreflightOptions);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Due to AWS API design API Gateway will always return 403 'Missing Authentication Token' for requests
|
|
147
|
+
* with a non-existent endpoint. This function translates this response to a 404.
|
|
148
|
+
* Requests with an invalid or missing API key are not affected (still return 403 'Forbidden').
|
|
149
|
+
* @param restApi RestApi
|
|
150
|
+
* @param stack Construct
|
|
151
|
+
*/
|
|
152
|
+
export function add404Support(restApi, stack) {
|
|
153
|
+
new GatewayResponse(stack, `MissingAuthenticationTokenResponse-${restApi.restApiName}`, {
|
|
154
|
+
restApi,
|
|
155
|
+
type: ResponseType.MISSING_AUTHENTICATION_TOKEN,
|
|
156
|
+
statusCode: "404",
|
|
157
|
+
templates: {
|
|
158
|
+
[MediaType.APPLICATION_JSON]: '{"message": "Not Found"}',
|
|
159
|
+
},
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
export function add401Support(restApi, stack) {
|
|
163
|
+
new GatewayResponse(stack, `AuthenticationFailedResponse-${restApi.restApiName}`, {
|
|
164
|
+
restApi,
|
|
165
|
+
type: ResponseType.UNAUTHORIZED,
|
|
166
|
+
statusCode: "401",
|
|
167
|
+
responseHeaders: {
|
|
168
|
+
"WWW-Authenticate": "'Basic'",
|
|
169
|
+
},
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Due to AWS API design API Gateway will always return 403 'Missing Authentication Token' for requests
|
|
174
|
+
* with a non-existent endpoint. This function converts this response to a custom one.
|
|
175
|
+
* Requests with an invalid or missing API key are not affected (still return 403 'Forbidden').
|
|
176
|
+
* @param returnCode
|
|
177
|
+
* @param message
|
|
178
|
+
* @param restApi RestApi
|
|
179
|
+
* @param stack Construct
|
|
180
|
+
*/
|
|
181
|
+
export function setReturnCodeForMissingAuthenticationToken(returnCode, message, restApi, stack) {
|
|
182
|
+
new GatewayResponse(stack, `MissingAuthenticationTokenResponse-${restApi.restApiName}`, {
|
|
183
|
+
restApi,
|
|
184
|
+
type: ResponseType.MISSING_AUTHENTICATION_TOKEN,
|
|
185
|
+
statusCode: `${returnCode}`,
|
|
186
|
+
templates: {
|
|
187
|
+
[MediaType.APPLICATION_JSON]: `{"message": ${message}}`,
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
export function createRestApi(stack, apiId, apiName, allowFromIpAddresses) {
|
|
192
|
+
const policyDocument = allowFromIpAddresses === null || allowFromIpAddresses === undefined
|
|
193
|
+
? createDefaultPolicyDocument()
|
|
194
|
+
: createIpRestrictionPolicyDocument(allowFromIpAddresses);
|
|
195
|
+
const restApi = new RestApi(stack, apiId, {
|
|
196
|
+
deployOptions: {
|
|
197
|
+
loggingLevel: MethodLoggingLevel.ERROR,
|
|
198
|
+
},
|
|
199
|
+
restApiName: apiName,
|
|
200
|
+
endpointTypes: [EndpointType.REGIONAL],
|
|
201
|
+
policy: policyDocument,
|
|
202
|
+
});
|
|
203
|
+
add404Support(restApi, stack);
|
|
204
|
+
return restApi;
|
|
205
|
+
}
|
|
206
|
+
export function createDefaultPolicyDocument() {
|
|
207
|
+
return new PolicyDocument({
|
|
208
|
+
statements: [
|
|
209
|
+
new PolicyStatement({
|
|
210
|
+
effect: Effect.ALLOW,
|
|
211
|
+
actions: ["execute-api:Invoke"],
|
|
212
|
+
resources: ["*"],
|
|
213
|
+
principals: [new AnyPrincipal()],
|
|
214
|
+
}),
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
export function createIpRestrictionPolicyDocument(allowFromIpAddresses) {
|
|
219
|
+
return new PolicyDocument({
|
|
220
|
+
statements: [
|
|
221
|
+
new PolicyStatement({
|
|
222
|
+
effect: Effect.ALLOW,
|
|
223
|
+
conditions: {
|
|
224
|
+
IpAddress: {
|
|
225
|
+
"aws:SourceIp": allowFromIpAddresses,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
actions: ["execute-api:Invoke"],
|
|
229
|
+
resources: ["*"],
|
|
230
|
+
principals: [new AnyPrincipal()],
|
|
231
|
+
}),
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
//# sourceMappingURL=rest-api.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IAspect } from "aws-cdk-lib";
|
|
2
|
+
import type { IConstruct } from "constructs";
|
|
3
|
+
export declare class StackCheckingAspect implements IAspect {
|
|
4
|
+
private readonly stackShortName?;
|
|
5
|
+
private readonly whitelistedResources?;
|
|
6
|
+
constructor(stackShortName?: string, whitelistedResources?: string[]);
|
|
7
|
+
visit(node: IConstruct): void;
|
|
8
|
+
private isWhitelisted;
|
|
9
|
+
private addAnnotation;
|
|
10
|
+
private isDigitrafficStack;
|
|
11
|
+
private checkStack;
|
|
12
|
+
private checkFunction;
|
|
13
|
+
private checkTags;
|
|
14
|
+
private checkBucket;
|
|
15
|
+
private static isValidPath;
|
|
16
|
+
private static isValidQueryString;
|
|
17
|
+
private checkResourceCasing;
|
|
18
|
+
private checkQueueEncryption;
|
|
19
|
+
private checkLogGroupRetention;
|
|
20
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Annotations, Stack } from "aws-cdk-lib";
|
|
2
|
+
import { CfnMethod, CfnResource } from "aws-cdk-lib/aws-apigateway";
|
|
3
|
+
import { CfnFunction, Runtime } from "aws-cdk-lib/aws-lambda";
|
|
4
|
+
import { LogRetention } from "aws-cdk-lib/aws-logs";
|
|
5
|
+
import { CfnBucket } from "aws-cdk-lib/aws-s3";
|
|
6
|
+
import { CfnQueue } from "aws-cdk-lib/aws-sqs";
|
|
7
|
+
import { kebabCase } from "change-case";
|
|
8
|
+
import { snakeCase } from "es-toolkit";
|
|
9
|
+
import { DigitrafficStack, SOLUTION_KEY } from "./stack.js";
|
|
10
|
+
const MAX_CONCURRENCY_LIMIT = 100;
|
|
11
|
+
const ALLOWED_RUNTIMES = [
|
|
12
|
+
Runtime.NODEJS_24_X.name,
|
|
13
|
+
Runtime.NODEJS_22_X.name,
|
|
14
|
+
Runtime.PYTHON_3_12.name,
|
|
15
|
+
Runtime.PYTHON_3_13.name,
|
|
16
|
+
];
|
|
17
|
+
var ResourceType;
|
|
18
|
+
(function (ResourceType) {
|
|
19
|
+
ResourceType["stackName"] = "STACK_NAME";
|
|
20
|
+
ResourceType["reservedConcurrentConcurrency"] = "RESERVED_CONCURRENT_CONCURRENCY";
|
|
21
|
+
ResourceType["functionTimeout"] = "FUNCTION_TIMEOUT";
|
|
22
|
+
ResourceType["functionMemorySize"] = "FUNCTION_MEMORY_SIZE";
|
|
23
|
+
ResourceType["functionRuntime"] = "FUNCTION_RUNTIME";
|
|
24
|
+
ResourceType["functionName"] = "FUNCTION_NAME";
|
|
25
|
+
ResourceType["tagSolution"] = "TAG_SOLUTION";
|
|
26
|
+
ResourceType["bucketPublicity"] = "BUCKET_PUBLICITY";
|
|
27
|
+
ResourceType["resourcePath"] = "RESOURCE_PATH";
|
|
28
|
+
ResourceType["queueEncryption"] = "QUEUE_ENCRYPTION";
|
|
29
|
+
ResourceType["logGroupRetention"] = "LOG_GROUP_RETENTION";
|
|
30
|
+
})(ResourceType || (ResourceType = {}));
|
|
31
|
+
export class StackCheckingAspect {
|
|
32
|
+
stackShortName;
|
|
33
|
+
whitelistedResources;
|
|
34
|
+
constructor(stackShortName, whitelistedResources) {
|
|
35
|
+
this.stackShortName = stackShortName;
|
|
36
|
+
this.whitelistedResources = whitelistedResources;
|
|
37
|
+
}
|
|
38
|
+
visit(node) {
|
|
39
|
+
//console.info("visiting class " + node.constructor.name);
|
|
40
|
+
this.checkStack(node);
|
|
41
|
+
this.checkFunction(node);
|
|
42
|
+
this.checkTags(node);
|
|
43
|
+
this.checkBucket(node);
|
|
44
|
+
this.checkResourceCasing(node);
|
|
45
|
+
this.checkQueueEncryption(node);
|
|
46
|
+
this.checkLogGroupRetention(node);
|
|
47
|
+
}
|
|
48
|
+
isWhitelisted(key) {
|
|
49
|
+
return this.whitelistedResources?.some((wl) => {
|
|
50
|
+
return key.matchAll(new RegExp(wl, "g"));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
addAnnotation(node, key, message, isError = true) {
|
|
54
|
+
const resourceKey = `${node.node.path}/${key}`;
|
|
55
|
+
const isWhiteListed = this.isWhitelisted(resourceKey);
|
|
56
|
+
const annotationMessage = `${resourceKey}:${message}`;
|
|
57
|
+
// error && whitelisted -> warning
|
|
58
|
+
// warning && whitelisted -> nothing
|
|
59
|
+
if (isError && !isWhiteListed) {
|
|
60
|
+
Annotations.of(node).addError(annotationMessage);
|
|
61
|
+
}
|
|
62
|
+
else if ((!isError && !isWhiteListed) || (isError && isWhiteListed)) {
|
|
63
|
+
Annotations.of(node).addWarning(annotationMessage);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
isDigitrafficStack(node) {
|
|
67
|
+
return node instanceof DigitrafficStack;
|
|
68
|
+
}
|
|
69
|
+
checkStack(node) {
|
|
70
|
+
// Fix Invalid 'instanceof' check: 'nodeToCheck' has type that is not related to 'DigitrafficStack'
|
|
71
|
+
if (this.isDigitrafficStack(node)) {
|
|
72
|
+
if ((node.stackName.includes("Test") || node.stackName.includes("Tst")) &&
|
|
73
|
+
node.configuration.production) {
|
|
74
|
+
this.addAnnotation(node, ResourceType.stackName, "Production is set for Test-stack");
|
|
75
|
+
}
|
|
76
|
+
if ((node.stackName.includes("Prod") || node.stackName.includes("Prd")) &&
|
|
77
|
+
!node.configuration.production) {
|
|
78
|
+
this.addAnnotation(node, ResourceType.stackName, "Production is not set for Production-stack");
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
checkFunction(node) {
|
|
83
|
+
if (node instanceof CfnFunction) {
|
|
84
|
+
if (!node.reservedConcurrentExecutions) {
|
|
85
|
+
this.addAnnotation(node, ResourceType.reservedConcurrentConcurrency, "Function must have reservedConcurrentConcurrency");
|
|
86
|
+
}
|
|
87
|
+
else if (node.reservedConcurrentExecutions > MAX_CONCURRENCY_LIMIT) {
|
|
88
|
+
this.addAnnotation(node, ResourceType.reservedConcurrentConcurrency, "Function reservedConcurrentConcurrency too high!");
|
|
89
|
+
}
|
|
90
|
+
if (!node.timeout) {
|
|
91
|
+
this.addAnnotation(node, ResourceType.functionTimeout, "Function must have timeout");
|
|
92
|
+
}
|
|
93
|
+
if (!node.memorySize) {
|
|
94
|
+
this.addAnnotation(node, ResourceType.functionMemorySize, "Function must have memorySize");
|
|
95
|
+
}
|
|
96
|
+
if (node.runtime !== undefined &&
|
|
97
|
+
!ALLOWED_RUNTIMES.includes(node.runtime)) {
|
|
98
|
+
this.addAnnotation(node, ResourceType.functionRuntime, `Function has wrong runtime ${node.runtime}!`);
|
|
99
|
+
}
|
|
100
|
+
if (this.stackShortName &&
|
|
101
|
+
node.functionName &&
|
|
102
|
+
!node.functionName.startsWith(this.stackShortName)) {
|
|
103
|
+
this.addAnnotation(node, ResourceType.functionName, `Function name does not begin with ${this.stackShortName}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
checkTags(node) {
|
|
108
|
+
if (node instanceof Stack) {
|
|
109
|
+
if (!node.tags.tagValues()[SOLUTION_KEY]) {
|
|
110
|
+
this.addAnnotation(node, ResourceType.tagSolution, "Solution tag is missing");
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
checkBucket(node) {
|
|
115
|
+
if (node instanceof CfnBucket) {
|
|
116
|
+
const c = node.publicAccessBlockConfiguration;
|
|
117
|
+
if (c &&
|
|
118
|
+
(!c.blockPublicAcls ||
|
|
119
|
+
!c.blockPublicPolicy ||
|
|
120
|
+
!c.ignorePublicAcls ||
|
|
121
|
+
!c.restrictPublicBuckets)) {
|
|
122
|
+
this.addAnnotation(node, ResourceType.bucketPublicity, "Check bucket publicity");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
static isValidPath(path) {
|
|
127
|
+
if (!path) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
// if path includes . or { check only the trailing part of path
|
|
131
|
+
if (path.includes(".")) {
|
|
132
|
+
return StackCheckingAspect.isValidPath(path.split(".")[0]);
|
|
133
|
+
}
|
|
134
|
+
if (path.includes("{")) {
|
|
135
|
+
return StackCheckingAspect.isValidPath(path.split("{")[0]);
|
|
136
|
+
}
|
|
137
|
+
return kebabCase(path) === path;
|
|
138
|
+
}
|
|
139
|
+
static isValidQueryString(name) {
|
|
140
|
+
return snakeCase(name) === name;
|
|
141
|
+
}
|
|
142
|
+
checkResourceCasing(node) {
|
|
143
|
+
if (node instanceof CfnResource) {
|
|
144
|
+
if (!StackCheckingAspect.isValidPath(node.pathPart)) {
|
|
145
|
+
this.addAnnotation(node, ResourceType.resourcePath, "Path part should be in kebab-case", false);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (node instanceof CfnMethod) {
|
|
149
|
+
const integration = node.integration;
|
|
150
|
+
if (integration?.requestParameters) {
|
|
151
|
+
Object.keys(integration.requestParameters).forEach((key) => {
|
|
152
|
+
const split = key.split(".");
|
|
153
|
+
const type = split[2];
|
|
154
|
+
const name = split[3];
|
|
155
|
+
if (name === undefined) {
|
|
156
|
+
throw Error("Name should not be undefined");
|
|
157
|
+
}
|
|
158
|
+
if (type === "querystring" &&
|
|
159
|
+
!StackCheckingAspect.isValidQueryString(name)) {
|
|
160
|
+
this.addAnnotation(node, name, "Querystring should be in snake_case");
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
checkQueueEncryption(node) {
|
|
167
|
+
if (node instanceof CfnQueue) {
|
|
168
|
+
if (!node.kmsMasterKeyId) {
|
|
169
|
+
this.addAnnotation(node, ResourceType.queueEncryption, "Queue must have encryption enabled");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
checkLogGroupRetention(node) {
|
|
174
|
+
if (node instanceof LogRetention) {
|
|
175
|
+
const child = node.node.defaultChild;
|
|
176
|
+
const retention = child?._cfnProperties?.RetentionInDays;
|
|
177
|
+
if (!retention) {
|
|
178
|
+
this.addAnnotation(node, ResourceType.logGroupRetention, "Log group must define log group retention");
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=stack-checking-aspect.js.map
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { StackProps } from "aws-cdk-lib";
|
|
2
|
+
import { Stack } from "aws-cdk-lib";
|
|
3
|
+
import type { ISecurityGroup, IVpc } from "aws-cdk-lib/aws-ec2";
|
|
4
|
+
import type { Function as AWSFunction } from "aws-cdk-lib/aws-lambda";
|
|
5
|
+
import type { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
6
|
+
import type { ITopic } from "aws-cdk-lib/aws-sns";
|
|
7
|
+
import type { Construct } from "constructs";
|
|
8
|
+
import type { TrafficType } from "../../../types/traffictype.js";
|
|
9
|
+
import type { DBLambdaEnvironment } from "./lambda-configs.js";
|
|
10
|
+
export declare const SOLUTION_KEY = "Solution";
|
|
11
|
+
export declare const SSM_KEY_WARNING_TOPIC = "/digitraffic/monitoring/warning-topic";
|
|
12
|
+
export declare const SSM_KEY_ALARM_TOPIC = "/digitraffic/monitoring/alarm-topic";
|
|
13
|
+
export interface StackConfiguration {
|
|
14
|
+
readonly shortName: string;
|
|
15
|
+
readonly secretId?: string;
|
|
16
|
+
readonly alarmTopicArn: string;
|
|
17
|
+
readonly warningTopicArn: string;
|
|
18
|
+
readonly logsDestinationArn?: string;
|
|
19
|
+
readonly vpcId?: string;
|
|
20
|
+
readonly lambdaDbSgId?: string;
|
|
21
|
+
readonly privateSubnetIds?: string[];
|
|
22
|
+
readonly availabilityZones?: string[];
|
|
23
|
+
readonly trafficType: TrafficType;
|
|
24
|
+
readonly production: boolean;
|
|
25
|
+
readonly stackProps: StackProps;
|
|
26
|
+
readonly stackFeatures?: {
|
|
27
|
+
readonly enableCanaries?: boolean;
|
|
28
|
+
readonly enableDocumentation?: boolean;
|
|
29
|
+
};
|
|
30
|
+
readonly whitelistedResources?: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface DigitrafficStackLike {
|
|
33
|
+
readonly configuration: StackConfiguration;
|
|
34
|
+
readonly vpc?: IVpc;
|
|
35
|
+
readonly lambdaDbSg?: ISecurityGroup;
|
|
36
|
+
readonly alarmTopic: ITopic;
|
|
37
|
+
readonly warningTopic: ITopic;
|
|
38
|
+
createLambdaEnvironment(): DBLambdaEnvironment;
|
|
39
|
+
createDefaultLambdaEnvironment(dbApplication: string): DBLambdaEnvironment;
|
|
40
|
+
getSecret(): ISecret;
|
|
41
|
+
grantSecret(...lambdas: AWSFunction[]): void;
|
|
42
|
+
}
|
|
43
|
+
export declare class DigitrafficStack extends Stack implements DigitrafficStackLike {
|
|
44
|
+
readonly vpc?: IVpc;
|
|
45
|
+
readonly lambdaDbSg?: ISecurityGroup;
|
|
46
|
+
readonly alarmTopic: ITopic;
|
|
47
|
+
readonly warningTopic: ITopic;
|
|
48
|
+
readonly secret?: ISecret;
|
|
49
|
+
readonly configuration: StackConfiguration;
|
|
50
|
+
constructor(scope: Construct, id: string, configuration: StackConfiguration);
|
|
51
|
+
addAspects(): void;
|
|
52
|
+
createLambdaEnvironment(): DBLambdaEnvironment;
|
|
53
|
+
createDefaultLambdaEnvironment(dbApplication: string): DBLambdaEnvironment;
|
|
54
|
+
getSecret(): ISecret;
|
|
55
|
+
grantSecret(...lambdas: AWSFunction[]): void;
|
|
56
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Aspects, Stack } from "aws-cdk-lib";
|
|
2
|
+
import { SecurityGroup, Vpc } from "aws-cdk-lib/aws-ec2";
|
|
3
|
+
import { Secret } from "aws-cdk-lib/aws-secretsmanager";
|
|
4
|
+
import { Topic } from "aws-cdk-lib/aws-sns";
|
|
5
|
+
import { StringParameter } from "aws-cdk-lib/aws-ssm";
|
|
6
|
+
import { StackCheckingAspect } from "./stack-checking-aspect.js";
|
|
7
|
+
const SSM_ROOT = "/digitraffic";
|
|
8
|
+
export const SOLUTION_KEY = "Solution";
|
|
9
|
+
const MONITORING_ROOT = "/monitoring";
|
|
10
|
+
export const SSM_KEY_WARNING_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/warning-topic`;
|
|
11
|
+
export const SSM_KEY_ALARM_TOPIC = `${SSM_ROOT}${MONITORING_ROOT}/alarm-topic`;
|
|
12
|
+
export class DigitrafficStack extends Stack {
|
|
13
|
+
vpc;
|
|
14
|
+
lambdaDbSg;
|
|
15
|
+
alarmTopic;
|
|
16
|
+
warningTopic;
|
|
17
|
+
secret;
|
|
18
|
+
configuration;
|
|
19
|
+
constructor(scope, id, configuration) {
|
|
20
|
+
super(scope, id, configuration.stackProps);
|
|
21
|
+
this.configuration = configuration;
|
|
22
|
+
if (configuration.secretId) {
|
|
23
|
+
this.secret = Secret.fromSecretNameV2(this, "Secret", configuration.secretId);
|
|
24
|
+
}
|
|
25
|
+
// VPC reference construction requires vpcId and availability zones
|
|
26
|
+
// private subnets are used in Lambda configuration
|
|
27
|
+
if (configuration.vpcId) {
|
|
28
|
+
this.vpc = Vpc.fromVpcAttributes(this, "vpc", {
|
|
29
|
+
vpcId: configuration.vpcId,
|
|
30
|
+
privateSubnetIds: configuration.privateSubnetIds,
|
|
31
|
+
availabilityZones: configuration.availabilityZones ?? [],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// security group that allows Lambda database access
|
|
35
|
+
if (configuration.lambdaDbSgId) {
|
|
36
|
+
this.lambdaDbSg = SecurityGroup.fromSecurityGroupId(this, "LambdaDbSG", configuration.lambdaDbSgId);
|
|
37
|
+
}
|
|
38
|
+
this.alarmTopic = Topic.fromTopicArn(this, "AlarmTopic", StringParameter.fromStringParameterName(this, "AlarmTopicParam", SSM_KEY_ALARM_TOPIC).stringValue);
|
|
39
|
+
this.warningTopic = Topic.fromTopicArn(this, "WarningTopic", StringParameter.fromStringParameterName(this, "WarningTopicParam", SSM_KEY_WARNING_TOPIC).stringValue);
|
|
40
|
+
this.addAspects();
|
|
41
|
+
}
|
|
42
|
+
addAspects() {
|
|
43
|
+
Aspects.of(this).add(new StackCheckingAspect(this.configuration.shortName, this.configuration.whitelistedResources));
|
|
44
|
+
}
|
|
45
|
+
createLambdaEnvironment() {
|
|
46
|
+
return this.createDefaultLambdaEnvironment(this.configuration.shortName);
|
|
47
|
+
}
|
|
48
|
+
createDefaultLambdaEnvironment(dbApplication) {
|
|
49
|
+
return this.configuration.secretId
|
|
50
|
+
? {
|
|
51
|
+
SECRET_ID: this.configuration.secretId,
|
|
52
|
+
DB_APPLICATION: dbApplication,
|
|
53
|
+
}
|
|
54
|
+
: {
|
|
55
|
+
DB_APPLICATION: dbApplication,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
getSecret() {
|
|
59
|
+
if (this.secret === undefined) {
|
|
60
|
+
throw new Error("Secret is undefined");
|
|
61
|
+
}
|
|
62
|
+
return this.secret;
|
|
63
|
+
}
|
|
64
|
+
grantSecret(...lambdas) {
|
|
65
|
+
const secret = this.getSecret();
|
|
66
|
+
lambdas.forEach((l) => {
|
|
67
|
+
secret.grantRead(l);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Function as AWSFunction } from "aws-cdk-lib/aws-lambda";
|
|
2
|
+
import { CfnSubscriptionFilter } from "aws-cdk-lib/aws-logs";
|
|
3
|
+
import type { Construct } from "constructs";
|
|
4
|
+
import type { MonitoredFunction } from "./monitoredfunction.js";
|
|
5
|
+
import type { DigitrafficStack } from "./stack.js";
|
|
6
|
+
/**
|
|
7
|
+
* Creates a subscription filter that subscribes to a Lambda Log Group and delivers the logs to another destination.
|
|
8
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-subscriptionfilter.html
|
|
9
|
+
* @param lambda The Lambda function, needed to create a dependency
|
|
10
|
+
* @param lambdaName The Lambda name from which the Log Group name is derived
|
|
11
|
+
* @param logDestinationArn Destination for streamed logs
|
|
12
|
+
* @param stack CloudFormation stack
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSubscription(lambda: AWSFunction, lambdaName: string, logDestinationArn: string | undefined, stack: Construct): CfnSubscriptionFilter | undefined;
|
|
15
|
+
export declare class DigitrafficLogSubscriptions {
|
|
16
|
+
constructor(stack: DigitrafficStack, ...lambdas: MonitoredFunction[]);
|
|
17
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { CfnSubscriptionFilter } from "aws-cdk-lib/aws-logs";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a subscription filter that subscribes to a Lambda Log Group and delivers the logs to another destination.
|
|
4
|
+
* https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-logs-subscriptionfilter.html
|
|
5
|
+
* @param lambda The Lambda function, needed to create a dependency
|
|
6
|
+
* @param lambdaName The Lambda name from which the Log Group name is derived
|
|
7
|
+
* @param logDestinationArn Destination for streamed logs
|
|
8
|
+
* @param stack CloudFormation stack
|
|
9
|
+
*/
|
|
10
|
+
export function createSubscription(lambda, lambdaName, logDestinationArn, stack) {
|
|
11
|
+
if (logDestinationArn === undefined || logDestinationArn === null) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
const filter = new CfnSubscriptionFilter(stack, `${lambdaName}LogsSubscription`, {
|
|
15
|
+
logGroupName: lambda.logGroup.logGroupName,
|
|
16
|
+
filterPattern: "",
|
|
17
|
+
destinationArn: logDestinationArn,
|
|
18
|
+
});
|
|
19
|
+
filter.node.addDependency(lambda);
|
|
20
|
+
return filter;
|
|
21
|
+
}
|
|
22
|
+
export class DigitrafficLogSubscriptions {
|
|
23
|
+
constructor(stack, ...lambdas) {
|
|
24
|
+
const destinationArn = stack.configuration.logsDestinationArn;
|
|
25
|
+
if (destinationArn !== undefined) {
|
|
26
|
+
lambdas.forEach((lambda) => {
|
|
27
|
+
const filter = new CfnSubscriptionFilter(stack, `${lambda.givenName}LogsSubscription`, {
|
|
28
|
+
logGroupName: lambda.logGroup.logGroupName,
|
|
29
|
+
filterPattern: "",
|
|
30
|
+
destinationArn,
|
|
31
|
+
});
|
|
32
|
+
filter.node.addDependency(lambda);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=subscription.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Stack } from "aws-cdk-lib";
|
|
2
|
+
import type { Construct } from "constructs";
|
|
3
|
+
import type { InfraStackConfiguration } from "./intra-stack-configuration.js";
|
|
4
|
+
/**
|
|
5
|
+
* Creates a dns local zone and creates records for cluster endpoints and proxy endpoints.
|
|
6
|
+
*
|
|
7
|
+
* Please note, that created PrivateHostedZone has RETAIN removalPolicy, so if you want to delete this stack,
|
|
8
|
+
* you must remove the zone by hand after.
|
|
9
|
+
*/
|
|
10
|
+
export declare class DbDnsStack extends Stack {
|
|
11
|
+
constructor(scope: Construct, id: string, isc: InfraStackConfiguration);
|
|
12
|
+
createDnsRecords(isc: InfraStackConfiguration): void;
|
|
13
|
+
}
|