@jaypie/constructs 1.1.64 → 1.1.65
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/package.json +2 -2
- package/dist/cjs/JaypieAccountLoggingBucket.d.ts +0 -60
- package/dist/cjs/JaypieApiGateway.d.ts +0 -47
- package/dist/cjs/JaypieAppStack.d.ts +0 -5
- package/dist/cjs/JaypieBucketQueuedLambda.d.ts +0 -48
- package/dist/cjs/JaypieDatadogBucket.d.ts +0 -55
- package/dist/cjs/JaypieDatadogForwarder.d.ts +0 -76
- package/dist/cjs/JaypieDatadogSecret.d.ts +0 -5
- package/dist/cjs/JaypieDistribution.d.ts +0 -76
- package/dist/cjs/JaypieDnsRecord.d.ts +0 -45
- package/dist/cjs/JaypieEnvSecret.d.ts +0 -41
- package/dist/cjs/JaypieEventsRule.d.ts +0 -45
- package/dist/cjs/JaypieExpressLambda.d.ts +0 -5
- package/dist/cjs/JaypieGitHubDeployRole.d.ts +0 -14
- package/dist/cjs/JaypieHostedZone.d.ts +0 -59
- package/dist/cjs/JaypieInfrastructureStack.d.ts +0 -5
- package/dist/cjs/JaypieLambda.d.ts +0 -100
- package/dist/cjs/JaypieMongoDbSecret.d.ts +0 -5
- package/dist/cjs/JaypieNextJs.d.ts +0 -18
- package/dist/cjs/JaypieNextJs.test.d.ts +0 -1
- package/dist/cjs/JaypieOpenAiSecret.d.ts +0 -5
- package/dist/cjs/JaypieOrganizationTrail.d.ts +0 -62
- package/dist/cjs/JaypieQueuedLambda.d.ts +0 -77
- package/dist/cjs/JaypieSsoPermissions.d.ts +0 -96
- package/dist/cjs/JaypieSsoSyncApplication.d.ts +0 -27
- package/dist/cjs/JaypieStack.d.ts +0 -8
- package/dist/cjs/JaypieStaticWebBucket.d.ts +0 -22
- package/dist/cjs/JaypieTraceSigningKeySecret.d.ts +0 -5
- package/dist/cjs/JaypieWebDeploymentBucket.d.ts +0 -84
- package/dist/cjs/__tests__/JaypieBucketQueuedLambda.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieDistribution.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieDnsRecord.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieEnvSecret.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieExpressLambda.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieHostedZone.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieLambda.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieQueuedLambda.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieSsoPermissions.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieSsoSyncApplication.spec.d.ts +0 -1
- package/dist/cjs/__tests__/JaypieStaticWebBucket.spec.d.ts +0 -1
- package/dist/cjs/__tests__/index.spec.d.ts +0 -1
- package/dist/cjs/constants.d.ts +0 -151
- package/dist/cjs/helpers/__tests__/envHostname.spec.d.ts +0 -1
- package/dist/cjs/helpers/__tests__/jaypieLambdaEnv.spec.d.ts +0 -1
- package/dist/cjs/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +0 -1
- package/dist/cjs/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +0 -1
- package/dist/cjs/helpers/addDatadogLayers.d.ts +0 -5
- package/dist/cjs/helpers/constructEnvName.d.ts +0 -5
- package/dist/cjs/helpers/constructStackName.d.ts +0 -1
- package/dist/cjs/helpers/constructTagger.d.ts +0 -4
- package/dist/cjs/helpers/envHostname.d.ts +0 -6
- package/dist/cjs/helpers/extendDatadogRole.d.ts +0 -31
- package/dist/cjs/helpers/index.d.ts +0 -16
- package/dist/cjs/helpers/isEnv.d.ts +0 -12
- package/dist/cjs/helpers/isValidHostname.d.ts +0 -1
- package/dist/cjs/helpers/isValidSubdomain.d.ts +0 -1
- package/dist/cjs/helpers/jaypieLambdaEnv.d.ts +0 -8
- package/dist/cjs/helpers/mergeDomain.d.ts +0 -1
- package/dist/cjs/helpers/resolveDatadogForwarderFunction.d.ts +0 -7
- package/dist/cjs/helpers/resolveDatadogLayers.d.ts +0 -7
- package/dist/cjs/helpers/resolveDatadogLoggingDestination.d.ts +0 -4
- package/dist/cjs/helpers/resolveHostedZone.d.ts +0 -6
- package/dist/cjs/helpers/resolveParamsAndSecrets.d.ts +0 -13
- package/dist/cjs/index.cjs +0 -3335
- package/dist/cjs/index.cjs.map +0 -1
- package/dist/cjs/index.d.ts +0 -29
- package/dist/esm/JaypieAccountLoggingBucket.d.ts +0 -60
- package/dist/esm/JaypieApiGateway.d.ts +0 -47
- package/dist/esm/JaypieAppStack.d.ts +0 -5
- package/dist/esm/JaypieBucketQueuedLambda.d.ts +0 -48
- package/dist/esm/JaypieDatadogBucket.d.ts +0 -55
- package/dist/esm/JaypieDatadogForwarder.d.ts +0 -76
- package/dist/esm/JaypieDatadogSecret.d.ts +0 -5
- package/dist/esm/JaypieDistribution.d.ts +0 -76
- package/dist/esm/JaypieDnsRecord.d.ts +0 -45
- package/dist/esm/JaypieEnvSecret.d.ts +0 -41
- package/dist/esm/JaypieEventsRule.d.ts +0 -45
- package/dist/esm/JaypieExpressLambda.d.ts +0 -5
- package/dist/esm/JaypieGitHubDeployRole.d.ts +0 -14
- package/dist/esm/JaypieHostedZone.d.ts +0 -59
- package/dist/esm/JaypieInfrastructureStack.d.ts +0 -5
- package/dist/esm/JaypieLambda.d.ts +0 -100
- package/dist/esm/JaypieMongoDbSecret.d.ts +0 -5
- package/dist/esm/JaypieNextJs.d.ts +0 -18
- package/dist/esm/JaypieNextJs.test.d.ts +0 -1
- package/dist/esm/JaypieOpenAiSecret.d.ts +0 -5
- package/dist/esm/JaypieOrganizationTrail.d.ts +0 -62
- package/dist/esm/JaypieQueuedLambda.d.ts +0 -77
- package/dist/esm/JaypieSsoPermissions.d.ts +0 -96
- package/dist/esm/JaypieSsoSyncApplication.d.ts +0 -27
- package/dist/esm/JaypieStack.d.ts +0 -8
- package/dist/esm/JaypieStaticWebBucket.d.ts +0 -22
- package/dist/esm/JaypieTraceSigningKeySecret.d.ts +0 -5
- package/dist/esm/JaypieWebDeploymentBucket.d.ts +0 -84
- package/dist/esm/__tests__/JaypieBucketQueuedLambda.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieDistribution.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieDnsRecord.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieEnvSecret.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieExpressLambda.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieHostedZone.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieLambda.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieQueuedLambda.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieSsoPermissions.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieSsoSyncApplication.spec.d.ts +0 -1
- package/dist/esm/__tests__/JaypieStaticWebBucket.spec.d.ts +0 -1
- package/dist/esm/__tests__/index.spec.d.ts +0 -1
- package/dist/esm/constants.d.ts +0 -151
- package/dist/esm/helpers/__tests__/envHostname.spec.d.ts +0 -1
- package/dist/esm/helpers/__tests__/jaypieLambdaEnv.spec.d.ts +0 -1
- package/dist/esm/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +0 -1
- package/dist/esm/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +0 -1
- package/dist/esm/helpers/addDatadogLayers.d.ts +0 -5
- package/dist/esm/helpers/constructEnvName.d.ts +0 -5
- package/dist/esm/helpers/constructStackName.d.ts +0 -1
- package/dist/esm/helpers/constructTagger.d.ts +0 -4
- package/dist/esm/helpers/envHostname.d.ts +0 -6
- package/dist/esm/helpers/extendDatadogRole.d.ts +0 -31
- package/dist/esm/helpers/index.d.ts +0 -16
- package/dist/esm/helpers/isEnv.d.ts +0 -12
- package/dist/esm/helpers/isValidHostname.d.ts +0 -1
- package/dist/esm/helpers/isValidSubdomain.d.ts +0 -1
- package/dist/esm/helpers/jaypieLambdaEnv.d.ts +0 -8
- package/dist/esm/helpers/mergeDomain.d.ts +0 -1
- package/dist/esm/helpers/resolveDatadogForwarderFunction.d.ts +0 -7
- package/dist/esm/helpers/resolveDatadogLayers.d.ts +0 -7
- package/dist/esm/helpers/resolveDatadogLoggingDestination.d.ts +0 -4
- package/dist/esm/helpers/resolveHostedZone.d.ts +0 -6
- package/dist/esm/helpers/resolveParamsAndSecrets.d.ts +0 -13
- package/dist/esm/index.d.ts +0 -29
- package/dist/esm/index.js +0 -3259
- package/dist/esm/index.js.map +0 -1
package/dist/cjs/index.cjs
DELETED
|
@@ -1,3335 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var cdk = require('aws-cdk-lib');
|
|
4
|
-
var s3 = require('aws-cdk-lib/aws-s3');
|
|
5
|
-
var constructs = require('constructs');
|
|
6
|
-
var acm = require('aws-cdk-lib/aws-certificatemanager');
|
|
7
|
-
var apiGateway = require('aws-cdk-lib/aws-apigateway');
|
|
8
|
-
var route53 = require('aws-cdk-lib/aws-route53');
|
|
9
|
-
var route53Targets = require('aws-cdk-lib/aws-route53-targets');
|
|
10
|
-
var secretsmanager = require('aws-cdk-lib/aws-secretsmanager');
|
|
11
|
-
var datadogCdkConstructsV2 = require('datadog-cdk-constructs-v2');
|
|
12
|
-
var errors = require('@jaypie/errors');
|
|
13
|
-
var awsIam = require('aws-cdk-lib/aws-iam');
|
|
14
|
-
var lambda = require('aws-cdk-lib/aws-lambda');
|
|
15
|
-
var logDestinations = require('aws-cdk-lib/aws-logs-destinations');
|
|
16
|
-
var s3n = require('aws-cdk-lib/aws-s3-notifications');
|
|
17
|
-
var sqs = require('aws-cdk-lib/aws-sqs');
|
|
18
|
-
var lambdaEventSources = require('aws-cdk-lib/aws-lambda-event-sources');
|
|
19
|
-
var logs = require('aws-cdk-lib/aws-logs');
|
|
20
|
-
var awsEvents = require('aws-cdk-lib/aws-events');
|
|
21
|
-
var awsEventsTargets = require('aws-cdk-lib/aws-events-targets');
|
|
22
|
-
var cloudfront = require('aws-cdk-lib/aws-cloudfront');
|
|
23
|
-
var origins = require('aws-cdk-lib/aws-cloudfront-origins');
|
|
24
|
-
var cdkNextjsStandalone = require('cdk-nextjs-standalone');
|
|
25
|
-
var path = require('path');
|
|
26
|
-
var awsCloudtrail = require('aws-cdk-lib/aws-cloudtrail');
|
|
27
|
-
var awsSso = require('aws-cdk-lib/aws-sso');
|
|
28
|
-
var awsSam = require('aws-cdk-lib/aws-sam');
|
|
29
|
-
|
|
30
|
-
function _interopNamespaceDefault(e) {
|
|
31
|
-
var n = Object.create(null);
|
|
32
|
-
if (e) {
|
|
33
|
-
Object.keys(e).forEach(function (k) {
|
|
34
|
-
if (k !== 'default') {
|
|
35
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
36
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
37
|
-
enumerable: true,
|
|
38
|
-
get: function () { return e[k]; }
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
n.default = e;
|
|
44
|
-
return Object.freeze(n);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
var cdk__namespace = /*#__PURE__*/_interopNamespaceDefault(cdk);
|
|
48
|
-
var s3__namespace = /*#__PURE__*/_interopNamespaceDefault(s3);
|
|
49
|
-
var acm__namespace = /*#__PURE__*/_interopNamespaceDefault(acm);
|
|
50
|
-
var apiGateway__namespace = /*#__PURE__*/_interopNamespaceDefault(apiGateway);
|
|
51
|
-
var route53__namespace = /*#__PURE__*/_interopNamespaceDefault(route53);
|
|
52
|
-
var route53Targets__namespace = /*#__PURE__*/_interopNamespaceDefault(route53Targets);
|
|
53
|
-
var secretsmanager__namespace = /*#__PURE__*/_interopNamespaceDefault(secretsmanager);
|
|
54
|
-
var lambda__namespace = /*#__PURE__*/_interopNamespaceDefault(lambda);
|
|
55
|
-
var logDestinations__namespace = /*#__PURE__*/_interopNamespaceDefault(logDestinations);
|
|
56
|
-
var s3n__namespace = /*#__PURE__*/_interopNamespaceDefault(s3n);
|
|
57
|
-
var sqs__namespace = /*#__PURE__*/_interopNamespaceDefault(sqs);
|
|
58
|
-
var lambdaEventSources__namespace = /*#__PURE__*/_interopNamespaceDefault(lambdaEventSources);
|
|
59
|
-
var logs__namespace = /*#__PURE__*/_interopNamespaceDefault(logs);
|
|
60
|
-
var cloudfront__namespace = /*#__PURE__*/_interopNamespaceDefault(cloudfront);
|
|
61
|
-
var origins__namespace = /*#__PURE__*/_interopNamespaceDefault(origins);
|
|
62
|
-
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
63
|
-
|
|
64
|
-
const CDK$2 = {
|
|
65
|
-
ACCOUNT: {
|
|
66
|
-
DEVELOPMENT: "development",
|
|
67
|
-
MANAGEMENT: "management",
|
|
68
|
-
OPERATIONS: "operations",
|
|
69
|
-
PRODUCTION: "production",
|
|
70
|
-
SANDBOX: "sandbox",
|
|
71
|
-
SECURITY: "security",
|
|
72
|
-
STAGE: "stage",
|
|
73
|
-
},
|
|
74
|
-
BUILD: {
|
|
75
|
-
CONFIG: {
|
|
76
|
-
ALL: "all",
|
|
77
|
-
API: "api",
|
|
78
|
-
INFRASTRUCTURE: "infrastructure",
|
|
79
|
-
NONE: "none",
|
|
80
|
-
WEB: "web",
|
|
81
|
-
},
|
|
82
|
-
PERSONAL: "personal",
|
|
83
|
-
/**
|
|
84
|
-
* @deprecated rename "ephemeral" to "personal" (since 2/24/2025)
|
|
85
|
-
*/
|
|
86
|
-
EPHEMERAL: "ephemeral",
|
|
87
|
-
/**
|
|
88
|
-
* @deprecated as even "ephemeral" builds have static assets (since 7/6/2024)
|
|
89
|
-
*/
|
|
90
|
-
STATIC: "static",
|
|
91
|
-
},
|
|
92
|
-
CREATION: {
|
|
93
|
-
CDK: "cdk",
|
|
94
|
-
CLOUDFORMATION_TEMPLATE: "template",
|
|
95
|
-
MANUAL: "manual",
|
|
96
|
-
},
|
|
97
|
-
DATADOG: {
|
|
98
|
-
SITE: "datadoghq.com",
|
|
99
|
-
LAYER: {
|
|
100
|
-
// https://docs.datadoghq.com/serverless/aws_lambda/installation/nodejs/?tab=awscdk
|
|
101
|
-
NODE: 127, // 127 on 9/12/2025
|
|
102
|
-
EXTENSION: 86, // 86 on 9/12/2025
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
DEFAULT: {
|
|
106
|
-
REGION: "us-east-1",
|
|
107
|
-
},
|
|
108
|
-
DNS: {
|
|
109
|
-
CONFIG: {
|
|
110
|
-
TTL: 300, // 5 minutes in seconds for Route53
|
|
111
|
-
},
|
|
112
|
-
RECORD: {
|
|
113
|
-
A: "A",
|
|
114
|
-
CNAME: "CNAME",
|
|
115
|
-
MX: "MX",
|
|
116
|
-
NS: "NS",
|
|
117
|
-
TXT: "TXT",
|
|
118
|
-
},
|
|
119
|
-
},
|
|
120
|
-
DURATION: {
|
|
121
|
-
EXPRESS_API: 30,
|
|
122
|
-
LAMBDA_MAXIMUM: 900,
|
|
123
|
-
LAMBDA_WORKER: 900,
|
|
124
|
-
},
|
|
125
|
-
ENV: {
|
|
126
|
-
DEMO: "demo", // Mirror of production
|
|
127
|
-
DEVELOPMENT: "development", // Internal most stable development space
|
|
128
|
-
/** @deprecated */ EPHEMERAL: "ephemeral", // Alias for "build"
|
|
129
|
-
LOCAL: "local",
|
|
130
|
-
/** @deprecated */ MAIN: "main", // Alias for development
|
|
131
|
-
META: "meta", // For non-environment/infrastructure stacks
|
|
132
|
-
PERSONAL: "personal", // Personal builds using resources provided by sandbox
|
|
133
|
-
PREVIEW: "preview", // External next thing to be released
|
|
134
|
-
PRODUCTION: "production",
|
|
135
|
-
RELEASE: "release", // Internal next thing to be released
|
|
136
|
-
REVIEW: "review", // Internal place to collaborate on issues
|
|
137
|
-
SANDBOX: "sandbox", // Internal build space with no guaranteed longevity
|
|
138
|
-
TRAINING: "training", // aka "test"; mirror of production for external audiences
|
|
139
|
-
},
|
|
140
|
-
HOST: {
|
|
141
|
-
APEX: "@",
|
|
142
|
-
},
|
|
143
|
-
IMPORT: {
|
|
144
|
-
DATADOG_LOG_FORWARDER: "account-datadog-forwarder",
|
|
145
|
-
DATADOG_ROLE: "account-datadog-role",
|
|
146
|
-
DATADOG_SECRET: "account-datadog-secret",
|
|
147
|
-
LOG_BUCKET: "account-log-bucket",
|
|
148
|
-
OIDC_PROVIDER: "github-oidc-provider",
|
|
149
|
-
},
|
|
150
|
-
LAMBDA: {
|
|
151
|
-
LOG_RETENTION: 90,
|
|
152
|
-
MEMORY_SIZE: 1024,
|
|
153
|
-
},
|
|
154
|
-
PRINCIPAL: {
|
|
155
|
-
ROUTE53: "route53.amazonaws.com",
|
|
156
|
-
},
|
|
157
|
-
PRINCIPAL_TYPE: {
|
|
158
|
-
GROUP: "GROUP",
|
|
159
|
-
USER: "USER",
|
|
160
|
-
},
|
|
161
|
-
PROJECT: {
|
|
162
|
-
INFRASTRUCTURE: "infrastructure",
|
|
163
|
-
},
|
|
164
|
-
ROLE: {
|
|
165
|
-
API: "api",
|
|
166
|
-
DEPLOY: "deploy",
|
|
167
|
-
HOSTING: "hosting",
|
|
168
|
-
MONITORING: "monitoring",
|
|
169
|
-
NETWORKING: "networking",
|
|
170
|
-
PROCESSING: "processing",
|
|
171
|
-
SECURITY: "security",
|
|
172
|
-
STACK: "stack",
|
|
173
|
-
STORAGE: "storage",
|
|
174
|
-
TOY: "toy",
|
|
175
|
-
},
|
|
176
|
-
SERVICE: {
|
|
177
|
-
DATADOG: "datadog",
|
|
178
|
-
INFRASTRUCTURE: "infrastructure",
|
|
179
|
-
LIBRARIES: "libraries",
|
|
180
|
-
NONE: "none",
|
|
181
|
-
SSO: "sso",
|
|
182
|
-
TRACE: "trace",
|
|
183
|
-
},
|
|
184
|
-
TAG: {
|
|
185
|
-
BUILD_DATE: "buildDate",
|
|
186
|
-
BUILD_HEX: "buildHex",
|
|
187
|
-
BUILD_NUMBER: "buildNumber",
|
|
188
|
-
BUILD_TIME: "buildTime",
|
|
189
|
-
BUILD_TYPE: "buildType",
|
|
190
|
-
COMMIT: "commit",
|
|
191
|
-
CREATION: "creation",
|
|
192
|
-
ENV: "env",
|
|
193
|
-
NONCE: "nonce",
|
|
194
|
-
PROJECT: "project",
|
|
195
|
-
ROLE: "role",
|
|
196
|
-
SERVICE: "service",
|
|
197
|
-
SPONSOR: "sponsor",
|
|
198
|
-
STACK: "stack",
|
|
199
|
-
STACK_SHA: "stackSha",
|
|
200
|
-
VENDOR: "vendor",
|
|
201
|
-
VERSION: "version",
|
|
202
|
-
},
|
|
203
|
-
TARGET_TYPE: {
|
|
204
|
-
AWS_ACCOUNT: "AWS_ACCOUNT",
|
|
205
|
-
},
|
|
206
|
-
VENDOR: {
|
|
207
|
-
ANTHROPIC: "anthropic",
|
|
208
|
-
AUTH0: "auth0",
|
|
209
|
-
DATADOG: "datadog",
|
|
210
|
-
KNOWTRACE: "knowtrace",
|
|
211
|
-
MONGODB: "mongodb",
|
|
212
|
-
OPENAI: "openai",
|
|
213
|
-
SPLINTERLANDS: "splinterlands",
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
class JaypieAccountLoggingBucket extends constructs.Construct {
|
|
218
|
-
/**
|
|
219
|
-
* Create a new account-wide logging S3 bucket with lifecycle policies and export
|
|
220
|
-
*/
|
|
221
|
-
constructor(scope, idOrProps, propsOrUndefined) {
|
|
222
|
-
// Handle overloaded constructor signatures
|
|
223
|
-
let props;
|
|
224
|
-
let id;
|
|
225
|
-
if (typeof idOrProps === "string") {
|
|
226
|
-
// First param is ID, second is props
|
|
227
|
-
props = propsOrUndefined || {};
|
|
228
|
-
id = idOrProps;
|
|
229
|
-
}
|
|
230
|
-
else {
|
|
231
|
-
// First param is props
|
|
232
|
-
props = idOrProps || {};
|
|
233
|
-
id = props.id || "AccountLoggingBucket";
|
|
234
|
-
}
|
|
235
|
-
super(scope, id);
|
|
236
|
-
// Generate default bucket name with PROJECT_NONCE
|
|
237
|
-
const defaultBucketName = process.env.PROJECT_NONCE
|
|
238
|
-
? `account-logging-stack-${process.env.PROJECT_NONCE.toLowerCase()}`
|
|
239
|
-
: "account-logging-stack";
|
|
240
|
-
// Extract Jaypie-specific options
|
|
241
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
242
|
-
const { bucketName = defaultBucketName, createOutput = true, expirationDays = 365, exportName = CDK$2.IMPORT.LOG_BUCKET, glacierTransitionDays = 180, id: _id, infrequentAccessTransitionDays = 30, outputDescription = "Account-wide logging bucket", project, service = CDK$2.SERVICE.INFRASTRUCTURE, ...bucketProps } = props;
|
|
243
|
-
// Create the bucket with lifecycle rules
|
|
244
|
-
this.bucket = new s3.Bucket(this, "Bucket", {
|
|
245
|
-
accessControl: s3.BucketAccessControl.LOG_DELIVERY_WRITE,
|
|
246
|
-
bucketName,
|
|
247
|
-
lifecycleRules: [
|
|
248
|
-
{
|
|
249
|
-
expiration: cdk__namespace.Duration.days(expirationDays),
|
|
250
|
-
transitions: [
|
|
251
|
-
{
|
|
252
|
-
storageClass: s3.StorageClass.INFREQUENT_ACCESS,
|
|
253
|
-
transitionAfter: cdk__namespace.Duration.days(infrequentAccessTransitionDays),
|
|
254
|
-
},
|
|
255
|
-
{
|
|
256
|
-
storageClass: s3.StorageClass.GLACIER,
|
|
257
|
-
transitionAfter: cdk__namespace.Duration.days(glacierTransitionDays),
|
|
258
|
-
},
|
|
259
|
-
],
|
|
260
|
-
},
|
|
261
|
-
],
|
|
262
|
-
...bucketProps,
|
|
263
|
-
});
|
|
264
|
-
// Add tags
|
|
265
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
266
|
-
if (service) {
|
|
267
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.SERVICE, service);
|
|
268
|
-
}
|
|
269
|
-
if (project) {
|
|
270
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.PROJECT, project);
|
|
271
|
-
}
|
|
272
|
-
// Create CloudFormation output if enabled
|
|
273
|
-
if (createOutput) {
|
|
274
|
-
new cdk__namespace.CfnOutput(this, "BucketNameOutput", {
|
|
275
|
-
description: outputDescription,
|
|
276
|
-
exportName,
|
|
277
|
-
value: this.bucket.bucketName,
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function addDatadogLayers(lambdaFunction, options = {}) {
|
|
284
|
-
const datadogApiKeyArn = options?.datadogApiKeyArn;
|
|
285
|
-
const resolvedDatadogApiKeyArn = datadogApiKeyArn ||
|
|
286
|
-
process.env.DATADOG_API_KEY_ARN ||
|
|
287
|
-
process.env.CDK_ENV_DATADOG_API_KEY_ARN;
|
|
288
|
-
if (!resolvedDatadogApiKeyArn) {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
// Define Datadog environment variables
|
|
292
|
-
const datadogEnvVars = {
|
|
293
|
-
DD_API_KEY_SECRET_ARN: resolvedDatadogApiKeyArn,
|
|
294
|
-
DD_ENHANCED_METRICS: "true",
|
|
295
|
-
DD_ENV: process.env.PROJECT_ENV || "",
|
|
296
|
-
DD_PROFILING_ENABLED: "false",
|
|
297
|
-
DD_SERVERLESS_APPSEC_ENABLED: "false",
|
|
298
|
-
DD_SERVICE: process.env.PROJECT_SERVICE || "",
|
|
299
|
-
DD_SITE: CDK$2.DATADOG.SITE,
|
|
300
|
-
DD_TAGS: `${CDK$2.TAG.SPONSOR}:${process.env.PROJECT_SPONSOR || ""}`,
|
|
301
|
-
DD_TRACE_OTEL_ENABLED: "false",
|
|
302
|
-
};
|
|
303
|
-
// Add environment variables only if they don't already exist
|
|
304
|
-
Object.entries(datadogEnvVars).forEach(([key, value]) => {
|
|
305
|
-
lambdaFunction.addEnvironment(key, value);
|
|
306
|
-
});
|
|
307
|
-
const datadogApiKeySecret = secretsmanager__namespace.Secret.fromSecretCompleteArn(lambdaFunction, "DatadogApiKey", resolvedDatadogApiKeyArn);
|
|
308
|
-
const datadogLambda = new datadogCdkConstructsV2.DatadogLambda(lambdaFunction, "DatadogLambda", {
|
|
309
|
-
apiKeySecret: datadogApiKeySecret, // apiKeySecret auto-grants secret access to the added lambdas
|
|
310
|
-
nodeLayerVersion: CDK$2.DATADOG.LAYER.NODE,
|
|
311
|
-
extensionLayerVersion: CDK$2.DATADOG.LAYER.EXTENSION,
|
|
312
|
-
env: process.env.PROJECT_ENV,
|
|
313
|
-
service: process.env.PROJECT_SERVICE,
|
|
314
|
-
version: process.env.PROJECT_VERSION,
|
|
315
|
-
});
|
|
316
|
-
datadogLambda.addLambdaFunctions([lambdaFunction]);
|
|
317
|
-
return true;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
function constructEnvName(name, opts) {
|
|
321
|
-
const env = opts?.env ?? process.env.PROJECT_ENV ?? "build";
|
|
322
|
-
const key = opts?.key ?? process.env.PROJECT_KEY ?? "project";
|
|
323
|
-
const nonce = opts?.nonce ?? process.env.PROJECT_NONCE ?? "cfe2"; // This default is intentionally short. It is not a special value but should not be changed.
|
|
324
|
-
return `${env}-${key}-${name}-${nonce}`;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function constructStackName(key) {
|
|
328
|
-
if (!key) {
|
|
329
|
-
return `cdk-${process.env.PROJECT_SPONSOR}-${process.env.PROJECT_KEY}-${process.env.PROJECT_ENV}-${process.env.PROJECT_NONCE}`;
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
return `cdk-${process.env.PROJECT_SPONSOR}-${process.env.PROJECT_KEY}-${process.env.PROJECT_ENV}-${process.env.PROJECT_NONCE}-${key}`;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
const CDK$1 = {
|
|
337
|
-
CREATION: {
|
|
338
|
-
CDK: "cdk",
|
|
339
|
-
},
|
|
340
|
-
ROLE: {
|
|
341
|
-
STACK: "stack",
|
|
342
|
-
},
|
|
343
|
-
TAG: {
|
|
344
|
-
BUILD_DATE: "buildDate",
|
|
345
|
-
BUILD_HEX: "buildHex",
|
|
346
|
-
BUILD_TIME: "buildTime",
|
|
347
|
-
COMMIT: "commit",
|
|
348
|
-
CREATION: "creation",
|
|
349
|
-
ENV: "env",
|
|
350
|
-
NONCE: "nonce",
|
|
351
|
-
PROJECT: "project",
|
|
352
|
-
ROLE: "role",
|
|
353
|
-
SERVICE: "service",
|
|
354
|
-
SPONSOR: "sponsor",
|
|
355
|
-
STACK: "stack",
|
|
356
|
-
VERSION: "version",
|
|
357
|
-
},
|
|
358
|
-
};
|
|
359
|
-
function constructTagger(construct, { name } = {}) {
|
|
360
|
-
const stackName = name || constructStackName();
|
|
361
|
-
const version = process.env.npm_package_version || process.env.PROJECT_VERSION || null;
|
|
362
|
-
if (process.env.PROJECT_COMMIT && process.env.PROJECT_COMMIT.length > 8) {
|
|
363
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.BUILD_HEX, process.env.PROJECT_COMMIT.slice(0, 8));
|
|
364
|
-
}
|
|
365
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.BUILD_DATE, new Date().toISOString());
|
|
366
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.BUILD_TIME, Date.now().toString());
|
|
367
|
-
if (process.env.PROJECT_COMMIT)
|
|
368
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.COMMIT, process.env.PROJECT_COMMIT);
|
|
369
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.CREATION, CDK$1.CREATION.CDK);
|
|
370
|
-
if (process.env.PROJECT_ENV)
|
|
371
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.ENV, process.env.PROJECT_ENV);
|
|
372
|
-
if (process.env.PROJECT_NONCE)
|
|
373
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.NONCE, process.env.PROJECT_NONCE);
|
|
374
|
-
if (process.env.PROJECT_KEY)
|
|
375
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.PROJECT, process.env.PROJECT_KEY);
|
|
376
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.ROLE, CDK$1.ROLE.STACK);
|
|
377
|
-
if (process.env.PROJECT_SERVICE)
|
|
378
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.SERVICE, process.env.PROJECT_SERVICE);
|
|
379
|
-
if (process.env.PROJECT_SPONSOR)
|
|
380
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.SPONSOR, process.env.PROJECT_SPONSOR);
|
|
381
|
-
if (stackName)
|
|
382
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.STACK, stackName);
|
|
383
|
-
if (version)
|
|
384
|
-
cdk.Tags.of(construct).add(CDK$1.TAG.VERSION, version);
|
|
385
|
-
return true;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
function envHostname({ component, domain, env, subdomain, } = {}) {
|
|
389
|
-
const resolvedDomain = domain || process.env.CDK_ENV_DOMAIN || process.env.CDK_ENV_HOSTED_ZONE;
|
|
390
|
-
if (!resolvedDomain) {
|
|
391
|
-
throw new errors.ConfigurationError("No hostname `domain` provided. Set CDK_ENV_DOMAIN or CDK_ENV_HOSTED_ZONE to use environment domain");
|
|
392
|
-
}
|
|
393
|
-
const resolvedComponent = component === "@" || component === "" ? undefined : component;
|
|
394
|
-
const resolvedSubdomain = subdomain || process.env.CDK_ENV_SUBDOMAIN;
|
|
395
|
-
const resolvedEnv = env || process.env.PROJECT_ENV;
|
|
396
|
-
const filteredEnv = resolvedEnv === CDK$2.ENV.PRODUCTION ? undefined : resolvedEnv;
|
|
397
|
-
const parts = [
|
|
398
|
-
resolvedComponent,
|
|
399
|
-
resolvedSubdomain,
|
|
400
|
-
filteredEnv,
|
|
401
|
-
resolvedDomain,
|
|
402
|
-
].filter((part) => part);
|
|
403
|
-
return parts.join(".");
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Extends the Datadog IAM role with additional permissions
|
|
408
|
-
*
|
|
409
|
-
* Checks for CDK_ENV_DATADOG_ROLE_ARN environment variable.
|
|
410
|
-
* If found, creates a custom policy with:
|
|
411
|
-
* - budgets:ViewBudget
|
|
412
|
-
* - logs:DescribeLogGroups
|
|
413
|
-
*
|
|
414
|
-
* @param scope - The construct scope
|
|
415
|
-
* @param options - Configuration options
|
|
416
|
-
* @returns The created Policy, or undefined if CDK_ENV_DATADOG_ROLE_ARN is not set
|
|
417
|
-
*/
|
|
418
|
-
function extendDatadogRole(scope, options) {
|
|
419
|
-
const datadogRoleArn = process.env.CDK_ENV_DATADOG_ROLE_ARN;
|
|
420
|
-
// Early return if no Datadog role ARN is configured
|
|
421
|
-
if (!datadogRoleArn) {
|
|
422
|
-
return undefined;
|
|
423
|
-
}
|
|
424
|
-
const { id = "DatadogCustomPolicy", project, service = CDK$2.SERVICE.DATADOG, } = options || {};
|
|
425
|
-
// Lookup the Datadog role
|
|
426
|
-
const datadogRole = awsIam.Role.fromRoleArn(scope, "DatadogRole", datadogRoleArn);
|
|
427
|
-
// Build policy statements
|
|
428
|
-
const statements = [
|
|
429
|
-
// Allow view budget
|
|
430
|
-
new awsIam.PolicyStatement({
|
|
431
|
-
actions: ["budgets:ViewBudget"],
|
|
432
|
-
resources: ["*"],
|
|
433
|
-
}),
|
|
434
|
-
// Allow describe log groups
|
|
435
|
-
new awsIam.PolicyStatement({
|
|
436
|
-
actions: ["logs:DescribeLogGroups"],
|
|
437
|
-
resources: ["*"],
|
|
438
|
-
}),
|
|
439
|
-
];
|
|
440
|
-
// Create the custom policy
|
|
441
|
-
const datadogCustomPolicy = new awsIam.Policy(scope, id, {
|
|
442
|
-
roles: [datadogRole],
|
|
443
|
-
statements,
|
|
444
|
-
});
|
|
445
|
-
// Add tags
|
|
446
|
-
cdk__namespace.Tags.of(datadogCustomPolicy).add(CDK$2.TAG.SERVICE, service);
|
|
447
|
-
cdk__namespace.Tags.of(datadogCustomPolicy).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
448
|
-
cdk__namespace.Tags.of(datadogCustomPolicy).add(CDK$2.TAG.VENDOR, CDK$2.VENDOR.DATADOG);
|
|
449
|
-
if (project) {
|
|
450
|
-
cdk__namespace.Tags.of(datadogCustomPolicy).add(CDK$2.TAG.PROJECT, project);
|
|
451
|
-
}
|
|
452
|
-
return datadogCustomPolicy;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* Check if the current environment matches the given environment
|
|
457
|
-
*/
|
|
458
|
-
function isEnv(env) {
|
|
459
|
-
return process.env.PROJECT_ENV === env;
|
|
460
|
-
}
|
|
461
|
-
/**
|
|
462
|
-
* Check if the current environment is production
|
|
463
|
-
*/
|
|
464
|
-
function isProductionEnv() {
|
|
465
|
-
return isEnv(CDK$2.ENV.PRODUCTION);
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Check if the current environment is sandbox
|
|
469
|
-
*/
|
|
470
|
-
function isSandboxEnv() {
|
|
471
|
-
return isEnv(CDK$2.ENV.SANDBOX);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
// In short the RFC 1035 standard for valid hostnames is:
|
|
475
|
-
// 1. Must be less than 253 characters
|
|
476
|
-
// 2. Must start with a letter
|
|
477
|
-
// 3. Must end with a letter or number
|
|
478
|
-
// 4. Can only contain letters, numbers, and hyphens
|
|
479
|
-
// 5. Last part of the domain must be at least 2 characters
|
|
480
|
-
function validPart$1(part) {
|
|
481
|
-
if (!part.match(/^[a-z]/))
|
|
482
|
-
return false;
|
|
483
|
-
if (!part.match(/[a-z0-9]$/))
|
|
484
|
-
return false;
|
|
485
|
-
return /^[a-zA-Z0-9-]+$/.test(part);
|
|
486
|
-
}
|
|
487
|
-
function isValidHostname$1(hostname) {
|
|
488
|
-
// Check hostname is a string
|
|
489
|
-
if (typeof hostname !== "string")
|
|
490
|
-
return false;
|
|
491
|
-
// Convert hostname to lowercase
|
|
492
|
-
const check = hostname.toString().toLowerCase();
|
|
493
|
-
// Check hostname is less than 253 characters
|
|
494
|
-
if (check.length > 253)
|
|
495
|
-
return false;
|
|
496
|
-
// Split on dots
|
|
497
|
-
const parts = check.split(".");
|
|
498
|
-
// Check each part is validPart
|
|
499
|
-
const validParts = parts.map(validPart$1);
|
|
500
|
-
// Confirm all parts are valid
|
|
501
|
-
if (!validParts.every((part) => part))
|
|
502
|
-
return false;
|
|
503
|
-
// Confirm last part is at least 2 characters
|
|
504
|
-
const lastPart = parts[parts.length - 1];
|
|
505
|
-
if (lastPart.length < 2)
|
|
506
|
-
return false;
|
|
507
|
-
// Confirm last part is all letters
|
|
508
|
-
if (!lastPart.match(/^[a-z]+$/))
|
|
509
|
-
return false;
|
|
510
|
-
// This is a valid hostname
|
|
511
|
-
return true;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
function validPart(part) {
|
|
515
|
-
if (!part.match(/^[a-z]/))
|
|
516
|
-
return false;
|
|
517
|
-
if (!part.match(/[a-z0-9]$/))
|
|
518
|
-
return false;
|
|
519
|
-
return /^[a-zA-Z0-9-]+$/.test(part);
|
|
520
|
-
}
|
|
521
|
-
function isValidSubdomain(subdomain) {
|
|
522
|
-
// Check subdomain is a string
|
|
523
|
-
if (typeof subdomain !== "string")
|
|
524
|
-
return false;
|
|
525
|
-
// Special case for apex
|
|
526
|
-
if (subdomain === CDK$2.HOST.APEX)
|
|
527
|
-
return true;
|
|
528
|
-
// Convert subdomain to lowercase
|
|
529
|
-
const check = subdomain.toString().toLowerCase();
|
|
530
|
-
// Check subdomain is less than 250 characters
|
|
531
|
-
// We use 250 instead of 253 because we need to leave room for the dot top-level domain
|
|
532
|
-
if (check.length > 250)
|
|
533
|
-
return false;
|
|
534
|
-
// Split on dots
|
|
535
|
-
const parts = check.split(".");
|
|
536
|
-
// Check each part is validPart
|
|
537
|
-
const validParts = parts.map(validPart);
|
|
538
|
-
// Confirm all parts are valid
|
|
539
|
-
if (!validParts.every((part) => part))
|
|
540
|
-
return false;
|
|
541
|
-
// Do not care if last part is at least 2 characters
|
|
542
|
-
// Do not care if last part is all letters
|
|
543
|
-
// This is a valid subdomain
|
|
544
|
-
return true;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
function jaypieLambdaEnv(options = {}) {
|
|
548
|
-
const { initialEnvironment = {} } = options;
|
|
549
|
-
// Start with empty environment - we'll only add valid values
|
|
550
|
-
let environment = {};
|
|
551
|
-
// First, add all valid string values from initialEnvironment
|
|
552
|
-
Object.entries(initialEnvironment).forEach(([key, value]) => {
|
|
553
|
-
if (typeof value === "string") {
|
|
554
|
-
environment[key] = value;
|
|
555
|
-
}
|
|
556
|
-
});
|
|
557
|
-
// Default environment values
|
|
558
|
-
const defaultEnvValues = {
|
|
559
|
-
AWS_LAMBDA_NODEJS_DISABLE_CALLBACK_WARNING: "true",
|
|
560
|
-
};
|
|
561
|
-
// Apply default environment values with user overrides
|
|
562
|
-
Object.entries(defaultEnvValues).forEach(([key, defaultValue]) => {
|
|
563
|
-
if (key in initialEnvironment) {
|
|
564
|
-
const userValue = initialEnvironment[key];
|
|
565
|
-
// If user passes a string, it's already added above
|
|
566
|
-
// If user passes non-string falsy value, omit the key
|
|
567
|
-
if (!userValue) {
|
|
568
|
-
delete environment[key];
|
|
569
|
-
}
|
|
570
|
-
// Ignore non-string truthy values (key not added)
|
|
571
|
-
}
|
|
572
|
-
else {
|
|
573
|
-
// No user override, use default value
|
|
574
|
-
environment[key] = defaultValue;
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
// Default environment variables from process.env if present
|
|
578
|
-
const defaultEnvVars = [
|
|
579
|
-
"DATADOG_API_KEY_ARN",
|
|
580
|
-
"LOG_LEVEL",
|
|
581
|
-
"MODULE_LOGGER",
|
|
582
|
-
"MODULE_LOG_LEVEL",
|
|
583
|
-
"PROJECT_CHAOS",
|
|
584
|
-
"PROJECT_COMMIT",
|
|
585
|
-
"PROJECT_ENV",
|
|
586
|
-
"PROJECT_KEY",
|
|
587
|
-
"PROJECT_SECRET",
|
|
588
|
-
"PROJECT_SERVICE",
|
|
589
|
-
"PROJECT_SPONSOR",
|
|
590
|
-
"PROJECT_VERSION",
|
|
591
|
-
];
|
|
592
|
-
// Add default environment variables if they exist in process.env
|
|
593
|
-
defaultEnvVars.forEach((envVar) => {
|
|
594
|
-
if (process.env[envVar] && !environment[envVar]) {
|
|
595
|
-
environment[envVar] = process.env[envVar];
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
return environment;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
function mergeDomain(subDomain, hostedZone) {
|
|
602
|
-
if (!hostedZone) {
|
|
603
|
-
throw new errors.ConfigurationError("hostedZone is required");
|
|
604
|
-
}
|
|
605
|
-
if (!subDomain) {
|
|
606
|
-
// Return hostedZone if subDomain is not passed
|
|
607
|
-
// Pass CDK.HOST.APEX to explicitly indicate apex domain
|
|
608
|
-
return hostedZone;
|
|
609
|
-
}
|
|
610
|
-
if (subDomain === CDK$2.HOST.APEX) {
|
|
611
|
-
return hostedZone;
|
|
612
|
-
}
|
|
613
|
-
return `${subDomain}.${hostedZone}`;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
const DEFAULT_FUNCTION_NAME$1 = "DatadogForwarderFunction";
|
|
617
|
-
// Cache to store resolved functions
|
|
618
|
-
// Using nested structure to support multiple functions per scope with automatic GC
|
|
619
|
-
const functionCache = new WeakMap();
|
|
620
|
-
function resolveDatadogForwarderFunction(scope, options) {
|
|
621
|
-
const { import: importValue, name } = options || {};
|
|
622
|
-
const functionName = name || DEFAULT_FUNCTION_NAME$1;
|
|
623
|
-
const importKey = importValue || CDK$2.IMPORT.DATADOG_LOG_FORWARDER;
|
|
624
|
-
// Create a cache key based on name and import
|
|
625
|
-
const cacheKey = `${functionName}:${importKey}`;
|
|
626
|
-
// Get or create scope cache
|
|
627
|
-
let scopeCache = functionCache.get(scope);
|
|
628
|
-
if (!scopeCache) {
|
|
629
|
-
scopeCache = new Map();
|
|
630
|
-
functionCache.set(scope, scopeCache);
|
|
631
|
-
}
|
|
632
|
-
// Return cached function if it exists
|
|
633
|
-
const cachedFunction = scopeCache.get(cacheKey);
|
|
634
|
-
if (cachedFunction) {
|
|
635
|
-
return cachedFunction;
|
|
636
|
-
}
|
|
637
|
-
// Create and cache the function
|
|
638
|
-
const func = lambda__namespace.Function.fromFunctionArn(scope, functionName, cdk__namespace.Fn.importValue(importKey));
|
|
639
|
-
scopeCache.set(cacheKey, func);
|
|
640
|
-
return func;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
function resolveDatadogLayers(scope, options = {}) {
|
|
644
|
-
const { datadogApiKeyArn, uniqueId } = options;
|
|
645
|
-
let resolvedRegion = cdk.Stack.of(scope).region || "us-east-1";
|
|
646
|
-
// Resolve the Datadog API key ARN from multiple sources
|
|
647
|
-
const resolvedDatadogApiKeyArn = datadogApiKeyArn ||
|
|
648
|
-
process.env.DATADOG_API_KEY_ARN ||
|
|
649
|
-
process.env.CDK_ENV_DATADOG_API_KEY_ARN;
|
|
650
|
-
// Return null if no API key is found
|
|
651
|
-
if (!resolvedDatadogApiKeyArn) {
|
|
652
|
-
return undefined;
|
|
653
|
-
}
|
|
654
|
-
const layerIdSuffix = uniqueId || process.env.PROJECT_NONCE || Date.now().toString();
|
|
655
|
-
// Create Datadog Node.js layer
|
|
656
|
-
const datadogNodeLayer = lambda__namespace.LayerVersion.fromLayerVersionArn(scope, `DatadogNodeLayer-${layerIdSuffix}`, `arn:aws:lambda:${resolvedRegion}:464622532012:layer:Datadog-Node20-x:${CDK$2.DATADOG.LAYER.NODE}`);
|
|
657
|
-
// Create Datadog Extension layer
|
|
658
|
-
const datadogExtensionLayer = lambda__namespace.LayerVersion.fromLayerVersionArn(scope, `DatadogExtensionLayer-${layerIdSuffix}`, `arn:aws:lambda:${resolvedRegion}:464622532012:layer:Datadog-Extension:${CDK$2.DATADOG.LAYER.EXTENSION}`);
|
|
659
|
-
return [datadogNodeLayer, datadogExtensionLayer];
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
const DEFAULT_FUNCTION_NAME = "DatadogForwarderFunction";
|
|
663
|
-
// Cache to store resolved logging destinations
|
|
664
|
-
// Using nested structure to support multiple destinations per scope with automatic GC
|
|
665
|
-
const destinationCache = new WeakMap();
|
|
666
|
-
function resolveDatadogLoggingDestination(scope, options) {
|
|
667
|
-
const { import: importValue, name } = options || {};
|
|
668
|
-
// Create a cache key based on name and import (same as forwarder function)
|
|
669
|
-
const functionName = name || DEFAULT_FUNCTION_NAME;
|
|
670
|
-
const importKey = importValue || CDK$2.IMPORT.DATADOG_LOG_FORWARDER;
|
|
671
|
-
const cacheKey = `${functionName}:${importKey}`;
|
|
672
|
-
// Get or create scope cache
|
|
673
|
-
let scopeCache = destinationCache.get(scope);
|
|
674
|
-
if (!scopeCache) {
|
|
675
|
-
scopeCache = new Map();
|
|
676
|
-
destinationCache.set(scope, scopeCache);
|
|
677
|
-
}
|
|
678
|
-
// Return cached destination if it exists
|
|
679
|
-
const cachedDestination = scopeCache.get(cacheKey);
|
|
680
|
-
if (cachedDestination) {
|
|
681
|
-
return cachedDestination;
|
|
682
|
-
}
|
|
683
|
-
// Resolve the Datadog forwarder function
|
|
684
|
-
const datadogForwarderFunction = resolveDatadogForwarderFunction(scope, options);
|
|
685
|
-
// Create and cache the logging destination
|
|
686
|
-
const datadogLoggingDestination = new logDestinations__namespace.LambdaDestination(datadogForwarderFunction);
|
|
687
|
-
scopeCache.set(cacheKey, datadogLoggingDestination);
|
|
688
|
-
return datadogLoggingDestination;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
function resolveHostedZone(scope, { name = "HostedZone", zone = process.env.CDK_ENV_HOSTED_ZONE, } = {}) {
|
|
692
|
-
if (!zone) {
|
|
693
|
-
throw new errors.ConfigurationError("No `zone` provided. Set CDK_ENV_HOSTED_ZONE to use environment zone");
|
|
694
|
-
}
|
|
695
|
-
if (typeof zone === "string") {
|
|
696
|
-
return route53__namespace.HostedZone.fromLookup(scope, name, {
|
|
697
|
-
domainName: zone,
|
|
698
|
-
});
|
|
699
|
-
}
|
|
700
|
-
return zone;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
const resolveParamsAndSecrets = ({ paramsAndSecrets, options, } = {}) => {
|
|
704
|
-
if (paramsAndSecrets === false) {
|
|
705
|
-
return;
|
|
706
|
-
}
|
|
707
|
-
let resolvedParamsAndSecrets;
|
|
708
|
-
if (paramsAndSecrets instanceof lambda__namespace.ParamsAndSecretsLayerVersion) {
|
|
709
|
-
resolvedParamsAndSecrets = paramsAndSecrets;
|
|
710
|
-
}
|
|
711
|
-
else {
|
|
712
|
-
const resolvedOptions = options || {};
|
|
713
|
-
resolvedParamsAndSecrets = lambda__namespace.ParamsAndSecretsLayerVersion.fromVersion(lambda__namespace.ParamsAndSecretsVersions.V1_0_103, {
|
|
714
|
-
cacheSize: resolvedOptions.cacheSize,
|
|
715
|
-
logLevel: resolvedOptions.logLevel || lambda__namespace.ParamsAndSecretsLogLevel.WARN,
|
|
716
|
-
parameterStoreTtl: resolvedOptions.parameterStoreTtl,
|
|
717
|
-
secretsManagerTtl: resolvedOptions.secretsManagerTtl,
|
|
718
|
-
});
|
|
719
|
-
}
|
|
720
|
-
return resolvedParamsAndSecrets;
|
|
721
|
-
};
|
|
722
|
-
|
|
723
|
-
class JaypieApiGateway extends constructs.Construct {
|
|
724
|
-
constructor(scope, id, props) {
|
|
725
|
-
super(scope, id);
|
|
726
|
-
const { certificate = true, handler, host: propsHost, name, roleTag = CDK$2.ROLE.API, zone: propsZone, } = props;
|
|
727
|
-
// Determine zone from props or environment
|
|
728
|
-
let zone = propsZone;
|
|
729
|
-
if (!zone && process.env.CDK_ENV_API_HOSTED_ZONE) {
|
|
730
|
-
zone = process.env.CDK_ENV_API_HOSTED_ZONE;
|
|
731
|
-
}
|
|
732
|
-
// Determine host from props or environment
|
|
733
|
-
let host = propsHost;
|
|
734
|
-
if (!host) {
|
|
735
|
-
if (process.env.CDK_ENV_API_HOST_NAME) {
|
|
736
|
-
host = process.env.CDK_ENV_API_HOST_NAME;
|
|
737
|
-
}
|
|
738
|
-
else if (process.env.CDK_ENV_API_SUBDOMAIN &&
|
|
739
|
-
process.env.CDK_ENV_API_HOSTED_ZONE) {
|
|
740
|
-
host = mergeDomain(process.env.CDK_ENV_API_SUBDOMAIN, process.env.CDK_ENV_API_HOSTED_ZONE);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
const apiGatewayName = name || constructEnvName("ApiGateway");
|
|
744
|
-
const certificateName = constructEnvName("Certificate");
|
|
745
|
-
const apiDomainName = constructEnvName("ApiDomainName");
|
|
746
|
-
let hostedZone;
|
|
747
|
-
let certificateToUse;
|
|
748
|
-
if (host && zone) {
|
|
749
|
-
hostedZone = resolveHostedZone(this, { zone });
|
|
750
|
-
if (certificate === true) {
|
|
751
|
-
certificateToUse = new acm__namespace.Certificate(this, certificateName, {
|
|
752
|
-
domainName: host,
|
|
753
|
-
validation: acm__namespace.CertificateValidation.fromDns(hostedZone),
|
|
754
|
-
});
|
|
755
|
-
cdk.Tags.of(certificateToUse).add(CDK$2.TAG.ROLE, CDK$2.ROLE.HOSTING);
|
|
756
|
-
}
|
|
757
|
-
else if (typeof certificate === "object") {
|
|
758
|
-
certificateToUse = certificate;
|
|
759
|
-
}
|
|
760
|
-
this._certificate = certificateToUse;
|
|
761
|
-
this._host = host;
|
|
762
|
-
}
|
|
763
|
-
const {
|
|
764
|
-
// * `...lambdaRestApiProps` cannot be moved to the first const destructuring because it needs to exclude the custom properties first.
|
|
765
|
-
// Ignore the variables we already assigned to other properties
|
|
766
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
767
|
-
certificate: _certificate, host: _host, name: _name, roleTag: _roleTag, zone: _zone, handler: _handler,
|
|
768
|
-
/* eslint-enable @typescript-eslint/no-unused-vars */
|
|
769
|
-
...lambdaRestApiProps } = props;
|
|
770
|
-
this._api = new apiGateway__namespace.LambdaRestApi(this, apiGatewayName, {
|
|
771
|
-
handler,
|
|
772
|
-
...lambdaRestApiProps,
|
|
773
|
-
});
|
|
774
|
-
cdk.Tags.of(this._api).add(CDK$2.TAG.ROLE, roleTag);
|
|
775
|
-
if (host && certificateToUse && hostedZone) {
|
|
776
|
-
this._domainName = this._api.addDomainName(apiDomainName, {
|
|
777
|
-
domainName: host,
|
|
778
|
-
certificate: certificateToUse,
|
|
779
|
-
});
|
|
780
|
-
cdk.Tags.of(this._domainName).add(CDK$2.TAG.ROLE, roleTag);
|
|
781
|
-
const record = new route53__namespace.ARecord(this, "AliasRecord", {
|
|
782
|
-
recordName: host,
|
|
783
|
-
target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.ApiGatewayDomain(this._domainName)),
|
|
784
|
-
zone: hostedZone,
|
|
785
|
-
});
|
|
786
|
-
cdk.Tags.of(record).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
get api() {
|
|
790
|
-
return this._api;
|
|
791
|
-
}
|
|
792
|
-
get url() {
|
|
793
|
-
return this._api.url;
|
|
794
|
-
}
|
|
795
|
-
get certificateArn() {
|
|
796
|
-
return this._certificate?.certificateArn;
|
|
797
|
-
}
|
|
798
|
-
get domainName() {
|
|
799
|
-
return this._domainName?.domainName;
|
|
800
|
-
}
|
|
801
|
-
get host() {
|
|
802
|
-
return this._host;
|
|
803
|
-
}
|
|
804
|
-
get restApiId() {
|
|
805
|
-
return this._api.restApiId;
|
|
806
|
-
}
|
|
807
|
-
get restApiName() {
|
|
808
|
-
return this._api.restApiName;
|
|
809
|
-
}
|
|
810
|
-
get restApiRootResourceId() {
|
|
811
|
-
return this._api.restApiRootResourceId;
|
|
812
|
-
}
|
|
813
|
-
get deploymentStage() {
|
|
814
|
-
return this._api.deploymentStage;
|
|
815
|
-
}
|
|
816
|
-
get domainNameAliasDomainName() {
|
|
817
|
-
return this._domainName?.domainNameAliasDomainName;
|
|
818
|
-
}
|
|
819
|
-
get domainNameAliasHostedZoneId() {
|
|
820
|
-
return this._domainName?.domainNameAliasHostedZoneId;
|
|
821
|
-
}
|
|
822
|
-
get root() {
|
|
823
|
-
return this._api.root;
|
|
824
|
-
}
|
|
825
|
-
get env() {
|
|
826
|
-
return {
|
|
827
|
-
account: cdk.Stack.of(this).account,
|
|
828
|
-
region: cdk.Stack.of(this).region,
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
get stack() {
|
|
832
|
-
return this._api.stack;
|
|
833
|
-
}
|
|
834
|
-
arnForExecuteApi(method, path, stage) {
|
|
835
|
-
return this._api.arnForExecuteApi(method, path, stage);
|
|
836
|
-
}
|
|
837
|
-
metric(metricName, props) {
|
|
838
|
-
return this._api.metric(metricName, props);
|
|
839
|
-
}
|
|
840
|
-
metricCacheHitCount(props) {
|
|
841
|
-
return this._api.metricCacheHitCount(props);
|
|
842
|
-
}
|
|
843
|
-
metricCacheMissCount(props) {
|
|
844
|
-
return this._api.metricCacheMissCount(props);
|
|
845
|
-
}
|
|
846
|
-
metricClientError(props) {
|
|
847
|
-
return this._api.metricClientError(props);
|
|
848
|
-
}
|
|
849
|
-
metricCount(props) {
|
|
850
|
-
return this._api.metricCount(props);
|
|
851
|
-
}
|
|
852
|
-
metricIntegrationLatency(props) {
|
|
853
|
-
return this._api.metricIntegrationLatency(props);
|
|
854
|
-
}
|
|
855
|
-
metricLatency(props) {
|
|
856
|
-
return this._api.metricLatency(props);
|
|
857
|
-
}
|
|
858
|
-
metricServerError(props) {
|
|
859
|
-
return this._api.metricServerError(props);
|
|
860
|
-
}
|
|
861
|
-
applyRemovalPolicy(policy) {
|
|
862
|
-
this._api.applyRemovalPolicy(policy);
|
|
863
|
-
}
|
|
864
|
-
get restApiRef() {
|
|
865
|
-
return {
|
|
866
|
-
restApiId: this._api.restApiId,
|
|
867
|
-
};
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
class JaypieStack extends cdk.Stack {
|
|
872
|
-
constructor(scope, id, props = {}) {
|
|
873
|
-
const { key, ...stackProps } = props;
|
|
874
|
-
// Handle stackName
|
|
875
|
-
if (!stackProps.stackName) {
|
|
876
|
-
stackProps.stackName = constructStackName(key);
|
|
877
|
-
}
|
|
878
|
-
// Handle env
|
|
879
|
-
stackProps.env = {
|
|
880
|
-
account: process.env.CDK_DEFAULT_ACCOUNT,
|
|
881
|
-
region: process.env.CDK_DEFAULT_REGION,
|
|
882
|
-
...stackProps.env,
|
|
883
|
-
};
|
|
884
|
-
super(scope, id, stackProps);
|
|
885
|
-
// Apply tags
|
|
886
|
-
constructTagger(this, { name: stackProps.stackName });
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
class JaypieAppStack extends JaypieStack {
|
|
891
|
-
constructor(scope, id, props = {}) {
|
|
892
|
-
const { key = "app", ...stackProps } = props;
|
|
893
|
-
// Handle stackName
|
|
894
|
-
if (!stackProps.stackName) {
|
|
895
|
-
stackProps.stackName = constructStackName(key);
|
|
896
|
-
}
|
|
897
|
-
super(scope, id, { key, ...stackProps });
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
class JaypieLambda extends constructs.Construct {
|
|
902
|
-
constructor(scope, id, props) {
|
|
903
|
-
super(scope, id);
|
|
904
|
-
const { allowAllOutbound, allowPublicSubnet, architecture = lambda__namespace.Architecture.X86_64, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment: initialEnvironment = {}, envSecrets = {}, ephemeralStorageSize, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag = CDK$2.ROLE.PROCESSING, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
|
|
905
|
-
supportsInlineCode: true,
|
|
906
|
-
}), runtimeManagementMode, secrets = [], securityGroups, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, vpc, vpcSubnets, } = props;
|
|
907
|
-
// Get base environment with defaults
|
|
908
|
-
const environment = jaypieLambdaEnv({ initialEnvironment });
|
|
909
|
-
const codeAsset = typeof code === "string" ? lambda__namespace.Code.fromAsset(code) : code;
|
|
910
|
-
// Create a working copy of layers
|
|
911
|
-
const resolvedLayers = [...layers];
|
|
912
|
-
// Process secrets environment variables
|
|
913
|
-
const secretsEnvironment = Object.entries(envSecrets).reduce((acc, [key, secret]) => ({
|
|
914
|
-
...acc,
|
|
915
|
-
[`SECRET_${key}`]: secret.secretName,
|
|
916
|
-
}), {});
|
|
917
|
-
// Process JaypieEnvSecret array
|
|
918
|
-
const jaypieSecretsEnvironment = secrets.reduce((acc, secret) => {
|
|
919
|
-
if (secret.envKey) {
|
|
920
|
-
return {
|
|
921
|
-
...acc,
|
|
922
|
-
[`SECRET_${secret.envKey}`]: secret.secretName,
|
|
923
|
-
};
|
|
924
|
-
}
|
|
925
|
-
return acc;
|
|
926
|
-
}, {});
|
|
927
|
-
// Add ParamsAndSecrets layer if configured
|
|
928
|
-
const resolvedParamsAndSecrets = resolveParamsAndSecrets({
|
|
929
|
-
paramsAndSecrets,
|
|
930
|
-
options: paramsAndSecretsOptions,
|
|
931
|
-
});
|
|
932
|
-
// Create LogGroup if not provided
|
|
933
|
-
const resolvedLogGroup = logGroup ??
|
|
934
|
-
new logs__namespace.LogGroup(this, "LogGroup", {
|
|
935
|
-
retention: logRetention,
|
|
936
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
937
|
-
});
|
|
938
|
-
// Create Lambda Function
|
|
939
|
-
this._lambda = new lambda__namespace.Function(this, "Function", {
|
|
940
|
-
allowAllOutbound,
|
|
941
|
-
allowPublicSubnet,
|
|
942
|
-
architecture,
|
|
943
|
-
code: codeAsset,
|
|
944
|
-
deadLetterQueue,
|
|
945
|
-
deadLetterQueueEnabled,
|
|
946
|
-
deadLetterTopic,
|
|
947
|
-
description,
|
|
948
|
-
environment: {
|
|
949
|
-
...environment,
|
|
950
|
-
...secretsEnvironment,
|
|
951
|
-
...jaypieSecretsEnvironment,
|
|
952
|
-
},
|
|
953
|
-
ephemeralStorageSize,
|
|
954
|
-
filesystem,
|
|
955
|
-
handler,
|
|
956
|
-
initialPolicy,
|
|
957
|
-
layers: resolvedLayers,
|
|
958
|
-
logGroup: resolvedLogGroup,
|
|
959
|
-
maxEventAge,
|
|
960
|
-
memorySize,
|
|
961
|
-
paramsAndSecrets: resolvedParamsAndSecrets,
|
|
962
|
-
profiling,
|
|
963
|
-
profilingGroup,
|
|
964
|
-
reservedConcurrentExecutions,
|
|
965
|
-
retryAttempts,
|
|
966
|
-
runtime,
|
|
967
|
-
runtimeManagementMode,
|
|
968
|
-
securityGroups,
|
|
969
|
-
timeout: typeof timeout === "number" ? cdk.Duration.seconds(timeout) : timeout,
|
|
970
|
-
tracing,
|
|
971
|
-
vpc,
|
|
972
|
-
vpcSubnets,
|
|
973
|
-
// Enable auto-publishing of versions when using provisioned concurrency
|
|
974
|
-
currentVersionOptions: provisionedConcurrentExecutions !== undefined
|
|
975
|
-
? {
|
|
976
|
-
removalPolicy: cdk.RemovalPolicy.RETAIN,
|
|
977
|
-
description: "Auto-published version for provisioned concurrency",
|
|
978
|
-
// Don't set provisioned concurrency here - it will be set on the alias
|
|
979
|
-
}
|
|
980
|
-
: undefined,
|
|
981
|
-
});
|
|
982
|
-
addDatadogLayers(this._lambda, { datadogApiKeyArn });
|
|
983
|
-
// Grant secret read permissions
|
|
984
|
-
Object.values(envSecrets).forEach((secret) => {
|
|
985
|
-
secret.grantRead(this._lambda);
|
|
986
|
-
});
|
|
987
|
-
// Grant read permissions for JaypieEnvSecrets
|
|
988
|
-
secrets.forEach((secret) => {
|
|
989
|
-
secret.grantRead(this._lambda);
|
|
990
|
-
});
|
|
991
|
-
// Configure provisioned concurrency if specified
|
|
992
|
-
if (provisionedConcurrentExecutions !== undefined) {
|
|
993
|
-
// Use currentVersion which is auto-published with proper configuration
|
|
994
|
-
const version = this._lambda.currentVersion;
|
|
995
|
-
// Create alias for provisioned concurrency
|
|
996
|
-
this._provisioned = new lambda__namespace.Alias(this, "ProvisionedAlias", {
|
|
997
|
-
aliasName: "provisioned",
|
|
998
|
-
version,
|
|
999
|
-
provisionedConcurrentExecutions,
|
|
1000
|
-
});
|
|
1001
|
-
// Add explicit dependencies to ensure proper creation order
|
|
1002
|
-
this._provisioned.node.addDependency(version);
|
|
1003
|
-
}
|
|
1004
|
-
if (roleTag) {
|
|
1005
|
-
cdk.Tags.of(this._lambda).add(CDK$2.TAG.ROLE, roleTag);
|
|
1006
|
-
}
|
|
1007
|
-
if (vendorTag) {
|
|
1008
|
-
cdk.Tags.of(this._lambda).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1009
|
-
}
|
|
1010
|
-
// Assign _reference based on provisioned state
|
|
1011
|
-
this._reference =
|
|
1012
|
-
this._provisioned !== undefined ? this._provisioned : this._lambda;
|
|
1013
|
-
}
|
|
1014
|
-
// Public accessors
|
|
1015
|
-
get lambda() {
|
|
1016
|
-
return this._lambda;
|
|
1017
|
-
}
|
|
1018
|
-
get provisioned() {
|
|
1019
|
-
return this._provisioned;
|
|
1020
|
-
}
|
|
1021
|
-
get reference() {
|
|
1022
|
-
return this._reference;
|
|
1023
|
-
}
|
|
1024
|
-
// IFunction implementation
|
|
1025
|
-
get functionArn() {
|
|
1026
|
-
return this._reference.functionArn;
|
|
1027
|
-
}
|
|
1028
|
-
get functionName() {
|
|
1029
|
-
return this._reference.functionName;
|
|
1030
|
-
}
|
|
1031
|
-
get grantPrincipal() {
|
|
1032
|
-
return this._reference.grantPrincipal;
|
|
1033
|
-
}
|
|
1034
|
-
get role() {
|
|
1035
|
-
return this._reference.role;
|
|
1036
|
-
}
|
|
1037
|
-
get architecture() {
|
|
1038
|
-
return this._reference.architecture;
|
|
1039
|
-
}
|
|
1040
|
-
get connections() {
|
|
1041
|
-
return this._reference.connections;
|
|
1042
|
-
}
|
|
1043
|
-
get isBoundToVpc() {
|
|
1044
|
-
return this._reference.isBoundToVpc;
|
|
1045
|
-
}
|
|
1046
|
-
get latestVersion() {
|
|
1047
|
-
return this._reference.latestVersion;
|
|
1048
|
-
}
|
|
1049
|
-
get permissionsNode() {
|
|
1050
|
-
return this._reference.permissionsNode;
|
|
1051
|
-
}
|
|
1052
|
-
get resourceArnsForGrantInvoke() {
|
|
1053
|
-
return this._reference.resourceArnsForGrantInvoke;
|
|
1054
|
-
}
|
|
1055
|
-
get functionRef() {
|
|
1056
|
-
return {
|
|
1057
|
-
functionArn: this._reference.functionArn,
|
|
1058
|
-
functionName: this._reference.functionName,
|
|
1059
|
-
};
|
|
1060
|
-
}
|
|
1061
|
-
addEventSource(source) {
|
|
1062
|
-
this._reference.addEventSource(source);
|
|
1063
|
-
}
|
|
1064
|
-
addEventSourceMapping(id, options) {
|
|
1065
|
-
return this._reference.addEventSourceMapping(id, options);
|
|
1066
|
-
}
|
|
1067
|
-
addFunctionUrl(options) {
|
|
1068
|
-
return this._reference.addFunctionUrl(options);
|
|
1069
|
-
}
|
|
1070
|
-
addPermission(id, permission) {
|
|
1071
|
-
this._reference.addPermission(id, permission);
|
|
1072
|
-
}
|
|
1073
|
-
addToRolePolicy(statement) {
|
|
1074
|
-
this._reference.addToRolePolicy(statement);
|
|
1075
|
-
}
|
|
1076
|
-
configureAsyncInvoke(options) {
|
|
1077
|
-
this._reference.configureAsyncInvoke(options);
|
|
1078
|
-
}
|
|
1079
|
-
grantInvoke(grantee) {
|
|
1080
|
-
return this._reference.grantInvoke(grantee);
|
|
1081
|
-
}
|
|
1082
|
-
grantInvokeCompositePrincipal(compositePrincipal) {
|
|
1083
|
-
return this._reference.grantInvokeCompositePrincipal(compositePrincipal);
|
|
1084
|
-
}
|
|
1085
|
-
grantInvokeUrl(grantee) {
|
|
1086
|
-
return this._reference.grantInvokeUrl(grantee);
|
|
1087
|
-
}
|
|
1088
|
-
grantInvokeLatestVersion(grantee) {
|
|
1089
|
-
return this._reference.grantInvokeLatestVersion(grantee);
|
|
1090
|
-
}
|
|
1091
|
-
grantInvokeVersion(grantee, version) {
|
|
1092
|
-
return this._reference.grantInvokeVersion(grantee, version);
|
|
1093
|
-
}
|
|
1094
|
-
metric(metricName, props) {
|
|
1095
|
-
return this._reference.metric(metricName, props);
|
|
1096
|
-
}
|
|
1097
|
-
metricDuration(props) {
|
|
1098
|
-
return this._reference.metricDuration(props);
|
|
1099
|
-
}
|
|
1100
|
-
metricErrors(props) {
|
|
1101
|
-
return this._reference.metricErrors(props);
|
|
1102
|
-
}
|
|
1103
|
-
metricInvocations(props) {
|
|
1104
|
-
return this._reference.metricInvocations(props);
|
|
1105
|
-
}
|
|
1106
|
-
metricThrottles(props) {
|
|
1107
|
-
return this._reference.metricThrottles(props);
|
|
1108
|
-
}
|
|
1109
|
-
get env() {
|
|
1110
|
-
return {
|
|
1111
|
-
account: cdk.Stack.of(this).account,
|
|
1112
|
-
region: cdk.Stack.of(this).region,
|
|
1113
|
-
};
|
|
1114
|
-
}
|
|
1115
|
-
get stack() {
|
|
1116
|
-
return this._reference.stack;
|
|
1117
|
-
}
|
|
1118
|
-
applyRemovalPolicy(policy) {
|
|
1119
|
-
this._reference.applyRemovalPolicy(policy);
|
|
1120
|
-
}
|
|
1121
|
-
addEnvironment(key, value) {
|
|
1122
|
-
this._lambda.addEnvironment(key, value);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
class JaypieQueuedLambda extends constructs.Construct {
|
|
1127
|
-
constructor(scope, id, props) {
|
|
1128
|
-
super(scope, id);
|
|
1129
|
-
const { allowAllOutbound, allowPublicSubnet, architecture, batchSize = 1, code, datadogApiKeyArn, deadLetterQueue, deadLetterQueueEnabled, deadLetterTopic, description, environment = {}, envSecrets = {}, ephemeralStorageSize, fifo = true, filesystem, handler = "index.handler", initialPolicy, layers = [], logGroup, logRetention = CDK$2.LAMBDA.LOG_RETENTION, maxEventAge, memorySize = CDK$2.LAMBDA.MEMORY_SIZE, paramsAndSecrets, paramsAndSecretsOptions, profiling, profilingGroup, provisionedConcurrentExecutions, reservedConcurrentExecutions, retryAttempts, roleTag, runtime = new lambda__namespace.Runtime("nodejs24.x", lambda__namespace.RuntimeFamily.NODEJS, {
|
|
1130
|
-
supportsInlineCode: true,
|
|
1131
|
-
}), runtimeManagementMode, secrets = [], securityGroups, timeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), tracing, vendorTag, visibilityTimeout = cdk.Duration.seconds(CDK$2.DURATION.LAMBDA_WORKER), vpc, vpcSubnets, } = props;
|
|
1132
|
-
// Create SQS Queue
|
|
1133
|
-
this._queue = new sqs__namespace.Queue(this, "Queue", {
|
|
1134
|
-
fifo,
|
|
1135
|
-
visibilityTimeout: typeof visibilityTimeout === "number"
|
|
1136
|
-
? cdk.Duration.seconds(visibilityTimeout)
|
|
1137
|
-
: visibilityTimeout,
|
|
1138
|
-
});
|
|
1139
|
-
if (roleTag) {
|
|
1140
|
-
cdk.Tags.of(this._queue).add(CDK$2.TAG.ROLE, roleTag);
|
|
1141
|
-
}
|
|
1142
|
-
if (vendorTag) {
|
|
1143
|
-
cdk.Tags.of(this._queue).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1144
|
-
}
|
|
1145
|
-
// Create Lambda with JaypieLambda
|
|
1146
|
-
this._lambdaConstruct = new JaypieLambda(this, "Function", {
|
|
1147
|
-
allowAllOutbound,
|
|
1148
|
-
allowPublicSubnet,
|
|
1149
|
-
architecture,
|
|
1150
|
-
code,
|
|
1151
|
-
datadogApiKeyArn,
|
|
1152
|
-
deadLetterQueue,
|
|
1153
|
-
deadLetterQueueEnabled,
|
|
1154
|
-
deadLetterTopic,
|
|
1155
|
-
description,
|
|
1156
|
-
environment: {
|
|
1157
|
-
...environment,
|
|
1158
|
-
CDK_ENV_QUEUE_URL: this._queue.queueUrl,
|
|
1159
|
-
},
|
|
1160
|
-
envSecrets,
|
|
1161
|
-
ephemeralStorageSize,
|
|
1162
|
-
filesystem,
|
|
1163
|
-
handler,
|
|
1164
|
-
initialPolicy,
|
|
1165
|
-
layers,
|
|
1166
|
-
logGroup,
|
|
1167
|
-
logRetention,
|
|
1168
|
-
maxEventAge,
|
|
1169
|
-
memorySize,
|
|
1170
|
-
paramsAndSecrets,
|
|
1171
|
-
paramsAndSecretsOptions,
|
|
1172
|
-
profiling,
|
|
1173
|
-
profilingGroup,
|
|
1174
|
-
provisionedConcurrentExecutions,
|
|
1175
|
-
reservedConcurrentExecutions,
|
|
1176
|
-
retryAttempts,
|
|
1177
|
-
roleTag,
|
|
1178
|
-
runtime,
|
|
1179
|
-
runtimeManagementMode,
|
|
1180
|
-
secrets,
|
|
1181
|
-
securityGroups,
|
|
1182
|
-
timeout,
|
|
1183
|
-
tracing,
|
|
1184
|
-
vendorTag,
|
|
1185
|
-
vpc,
|
|
1186
|
-
vpcSubnets,
|
|
1187
|
-
});
|
|
1188
|
-
// Set up queue and lambda integration
|
|
1189
|
-
this._queue.grantConsumeMessages(this._lambdaConstruct);
|
|
1190
|
-
this._queue.grantSendMessages(this._lambdaConstruct);
|
|
1191
|
-
this._lambdaConstruct.addEventSource(new lambdaEventSources__namespace.SqsEventSource(this._queue, {
|
|
1192
|
-
batchSize,
|
|
1193
|
-
}));
|
|
1194
|
-
}
|
|
1195
|
-
// Public accessors
|
|
1196
|
-
get queue() {
|
|
1197
|
-
return this._queue;
|
|
1198
|
-
}
|
|
1199
|
-
get lambda() {
|
|
1200
|
-
return this._lambdaConstruct.lambda;
|
|
1201
|
-
}
|
|
1202
|
-
// IFunction implementation
|
|
1203
|
-
get functionArn() {
|
|
1204
|
-
return this._lambdaConstruct.functionArn;
|
|
1205
|
-
}
|
|
1206
|
-
get functionName() {
|
|
1207
|
-
return this._lambdaConstruct.functionName;
|
|
1208
|
-
}
|
|
1209
|
-
get grantPrincipal() {
|
|
1210
|
-
return this._lambdaConstruct.grantPrincipal;
|
|
1211
|
-
}
|
|
1212
|
-
get role() {
|
|
1213
|
-
return this._lambdaConstruct.role;
|
|
1214
|
-
}
|
|
1215
|
-
get architecture() {
|
|
1216
|
-
return this._lambdaConstruct.architecture;
|
|
1217
|
-
}
|
|
1218
|
-
get connections() {
|
|
1219
|
-
return this._lambdaConstruct.connections;
|
|
1220
|
-
}
|
|
1221
|
-
get isBoundToVpc() {
|
|
1222
|
-
return this._lambdaConstruct.isBoundToVpc;
|
|
1223
|
-
}
|
|
1224
|
-
get latestVersion() {
|
|
1225
|
-
return this._lambdaConstruct.latestVersion;
|
|
1226
|
-
}
|
|
1227
|
-
get permissionsNode() {
|
|
1228
|
-
return this._lambdaConstruct.permissionsNode;
|
|
1229
|
-
}
|
|
1230
|
-
get resourceArnsForGrantInvoke() {
|
|
1231
|
-
return this._lambdaConstruct.resourceArnsForGrantInvoke;
|
|
1232
|
-
}
|
|
1233
|
-
get functionRef() {
|
|
1234
|
-
return this._lambdaConstruct.functionRef;
|
|
1235
|
-
}
|
|
1236
|
-
addEventSource(source) {
|
|
1237
|
-
this._lambdaConstruct.addEventSource(source);
|
|
1238
|
-
}
|
|
1239
|
-
addEventSourceMapping(id, options) {
|
|
1240
|
-
return this._lambdaConstruct.addEventSourceMapping(id, options);
|
|
1241
|
-
}
|
|
1242
|
-
addFunctionUrl(options) {
|
|
1243
|
-
return this._lambdaConstruct.addFunctionUrl(options);
|
|
1244
|
-
}
|
|
1245
|
-
addPermission(id, permission) {
|
|
1246
|
-
this._lambdaConstruct.addPermission(id, permission);
|
|
1247
|
-
}
|
|
1248
|
-
addToRolePolicy(statement) {
|
|
1249
|
-
this._lambdaConstruct.addToRolePolicy(statement);
|
|
1250
|
-
}
|
|
1251
|
-
configureAsyncInvoke(options) {
|
|
1252
|
-
this._lambdaConstruct.configureAsyncInvoke(options);
|
|
1253
|
-
}
|
|
1254
|
-
grantInvoke(grantee) {
|
|
1255
|
-
return this._lambdaConstruct.grantInvoke(grantee);
|
|
1256
|
-
}
|
|
1257
|
-
grantInvokeCompositePrincipal(compositePrincipal) {
|
|
1258
|
-
return this._lambdaConstruct.grantInvokeCompositePrincipal(compositePrincipal);
|
|
1259
|
-
}
|
|
1260
|
-
grantInvokeUrl(grantee) {
|
|
1261
|
-
return this._lambdaConstruct.grantInvokeUrl(grantee);
|
|
1262
|
-
}
|
|
1263
|
-
metric(metricName, props) {
|
|
1264
|
-
return this._lambdaConstruct.metric(metricName, props);
|
|
1265
|
-
}
|
|
1266
|
-
metricDuration(props) {
|
|
1267
|
-
return this._lambdaConstruct.metricDuration(props);
|
|
1268
|
-
}
|
|
1269
|
-
metricErrors(props) {
|
|
1270
|
-
return this._lambdaConstruct.metricErrors(props);
|
|
1271
|
-
}
|
|
1272
|
-
metricInvocations(props) {
|
|
1273
|
-
return this._lambdaConstruct.metricInvocations(props);
|
|
1274
|
-
}
|
|
1275
|
-
metricThrottles(props) {
|
|
1276
|
-
return this._lambdaConstruct.metricThrottles(props);
|
|
1277
|
-
}
|
|
1278
|
-
// Additional IFunction implementation
|
|
1279
|
-
grantInvokeLatestVersion(grantee) {
|
|
1280
|
-
return this._lambdaConstruct.grantInvokeLatestVersion(grantee);
|
|
1281
|
-
}
|
|
1282
|
-
grantInvokeVersion(grantee, version) {
|
|
1283
|
-
return this._lambdaConstruct.grantInvokeVersion(grantee, version);
|
|
1284
|
-
}
|
|
1285
|
-
get env() {
|
|
1286
|
-
return {
|
|
1287
|
-
account: cdk.Stack.of(this).account,
|
|
1288
|
-
region: cdk.Stack.of(this).region,
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
get stack() {
|
|
1292
|
-
return cdk.Stack.of(this);
|
|
1293
|
-
}
|
|
1294
|
-
applyRemovalPolicy(policy) {
|
|
1295
|
-
this._lambdaConstruct.applyRemovalPolicy(policy);
|
|
1296
|
-
this._queue.applyRemovalPolicy(policy);
|
|
1297
|
-
}
|
|
1298
|
-
// IQueue implementation
|
|
1299
|
-
get queueRef() {
|
|
1300
|
-
return {
|
|
1301
|
-
queueUrl: this._queue.queueUrl,
|
|
1302
|
-
queueArn: this._queue.queueArn,
|
|
1303
|
-
};
|
|
1304
|
-
}
|
|
1305
|
-
get fifo() {
|
|
1306
|
-
return this._queue.fifo;
|
|
1307
|
-
}
|
|
1308
|
-
get queueArn() {
|
|
1309
|
-
return this._queue.queueArn;
|
|
1310
|
-
}
|
|
1311
|
-
get queueName() {
|
|
1312
|
-
return this._queue.queueName;
|
|
1313
|
-
}
|
|
1314
|
-
get queueUrl() {
|
|
1315
|
-
return this._queue.queueUrl;
|
|
1316
|
-
}
|
|
1317
|
-
get encryptionMasterKey() {
|
|
1318
|
-
return this._queue.encryptionMasterKey;
|
|
1319
|
-
}
|
|
1320
|
-
addToResourcePolicy(statement) {
|
|
1321
|
-
return this._queue.addToResourcePolicy(statement);
|
|
1322
|
-
}
|
|
1323
|
-
grant(grantee, ...actions) {
|
|
1324
|
-
return this._queue.grant(grantee, ...actions);
|
|
1325
|
-
}
|
|
1326
|
-
grantConsumeMessages(grantee) {
|
|
1327
|
-
return this._queue.grantConsumeMessages(grantee);
|
|
1328
|
-
}
|
|
1329
|
-
grantPurge(grantee) {
|
|
1330
|
-
return this._queue.grantPurge(grantee);
|
|
1331
|
-
}
|
|
1332
|
-
grantSendMessages(grantee) {
|
|
1333
|
-
return this._queue.grantSendMessages(grantee);
|
|
1334
|
-
}
|
|
1335
|
-
// Queue metrics
|
|
1336
|
-
metricApproximateAgeOfOldestMessage(props) {
|
|
1337
|
-
return this._queue.metricApproximateAgeOfOldestMessage(props);
|
|
1338
|
-
}
|
|
1339
|
-
metricApproximateNumberOfMessagesDelayed(props) {
|
|
1340
|
-
return this._queue.metricApproximateNumberOfMessagesDelayed(props);
|
|
1341
|
-
}
|
|
1342
|
-
metricApproximateNumberOfMessagesNotVisible(props) {
|
|
1343
|
-
return this._queue.metricApproximateNumberOfMessagesNotVisible(props);
|
|
1344
|
-
}
|
|
1345
|
-
metricApproximateNumberOfMessagesVisible(props) {
|
|
1346
|
-
return this._queue.metricApproximateNumberOfMessagesVisible(props);
|
|
1347
|
-
}
|
|
1348
|
-
metricNumberOfEmptyReceives(props) {
|
|
1349
|
-
return this._queue.metricNumberOfEmptyReceives(props);
|
|
1350
|
-
}
|
|
1351
|
-
metricNumberOfMessagesDeleted(props) {
|
|
1352
|
-
return this._queue.metricNumberOfMessagesDeleted(props);
|
|
1353
|
-
}
|
|
1354
|
-
metricNumberOfMessagesReceived(props) {
|
|
1355
|
-
return this._queue.metricNumberOfMessagesReceived(props);
|
|
1356
|
-
}
|
|
1357
|
-
metricNumberOfMessagesSent(props) {
|
|
1358
|
-
return this._queue.metricNumberOfMessagesSent(props);
|
|
1359
|
-
}
|
|
1360
|
-
metricSentMessageSize(props) {
|
|
1361
|
-
return this._queue.metricSentMessageSize(props);
|
|
1362
|
-
}
|
|
1363
|
-
addEnvironment(key, value) {
|
|
1364
|
-
this._lambdaConstruct.addEnvironment(key, value);
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
|
|
1368
|
-
class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
1369
|
-
constructor(scope, id, props) {
|
|
1370
|
-
props.fifo = false; // S3 event notifications are not supported for FIFO queues
|
|
1371
|
-
super(scope, id, props);
|
|
1372
|
-
const { bucketName, roleTag, vendorTag, bucketOptions = {} } = props;
|
|
1373
|
-
// Create S3 Bucket
|
|
1374
|
-
this._bucket = new s3__namespace.Bucket(this, "Bucket", {
|
|
1375
|
-
bucketName: bucketOptions.bucketName || bucketName,
|
|
1376
|
-
removalPolicy: bucketOptions.removalPolicy || cdk.RemovalPolicy.RETAIN,
|
|
1377
|
-
...bucketOptions,
|
|
1378
|
-
});
|
|
1379
|
-
// Add tags to bucket
|
|
1380
|
-
if (roleTag) {
|
|
1381
|
-
cdk.Tags.of(this._bucket).add(CDK$2.TAG.ROLE, roleTag);
|
|
1382
|
-
}
|
|
1383
|
-
if (vendorTag) {
|
|
1384
|
-
cdk.Tags.of(this._bucket).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1385
|
-
}
|
|
1386
|
-
// Add an event notification from the bucket to the queue
|
|
1387
|
-
this._bucket.addEventNotification(s3__namespace.EventType.OBJECT_CREATED, new s3n__namespace.SqsDestination(this.queue));
|
|
1388
|
-
// Grant the lambda access to the bucket
|
|
1389
|
-
this._bucket.grantReadWrite(this);
|
|
1390
|
-
// Add environment variable for bucket name
|
|
1391
|
-
this.lambda.addEnvironment("CDK_ENV_BUCKET_NAME", this._bucket.bucketName);
|
|
1392
|
-
}
|
|
1393
|
-
// Public accessors
|
|
1394
|
-
get bucket() {
|
|
1395
|
-
return this._bucket;
|
|
1396
|
-
}
|
|
1397
|
-
// IBucket implementation
|
|
1398
|
-
get bucketArn() {
|
|
1399
|
-
return this._bucket.bucketArn;
|
|
1400
|
-
}
|
|
1401
|
-
get bucketDomainName() {
|
|
1402
|
-
return this._bucket.bucketDomainName;
|
|
1403
|
-
}
|
|
1404
|
-
get bucketDualStackDomainName() {
|
|
1405
|
-
return this._bucket.bucketDualStackDomainName;
|
|
1406
|
-
}
|
|
1407
|
-
get bucketName() {
|
|
1408
|
-
return this._bucket.bucketName;
|
|
1409
|
-
}
|
|
1410
|
-
get bucketRegionalDomainName() {
|
|
1411
|
-
return this._bucket.bucketRegionalDomainName;
|
|
1412
|
-
}
|
|
1413
|
-
get bucketWebsiteDomainName() {
|
|
1414
|
-
return this._bucket.bucketWebsiteDomainName;
|
|
1415
|
-
}
|
|
1416
|
-
get bucketWebsiteUrl() {
|
|
1417
|
-
return this._bucket.bucketWebsiteUrl;
|
|
1418
|
-
}
|
|
1419
|
-
get encryptionKey() {
|
|
1420
|
-
return this._bucket.encryptionKey;
|
|
1421
|
-
}
|
|
1422
|
-
get isWebsite() {
|
|
1423
|
-
return this._bucket.isWebsite || false;
|
|
1424
|
-
}
|
|
1425
|
-
get policy() {
|
|
1426
|
-
return this._bucket.policy;
|
|
1427
|
-
}
|
|
1428
|
-
addEventNotification(event, dest, ...filters) {
|
|
1429
|
-
this._bucket.addEventNotification(event, dest, ...filters);
|
|
1430
|
-
}
|
|
1431
|
-
addObjectCreatedNotification(dest, ...filters) {
|
|
1432
|
-
this._bucket.addObjectCreatedNotification(dest, ...filters);
|
|
1433
|
-
}
|
|
1434
|
-
addObjectRemovedNotification(dest, ...filters) {
|
|
1435
|
-
this._bucket.addObjectRemovedNotification(dest, ...filters);
|
|
1436
|
-
}
|
|
1437
|
-
addToResourcePolicy(permission) {
|
|
1438
|
-
return this._bucket.addToResourcePolicy(permission);
|
|
1439
|
-
}
|
|
1440
|
-
arnForObjects(objectKeyPattern) {
|
|
1441
|
-
return this._bucket.arnForObjects(objectKeyPattern);
|
|
1442
|
-
}
|
|
1443
|
-
enableEventBridgeNotification() {
|
|
1444
|
-
this._bucket.enableEventBridgeNotification();
|
|
1445
|
-
}
|
|
1446
|
-
grantDelete(grantee, objectsKeyPattern) {
|
|
1447
|
-
return this._bucket.grantDelete(grantee, objectsKeyPattern);
|
|
1448
|
-
}
|
|
1449
|
-
grantPublicAccess(keyPrefix, ...allowedActions) {
|
|
1450
|
-
return this._bucket.grantPublicAccess(keyPrefix, ...allowedActions);
|
|
1451
|
-
}
|
|
1452
|
-
grantPut(grantee, objectsKeyPattern) {
|
|
1453
|
-
return this._bucket.grantPut(grantee, objectsKeyPattern);
|
|
1454
|
-
}
|
|
1455
|
-
grantPutAcl(grantee, objectsKeyPattern) {
|
|
1456
|
-
return this._bucket.grantPutAcl(grantee, objectsKeyPattern);
|
|
1457
|
-
}
|
|
1458
|
-
grantRead(grantee, objectsKeyPattern) {
|
|
1459
|
-
return this._bucket.grantRead(grantee, objectsKeyPattern);
|
|
1460
|
-
}
|
|
1461
|
-
grantReadWrite(grantee, objectsKeyPattern) {
|
|
1462
|
-
return this._bucket.grantReadWrite(grantee, objectsKeyPattern);
|
|
1463
|
-
}
|
|
1464
|
-
grantWrite(grantee, objectsKeyPattern) {
|
|
1465
|
-
return this._bucket.grantWrite(grantee, objectsKeyPattern);
|
|
1466
|
-
}
|
|
1467
|
-
onCloudTrailEvent(id, options) {
|
|
1468
|
-
return this._bucket.onCloudTrailEvent(id, options);
|
|
1469
|
-
}
|
|
1470
|
-
onCloudTrailPutObject(id, options) {
|
|
1471
|
-
return this._bucket.onCloudTrailPutObject(id, options);
|
|
1472
|
-
}
|
|
1473
|
-
onCloudTrailWriteObject(id, options) {
|
|
1474
|
-
return this._bucket.onCloudTrailWriteObject(id, options);
|
|
1475
|
-
}
|
|
1476
|
-
s3UrlForObject(key) {
|
|
1477
|
-
return this._bucket.s3UrlForObject(key);
|
|
1478
|
-
}
|
|
1479
|
-
transferAccelerationUrlForObject(key, options) {
|
|
1480
|
-
return this._bucket.transferAccelerationUrlForObject(key, options);
|
|
1481
|
-
}
|
|
1482
|
-
urlForObject(key) {
|
|
1483
|
-
return this._bucket.urlForObject(key);
|
|
1484
|
-
}
|
|
1485
|
-
virtualHostedUrlForObject(key, options) {
|
|
1486
|
-
return this._bucket.virtualHostedUrlForObject(key, options);
|
|
1487
|
-
}
|
|
1488
|
-
grantReplicationPermission(identity, props) {
|
|
1489
|
-
return this._bucket.grantReplicationPermission(identity, props);
|
|
1490
|
-
}
|
|
1491
|
-
addReplicationPolicy(policy) {
|
|
1492
|
-
this._bucket.addReplicationPolicy(policy);
|
|
1493
|
-
}
|
|
1494
|
-
get bucketRef() {
|
|
1495
|
-
return {
|
|
1496
|
-
bucketArn: this._bucket.bucketArn,
|
|
1497
|
-
bucketName: this._bucket.bucketName,
|
|
1498
|
-
};
|
|
1499
|
-
}
|
|
1500
|
-
// Override applyRemovalPolicy to apply to all resources
|
|
1501
|
-
applyRemovalPolicy(policy) {
|
|
1502
|
-
super.applyRemovalPolicy(policy);
|
|
1503
|
-
this._bucket.applyRemovalPolicy(policy);
|
|
1504
|
-
}
|
|
1505
|
-
}
|
|
1506
|
-
|
|
1507
|
-
class JaypieDatadogBucket extends constructs.Construct {
|
|
1508
|
-
/**
|
|
1509
|
-
* Create a new S3 bucket for Datadog log archiving with automatic IAM permissions
|
|
1510
|
-
*/
|
|
1511
|
-
constructor(scope, idOrProps, propsOrUndefined) {
|
|
1512
|
-
// Handle overloaded constructor signatures
|
|
1513
|
-
let props;
|
|
1514
|
-
let id;
|
|
1515
|
-
if (typeof idOrProps === "string") {
|
|
1516
|
-
// First param is ID, second is props
|
|
1517
|
-
props = propsOrUndefined || {};
|
|
1518
|
-
id = idOrProps;
|
|
1519
|
-
}
|
|
1520
|
-
else {
|
|
1521
|
-
// First param is props
|
|
1522
|
-
props = idOrProps || {};
|
|
1523
|
-
id = props.id || "JaypieDatadogBucket";
|
|
1524
|
-
}
|
|
1525
|
-
super(scope, id);
|
|
1526
|
-
// Extract Jaypie-specific options
|
|
1527
|
-
const { bucketId = "DatadogArchiveBucket", bucketScope, grantDatadogAccess = true, project, service = CDK$2.SERVICE.DATADOG, ...bucketProps } = props;
|
|
1528
|
-
// Create the bucket using bucketScope (defaults to this) and bucketId
|
|
1529
|
-
const effectiveBucketScope = bucketScope || this;
|
|
1530
|
-
this.bucket = new s3.Bucket(effectiveBucketScope, bucketId, bucketProps);
|
|
1531
|
-
// Add tags to bucket
|
|
1532
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.SERVICE, service);
|
|
1533
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
1534
|
-
if (project) {
|
|
1535
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.PROJECT, project);
|
|
1536
|
-
}
|
|
1537
|
-
// Grant Datadog role access to bucket if enabled
|
|
1538
|
-
if (grantDatadogAccess) {
|
|
1539
|
-
this.policy = this.grantDatadogRoleBucketAccess({ project, service });
|
|
1540
|
-
}
|
|
1541
|
-
}
|
|
1542
|
-
/**
|
|
1543
|
-
* Grants the Datadog IAM role access to this bucket
|
|
1544
|
-
*
|
|
1545
|
-
* Checks for CDK_ENV_DATADOG_ROLE_ARN environment variable.
|
|
1546
|
-
* If found, creates a custom policy with:
|
|
1547
|
-
* - s3:ListBucket on bucket
|
|
1548
|
-
* - s3:GetObject and s3:PutObject on bucket/*
|
|
1549
|
-
*
|
|
1550
|
-
* @param options - Configuration options
|
|
1551
|
-
* @returns The created Policy, or undefined if CDK_ENV_DATADOG_ROLE_ARN is not set
|
|
1552
|
-
*/
|
|
1553
|
-
grantDatadogRoleBucketAccess(options) {
|
|
1554
|
-
const datadogRoleArn = process.env.CDK_ENV_DATADOG_ROLE_ARN;
|
|
1555
|
-
// Early return if no Datadog role ARN is configured
|
|
1556
|
-
if (!datadogRoleArn) {
|
|
1557
|
-
return undefined;
|
|
1558
|
-
}
|
|
1559
|
-
const { project, service = CDK$2.SERVICE.DATADOG } = options || {};
|
|
1560
|
-
// Lookup the Datadog role
|
|
1561
|
-
const datadogRole = awsIam.Role.fromRoleArn(this, "DatadogRole", datadogRoleArn);
|
|
1562
|
-
// Build policy statements for bucket access
|
|
1563
|
-
const statements = [
|
|
1564
|
-
// Allow list bucket
|
|
1565
|
-
new awsIam.PolicyStatement({
|
|
1566
|
-
actions: ["s3:ListBucket"],
|
|
1567
|
-
resources: [this.bucket.bucketArn],
|
|
1568
|
-
}),
|
|
1569
|
-
// Allow read and write to the bucket
|
|
1570
|
-
new awsIam.PolicyStatement({
|
|
1571
|
-
actions: ["s3:GetObject", "s3:PutObject"],
|
|
1572
|
-
resources: [`${this.bucket.bucketArn}/*`],
|
|
1573
|
-
}),
|
|
1574
|
-
];
|
|
1575
|
-
// Create the custom policy
|
|
1576
|
-
const datadogBucketPolicy = new awsIam.Policy(this, "DatadogBucketPolicy", {
|
|
1577
|
-
roles: [datadogRole],
|
|
1578
|
-
statements,
|
|
1579
|
-
});
|
|
1580
|
-
// Add tags
|
|
1581
|
-
cdk__namespace.Tags.of(datadogBucketPolicy).add(CDK$2.TAG.SERVICE, service);
|
|
1582
|
-
cdk__namespace.Tags.of(datadogBucketPolicy).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
1583
|
-
cdk__namespace.Tags.of(datadogBucketPolicy).add(CDK$2.TAG.VENDOR, CDK$2.VENDOR.DATADOG);
|
|
1584
|
-
if (project) {
|
|
1585
|
-
cdk__namespace.Tags.of(datadogBucketPolicy).add(CDK$2.TAG.PROJECT, project);
|
|
1586
|
-
}
|
|
1587
|
-
return datadogBucketPolicy;
|
|
1588
|
-
}
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1591
|
-
const DATADOG_FORWARDER_TEMPLATE_URL = "https://datadog-cloudformation-template.s3.amazonaws.com/aws/forwarder/latest.yaml";
|
|
1592
|
-
const DEFAULT_RESERVED_CONCURRENCY = "10";
|
|
1593
|
-
class JaypieDatadogForwarder extends constructs.Construct {
|
|
1594
|
-
/**
|
|
1595
|
-
* Create a new Datadog forwarder with CloudFormation nested stack
|
|
1596
|
-
*/
|
|
1597
|
-
constructor(scope, idOrProps, propsOrUndefined) {
|
|
1598
|
-
// Handle overloaded constructor signatures
|
|
1599
|
-
let props;
|
|
1600
|
-
let id;
|
|
1601
|
-
if (typeof idOrProps === "string") {
|
|
1602
|
-
// First param is ID, second is props
|
|
1603
|
-
props = propsOrUndefined || {};
|
|
1604
|
-
id = idOrProps;
|
|
1605
|
-
}
|
|
1606
|
-
else {
|
|
1607
|
-
// First param is props
|
|
1608
|
-
props = idOrProps || {};
|
|
1609
|
-
id = props.id || "DatadogForwarder";
|
|
1610
|
-
}
|
|
1611
|
-
super(scope, id);
|
|
1612
|
-
// Resolve options with defaults
|
|
1613
|
-
const { account = process.env.CDK_ENV_ACCOUNT, additionalTags, createOutput = true, datadogApiKey = process.env.CDK_ENV_DATADOG_API_KEY, enableCloudFormationEvents = true, enableRoleExtension = true, exportName = CDK$2.IMPORT.DATADOG_LOG_FORWARDER, project, reservedConcurrency = DEFAULT_RESERVED_CONCURRENCY, service = CDK$2.VENDOR.DATADOG, templateUrl = DATADOG_FORWARDER_TEMPLATE_URL, } = props;
|
|
1614
|
-
// Validate required parameters
|
|
1615
|
-
if (!datadogApiKey) {
|
|
1616
|
-
throw new Error("Datadog API key is required. Provide via datadogApiKey prop or CDK_ENV_DATADOG_API_KEY environment variable.");
|
|
1617
|
-
}
|
|
1618
|
-
// Build Datadog tags
|
|
1619
|
-
let ddTags = account ? `account:${account}` : "";
|
|
1620
|
-
if (additionalTags) {
|
|
1621
|
-
ddTags = ddTags ? `${ddTags},${additionalTags}` : additionalTags;
|
|
1622
|
-
}
|
|
1623
|
-
// Deploy Datadog CloudFormation stack
|
|
1624
|
-
this.cfnStack = new cdk.CfnStack(this, "Stack", {
|
|
1625
|
-
parameters: {
|
|
1626
|
-
DdApiKey: datadogApiKey,
|
|
1627
|
-
DdTags: ddTags,
|
|
1628
|
-
ReservedConcurrency: reservedConcurrency,
|
|
1629
|
-
},
|
|
1630
|
-
templateUrl,
|
|
1631
|
-
});
|
|
1632
|
-
// Add tags to stack
|
|
1633
|
-
cdk__namespace.Tags.of(this.cfnStack).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
1634
|
-
cdk__namespace.Tags.of(this.cfnStack).add(CDK$2.TAG.SERVICE, service);
|
|
1635
|
-
cdk__namespace.Tags.of(this.cfnStack).add(CDK$2.TAG.VENDOR, CDK$2.VENDOR.DATADOG);
|
|
1636
|
-
if (project) {
|
|
1637
|
-
cdk__namespace.Tags.of(this.cfnStack).add(CDK$2.TAG.PROJECT, project);
|
|
1638
|
-
}
|
|
1639
|
-
// Extract forwarder function from stack outputs
|
|
1640
|
-
this.forwarderFunction = lambda__namespace.Function.fromFunctionArn(this, "Function", this.cfnStack.getAtt("Outputs.DatadogForwarderArn").toString());
|
|
1641
|
-
// Extend Datadog role with custom permissions if enabled
|
|
1642
|
-
if (enableRoleExtension) {
|
|
1643
|
-
extendDatadogRole(this, { project, service });
|
|
1644
|
-
}
|
|
1645
|
-
// Create CloudFormation events rule if enabled
|
|
1646
|
-
if (enableCloudFormationEvents) {
|
|
1647
|
-
this.eventsRule = new awsEvents.Rule(this, "CloudFormationEventsRule", {
|
|
1648
|
-
eventPattern: {
|
|
1649
|
-
source: ["aws.cloudformation"],
|
|
1650
|
-
},
|
|
1651
|
-
targets: [
|
|
1652
|
-
new awsEventsTargets.LambdaFunction(this.forwarderFunction, {
|
|
1653
|
-
event: awsEvents.RuleTargetInput.fromEventPath("$"),
|
|
1654
|
-
}),
|
|
1655
|
-
],
|
|
1656
|
-
});
|
|
1657
|
-
// Add tags to events rule
|
|
1658
|
-
cdk__namespace.Tags.of(this.eventsRule).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
1659
|
-
cdk__namespace.Tags.of(this.eventsRule).add(CDK$2.TAG.SERVICE, service);
|
|
1660
|
-
cdk__namespace.Tags.of(this.eventsRule).add(CDK$2.TAG.VENDOR, CDK$2.VENDOR.DATADOG);
|
|
1661
|
-
if (project) {
|
|
1662
|
-
cdk__namespace.Tags.of(this.eventsRule).add(CDK$2.TAG.PROJECT, project);
|
|
1663
|
-
}
|
|
1664
|
-
}
|
|
1665
|
-
// Create CloudFormation output if enabled
|
|
1666
|
-
if (createOutput) {
|
|
1667
|
-
new cdk__namespace.CfnOutput(this, "ForwarderArnOutput", {
|
|
1668
|
-
description: "Datadog Log Forwarder Lambda ARN",
|
|
1669
|
-
exportName,
|
|
1670
|
-
value: this.cfnStack.getAtt("Outputs.DatadogForwarderArn").toString(),
|
|
1671
|
-
});
|
|
1672
|
-
}
|
|
1673
|
-
}
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
class JaypieDistribution extends constructs.Construct {
|
|
1677
|
-
constructor(scope, id, props) {
|
|
1678
|
-
super(scope, id);
|
|
1679
|
-
const { certificate: certificateProp = true, defaultBehavior: propsDefaultBehavior, destination: destinationProp = true, handler, host: propsHost, invokeMode = lambda__namespace.InvokeMode.BUFFERED, roleTag = CDK$2.ROLE.API, zone: propsZone, ...distributionProps } = props;
|
|
1680
|
-
// Validate environment variables
|
|
1681
|
-
if (process.env.CDK_ENV_API_SUBDOMAIN &&
|
|
1682
|
-
!isValidSubdomain(process.env.CDK_ENV_API_SUBDOMAIN)) {
|
|
1683
|
-
throw new Error("CDK_ENV_API_SUBDOMAIN is not a valid subdomain");
|
|
1684
|
-
}
|
|
1685
|
-
if (process.env.CDK_ENV_API_HOSTED_ZONE &&
|
|
1686
|
-
!isValidHostname$1(process.env.CDK_ENV_API_HOSTED_ZONE)) {
|
|
1687
|
-
throw new Error("CDK_ENV_API_HOSTED_ZONE is not a valid hostname");
|
|
1688
|
-
}
|
|
1689
|
-
if (process.env.CDK_ENV_HOSTED_ZONE &&
|
|
1690
|
-
!isValidHostname$1(process.env.CDK_ENV_HOSTED_ZONE)) {
|
|
1691
|
-
throw new Error("CDK_ENV_HOSTED_ZONE is not a valid hostname");
|
|
1692
|
-
}
|
|
1693
|
-
// Determine host from props or environment
|
|
1694
|
-
let host = propsHost;
|
|
1695
|
-
if (!host) {
|
|
1696
|
-
try {
|
|
1697
|
-
if (process.env.CDK_ENV_API_HOST_NAME) {
|
|
1698
|
-
host = process.env.CDK_ENV_API_HOST_NAME;
|
|
1699
|
-
}
|
|
1700
|
-
else if (process.env.CDK_ENV_API_SUBDOMAIN) {
|
|
1701
|
-
host = mergeDomain(process.env.CDK_ENV_API_SUBDOMAIN, process.env.CDK_ENV_API_HOSTED_ZONE ||
|
|
1702
|
-
process.env.CDK_ENV_HOSTED_ZONE ||
|
|
1703
|
-
"");
|
|
1704
|
-
}
|
|
1705
|
-
}
|
|
1706
|
-
catch {
|
|
1707
|
-
host = undefined;
|
|
1708
|
-
}
|
|
1709
|
-
}
|
|
1710
|
-
if (host && !isValidHostname$1(host)) {
|
|
1711
|
-
throw new Error("Host is not a valid hostname");
|
|
1712
|
-
}
|
|
1713
|
-
this.host = host;
|
|
1714
|
-
// Determine zone from props or environment
|
|
1715
|
-
const zone = propsZone || process.env.CDK_ENV_HOSTED_ZONE;
|
|
1716
|
-
// Resolve the origin from handler
|
|
1717
|
-
// Check order matters: IFunctionUrl before IOrigin (FunctionUrl also has bind method)
|
|
1718
|
-
// IFunction before IFunctionUrl (IFunction doesn't have functionUrlId)
|
|
1719
|
-
let origin;
|
|
1720
|
-
if (handler) {
|
|
1721
|
-
if (this.isIFunction(handler)) {
|
|
1722
|
-
// Create FunctionUrl for the Lambda function
|
|
1723
|
-
const functionUrl = new lambda__namespace.FunctionUrl(this, "FunctionUrl", {
|
|
1724
|
-
function: handler,
|
|
1725
|
-
authType: lambda__namespace.FunctionUrlAuthType.NONE,
|
|
1726
|
-
invokeMode,
|
|
1727
|
-
});
|
|
1728
|
-
this.functionUrl = functionUrl;
|
|
1729
|
-
origin = new origins__namespace.FunctionUrlOrigin(functionUrl);
|
|
1730
|
-
}
|
|
1731
|
-
else if (this.isIFunctionUrl(handler)) {
|
|
1732
|
-
origin = new origins__namespace.FunctionUrlOrigin(handler);
|
|
1733
|
-
}
|
|
1734
|
-
else if (this.isIOrigin(handler)) {
|
|
1735
|
-
origin = handler;
|
|
1736
|
-
}
|
|
1737
|
-
}
|
|
1738
|
-
// Build default behavior
|
|
1739
|
-
let defaultBehavior;
|
|
1740
|
-
if (propsDefaultBehavior) {
|
|
1741
|
-
defaultBehavior = propsDefaultBehavior;
|
|
1742
|
-
}
|
|
1743
|
-
else if (origin) {
|
|
1744
|
-
defaultBehavior = {
|
|
1745
|
-
allowedMethods: cloudfront__namespace.AllowedMethods.ALLOW_ALL,
|
|
1746
|
-
cachePolicy: cloudfront__namespace.CachePolicy.CACHING_DISABLED,
|
|
1747
|
-
origin,
|
|
1748
|
-
originRequestPolicy: cloudfront__namespace.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER,
|
|
1749
|
-
viewerProtocolPolicy: cloudfront__namespace.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
1750
|
-
};
|
|
1751
|
-
}
|
|
1752
|
-
else {
|
|
1753
|
-
throw new Error("Either handler or defaultBehavior must be provided to JaypieDistribution");
|
|
1754
|
-
}
|
|
1755
|
-
// Resolve hosted zone and certificate
|
|
1756
|
-
// Only resolve zone when we need it (for certificate or DNS)
|
|
1757
|
-
let hostedZone;
|
|
1758
|
-
let certificateToUse;
|
|
1759
|
-
if (host && zone && certificateProp !== false) {
|
|
1760
|
-
hostedZone = resolveHostedZone(this, { zone });
|
|
1761
|
-
if (certificateProp === true) {
|
|
1762
|
-
certificateToUse = new acm__namespace.Certificate(this, constructEnvName("Certificate"), {
|
|
1763
|
-
domainName: host,
|
|
1764
|
-
validation: acm__namespace.CertificateValidation.fromDns(hostedZone),
|
|
1765
|
-
});
|
|
1766
|
-
cdk.Tags.of(certificateToUse).add(CDK$2.TAG.ROLE, roleTag);
|
|
1767
|
-
}
|
|
1768
|
-
else if (typeof certificateProp === "object") {
|
|
1769
|
-
certificateToUse = certificateProp;
|
|
1770
|
-
}
|
|
1771
|
-
this.certificate = certificateToUse;
|
|
1772
|
-
}
|
|
1773
|
-
// Create log bucket if logging is enabled
|
|
1774
|
-
let logBucket;
|
|
1775
|
-
if (destinationProp !== false) {
|
|
1776
|
-
logBucket = new s3__namespace.Bucket(this, constructEnvName("LogBucket"), {
|
|
1777
|
-
objectOwnership: s3__namespace.ObjectOwnership.OBJECT_WRITER,
|
|
1778
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
1779
|
-
autoDeleteObjects: true,
|
|
1780
|
-
lifecycleRules: [
|
|
1781
|
-
{
|
|
1782
|
-
expiration: cdk.Duration.days(90),
|
|
1783
|
-
transitions: [
|
|
1784
|
-
{
|
|
1785
|
-
storageClass: s3__namespace.StorageClass.INFREQUENT_ACCESS,
|
|
1786
|
-
transitionAfter: cdk.Duration.days(30),
|
|
1787
|
-
},
|
|
1788
|
-
],
|
|
1789
|
-
},
|
|
1790
|
-
],
|
|
1791
|
-
});
|
|
1792
|
-
cdk.Tags.of(logBucket).add(CDK$2.TAG.ROLE, CDK$2.ROLE.STORAGE);
|
|
1793
|
-
// Add S3 notification to Datadog forwarder
|
|
1794
|
-
const lambdaDestination = destinationProp === true
|
|
1795
|
-
? new s3n.LambdaDestination(resolveDatadogForwarderFunction(this))
|
|
1796
|
-
: destinationProp;
|
|
1797
|
-
logBucket.addEventNotification(s3__namespace.EventType.OBJECT_CREATED, lambdaDestination);
|
|
1798
|
-
this.logBucket = logBucket;
|
|
1799
|
-
}
|
|
1800
|
-
// Create the CloudFront distribution
|
|
1801
|
-
this.distribution = new cloudfront__namespace.Distribution(this, constructEnvName("Distribution"), {
|
|
1802
|
-
defaultBehavior,
|
|
1803
|
-
...(host && certificateToUse
|
|
1804
|
-
? {
|
|
1805
|
-
certificate: certificateToUse,
|
|
1806
|
-
domainNames: [host],
|
|
1807
|
-
}
|
|
1808
|
-
: {}),
|
|
1809
|
-
...(logBucket
|
|
1810
|
-
? {
|
|
1811
|
-
enableLogging: true,
|
|
1812
|
-
logBucket,
|
|
1813
|
-
logFilePrefix: "cloudfront-logs/",
|
|
1814
|
-
}
|
|
1815
|
-
: {}),
|
|
1816
|
-
...distributionProps,
|
|
1817
|
-
});
|
|
1818
|
-
cdk.Tags.of(this.distribution).add(CDK$2.TAG.ROLE, roleTag);
|
|
1819
|
-
this.distributionArn = `arn:aws:cloudfront::${cdk.Stack.of(this).account}:distribution/${this.distribution.distributionId}`;
|
|
1820
|
-
this.distributionDomainName = this.distribution.distributionDomainName;
|
|
1821
|
-
this.distributionId = this.distribution.distributionId;
|
|
1822
|
-
this.domainName = this.distribution.domainName;
|
|
1823
|
-
// Create DNS records if we have host and zone
|
|
1824
|
-
if (host && hostedZone) {
|
|
1825
|
-
const aRecord = new route53__namespace.ARecord(this, "AliasRecord", {
|
|
1826
|
-
recordName: host,
|
|
1827
|
-
target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.CloudFrontTarget(this.distribution)),
|
|
1828
|
-
zone: hostedZone,
|
|
1829
|
-
});
|
|
1830
|
-
cdk.Tags.of(aRecord).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
1831
|
-
const aaaaRecord = new route53__namespace.AaaaRecord(this, "AaaaAliasRecord", {
|
|
1832
|
-
recordName: host,
|
|
1833
|
-
target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.CloudFrontTarget(this.distribution)),
|
|
1834
|
-
zone: hostedZone,
|
|
1835
|
-
});
|
|
1836
|
-
cdk.Tags.of(aaaaRecord).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
1837
|
-
}
|
|
1838
|
-
}
|
|
1839
|
-
// Type guards for handler types
|
|
1840
|
-
isIOrigin(handler) {
|
|
1841
|
-
return (typeof handler === "object" &&
|
|
1842
|
-
handler !== null &&
|
|
1843
|
-
"bind" in handler &&
|
|
1844
|
-
typeof handler.bind === "function");
|
|
1845
|
-
}
|
|
1846
|
-
isIFunctionUrl(handler) {
|
|
1847
|
-
// FunctionUrl has 'url' property which is the function URL string
|
|
1848
|
-
// IFunction does not have 'url' property
|
|
1849
|
-
return (typeof handler === "object" &&
|
|
1850
|
-
handler !== null &&
|
|
1851
|
-
"url" in handler &&
|
|
1852
|
-
"functionArn" in handler);
|
|
1853
|
-
}
|
|
1854
|
-
isIFunction(handler) {
|
|
1855
|
-
// IFunction has functionArn and functionName but NOT 'url'
|
|
1856
|
-
// (FunctionUrl also has functionArn but also has 'url')
|
|
1857
|
-
return (typeof handler === "object" &&
|
|
1858
|
-
handler !== null &&
|
|
1859
|
-
"functionArn" in handler &&
|
|
1860
|
-
"functionName" in handler &&
|
|
1861
|
-
!("url" in handler));
|
|
1862
|
-
}
|
|
1863
|
-
// Implement IDistribution interface
|
|
1864
|
-
get env() {
|
|
1865
|
-
return {
|
|
1866
|
-
account: cdk.Stack.of(this).account,
|
|
1867
|
-
region: cdk.Stack.of(this).region,
|
|
1868
|
-
};
|
|
1869
|
-
}
|
|
1870
|
-
get stack() {
|
|
1871
|
-
return this.distribution.stack;
|
|
1872
|
-
}
|
|
1873
|
-
applyRemovalPolicy(policy) {
|
|
1874
|
-
this.distribution.applyRemovalPolicy(policy);
|
|
1875
|
-
}
|
|
1876
|
-
grant(identity, ...actions) {
|
|
1877
|
-
return this.distribution.grant(identity, ...actions);
|
|
1878
|
-
}
|
|
1879
|
-
grantCreateInvalidation(identity) {
|
|
1880
|
-
return this.distribution.grantCreateInvalidation(identity);
|
|
1881
|
-
}
|
|
1882
|
-
get distributionRef() {
|
|
1883
|
-
return {
|
|
1884
|
-
distributionId: this.distribution.distributionId,
|
|
1885
|
-
};
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
|
|
1889
|
-
// It is a consumer if the environment is ephemeral
|
|
1890
|
-
function checkEnvIsConsumer(env = process.env) {
|
|
1891
|
-
return (env.PROJECT_ENV === CDK$2.ENV.PERSONAL ||
|
|
1892
|
-
!!env.CDK_ENV_PERSONAL ||
|
|
1893
|
-
/** @deprecated */ env.PROJECT_ENV === "ephemeral" ||
|
|
1894
|
-
/** @deprecated */ !!env.CDK_ENV_EPHEMERAL);
|
|
1895
|
-
}
|
|
1896
|
-
function checkEnvIsProvider(env = process.env) {
|
|
1897
|
-
return env.PROJECT_ENV === CDK$2.ENV.SANDBOX;
|
|
1898
|
-
}
|
|
1899
|
-
function cleanName(name) {
|
|
1900
|
-
return name.replace(/[^a-zA-Z0-9:-]/g, "");
|
|
1901
|
-
}
|
|
1902
|
-
function exportEnvName(name, env = process.env) {
|
|
1903
|
-
let rawName;
|
|
1904
|
-
if (checkEnvIsProvider(env)) {
|
|
1905
|
-
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
1906
|
-
// Clean the entire name to only allow alphanumeric, colons, and hyphens
|
|
1907
|
-
return cleanName(rawName);
|
|
1908
|
-
}
|
|
1909
|
-
else {
|
|
1910
|
-
if (checkEnvIsConsumer(env)) {
|
|
1911
|
-
rawName = `env-${CDK$2.ENV.SANDBOX}-${env.PROJECT_KEY}-${name}`;
|
|
1912
|
-
}
|
|
1913
|
-
else {
|
|
1914
|
-
rawName = `env-${env.PROJECT_ENV}-${env.PROJECT_KEY}-${name}`;
|
|
1915
|
-
}
|
|
1916
|
-
}
|
|
1917
|
-
return cleanName(rawName);
|
|
1918
|
-
}
|
|
1919
|
-
class JaypieEnvSecret extends constructs.Construct {
|
|
1920
|
-
constructor(scope, idOrEnvKey, props) {
|
|
1921
|
-
// Check if idOrEnvKey should be treated as envKey:
|
|
1922
|
-
// - No props provided OR props.envKey is not set
|
|
1923
|
-
// - AND idOrEnvKey exists as a non-empty string in process.env
|
|
1924
|
-
const treatAsEnvKey = (!props || props.envKey === undefined) &&
|
|
1925
|
-
typeof process.env[idOrEnvKey] === "string" &&
|
|
1926
|
-
process.env[idOrEnvKey] !== "";
|
|
1927
|
-
const id = treatAsEnvKey ? `EnvSecret_${idOrEnvKey}` : idOrEnvKey;
|
|
1928
|
-
super(scope, id);
|
|
1929
|
-
const { consumer = checkEnvIsConsumer(), envKey: envKeyProp, export: exportParam, generateSecretString, provider = checkEnvIsProvider(), roleTag, vendorTag, value, } = props || {};
|
|
1930
|
-
const envKey = treatAsEnvKey ? idOrEnvKey : envKeyProp;
|
|
1931
|
-
this._envKey = envKey;
|
|
1932
|
-
let exportName;
|
|
1933
|
-
if (!exportParam) {
|
|
1934
|
-
exportName = exportEnvName(id);
|
|
1935
|
-
}
|
|
1936
|
-
else {
|
|
1937
|
-
exportName = cleanName(exportParam);
|
|
1938
|
-
}
|
|
1939
|
-
if (consumer) {
|
|
1940
|
-
const secretName = cdk.Fn.importValue(exportName);
|
|
1941
|
-
this._secret = secretsmanager__namespace.Secret.fromSecretNameV2(this, id, secretName);
|
|
1942
|
-
// Add CfnOutput for consumer secrets
|
|
1943
|
-
new cdk.CfnOutput(this, `ConsumedName`, {
|
|
1944
|
-
value: this._secret.secretName,
|
|
1945
|
-
});
|
|
1946
|
-
}
|
|
1947
|
-
else {
|
|
1948
|
-
const secretValue = envKey && process.env[envKey] ? process.env[envKey] : value;
|
|
1949
|
-
const secretProps = {
|
|
1950
|
-
generateSecretString,
|
|
1951
|
-
secretStringValue: !generateSecretString && secretValue
|
|
1952
|
-
? cdk.SecretValue.unsafePlainText(secretValue)
|
|
1953
|
-
: undefined,
|
|
1954
|
-
};
|
|
1955
|
-
this._secret = new secretsmanager__namespace.Secret(this, id, secretProps);
|
|
1956
|
-
if (roleTag) {
|
|
1957
|
-
cdk.Tags.of(this._secret).add(CDK$2.TAG.ROLE, roleTag);
|
|
1958
|
-
}
|
|
1959
|
-
if (vendorTag) {
|
|
1960
|
-
cdk.Tags.of(this._secret).add(CDK$2.TAG.VENDOR, vendorTag);
|
|
1961
|
-
}
|
|
1962
|
-
if (provider) {
|
|
1963
|
-
new cdk.CfnOutput(this, `ProvidedName`, {
|
|
1964
|
-
value: this._secret.secretName,
|
|
1965
|
-
exportName,
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
else {
|
|
1969
|
-
new cdk.CfnOutput(this, `CreatedName`, {
|
|
1970
|
-
value: this._secret.secretName,
|
|
1971
|
-
});
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
}
|
|
1975
|
-
// IResource implementation
|
|
1976
|
-
get stack() {
|
|
1977
|
-
return cdk.Stack.of(this);
|
|
1978
|
-
}
|
|
1979
|
-
get env() {
|
|
1980
|
-
return {
|
|
1981
|
-
account: cdk.Stack.of(this).account,
|
|
1982
|
-
region: cdk.Stack.of(this).region,
|
|
1983
|
-
};
|
|
1984
|
-
}
|
|
1985
|
-
applyRemovalPolicy(policy) {
|
|
1986
|
-
this._secret.applyRemovalPolicy(policy);
|
|
1987
|
-
}
|
|
1988
|
-
// ISecret implementation
|
|
1989
|
-
get secretArn() {
|
|
1990
|
-
return this._secret.secretArn;
|
|
1991
|
-
}
|
|
1992
|
-
get secretName() {
|
|
1993
|
-
return this._secret.secretName;
|
|
1994
|
-
}
|
|
1995
|
-
get secretFullArn() {
|
|
1996
|
-
return this._secret.secretFullArn;
|
|
1997
|
-
}
|
|
1998
|
-
get encryptionKey() {
|
|
1999
|
-
return this._secret.encryptionKey;
|
|
2000
|
-
}
|
|
2001
|
-
get secretValue() {
|
|
2002
|
-
return this._secret.secretValue;
|
|
2003
|
-
}
|
|
2004
|
-
secretValueFromJson(key) {
|
|
2005
|
-
return this._secret.secretValueFromJson(key);
|
|
2006
|
-
}
|
|
2007
|
-
grantRead(grantee, versionStages) {
|
|
2008
|
-
return this._secret.grantRead(grantee, versionStages);
|
|
2009
|
-
}
|
|
2010
|
-
grantWrite(grantee) {
|
|
2011
|
-
return this._secret.grantWrite(grantee);
|
|
2012
|
-
}
|
|
2013
|
-
addRotationSchedule(id, options) {
|
|
2014
|
-
return this._secret.addRotationSchedule(id, options);
|
|
2015
|
-
}
|
|
2016
|
-
addToResourcePolicy(statement) {
|
|
2017
|
-
return this._secret.addToResourcePolicy(statement);
|
|
2018
|
-
}
|
|
2019
|
-
denyAccountRootDelete() {
|
|
2020
|
-
this._secret.denyAccountRootDelete();
|
|
2021
|
-
}
|
|
2022
|
-
attach(target) {
|
|
2023
|
-
return this._secret.attach(target);
|
|
2024
|
-
}
|
|
2025
|
-
cfnDynamicReferenceKey(options) {
|
|
2026
|
-
return this._secret.cfnDynamicReferenceKey(options);
|
|
2027
|
-
}
|
|
2028
|
-
get envKey() {
|
|
2029
|
-
return this._envKey;
|
|
2030
|
-
}
|
|
2031
|
-
}
|
|
2032
|
-
|
|
2033
|
-
class JaypieDatadogSecret extends JaypieEnvSecret {
|
|
2034
|
-
constructor(scope, id = "MongoConnectionString", props) {
|
|
2035
|
-
const defaultProps = {
|
|
2036
|
-
envKey: "DATADOG_API_KEY",
|
|
2037
|
-
roleTag: CDK$2.ROLE.MONITORING,
|
|
2038
|
-
vendorTag: CDK$2.VENDOR.DATADOG,
|
|
2039
|
-
...props,
|
|
2040
|
-
};
|
|
2041
|
-
super(scope, id, defaultProps);
|
|
2042
|
-
}
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
class JaypieDnsRecord extends constructs.Construct {
|
|
2046
|
-
constructor(scope, id, props) {
|
|
2047
|
-
super(scope, id);
|
|
2048
|
-
const { comment, recordName, type, values } = props;
|
|
2049
|
-
const ttl = props.ttl || cdk__namespace.Duration.seconds(CDK$2.DNS.CONFIG.TTL);
|
|
2050
|
-
// Resolve the hosted zone (supports both string and IHostedZone)
|
|
2051
|
-
const zone = resolveHostedZone(scope, {
|
|
2052
|
-
name: `${id}HostedZone`,
|
|
2053
|
-
zone: props.zone,
|
|
2054
|
-
});
|
|
2055
|
-
// Common properties for all record types
|
|
2056
|
-
const baseProps = {
|
|
2057
|
-
comment,
|
|
2058
|
-
recordName,
|
|
2059
|
-
ttl,
|
|
2060
|
-
zone,
|
|
2061
|
-
};
|
|
2062
|
-
// Create the appropriate record based on type
|
|
2063
|
-
switch (type) {
|
|
2064
|
-
case CDK$2.DNS.RECORD.A: {
|
|
2065
|
-
if (!Array.isArray(values) || values.length === 0) {
|
|
2066
|
-
throw new errors.ConfigurationError("A record requires at least one IP address");
|
|
2067
|
-
}
|
|
2068
|
-
this.record = new route53.ARecord(this, "Record", {
|
|
2069
|
-
...baseProps,
|
|
2070
|
-
target: route53.RecordTarget.fromIpAddresses(...values),
|
|
2071
|
-
});
|
|
2072
|
-
break;
|
|
2073
|
-
}
|
|
2074
|
-
case CDK$2.DNS.RECORD.CNAME: {
|
|
2075
|
-
if (!Array.isArray(values) || values.length === 0) {
|
|
2076
|
-
throw new errors.ConfigurationError("CNAME record requires a domain name");
|
|
2077
|
-
}
|
|
2078
|
-
this.record = new route53.CnameRecord(this, "Record", {
|
|
2079
|
-
...baseProps,
|
|
2080
|
-
domainName: values[0],
|
|
2081
|
-
});
|
|
2082
|
-
break;
|
|
2083
|
-
}
|
|
2084
|
-
case CDK$2.DNS.RECORD.MX: {
|
|
2085
|
-
if (!Array.isArray(values) || values.length === 0) {
|
|
2086
|
-
throw new errors.ConfigurationError("MX record requires at least one mail server");
|
|
2087
|
-
}
|
|
2088
|
-
this.record = new route53.MxRecord(this, "Record", {
|
|
2089
|
-
...baseProps,
|
|
2090
|
-
values: values,
|
|
2091
|
-
});
|
|
2092
|
-
break;
|
|
2093
|
-
}
|
|
2094
|
-
case CDK$2.DNS.RECORD.NS: {
|
|
2095
|
-
if (!Array.isArray(values) || values.length === 0) {
|
|
2096
|
-
throw new errors.ConfigurationError("NS record requires at least one name server");
|
|
2097
|
-
}
|
|
2098
|
-
this.record = new route53.NsRecord(this, "Record", {
|
|
2099
|
-
...baseProps,
|
|
2100
|
-
values: values,
|
|
2101
|
-
});
|
|
2102
|
-
break;
|
|
2103
|
-
}
|
|
2104
|
-
case CDK$2.DNS.RECORD.TXT: {
|
|
2105
|
-
if (!Array.isArray(values) || values.length === 0) {
|
|
2106
|
-
throw new errors.ConfigurationError("TXT record requires at least one value");
|
|
2107
|
-
}
|
|
2108
|
-
this.record = new route53.TxtRecord(this, "Record", {
|
|
2109
|
-
...baseProps,
|
|
2110
|
-
values: values,
|
|
2111
|
-
});
|
|
2112
|
-
break;
|
|
2113
|
-
}
|
|
2114
|
-
default:
|
|
2115
|
-
throw new errors.ConfigurationError(`Unsupported DNS record type: ${type}. Supported types: A, CNAME, MX, NS, TXT`);
|
|
2116
|
-
}
|
|
2117
|
-
// Add standard tags to the DNS record
|
|
2118
|
-
cdk__namespace.Tags.of(this.record).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.INFRASTRUCTURE);
|
|
2119
|
-
cdk__namespace.Tags.of(this.record).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
|
|
2123
|
-
class JaypieEventsRule extends constructs.Construct {
|
|
2124
|
-
/**
|
|
2125
|
-
* Create a new EventBridge rule that targets a Lambda function
|
|
2126
|
-
*/
|
|
2127
|
-
constructor(scope, idOrSourceOrProps, propsOrUndefined) {
|
|
2128
|
-
// Handle overloaded constructor signatures
|
|
2129
|
-
let props;
|
|
2130
|
-
let id;
|
|
2131
|
-
if (typeof idOrSourceOrProps === "string") {
|
|
2132
|
-
// Check if it looks like an AWS source (starts with "aws.")
|
|
2133
|
-
if (idOrSourceOrProps.startsWith("aws.")) {
|
|
2134
|
-
// First param is source, second is props
|
|
2135
|
-
props = propsOrUndefined || {};
|
|
2136
|
-
props.source = idOrSourceOrProps;
|
|
2137
|
-
// Generate ID from source
|
|
2138
|
-
const sourceName = idOrSourceOrProps
|
|
2139
|
-
.replace("aws.", "")
|
|
2140
|
-
.split(".")
|
|
2141
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
2142
|
-
.join("");
|
|
2143
|
-
id = props.id || `${sourceName}EventsRule`;
|
|
2144
|
-
}
|
|
2145
|
-
else {
|
|
2146
|
-
// First param is ID, second is props
|
|
2147
|
-
props = propsOrUndefined || {};
|
|
2148
|
-
id = idOrSourceOrProps;
|
|
2149
|
-
}
|
|
2150
|
-
}
|
|
2151
|
-
else {
|
|
2152
|
-
// First param is props
|
|
2153
|
-
props = idOrSourceOrProps || {};
|
|
2154
|
-
if (props.source) {
|
|
2155
|
-
const sourceName = typeof props.source === "string"
|
|
2156
|
-
? props.source
|
|
2157
|
-
.replace("aws.", "")
|
|
2158
|
-
.split(".")
|
|
2159
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
2160
|
-
.join("")
|
|
2161
|
-
: "Events";
|
|
2162
|
-
id = props.id || `${sourceName}EventsRule`;
|
|
2163
|
-
}
|
|
2164
|
-
else {
|
|
2165
|
-
id = props.id || "EventsRule";
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
super(scope, id);
|
|
2169
|
-
// Extract Jaypie-specific options
|
|
2170
|
-
const { id: _id, project, service = CDK$2.SERVICE.DATADOG, source, targetFunction, vendor = CDK$2.VENDOR.DATADOG, ...ruleProps } = props;
|
|
2171
|
-
// Resolve target function
|
|
2172
|
-
this.targetFunction =
|
|
2173
|
-
targetFunction || resolveDatadogForwarderFunction(scope);
|
|
2174
|
-
// Build event pattern if source is specified
|
|
2175
|
-
const eventPattern = source
|
|
2176
|
-
? {
|
|
2177
|
-
...ruleProps.eventPattern,
|
|
2178
|
-
source: Array.isArray(source) ? source : [source],
|
|
2179
|
-
}
|
|
2180
|
-
: ruleProps.eventPattern;
|
|
2181
|
-
// Build rule props
|
|
2182
|
-
const finalRuleProps = {
|
|
2183
|
-
...ruleProps,
|
|
2184
|
-
eventPattern,
|
|
2185
|
-
targets: [
|
|
2186
|
-
new awsEventsTargets.LambdaFunction(this.targetFunction, {
|
|
2187
|
-
event: awsEvents.RuleTargetInput.fromEventPath("$"),
|
|
2188
|
-
}),
|
|
2189
|
-
],
|
|
2190
|
-
};
|
|
2191
|
-
// Create the rule
|
|
2192
|
-
this.rule = new awsEvents.Rule(this, "Rule", finalRuleProps);
|
|
2193
|
-
// Add tags
|
|
2194
|
-
cdk__namespace.Tags.of(this.rule).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
2195
|
-
cdk__namespace.Tags.of(this.rule).add(CDK$2.TAG.SERVICE, service);
|
|
2196
|
-
cdk__namespace.Tags.of(this.rule).add(CDK$2.TAG.VENDOR, vendor);
|
|
2197
|
-
if (project) {
|
|
2198
|
-
cdk__namespace.Tags.of(this.rule).add(CDK$2.TAG.PROJECT, project);
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
}
|
|
2202
|
-
|
|
2203
|
-
class JaypieGitHubDeployRole extends constructs.Construct {
|
|
2204
|
-
constructor(scope, id = "GitHubDeployRole", props = {}) {
|
|
2205
|
-
super(scope, id);
|
|
2206
|
-
const { oidcProviderArn = cdk.Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, } = props;
|
|
2207
|
-
// Extract account ID from the scope
|
|
2208
|
-
const accountId = cdk.Stack.of(this).account;
|
|
2209
|
-
// Resolve repoRestriction from props or environment variables
|
|
2210
|
-
let repoRestriction = propsRepoRestriction;
|
|
2211
|
-
if (!repoRestriction) {
|
|
2212
|
-
const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
|
|
2213
|
-
if (!envRepo) {
|
|
2214
|
-
throw new errors.ConfigurationError("No repoRestriction provided. Set repoRestriction prop, CDK_ENV_REPO, or PROJECT_REPO environment variable");
|
|
2215
|
-
}
|
|
2216
|
-
// Extract organization from owner/repo format and create org-wide restriction
|
|
2217
|
-
const organization = envRepo.split("/")[0];
|
|
2218
|
-
repoRestriction = `repo:${organization}/*:*`;
|
|
2219
|
-
}
|
|
2220
|
-
// Create the IAM role
|
|
2221
|
-
this._role = new awsIam.Role(this, "GitHubActionsRole", {
|
|
2222
|
-
assumedBy: new awsIam.FederatedPrincipal(oidcProviderArn, {
|
|
2223
|
-
StringLike: {
|
|
2224
|
-
"token.actions.githubusercontent.com:sub": repoRestriction,
|
|
2225
|
-
},
|
|
2226
|
-
}, "sts:AssumeRoleWithWebIdentity"),
|
|
2227
|
-
maxSessionDuration: cdk.Duration.hours(1),
|
|
2228
|
-
path: "/",
|
|
2229
|
-
});
|
|
2230
|
-
cdk.Tags.of(this._role).add(CDK$2.TAG.ROLE, CDK$2.ROLE.DEPLOY);
|
|
2231
|
-
// Allow the role to access the GitHub OIDC provider
|
|
2232
|
-
this._role.addToPolicy(new awsIam.PolicyStatement({
|
|
2233
|
-
actions: ["sts:AssumeRoleWithWebIdentity"],
|
|
2234
|
-
resources: [`arn:aws:iam::${accountId}:oidc-provider/*`],
|
|
2235
|
-
}));
|
|
2236
|
-
// Allow the role to deploy CDK apps
|
|
2237
|
-
this._role.addToPolicy(new awsIam.PolicyStatement({
|
|
2238
|
-
actions: [
|
|
2239
|
-
"cloudformation:CreateStack",
|
|
2240
|
-
"cloudformation:DeleteStack",
|
|
2241
|
-
"cloudformation:DescribeStackEvents",
|
|
2242
|
-
"cloudformation:DescribeStackResource",
|
|
2243
|
-
"cloudformation:DescribeStackResources",
|
|
2244
|
-
"cloudformation:DescribeStacks",
|
|
2245
|
-
"cloudformation:GetTemplate",
|
|
2246
|
-
"cloudformation:SetStackPolicy",
|
|
2247
|
-
"cloudformation:UpdateStack",
|
|
2248
|
-
"cloudformation:ValidateTemplate",
|
|
2249
|
-
"iam:PassRole",
|
|
2250
|
-
"route53:ListHostedZones*",
|
|
2251
|
-
"s3:GetObject",
|
|
2252
|
-
"s3:ListBucket",
|
|
2253
|
-
],
|
|
2254
|
-
effect: awsIam.Effect.ALLOW,
|
|
2255
|
-
resources: ["*"],
|
|
2256
|
-
}));
|
|
2257
|
-
this._role.addToPolicy(new awsIam.PolicyStatement({
|
|
2258
|
-
actions: ["iam:PassRole", "sts:AssumeRole"],
|
|
2259
|
-
effect: awsIam.Effect.ALLOW,
|
|
2260
|
-
resources: [
|
|
2261
|
-
"arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*",
|
|
2262
|
-
"arn:aws:iam::*:role/cdk-hnb659fds-file-publishing-*",
|
|
2263
|
-
"arn:aws:iam::*:role/cdk-readOnlyRole",
|
|
2264
|
-
],
|
|
2265
|
-
}));
|
|
2266
|
-
// Export the ARN of the role
|
|
2267
|
-
if (output !== false) {
|
|
2268
|
-
const outputId = typeof output === "string" ? output : "GitHubActionsRoleArn";
|
|
2269
|
-
new cdk.CfnOutput(this, outputId, {
|
|
2270
|
-
value: this._role.roleArn,
|
|
2271
|
-
});
|
|
2272
|
-
}
|
|
2273
|
-
}
|
|
2274
|
-
get role() {
|
|
2275
|
-
return this._role;
|
|
2276
|
-
}
|
|
2277
|
-
get roleArn() {
|
|
2278
|
-
return this._role.roleArn;
|
|
2279
|
-
}
|
|
2280
|
-
get roleName() {
|
|
2281
|
-
return this._role.roleName;
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
|
|
2285
|
-
class JaypieExpressLambda extends JaypieLambda {
|
|
2286
|
-
constructor(scope, id, props) {
|
|
2287
|
-
super(scope, id, {
|
|
2288
|
-
timeout: cdk.Duration.seconds(CDK$2.DURATION.EXPRESS_API),
|
|
2289
|
-
roleTag: CDK$2.ROLE.API,
|
|
2290
|
-
...props,
|
|
2291
|
-
});
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2294
|
-
|
|
2295
|
-
const SERVICE = {
|
|
2296
|
-
ROUTE53: "route53.amazonaws.com",
|
|
2297
|
-
};
|
|
2298
|
-
/**
|
|
2299
|
-
* Check if a string is a valid hostname
|
|
2300
|
-
*/
|
|
2301
|
-
function isValidHostname(str) {
|
|
2302
|
-
// Check if it contains a dot and matches hostname pattern
|
|
2303
|
-
if (!str.includes("."))
|
|
2304
|
-
return false;
|
|
2305
|
-
// Basic hostname validation: alphanumeric, hyphens, dots
|
|
2306
|
-
// Each label must start and end with alphanumeric
|
|
2307
|
-
const hostnameRegex = /^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,}$/i;
|
|
2308
|
-
return hostnameRegex.test(str);
|
|
2309
|
-
}
|
|
2310
|
-
class JaypieHostedZone extends constructs.Construct {
|
|
2311
|
-
/**
|
|
2312
|
-
* Create a new hosted zone with query logging and optional DNS records
|
|
2313
|
-
*/
|
|
2314
|
-
constructor(scope, idOrProps, propsOrRecords) {
|
|
2315
|
-
// Handle overloaded constructor signatures
|
|
2316
|
-
let props;
|
|
2317
|
-
let id;
|
|
2318
|
-
if (typeof idOrProps === "string") {
|
|
2319
|
-
// If it's a valid hostname, treat it as zoneName
|
|
2320
|
-
if (isValidHostname(idOrProps)) {
|
|
2321
|
-
// Third param can be props object or records array
|
|
2322
|
-
if (Array.isArray(propsOrRecords)) {
|
|
2323
|
-
props = { zoneName: idOrProps, records: propsOrRecords };
|
|
2324
|
-
}
|
|
2325
|
-
else {
|
|
2326
|
-
props = propsOrRecords || { zoneName: idOrProps };
|
|
2327
|
-
// Set zoneName if not already set
|
|
2328
|
-
if (!props.zoneName) {
|
|
2329
|
-
props = { ...props, zoneName: idOrProps };
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
// Use id from props if provided, otherwise derive from zoneName
|
|
2333
|
-
id = props.id || `${idOrProps}-HostedZone`;
|
|
2334
|
-
}
|
|
2335
|
-
else {
|
|
2336
|
-
// Otherwise treat it as an explicit id
|
|
2337
|
-
props = propsOrRecords;
|
|
2338
|
-
id = idOrProps;
|
|
2339
|
-
}
|
|
2340
|
-
}
|
|
2341
|
-
else {
|
|
2342
|
-
// idOrProps is props
|
|
2343
|
-
props = idOrProps;
|
|
2344
|
-
id = props.id || `${props.zoneName}-HostedZone`;
|
|
2345
|
-
}
|
|
2346
|
-
super(scope, id);
|
|
2347
|
-
const { zoneName, project } = props;
|
|
2348
|
-
const destination = props.destination ?? true;
|
|
2349
|
-
const service = props.service || CDK$2.SERVICE.INFRASTRUCTURE;
|
|
2350
|
-
// Create the log group
|
|
2351
|
-
this.logGroup = new logs.LogGroup(this, "LogGroup", {
|
|
2352
|
-
logGroupName: process.env.PROJECT_NONCE
|
|
2353
|
-
? `/aws/route53/${zoneName}-${process.env.PROJECT_NONCE}`
|
|
2354
|
-
: `/aws/route53/${zoneName}`,
|
|
2355
|
-
retention: logs.RetentionDays.ONE_WEEK,
|
|
2356
|
-
});
|
|
2357
|
-
// Add tags
|
|
2358
|
-
cdk__namespace.Tags.of(this.logGroup).add(CDK$2.TAG.SERVICE, service);
|
|
2359
|
-
cdk__namespace.Tags.of(this.logGroup).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
2360
|
-
if (project) {
|
|
2361
|
-
cdk__namespace.Tags.of(this.logGroup).add(CDK$2.TAG.PROJECT, project);
|
|
2362
|
-
}
|
|
2363
|
-
// Grant Route 53 permissions to write to the log group
|
|
2364
|
-
this.logGroup.grantWrite(new awsIam.ServicePrincipal(SERVICE.ROUTE53));
|
|
2365
|
-
// Add destination based on configuration
|
|
2366
|
-
if (destination !== false) {
|
|
2367
|
-
const lambdaDestination = destination === true
|
|
2368
|
-
? resolveDatadogLoggingDestination(scope)
|
|
2369
|
-
: destination;
|
|
2370
|
-
this.logGroup.addSubscriptionFilter("DatadogLambdaDestination", {
|
|
2371
|
-
destination: lambdaDestination,
|
|
2372
|
-
filterPattern: logs.FilterPattern.allEvents(),
|
|
2373
|
-
});
|
|
2374
|
-
}
|
|
2375
|
-
// Create the hosted zone
|
|
2376
|
-
this.hostedZone = new route53.HostedZone(this, "HostedZone", {
|
|
2377
|
-
queryLogsLogGroupArn: this.logGroup.logGroupArn,
|
|
2378
|
-
zoneName,
|
|
2379
|
-
});
|
|
2380
|
-
// Add tags
|
|
2381
|
-
cdk__namespace.Tags.of(this.hostedZone).add(CDK$2.TAG.SERVICE, service);
|
|
2382
|
-
cdk__namespace.Tags.of(this.hostedZone).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
2383
|
-
if (project) {
|
|
2384
|
-
cdk__namespace.Tags.of(this.hostedZone).add(CDK$2.TAG.PROJECT, project);
|
|
2385
|
-
}
|
|
2386
|
-
// Create DNS records if provided
|
|
2387
|
-
this.dnsRecords = [];
|
|
2388
|
-
if (props.records) {
|
|
2389
|
-
props.records.forEach((recordConfig, index) => {
|
|
2390
|
-
const { id, ...recordProps } = recordConfig;
|
|
2391
|
-
// Generate a default ID if not provided
|
|
2392
|
-
const recordId = id ||
|
|
2393
|
-
`${recordProps.type}${recordProps.recordName ? `-${recordProps.recordName}` : ""}-${index}`;
|
|
2394
|
-
const dnsRecord = new JaypieDnsRecord(this, recordId, {
|
|
2395
|
-
...recordProps,
|
|
2396
|
-
zone: this.hostedZone,
|
|
2397
|
-
});
|
|
2398
|
-
this.dnsRecords.push(dnsRecord);
|
|
2399
|
-
});
|
|
2400
|
-
}
|
|
2401
|
-
}
|
|
2402
|
-
}
|
|
2403
|
-
|
|
2404
|
-
const CDK = {
|
|
2405
|
-
TAG: {
|
|
2406
|
-
STACK_SHA: "stackSha",
|
|
2407
|
-
},
|
|
2408
|
-
};
|
|
2409
|
-
class JaypieInfrastructureStack extends JaypieStack {
|
|
2410
|
-
constructor(scope, id, props = {}) {
|
|
2411
|
-
const { key = "infra", ...stackProps } = props;
|
|
2412
|
-
// Handle stackName
|
|
2413
|
-
if (!stackProps.stackName) {
|
|
2414
|
-
stackProps.stackName = constructStackName(key);
|
|
2415
|
-
}
|
|
2416
|
-
super(scope, id, { key, ...stackProps });
|
|
2417
|
-
// Add infrastructure-specific tag
|
|
2418
|
-
if (process.env.CDK_ENV_INFRASTRUCTURE_STACK_SHA) {
|
|
2419
|
-
cdk.Tags.of(this).add(CDK.TAG.STACK_SHA, process.env.CDK_ENV_INFRASTRUCTURE_STACK_SHA);
|
|
2420
|
-
}
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
|
|
2424
|
-
class JaypieMongoDbSecret extends JaypieEnvSecret {
|
|
2425
|
-
constructor(scope, id = "MongoConnectionString", props) {
|
|
2426
|
-
const defaultProps = {
|
|
2427
|
-
envKey: "MONGODB_URI",
|
|
2428
|
-
roleTag: CDK$2.ROLE.STORAGE,
|
|
2429
|
-
vendorTag: CDK$2.VENDOR.MONGODB,
|
|
2430
|
-
...props,
|
|
2431
|
-
};
|
|
2432
|
-
super(scope, id, defaultProps);
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
|
|
2436
|
-
class JaypieNextJs extends constructs.Construct {
|
|
2437
|
-
constructor(scope, id, props) {
|
|
2438
|
-
super(scope, id);
|
|
2439
|
-
const domainName = props?.domainName || envHostname();
|
|
2440
|
-
this.domainName = domainName;
|
|
2441
|
-
const domainNameSanitized = domainName
|
|
2442
|
-
.replace(/\./g, "-")
|
|
2443
|
-
.replace(/[^a-zA-Z0-9]/g, "_");
|
|
2444
|
-
const envSecrets = props?.envSecrets || {};
|
|
2445
|
-
const nextjsPath = props?.nextjsPath?.startsWith("..")
|
|
2446
|
-
? path__namespace.join(process.cwd(), props.nextjsPath)
|
|
2447
|
-
: props?.nextjsPath || path__namespace.join(process.cwd(), "..", "nextjs");
|
|
2448
|
-
const paramsAndSecrets = resolveParamsAndSecrets();
|
|
2449
|
-
const secrets = props?.secrets || [];
|
|
2450
|
-
// Process secrets environment variables
|
|
2451
|
-
const secretsEnvironment = Object.entries(envSecrets).reduce((acc, [key, secret]) => ({
|
|
2452
|
-
...acc,
|
|
2453
|
-
[`SECRET_${key}`]: secret.secretName,
|
|
2454
|
-
}), {});
|
|
2455
|
-
// Process JaypieEnvSecret array
|
|
2456
|
-
const jaypieSecretsEnvironment = secrets.reduce((acc, secret) => {
|
|
2457
|
-
if (secret.envKey) {
|
|
2458
|
-
return {
|
|
2459
|
-
...acc,
|
|
2460
|
-
[`SECRET_${secret.envKey}`]: secret.secretName,
|
|
2461
|
-
};
|
|
2462
|
-
}
|
|
2463
|
-
return acc;
|
|
2464
|
-
}, {});
|
|
2465
|
-
// Process NEXT_PUBLIC_ environment variables
|
|
2466
|
-
const nextPublicEnv = Object.entries(process.env).reduce((acc, [key, value]) => {
|
|
2467
|
-
if (key.startsWith("NEXT_PUBLIC_") && value) {
|
|
2468
|
-
return {
|
|
2469
|
-
...acc,
|
|
2470
|
-
[key]: value,
|
|
2471
|
-
};
|
|
2472
|
-
}
|
|
2473
|
-
return acc;
|
|
2474
|
-
}, {});
|
|
2475
|
-
const nextjs = new cdkNextjsStandalone.Nextjs(this, "NextJsApp", {
|
|
2476
|
-
nextjsPath,
|
|
2477
|
-
domainProps: {
|
|
2478
|
-
domainName,
|
|
2479
|
-
hostedZone: resolveHostedZone(this, {
|
|
2480
|
-
zone: props?.hostedZone,
|
|
2481
|
-
}),
|
|
2482
|
-
},
|
|
2483
|
-
environment: {
|
|
2484
|
-
...jaypieLambdaEnv(),
|
|
2485
|
-
...secretsEnvironment,
|
|
2486
|
-
...jaypieSecretsEnvironment,
|
|
2487
|
-
...nextPublicEnv,
|
|
2488
|
-
NEXT_PUBLIC_SITE_URL: `https://${domainName}`,
|
|
2489
|
-
},
|
|
2490
|
-
overrides: {
|
|
2491
|
-
nextjsDistribution: {
|
|
2492
|
-
imageCachePolicyProps: {
|
|
2493
|
-
cachePolicyName: `NextJsImageCachePolicy-${domainNameSanitized}`,
|
|
2494
|
-
},
|
|
2495
|
-
serverCachePolicyProps: {
|
|
2496
|
-
cachePolicyName: `NextJsServerCachePolicy-${domainNameSanitized}`,
|
|
2497
|
-
},
|
|
2498
|
-
},
|
|
2499
|
-
nextjsImage: {
|
|
2500
|
-
functionProps: {
|
|
2501
|
-
paramsAndSecrets,
|
|
2502
|
-
},
|
|
2503
|
-
},
|
|
2504
|
-
nextjsServer: {
|
|
2505
|
-
functionProps: {
|
|
2506
|
-
paramsAndSecrets,
|
|
2507
|
-
},
|
|
2508
|
-
},
|
|
2509
|
-
},
|
|
2510
|
-
});
|
|
2511
|
-
addDatadogLayers(nextjs.imageOptimizationFunction);
|
|
2512
|
-
addDatadogLayers(nextjs.serverFunction.lambdaFunction);
|
|
2513
|
-
// Grant secret read permissions
|
|
2514
|
-
Object.values(envSecrets).forEach((secret) => {
|
|
2515
|
-
secret.grantRead(nextjs.serverFunction.lambdaFunction);
|
|
2516
|
-
});
|
|
2517
|
-
// Grant read permissions for JaypieEnvSecrets
|
|
2518
|
-
secrets.forEach((secret) => {
|
|
2519
|
-
secret.grantRead(nextjs.serverFunction.lambdaFunction);
|
|
2520
|
-
});
|
|
2521
|
-
}
|
|
2522
|
-
}
|
|
2523
|
-
|
|
2524
|
-
class JaypieOpenAiSecret extends JaypieEnvSecret {
|
|
2525
|
-
constructor(scope, id = "OpenAiApiKey", props) {
|
|
2526
|
-
const defaultProps = {
|
|
2527
|
-
envKey: "OPENAI_API_KEY",
|
|
2528
|
-
roleTag: CDK$2.ROLE.PROCESSING,
|
|
2529
|
-
vendorTag: CDK$2.VENDOR.OPENAI,
|
|
2530
|
-
...props,
|
|
2531
|
-
};
|
|
2532
|
-
super(scope, id, defaultProps);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
|
|
2536
|
-
class JaypieOrganizationTrail extends constructs.Construct {
|
|
2537
|
-
/**
|
|
2538
|
-
* Create a new organization CloudTrail with S3 bucket and lifecycle policies
|
|
2539
|
-
*/
|
|
2540
|
-
constructor(scope, idOrProps, propsOrUndefined) {
|
|
2541
|
-
// Handle overloaded constructor signatures
|
|
2542
|
-
let props;
|
|
2543
|
-
let id;
|
|
2544
|
-
if (typeof idOrProps === "string") {
|
|
2545
|
-
// First param is ID, second is props
|
|
2546
|
-
props = propsOrUndefined || {};
|
|
2547
|
-
id = idOrProps;
|
|
2548
|
-
}
|
|
2549
|
-
else {
|
|
2550
|
-
// First param is props
|
|
2551
|
-
props = idOrProps || {};
|
|
2552
|
-
const defaultName = process.env.PROJECT_NONCE
|
|
2553
|
-
? `organization-cloudtrail-${process.env.PROJECT_NONCE}`
|
|
2554
|
-
: "organization-cloudtrail";
|
|
2555
|
-
id = props.id || `${props.trailName || defaultName}-Trail`;
|
|
2556
|
-
}
|
|
2557
|
-
super(scope, id);
|
|
2558
|
-
// Resolve options with defaults
|
|
2559
|
-
const { bucketName = process.env.PROJECT_NONCE
|
|
2560
|
-
? `organization-cloudtrail-${process.env.PROJECT_NONCE}`
|
|
2561
|
-
: "organization-cloudtrail", enableDatadogNotifications = true, enableFileValidation = false, expirationDays = 365, glacierTransitionDays = 180, infrequentAccessTransitionDays = 30, project, service = CDK$2.SERVICE.INFRASTRUCTURE, trailName = process.env.PROJECT_NONCE
|
|
2562
|
-
? `organization-cloudtrail-${process.env.PROJECT_NONCE}`
|
|
2563
|
-
: "organization-cloudtrail", } = props;
|
|
2564
|
-
// Create the S3 bucket for CloudTrail logs
|
|
2565
|
-
this.bucket = new s3.Bucket(this, "Bucket", {
|
|
2566
|
-
accessControl: s3.BucketAccessControl.LOG_DELIVERY_WRITE,
|
|
2567
|
-
bucketName,
|
|
2568
|
-
lifecycleRules: [
|
|
2569
|
-
{
|
|
2570
|
-
expiration: cdk__namespace.Duration.days(expirationDays),
|
|
2571
|
-
transitions: [
|
|
2572
|
-
{
|
|
2573
|
-
storageClass: s3.StorageClass.INFREQUENT_ACCESS,
|
|
2574
|
-
transitionAfter: cdk__namespace.Duration.days(infrequentAccessTransitionDays),
|
|
2575
|
-
},
|
|
2576
|
-
{
|
|
2577
|
-
storageClass: s3.StorageClass.GLACIER,
|
|
2578
|
-
transitionAfter: cdk__namespace.Duration.days(glacierTransitionDays),
|
|
2579
|
-
},
|
|
2580
|
-
],
|
|
2581
|
-
},
|
|
2582
|
-
],
|
|
2583
|
-
});
|
|
2584
|
-
// Add CloudTrail bucket policies
|
|
2585
|
-
this.bucket.addToResourcePolicy(new awsIam.PolicyStatement({
|
|
2586
|
-
actions: ["s3:GetBucketAcl"],
|
|
2587
|
-
effect: awsIam.Effect.ALLOW,
|
|
2588
|
-
principals: [new awsIam.ServicePrincipal("cloudtrail.amazonaws.com")],
|
|
2589
|
-
resources: [this.bucket.bucketArn],
|
|
2590
|
-
}));
|
|
2591
|
-
this.bucket.addToResourcePolicy(new awsIam.PolicyStatement({
|
|
2592
|
-
actions: ["s3:PutObject"],
|
|
2593
|
-
conditions: {
|
|
2594
|
-
StringEquals: {
|
|
2595
|
-
"s3:x-amz-acl": "bucket-owner-full-control",
|
|
2596
|
-
},
|
|
2597
|
-
},
|
|
2598
|
-
effect: awsIam.Effect.ALLOW,
|
|
2599
|
-
principals: [new awsIam.ServicePrincipal("cloudtrail.amazonaws.com")],
|
|
2600
|
-
resources: [`${this.bucket.bucketArn}/*`],
|
|
2601
|
-
}));
|
|
2602
|
-
// Add tags to bucket
|
|
2603
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.SERVICE, service);
|
|
2604
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
2605
|
-
if (project) {
|
|
2606
|
-
cdk__namespace.Tags.of(this.bucket).add(CDK$2.TAG.PROJECT, project);
|
|
2607
|
-
}
|
|
2608
|
-
// Add Datadog notifications if enabled
|
|
2609
|
-
if (enableDatadogNotifications) {
|
|
2610
|
-
const datadogForwarderFunction = resolveDatadogForwarderFunction(scope);
|
|
2611
|
-
this.bucket.addEventNotification(s3.EventType.OBJECT_CREATED, new s3n.LambdaDestination(datadogForwarderFunction));
|
|
2612
|
-
}
|
|
2613
|
-
// Create the organization trail
|
|
2614
|
-
this.trail = new awsCloudtrail.Trail(this, "Trail", {
|
|
2615
|
-
bucket: this.bucket,
|
|
2616
|
-
enableFileValidation,
|
|
2617
|
-
isOrganizationTrail: true,
|
|
2618
|
-
managementEvents: awsCloudtrail.ReadWriteType.ALL,
|
|
2619
|
-
trailName,
|
|
2620
|
-
});
|
|
2621
|
-
// Add tags to trail
|
|
2622
|
-
cdk__namespace.Tags.of(this.trail).add(CDK$2.TAG.SERVICE, service);
|
|
2623
|
-
cdk__namespace.Tags.of(this.trail).add(CDK$2.TAG.ROLE, CDK$2.ROLE.MONITORING);
|
|
2624
|
-
if (project) {
|
|
2625
|
-
cdk__namespace.Tags.of(this.trail).add(CDK$2.TAG.PROJECT, project);
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
/**
|
|
2631
|
-
* JaypieSsoPermissions Construct
|
|
2632
|
-
*
|
|
2633
|
-
* Creates and manages AWS IAM Identity Center (SSO) permission sets and assignments
|
|
2634
|
-
*
|
|
2635
|
-
* @example
|
|
2636
|
-
* const permissionSets = new JaypieSsoPermissions(this, "PermissionSets", {
|
|
2637
|
-
* iamIdentityCenterArn: "arn:aws:sso:::instance/...",
|
|
2638
|
-
* administratorGroupId: "b4c8b438-4031-7000-782d-5046945fb956",
|
|
2639
|
-
* analystGroupId: "2488f4e8-d061-708e-abe1-c315f0e30005",
|
|
2640
|
-
* developerGroupId: "b438a4f8-e0e1-707c-c6e8-21841daf9ad1",
|
|
2641
|
-
* administratorAccountAssignments: {
|
|
2642
|
-
* "211125635435": ["Administrator", "Analyst", "Developer"],
|
|
2643
|
-
* "381492033431": ["Administrator", "Analyst"],
|
|
2644
|
-
* },
|
|
2645
|
-
* analystAccountAssignments: {
|
|
2646
|
-
* "211125635435": ["Analyst", "Developer"],
|
|
2647
|
-
* "381492033431": [],
|
|
2648
|
-
* },
|
|
2649
|
-
* developerAccountAssignments: {
|
|
2650
|
-
* "211125635435": ["Analyst", "Developer"],
|
|
2651
|
-
* "381492033431": [],
|
|
2652
|
-
* },
|
|
2653
|
-
* });
|
|
2654
|
-
*/
|
|
2655
|
-
class JaypieSsoPermissions extends constructs.Construct {
|
|
2656
|
-
constructor(scope, id, props) {
|
|
2657
|
-
super(scope, id);
|
|
2658
|
-
const { iamIdentityCenterArn: iamIdentityCenterArnProp, administratorGroupId, analystGroupId, developerGroupId, administratorAccountAssignments, analystAccountAssignments, developerAccountAssignments, } = props;
|
|
2659
|
-
const iamIdentityCenterArn = iamIdentityCenterArnProp || process.env.CDK_ENV_IAM_IDENTITY_CENTER_ARN;
|
|
2660
|
-
if (!iamIdentityCenterArn) {
|
|
2661
|
-
// If no IAM Identity Center ARN provided, skip SSO setup
|
|
2662
|
-
return;
|
|
2663
|
-
}
|
|
2664
|
-
//
|
|
2665
|
-
// Permission Sets
|
|
2666
|
-
//
|
|
2667
|
-
this.administratorPermissionSet = new awsSso.CfnPermissionSet(this, "AdministratorPermissionSet", {
|
|
2668
|
-
// Required
|
|
2669
|
-
instanceArn: iamIdentityCenterArn,
|
|
2670
|
-
name: "Administrator",
|
|
2671
|
-
// Optional
|
|
2672
|
-
description: "Unrestricted access",
|
|
2673
|
-
inlinePolicy: {
|
|
2674
|
-
Version: "2012-10-17",
|
|
2675
|
-
Statement: [
|
|
2676
|
-
{
|
|
2677
|
-
Effect: "Allow",
|
|
2678
|
-
Action: [
|
|
2679
|
-
"aws-portal:ViewUsage",
|
|
2680
|
-
"aws-portal:ViewBilling",
|
|
2681
|
-
"budgets:*",
|
|
2682
|
-
"cur:DescribeReportDefinitions",
|
|
2683
|
-
"cur:PutReportDefinition",
|
|
2684
|
-
"cur:DeleteReportDefinition",
|
|
2685
|
-
"cur:ModifyReportDefinition",
|
|
2686
|
-
],
|
|
2687
|
-
Resource: "*",
|
|
2688
|
-
},
|
|
2689
|
-
],
|
|
2690
|
-
},
|
|
2691
|
-
managedPolicies: [
|
|
2692
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess")
|
|
2693
|
-
.managedPolicyArn,
|
|
2694
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
2695
|
-
],
|
|
2696
|
-
sessionDuration: cdk.Duration.hours(1).toIsoString(),
|
|
2697
|
-
tags: [
|
|
2698
|
-
{
|
|
2699
|
-
key: CDK$2.TAG.SERVICE,
|
|
2700
|
-
value: CDK$2.SERVICE.SSO,
|
|
2701
|
-
},
|
|
2702
|
-
{
|
|
2703
|
-
key: CDK$2.TAG.ROLE,
|
|
2704
|
-
value: CDK$2.ROLE.SECURITY,
|
|
2705
|
-
},
|
|
2706
|
-
],
|
|
2707
|
-
});
|
|
2708
|
-
this.analystPermissionSet = new awsSso.CfnPermissionSet(this, "AnalystPermissionSet", {
|
|
2709
|
-
// Required
|
|
2710
|
-
instanceArn: iamIdentityCenterArn,
|
|
2711
|
-
name: "Analyst",
|
|
2712
|
-
// Optional
|
|
2713
|
-
description: "Read-only access; may expand to limited write access",
|
|
2714
|
-
inlinePolicy: {
|
|
2715
|
-
Version: "2012-10-17",
|
|
2716
|
-
Statement: [
|
|
2717
|
-
{
|
|
2718
|
-
Effect: "Allow",
|
|
2719
|
-
Action: [
|
|
2720
|
-
"aws-portal:ViewUsage",
|
|
2721
|
-
"aws-portal:ViewBilling",
|
|
2722
|
-
"budgets:Describe*",
|
|
2723
|
-
"budgets:View*",
|
|
2724
|
-
"ce:Get*",
|
|
2725
|
-
"ce:List*",
|
|
2726
|
-
"cloudformation:Describe*",
|
|
2727
|
-
"cloudformation:Get*",
|
|
2728
|
-
"cloudformation:List*",
|
|
2729
|
-
"cloudwatch:BatchGet*",
|
|
2730
|
-
"cloudwatch:Get*",
|
|
2731
|
-
"cloudwatch:List*",
|
|
2732
|
-
"cost-optimization-hub:Get*",
|
|
2733
|
-
"cost-optimization-hub:List*",
|
|
2734
|
-
"ec2:Describe*",
|
|
2735
|
-
"ec2:Get*",
|
|
2736
|
-
"ec2:List*",
|
|
2737
|
-
"ec2:Search*",
|
|
2738
|
-
"iam:Get*",
|
|
2739
|
-
"iam:List*",
|
|
2740
|
-
"iam:PassRole",
|
|
2741
|
-
"lambda:Get*",
|
|
2742
|
-
"lambda:List*",
|
|
2743
|
-
"logs:Describe*",
|
|
2744
|
-
"logs:Get*",
|
|
2745
|
-
"logs:List*",
|
|
2746
|
-
"pipes:Describe*",
|
|
2747
|
-
"pipes:List*",
|
|
2748
|
-
"s3:Get*",
|
|
2749
|
-
"s3:List*",
|
|
2750
|
-
"secretsmanager:GetRandomPassword",
|
|
2751
|
-
"secretsmanager:GetResourcePolicy",
|
|
2752
|
-
"secretsmanager:List*",
|
|
2753
|
-
"securityhub:Describe*",
|
|
2754
|
-
"securityhub:Get*",
|
|
2755
|
-
"securityhub:List*",
|
|
2756
|
-
"servicecatalog:Describe*",
|
|
2757
|
-
"sns:Get*",
|
|
2758
|
-
"sns:List*",
|
|
2759
|
-
"sqs:Get*",
|
|
2760
|
-
"sqs:List*",
|
|
2761
|
-
"states:Describe*",
|
|
2762
|
-
"states:Get*",
|
|
2763
|
-
"states:List*",
|
|
2764
|
-
"tag:*",
|
|
2765
|
-
"uxc:*",
|
|
2766
|
-
"xray:*",
|
|
2767
|
-
],
|
|
2768
|
-
Resource: "*",
|
|
2769
|
-
},
|
|
2770
|
-
],
|
|
2771
|
-
},
|
|
2772
|
-
managedPolicies: [
|
|
2773
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
2774
|
-
.managedPolicyArn,
|
|
2775
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
2776
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
2777
|
-
.managedPolicyArn,
|
|
2778
|
-
],
|
|
2779
|
-
sessionDuration: cdk.Duration.hours(12).toIsoString(),
|
|
2780
|
-
tags: [
|
|
2781
|
-
{
|
|
2782
|
-
key: CDK$2.TAG.SERVICE,
|
|
2783
|
-
value: CDK$2.SERVICE.SSO,
|
|
2784
|
-
},
|
|
2785
|
-
{
|
|
2786
|
-
key: CDK$2.TAG.ROLE,
|
|
2787
|
-
value: CDK$2.ROLE.SECURITY,
|
|
2788
|
-
},
|
|
2789
|
-
],
|
|
2790
|
-
});
|
|
2791
|
-
this.developerPermissionSet = new awsSso.CfnPermissionSet(this, "DeveloperPermissionSet", {
|
|
2792
|
-
// Required
|
|
2793
|
-
instanceArn: iamIdentityCenterArn,
|
|
2794
|
-
name: "Developer",
|
|
2795
|
-
// Optional
|
|
2796
|
-
description: "Administrative access with limited restrictions",
|
|
2797
|
-
inlinePolicy: {
|
|
2798
|
-
Version: "2012-10-17",
|
|
2799
|
-
Statement: [
|
|
2800
|
-
{
|
|
2801
|
-
Effect: "Allow",
|
|
2802
|
-
Action: [
|
|
2803
|
-
"budgets:*",
|
|
2804
|
-
"ce:*",
|
|
2805
|
-
"cloudformation:*",
|
|
2806
|
-
"cloudwatch:*",
|
|
2807
|
-
"cost-optimization-hub:*",
|
|
2808
|
-
"ec2:*",
|
|
2809
|
-
"iam:Get*",
|
|
2810
|
-
"iam:List*",
|
|
2811
|
-
"iam:PassRole",
|
|
2812
|
-
"lambda:*",
|
|
2813
|
-
"logs:*",
|
|
2814
|
-
"pipes:*",
|
|
2815
|
-
"s3:*",
|
|
2816
|
-
"secretsmanager:*",
|
|
2817
|
-
"securityhub:*",
|
|
2818
|
-
"servicecatalog:*",
|
|
2819
|
-
"sns:*",
|
|
2820
|
-
"sqs:*",
|
|
2821
|
-
"states:*",
|
|
2822
|
-
"tag:*",
|
|
2823
|
-
"uxc:*",
|
|
2824
|
-
"xray:*",
|
|
2825
|
-
],
|
|
2826
|
-
Resource: "*",
|
|
2827
|
-
},
|
|
2828
|
-
],
|
|
2829
|
-
},
|
|
2830
|
-
managedPolicies: [
|
|
2831
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
2832
|
-
.managedPolicyArn,
|
|
2833
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
2834
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
2835
|
-
.managedPolicyArn,
|
|
2836
|
-
awsIam.ManagedPolicy.fromAwsManagedPolicyName("job-function/SystemAdministrator").managedPolicyArn,
|
|
2837
|
-
],
|
|
2838
|
-
sessionDuration: cdk.Duration.hours(4).toIsoString(),
|
|
2839
|
-
tags: [
|
|
2840
|
-
{
|
|
2841
|
-
key: CDK$2.TAG.SERVICE,
|
|
2842
|
-
value: CDK$2.SERVICE.SSO,
|
|
2843
|
-
},
|
|
2844
|
-
{
|
|
2845
|
-
key: CDK$2.TAG.ROLE,
|
|
2846
|
-
value: CDK$2.ROLE.SECURITY,
|
|
2847
|
-
},
|
|
2848
|
-
],
|
|
2849
|
-
});
|
|
2850
|
-
// Map permission set names to their ARNs and labels
|
|
2851
|
-
const permissionSetMap = {
|
|
2852
|
-
Administrator: {
|
|
2853
|
-
arn: this.administratorPermissionSet.attrPermissionSetArn,
|
|
2854
|
-
label: "Administrator",
|
|
2855
|
-
},
|
|
2856
|
-
Analyst: {
|
|
2857
|
-
arn: this.analystPermissionSet.attrPermissionSetArn,
|
|
2858
|
-
label: "Analyst",
|
|
2859
|
-
},
|
|
2860
|
-
Developer: {
|
|
2861
|
-
arn: this.developerPermissionSet.attrPermissionSetArn,
|
|
2862
|
-
label: "Developer",
|
|
2863
|
-
},
|
|
2864
|
-
};
|
|
2865
|
-
//
|
|
2866
|
-
// Assignments
|
|
2867
|
-
//
|
|
2868
|
-
// Helper function to create assignments for a group
|
|
2869
|
-
const createAssignments = (groupId, accountAssignments) => {
|
|
2870
|
-
if (!groupId || !accountAssignments) {
|
|
2871
|
-
return; // Skip if group ID or assignments not provided
|
|
2872
|
-
}
|
|
2873
|
-
Object.keys(accountAssignments).forEach((accountId) => {
|
|
2874
|
-
const permissionSetNames = accountAssignments[accountId];
|
|
2875
|
-
permissionSetNames.forEach((permissionSetName) => {
|
|
2876
|
-
const permissionSet = permissionSetMap[permissionSetName];
|
|
2877
|
-
if (!permissionSet) {
|
|
2878
|
-
throw new errors.ConfigurationError(`Unknown permission set: ${permissionSetName}. Valid options: ${Object.keys(permissionSetMap).join(", ")}`);
|
|
2879
|
-
}
|
|
2880
|
-
const accountAssignment = new awsSso.CfnAssignment(this, `AccountAssignment-${accountId}-${permissionSet.label}Role-${groupId}Group`, {
|
|
2881
|
-
// Required
|
|
2882
|
-
instanceArn: iamIdentityCenterArn,
|
|
2883
|
-
permissionSetArn: permissionSet.arn,
|
|
2884
|
-
principalId: groupId,
|
|
2885
|
-
principalType: CDK$2.PRINCIPAL_TYPE.GROUP,
|
|
2886
|
-
targetId: accountId,
|
|
2887
|
-
targetType: CDK$2.TARGET_TYPE.AWS_ACCOUNT,
|
|
2888
|
-
});
|
|
2889
|
-
cdk.Tags.of(accountAssignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
2890
|
-
cdk.Tags.of(accountAssignment).add(CDK$2.TAG.ROLE, CDK$2.ROLE.SECURITY);
|
|
2891
|
-
});
|
|
2892
|
-
});
|
|
2893
|
-
};
|
|
2894
|
-
// Create assignments for each group
|
|
2895
|
-
createAssignments(administratorGroupId, administratorAccountAssignments);
|
|
2896
|
-
createAssignments(analystGroupId, analystAccountAssignments);
|
|
2897
|
-
createAssignments(developerGroupId, developerAccountAssignments);
|
|
2898
|
-
}
|
|
2899
|
-
}
|
|
2900
|
-
|
|
2901
|
-
//
|
|
2902
|
-
//
|
|
2903
|
-
// Constants
|
|
2904
|
-
//
|
|
2905
|
-
const DEFAULT_APPLICATION_ID = "arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync";
|
|
2906
|
-
const DEFAULT_APPLICATION_VERSION = "2.3.3";
|
|
2907
|
-
const DEFAULT_GOOGLE_GROUP_MATCH = "name:AWS*";
|
|
2908
|
-
//
|
|
2909
|
-
//
|
|
2910
|
-
// Class
|
|
2911
|
-
//
|
|
2912
|
-
class JaypieSsoSyncApplication extends constructs.Construct {
|
|
2913
|
-
constructor(scope, id = "SsoSyncApplication", props = {}) {
|
|
2914
|
-
super(scope, id);
|
|
2915
|
-
const { googleAdminEmail, googleAdminEmailEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_ADMIN_EMAIL", googleCredentials, googleCredentialsEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_CREDENTIALS", googleGroupMatch, googleGroupMatchEnvKey = "CDK_ENV_SSOSYNC_GOOGLE_GROUP_MATCH", identityStoreId, identityStoreIdEnvKey = "CDK_ENV_SSOSYNC_IDENTITY_STORE_ID", scimEndpointAccessToken, scimEndpointAccessTokenEnvKey = "CDK_ENV_SCIM_ENDPOINT_ACCESS_TOKEN", scimEndpointUrl, scimEndpointUrlEnvKey = "CDK_ENV_SSOSYNC_SCIM_ENDPOINT_URL", semanticVersion, semanticVersionEnvKey = "CDK_ENV_SSOSYNC_SEMANTIC_VERSION", ssoSyncApplicationId = DEFAULT_APPLICATION_ID, tags, } = props;
|
|
2916
|
-
// Resolve all values from props or environment variables
|
|
2917
|
-
const resolvedGoogleAdminEmail = googleAdminEmail || process.env[googleAdminEmailEnvKey];
|
|
2918
|
-
const resolvedGoogleCredentials = googleCredentials || process.env[googleCredentialsEnvKey];
|
|
2919
|
-
const resolvedGoogleGroupMatch = googleGroupMatch ||
|
|
2920
|
-
process.env[googleGroupMatchEnvKey] ||
|
|
2921
|
-
DEFAULT_GOOGLE_GROUP_MATCH;
|
|
2922
|
-
const resolvedIdentityStoreId = identityStoreId || process.env[identityStoreIdEnvKey];
|
|
2923
|
-
const resolvedScimEndpointAccessToken = scimEndpointAccessToken || process.env[scimEndpointAccessTokenEnvKey];
|
|
2924
|
-
const resolvedScimEndpointUrl = scimEndpointUrl || process.env[scimEndpointUrlEnvKey];
|
|
2925
|
-
const resolvedSemanticVersion = semanticVersion ||
|
|
2926
|
-
process.env[semanticVersionEnvKey] ||
|
|
2927
|
-
DEFAULT_APPLICATION_VERSION;
|
|
2928
|
-
// Validate required parameters
|
|
2929
|
-
const missingParams = [];
|
|
2930
|
-
if (!resolvedGoogleAdminEmail) {
|
|
2931
|
-
missingParams.push(`googleAdminEmail or ${googleAdminEmailEnvKey} environment variable`);
|
|
2932
|
-
}
|
|
2933
|
-
if (!resolvedGoogleCredentials) {
|
|
2934
|
-
missingParams.push(`googleCredentials or ${googleCredentialsEnvKey} environment variable`);
|
|
2935
|
-
}
|
|
2936
|
-
if (!resolvedIdentityStoreId) {
|
|
2937
|
-
missingParams.push(`identityStoreId or ${identityStoreIdEnvKey} environment variable`);
|
|
2938
|
-
}
|
|
2939
|
-
if (!resolvedScimEndpointAccessToken) {
|
|
2940
|
-
missingParams.push(`scimEndpointAccessToken or ${scimEndpointAccessTokenEnvKey} environment variable`);
|
|
2941
|
-
}
|
|
2942
|
-
if (!resolvedScimEndpointUrl) {
|
|
2943
|
-
missingParams.push(`scimEndpointUrl or ${scimEndpointUrlEnvKey} environment variable`);
|
|
2944
|
-
}
|
|
2945
|
-
if (missingParams.length > 0) {
|
|
2946
|
-
throw new errors.ConfigurationError(`JaypieSsoSyncApplication missing required configuration: ${missingParams.join(", ")}`);
|
|
2947
|
-
}
|
|
2948
|
-
// Create the SSO Sync Application
|
|
2949
|
-
// Type assertion is safe because we validated all required values above
|
|
2950
|
-
this._application = new awsSam.CfnApplication(this, "Application", {
|
|
2951
|
-
location: {
|
|
2952
|
-
applicationId: ssoSyncApplicationId,
|
|
2953
|
-
semanticVersion: resolvedSemanticVersion,
|
|
2954
|
-
},
|
|
2955
|
-
parameters: {
|
|
2956
|
-
GoogleAdminEmail: resolvedGoogleAdminEmail,
|
|
2957
|
-
GoogleCredentials: resolvedGoogleCredentials,
|
|
2958
|
-
GoogleGroupMatch: resolvedGoogleGroupMatch,
|
|
2959
|
-
IdentityStoreID: resolvedIdentityStoreId,
|
|
2960
|
-
Region: cdk.Stack.of(this).region,
|
|
2961
|
-
SCIMEndpointAccessToken: resolvedScimEndpointAccessToken,
|
|
2962
|
-
SCIMEndpointUrl: resolvedScimEndpointUrl,
|
|
2963
|
-
},
|
|
2964
|
-
});
|
|
2965
|
-
// Add tags
|
|
2966
|
-
const defaultTags = {
|
|
2967
|
-
[CDK$2.TAG.ROLE]: CDK$2.ROLE.SECURITY,
|
|
2968
|
-
};
|
|
2969
|
-
const allTags = { ...defaultTags, ...tags };
|
|
2970
|
-
Object.entries(allTags).forEach(([key, value]) => {
|
|
2971
|
-
cdk.Tags.of(this._application).add(key, value);
|
|
2972
|
-
});
|
|
2973
|
-
}
|
|
2974
|
-
get application() {
|
|
2975
|
-
return this._application;
|
|
2976
|
-
}
|
|
2977
|
-
}
|
|
2978
|
-
|
|
2979
|
-
class JaypieWebDeploymentBucket extends constructs.Construct {
|
|
2980
|
-
constructor(scope, id, props = {}) {
|
|
2981
|
-
super(scope, id);
|
|
2982
|
-
const roleTag = props.roleTag || CDK$2.ROLE.HOSTING;
|
|
2983
|
-
// Environment variable validation
|
|
2984
|
-
if (process.env.CDK_ENV_WEB_SUBDOMAIN &&
|
|
2985
|
-
!isValidSubdomain(process.env.CDK_ENV_WEB_SUBDOMAIN)) {
|
|
2986
|
-
throw new errors.ConfigurationError("CDK_ENV_WEB_SUBDOMAIN is not a valid subdomain");
|
|
2987
|
-
}
|
|
2988
|
-
if (process.env.CDK_ENV_WEB_HOSTED_ZONE &&
|
|
2989
|
-
!isValidHostname$1(process.env.CDK_ENV_WEB_HOSTED_ZONE)) {
|
|
2990
|
-
throw new errors.ConfigurationError("CDK_ENV_WEB_HOSTED_ZONE is not a valid hostname");
|
|
2991
|
-
}
|
|
2992
|
-
if (process.env.CDK_ENV_HOSTED_ZONE &&
|
|
2993
|
-
!isValidHostname$1(process.env.CDK_ENV_HOSTED_ZONE)) {
|
|
2994
|
-
throw new errors.ConfigurationError("CDK_ENV_HOSTED_ZONE is not a valid hostname");
|
|
2995
|
-
}
|
|
2996
|
-
// Determine host from props or environment
|
|
2997
|
-
let host = props.host;
|
|
2998
|
-
if (!host) {
|
|
2999
|
-
try {
|
|
3000
|
-
host =
|
|
3001
|
-
process.env.CDK_ENV_WEB_HOST ||
|
|
3002
|
-
mergeDomain(process.env.CDK_ENV_WEB_SUBDOMAIN || "", process.env.CDK_ENV_WEB_HOSTED_ZONE ||
|
|
3003
|
-
process.env.CDK_ENV_HOSTED_ZONE ||
|
|
3004
|
-
"");
|
|
3005
|
-
}
|
|
3006
|
-
catch {
|
|
3007
|
-
host = undefined;
|
|
3008
|
-
}
|
|
3009
|
-
}
|
|
3010
|
-
if (host && !isValidHostname$1(host)) {
|
|
3011
|
-
throw new errors.ConfigurationError("Host is not a valid hostname");
|
|
3012
|
-
}
|
|
3013
|
-
// Determine zone from props or environment
|
|
3014
|
-
const zone = props.zone ||
|
|
3015
|
-
process.env.CDK_ENV_WEB_HOSTED_ZONE ||
|
|
3016
|
-
process.env.CDK_ENV_HOSTED_ZONE;
|
|
3017
|
-
// Create the S3 bucket
|
|
3018
|
-
this.bucket = new s3__namespace.Bucket(this, "DestinationBucket", {
|
|
3019
|
-
accessControl: s3__namespace.BucketAccessControl.BUCKET_OWNER_FULL_CONTROL,
|
|
3020
|
-
autoDeleteObjects: true,
|
|
3021
|
-
blockPublicAccess: s3__namespace.BlockPublicAccess.BLOCK_ACLS_ONLY,
|
|
3022
|
-
bucketName: props.name || constructEnvName("web"),
|
|
3023
|
-
publicReadAccess: true,
|
|
3024
|
-
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
3025
|
-
versioned: false,
|
|
3026
|
-
websiteErrorDocument: "index.html",
|
|
3027
|
-
websiteIndexDocument: "index.html",
|
|
3028
|
-
...props,
|
|
3029
|
-
});
|
|
3030
|
-
// Delegate IBucket properties to the bucket
|
|
3031
|
-
this.bucketArn = this.bucket.bucketArn;
|
|
3032
|
-
this.bucketDomainName = this.bucket.bucketDomainName;
|
|
3033
|
-
this.bucketDualStackDomainName = this.bucket.bucketDualStackDomainName;
|
|
3034
|
-
this.bucketName = this.bucket.bucketName;
|
|
3035
|
-
this.bucketRegionalDomainName = this.bucket.bucketRegionalDomainName;
|
|
3036
|
-
this.bucketWebsiteDomainName = this.bucket.bucketWebsiteDomainName;
|
|
3037
|
-
this.bucketWebsiteUrl = this.bucket.bucketWebsiteUrl;
|
|
3038
|
-
this.encryptionKey = this.bucket.encryptionKey;
|
|
3039
|
-
this.isWebsite = this.bucket.isWebsite;
|
|
3040
|
-
this.notificationsHandlerRole = undefined;
|
|
3041
|
-
this.policy = this.bucket.policy;
|
|
3042
|
-
cdk.Tags.of(this.bucket).add(CDK$2.TAG.ROLE, roleTag);
|
|
3043
|
-
// Create deployment role if repository is configured
|
|
3044
|
-
let repo;
|
|
3045
|
-
if (process.env.CDK_ENV_REPO) {
|
|
3046
|
-
repo = `repo:${process.env.CDK_ENV_REPO}:*`;
|
|
3047
|
-
}
|
|
3048
|
-
if (repo) {
|
|
3049
|
-
const bucketDeployRole = new awsIam.Role(this, "DestinationBucketDeployRole", {
|
|
3050
|
-
assumedBy: new awsIam.FederatedPrincipal(cdk.Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), {
|
|
3051
|
-
StringLike: {
|
|
3052
|
-
"token.actions.githubusercontent.com:sub": repo,
|
|
3053
|
-
},
|
|
3054
|
-
}, "sts:AssumeRoleWithWebIdentity"),
|
|
3055
|
-
maxSessionDuration: cdk.Duration.hours(1),
|
|
3056
|
-
});
|
|
3057
|
-
cdk.Tags.of(bucketDeployRole).add(CDK$2.TAG.ROLE, CDK$2.ROLE.DEPLOY);
|
|
3058
|
-
// Allow the role to write to the bucket
|
|
3059
|
-
bucketDeployRole.addToPolicy(new awsIam.PolicyStatement({
|
|
3060
|
-
effect: awsIam.Effect.ALLOW,
|
|
3061
|
-
actions: [
|
|
3062
|
-
"s3:DeleteObject",
|
|
3063
|
-
"s3:GetObject",
|
|
3064
|
-
"s3:ListObjectsV2",
|
|
3065
|
-
"s3:PutObject",
|
|
3066
|
-
],
|
|
3067
|
-
resources: [`${this.bucket.bucketArn}/*`],
|
|
3068
|
-
}));
|
|
3069
|
-
bucketDeployRole.addToPolicy(new awsIam.PolicyStatement({
|
|
3070
|
-
effect: awsIam.Effect.ALLOW,
|
|
3071
|
-
actions: ["s3:ListBucket"],
|
|
3072
|
-
resources: [this.bucket.bucketArn],
|
|
3073
|
-
}));
|
|
3074
|
-
// Allow the role to describe the current stack
|
|
3075
|
-
const stack = cdk.Stack.of(this);
|
|
3076
|
-
bucketDeployRole.addToPolicy(new awsIam.PolicyStatement({
|
|
3077
|
-
actions: ["cloudformation:DescribeStacks"],
|
|
3078
|
-
effect: awsIam.Effect.ALLOW,
|
|
3079
|
-
resources: [
|
|
3080
|
-
`arn:aws:cloudformation:${stack.region}:${stack.account}:stack/${stack.stackName}/*`,
|
|
3081
|
-
],
|
|
3082
|
-
}));
|
|
3083
|
-
this.deployRoleArn = bucketDeployRole.roleArn;
|
|
3084
|
-
// Output the deploy role ARN
|
|
3085
|
-
new cdk.CfnOutput(this, "DestinationBucketDeployRoleArn", {
|
|
3086
|
-
value: bucketDeployRole.roleArn,
|
|
3087
|
-
});
|
|
3088
|
-
}
|
|
3089
|
-
// Create CloudFront distribution and certificate if host and zone are provided
|
|
3090
|
-
if (host && zone) {
|
|
3091
|
-
let hostedZone;
|
|
3092
|
-
if (typeof zone === "string") {
|
|
3093
|
-
hostedZone = route53__namespace.HostedZone.fromLookup(this, "HostedZone", {
|
|
3094
|
-
domainName: zone,
|
|
3095
|
-
});
|
|
3096
|
-
}
|
|
3097
|
-
else if (zone instanceof JaypieHostedZone) {
|
|
3098
|
-
hostedZone = zone.hostedZone;
|
|
3099
|
-
}
|
|
3100
|
-
else {
|
|
3101
|
-
hostedZone = zone;
|
|
3102
|
-
}
|
|
3103
|
-
// Create certificate if not provided
|
|
3104
|
-
if (props.certificate !== false) {
|
|
3105
|
-
this.certificate =
|
|
3106
|
-
typeof props.certificate === "object"
|
|
3107
|
-
? props.certificate
|
|
3108
|
-
: new acm__namespace.Certificate(this, "Certificate", {
|
|
3109
|
-
domainName: host,
|
|
3110
|
-
validation: acm__namespace.CertificateValidation.fromDns(hostedZone),
|
|
3111
|
-
});
|
|
3112
|
-
new cdk.CfnOutput(this, "CertificateArn", {
|
|
3113
|
-
value: this.certificate.certificateArn,
|
|
3114
|
-
});
|
|
3115
|
-
cdk.Tags.of(this.certificate).add(CDK$2.TAG.ROLE, roleTag);
|
|
3116
|
-
}
|
|
3117
|
-
// Create CloudFront distribution
|
|
3118
|
-
this.distribution = new cloudfront__namespace.Distribution(this, "Distribution", {
|
|
3119
|
-
defaultBehavior: {
|
|
3120
|
-
cachePolicy: cloudfront__namespace.CachePolicy.CACHING_DISABLED,
|
|
3121
|
-
origin: new origins__namespace.S3StaticWebsiteOrigin(this.bucket),
|
|
3122
|
-
viewerProtocolPolicy: cloudfront__namespace.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
3123
|
-
},
|
|
3124
|
-
certificate: this.certificate,
|
|
3125
|
-
domainNames: [host],
|
|
3126
|
-
});
|
|
3127
|
-
cdk.Tags.of(this.distribution).add(CDK$2.TAG.ROLE, roleTag);
|
|
3128
|
-
// If this is production, enable caching on everything but index.html
|
|
3129
|
-
if (isProductionEnv()) {
|
|
3130
|
-
this.distribution.addBehavior("/*", new origins__namespace.S3StaticWebsiteOrigin(this.bucket), {
|
|
3131
|
-
viewerProtocolPolicy: cloudfront__namespace.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
|
|
3132
|
-
cachePolicy: cloudfront__namespace.CachePolicy.CACHING_OPTIMIZED,
|
|
3133
|
-
});
|
|
3134
|
-
}
|
|
3135
|
-
// Create DNS record
|
|
3136
|
-
const record = new route53__namespace.ARecord(this, "AliasRecord", {
|
|
3137
|
-
recordName: host,
|
|
3138
|
-
target: route53__namespace.RecordTarget.fromAlias(new route53Targets__namespace.CloudFrontTarget(this.distribution)),
|
|
3139
|
-
zone: hostedZone,
|
|
3140
|
-
});
|
|
3141
|
-
cdk.Tags.of(record).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
3142
|
-
this.distributionDomainName = this.distribution.distributionDomainName;
|
|
3143
|
-
}
|
|
3144
|
-
}
|
|
3145
|
-
// Implement remaining IBucket methods by delegating to the bucket
|
|
3146
|
-
addEventNotification(event, dest, ...filters) {
|
|
3147
|
-
this.bucket.addEventNotification(event, dest, ...filters);
|
|
3148
|
-
}
|
|
3149
|
-
addObjectCreatedNotification(dest, ...filters) {
|
|
3150
|
-
this.bucket.addObjectCreatedNotification(dest, ...filters);
|
|
3151
|
-
}
|
|
3152
|
-
addObjectRemovedNotification(dest, ...filters) {
|
|
3153
|
-
this.bucket.addObjectRemovedNotification(dest, ...filters);
|
|
3154
|
-
}
|
|
3155
|
-
addToResourcePolicy(permission) {
|
|
3156
|
-
return this.bucket.addToResourcePolicy(permission);
|
|
3157
|
-
}
|
|
3158
|
-
arnForObjects(keyPattern) {
|
|
3159
|
-
return this.bucket.arnForObjects(keyPattern);
|
|
3160
|
-
}
|
|
3161
|
-
grantDelete(identity, objectsKeyPattern) {
|
|
3162
|
-
return this.bucket.grantDelete(identity, objectsKeyPattern);
|
|
3163
|
-
}
|
|
3164
|
-
grantPublicAccess(allowedActions, keyPrefix) {
|
|
3165
|
-
return keyPrefix
|
|
3166
|
-
? this.bucket.grantPublicAccess(allowedActions, keyPrefix)
|
|
3167
|
-
: this.bucket.grantPublicAccess(allowedActions);
|
|
3168
|
-
}
|
|
3169
|
-
grantPut(identity, objectsKeyPattern) {
|
|
3170
|
-
return this.bucket.grantPut(identity, objectsKeyPattern);
|
|
3171
|
-
}
|
|
3172
|
-
grantPutAcl(identity, objectsKeyPattern) {
|
|
3173
|
-
return this.bucket.grantPutAcl(identity, objectsKeyPattern);
|
|
3174
|
-
}
|
|
3175
|
-
grantRead(identity, objectsKeyPattern) {
|
|
3176
|
-
return this.bucket.grantRead(identity, objectsKeyPattern);
|
|
3177
|
-
}
|
|
3178
|
-
grantReadWrite(identity, objectsKeyPattern) {
|
|
3179
|
-
return this.bucket.grantReadWrite(identity, objectsKeyPattern);
|
|
3180
|
-
}
|
|
3181
|
-
grantWrite(identity, objectsKeyPattern) {
|
|
3182
|
-
return this.bucket.grantWrite(identity, objectsKeyPattern);
|
|
3183
|
-
}
|
|
3184
|
-
grantReplicationPermission(identity, props) {
|
|
3185
|
-
return this.bucket.grantReplicationPermission(identity, props);
|
|
3186
|
-
}
|
|
3187
|
-
s3UrlForObject(key) {
|
|
3188
|
-
return this.bucket.s3UrlForObject(key);
|
|
3189
|
-
}
|
|
3190
|
-
urlForObject(key) {
|
|
3191
|
-
return this.bucket.urlForObject(key);
|
|
3192
|
-
}
|
|
3193
|
-
virtualHostedUrlForObject(key, options) {
|
|
3194
|
-
return this.bucket.virtualHostedUrlForObject(key, options);
|
|
3195
|
-
}
|
|
3196
|
-
transferAccelerationUrlForObject(key) {
|
|
3197
|
-
return this.bucket.transferAccelerationUrlForObject(key);
|
|
3198
|
-
}
|
|
3199
|
-
onCloudTrailEvent(id, options) {
|
|
3200
|
-
return this.bucket.onCloudTrailEvent(id, options);
|
|
3201
|
-
}
|
|
3202
|
-
onCloudTrailPutObject(id, options) {
|
|
3203
|
-
return this.bucket.onCloudTrailPutObject(id, options);
|
|
3204
|
-
}
|
|
3205
|
-
onCloudTrailWriteObject(id, options) {
|
|
3206
|
-
return this.bucket.onCloudTrailWriteObject(id, options);
|
|
3207
|
-
}
|
|
3208
|
-
addCorsRule(rule) {
|
|
3209
|
-
this.bucket.addCorsRule(rule);
|
|
3210
|
-
}
|
|
3211
|
-
addInventory(inventory) {
|
|
3212
|
-
this.bucket.addInventory(inventory);
|
|
3213
|
-
}
|
|
3214
|
-
addLifecycleRule(rule) {
|
|
3215
|
-
this.bucket.addLifecycleRule(rule);
|
|
3216
|
-
}
|
|
3217
|
-
addMetric(metric) {
|
|
3218
|
-
this.bucket.addMetric(metric);
|
|
3219
|
-
}
|
|
3220
|
-
enableEventBridgeNotification() {
|
|
3221
|
-
this.bucket.enableEventBridgeNotification();
|
|
3222
|
-
}
|
|
3223
|
-
addReplicationPolicy(policy) {
|
|
3224
|
-
this.bucket.addReplicationPolicy(policy);
|
|
3225
|
-
}
|
|
3226
|
-
get stack() {
|
|
3227
|
-
return this.bucket.stack;
|
|
3228
|
-
}
|
|
3229
|
-
get env() {
|
|
3230
|
-
return this.bucket.env;
|
|
3231
|
-
}
|
|
3232
|
-
applyRemovalPolicy(policy) {
|
|
3233
|
-
this.bucket.applyRemovalPolicy(policy);
|
|
3234
|
-
}
|
|
3235
|
-
get bucketRef() {
|
|
3236
|
-
return {
|
|
3237
|
-
bucketArn: this.bucket.bucketArn,
|
|
3238
|
-
bucketName: this.bucket.bucketName,
|
|
3239
|
-
};
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
|
|
3243
|
-
class JaypieStaticWebBucket extends JaypieWebDeploymentBucket {
|
|
3244
|
-
constructor(scope, id, props = {}) {
|
|
3245
|
-
// Handle overloaded signatures: (scope), (scope, props), (scope, id, props)
|
|
3246
|
-
let resolvedId;
|
|
3247
|
-
let resolvedProps;
|
|
3248
|
-
if (typeof id === "string") {
|
|
3249
|
-
resolvedId = id;
|
|
3250
|
-
resolvedProps = props;
|
|
3251
|
-
}
|
|
3252
|
-
else if (typeof id === "object") {
|
|
3253
|
-
resolvedId = "JaypieStaticWebBucket";
|
|
3254
|
-
resolvedProps = id;
|
|
3255
|
-
}
|
|
3256
|
-
else {
|
|
3257
|
-
resolvedId = "JaypieStaticWebBucket";
|
|
3258
|
-
resolvedProps = props;
|
|
3259
|
-
}
|
|
3260
|
-
const host = resolvedProps.host ?? envHostname({ subdomain: "static" });
|
|
3261
|
-
const name = resolvedProps.name ?? constructEnvName("static");
|
|
3262
|
-
const roleTag = resolvedProps.roleTag ?? CDK$2.ROLE.HOSTING;
|
|
3263
|
-
// Only use default zone if zone is not explicitly provided (including undefined)
|
|
3264
|
-
const zone = "zone" in resolvedProps
|
|
3265
|
-
? resolvedProps.zone
|
|
3266
|
-
: process.env.CDK_ENV_DOMAIN || process.env.CDK_ENV_HOSTED_ZONE;
|
|
3267
|
-
super(scope, resolvedId, {
|
|
3268
|
-
...resolvedProps,
|
|
3269
|
-
host,
|
|
3270
|
-
name,
|
|
3271
|
-
roleTag,
|
|
3272
|
-
zone,
|
|
3273
|
-
});
|
|
3274
|
-
}
|
|
3275
|
-
}
|
|
3276
|
-
|
|
3277
|
-
class JaypieTraceSigningKeySecret extends JaypieEnvSecret {
|
|
3278
|
-
constructor(scope, id = "TraceSigningKey", props) {
|
|
3279
|
-
const defaultProps = {
|
|
3280
|
-
envKey: "TRACE_SIGNING_KEY",
|
|
3281
|
-
roleTag: CDK$2.ROLE.API,
|
|
3282
|
-
vendorTag: CDK$2.VENDOR.KNOWTRACE,
|
|
3283
|
-
...props,
|
|
3284
|
-
};
|
|
3285
|
-
super(scope, id, defaultProps);
|
|
3286
|
-
}
|
|
3287
|
-
}
|
|
3288
|
-
|
|
3289
|
-
exports.CDK = CDK$2;
|
|
3290
|
-
exports.JaypieAccountLoggingBucket = JaypieAccountLoggingBucket;
|
|
3291
|
-
exports.JaypieApiGateway = JaypieApiGateway;
|
|
3292
|
-
exports.JaypieAppStack = JaypieAppStack;
|
|
3293
|
-
exports.JaypieBucketQueuedLambda = JaypieBucketQueuedLambda;
|
|
3294
|
-
exports.JaypieDatadogBucket = JaypieDatadogBucket;
|
|
3295
|
-
exports.JaypieDatadogForwarder = JaypieDatadogForwarder;
|
|
3296
|
-
exports.JaypieDatadogSecret = JaypieDatadogSecret;
|
|
3297
|
-
exports.JaypieDistribution = JaypieDistribution;
|
|
3298
|
-
exports.JaypieDnsRecord = JaypieDnsRecord;
|
|
3299
|
-
exports.JaypieEnvSecret = JaypieEnvSecret;
|
|
3300
|
-
exports.JaypieEventsRule = JaypieEventsRule;
|
|
3301
|
-
exports.JaypieExpressLambda = JaypieExpressLambda;
|
|
3302
|
-
exports.JaypieGitHubDeployRole = JaypieGitHubDeployRole;
|
|
3303
|
-
exports.JaypieHostedZone = JaypieHostedZone;
|
|
3304
|
-
exports.JaypieInfrastructureStack = JaypieInfrastructureStack;
|
|
3305
|
-
exports.JaypieLambda = JaypieLambda;
|
|
3306
|
-
exports.JaypieMongoDbSecret = JaypieMongoDbSecret;
|
|
3307
|
-
exports.JaypieNextJs = JaypieNextJs;
|
|
3308
|
-
exports.JaypieOpenAiSecret = JaypieOpenAiSecret;
|
|
3309
|
-
exports.JaypieOrganizationTrail = JaypieOrganizationTrail;
|
|
3310
|
-
exports.JaypieQueuedLambda = JaypieQueuedLambda;
|
|
3311
|
-
exports.JaypieSsoPermissions = JaypieSsoPermissions;
|
|
3312
|
-
exports.JaypieSsoSyncApplication = JaypieSsoSyncApplication;
|
|
3313
|
-
exports.JaypieStack = JaypieStack;
|
|
3314
|
-
exports.JaypieStaticWebBucket = JaypieStaticWebBucket;
|
|
3315
|
-
exports.JaypieTraceSigningKeySecret = JaypieTraceSigningKeySecret;
|
|
3316
|
-
exports.JaypieWebDeploymentBucket = JaypieWebDeploymentBucket;
|
|
3317
|
-
exports.addDatadogLayers = addDatadogLayers;
|
|
3318
|
-
exports.constructEnvName = constructEnvName;
|
|
3319
|
-
exports.constructStackName = constructStackName;
|
|
3320
|
-
exports.constructTagger = constructTagger;
|
|
3321
|
-
exports.envHostname = envHostname;
|
|
3322
|
-
exports.extendDatadogRole = extendDatadogRole;
|
|
3323
|
-
exports.isEnv = isEnv;
|
|
3324
|
-
exports.isProductionEnv = isProductionEnv;
|
|
3325
|
-
exports.isSandboxEnv = isSandboxEnv;
|
|
3326
|
-
exports.isValidHostname = isValidHostname$1;
|
|
3327
|
-
exports.isValidSubdomain = isValidSubdomain;
|
|
3328
|
-
exports.jaypieLambdaEnv = jaypieLambdaEnv;
|
|
3329
|
-
exports.mergeDomain = mergeDomain;
|
|
3330
|
-
exports.resolveDatadogForwarderFunction = resolveDatadogForwarderFunction;
|
|
3331
|
-
exports.resolveDatadogLayers = resolveDatadogLayers;
|
|
3332
|
-
exports.resolveDatadogLoggingDestination = resolveDatadogLoggingDestination;
|
|
3333
|
-
exports.resolveHostedZone = resolveHostedZone;
|
|
3334
|
-
exports.resolveParamsAndSecrets = resolveParamsAndSecrets;
|
|
3335
|
-
//# sourceMappingURL=index.cjs.map
|