@jaypie/constructs 1.1.48 → 1.1.50
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/dist/cjs/JaypieApiGateway.d.ts +1 -0
- package/dist/cjs/JaypieBucketQueuedLambda.d.ts +4 -19
- package/dist/cjs/JaypieDnsRecord.d.ts +45 -0
- package/dist/cjs/JaypieGitHubDeployRole.d.ts +15 -0
- package/dist/cjs/JaypieHostedZone.d.ts +26 -4
- package/dist/cjs/JaypieLambda.d.ts +1 -1
- package/dist/cjs/JaypieQueuedLambda.d.ts +1 -1
- package/dist/cjs/JaypieSsoPermissions.d.ts +95 -0
- package/dist/cjs/JaypieSsoSyncApplication.d.ts +27 -0
- package/dist/cjs/JaypieWebDeploymentBucket.d.ts +1 -0
- package/dist/cjs/__tests__/JaypieSsoSyncApplication.spec.d.ts +1 -0
- package/dist/cjs/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +1 -0
- package/dist/cjs/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +1 -0
- package/dist/cjs/helpers/index.d.ts +2 -0
- package/dist/cjs/helpers/resolveDatadogForwarderFunction.d.ts +7 -0
- package/dist/cjs/helpers/resolveDatadogLoggingDestination.d.ts +4 -0
- package/dist/cjs/index.cjs +599 -308
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.ts +6 -2
- package/dist/esm/JaypieApiGateway.d.ts +1 -0
- package/dist/esm/JaypieBucketQueuedLambda.d.ts +4 -19
- package/dist/esm/JaypieDnsRecord.d.ts +45 -0
- package/dist/esm/JaypieGitHubDeployRole.d.ts +15 -0
- package/dist/esm/JaypieHostedZone.d.ts +26 -4
- package/dist/esm/JaypieLambda.d.ts +1 -1
- package/dist/esm/JaypieQueuedLambda.d.ts +1 -1
- package/dist/esm/JaypieSsoPermissions.d.ts +95 -0
- package/dist/esm/JaypieSsoSyncApplication.d.ts +27 -0
- package/dist/esm/JaypieWebDeploymentBucket.d.ts +1 -0
- package/dist/esm/__tests__/JaypieDnsRecord.spec.d.ts +1 -0
- package/dist/esm/__tests__/JaypieSsoPermissions.spec.d.ts +1 -0
- package/dist/esm/__tests__/JaypieSsoSyncApplication.spec.d.ts +1 -0
- package/dist/esm/helpers/__tests__/resolveDatadogForwarderFunction.spec.d.ts +1 -0
- package/dist/esm/helpers/__tests__/resolveDatadogLoggingDestination.spec.d.ts +1 -0
- package/dist/esm/helpers/index.d.ts +2 -0
- package/dist/esm/helpers/resolveDatadogForwarderFunction.d.ts +7 -0
- package/dist/esm/helpers/resolveDatadogLoggingDestination.d.ts +4 -0
- package/dist/esm/index.d.ts +6 -2
- package/dist/esm/index.js +592 -309
- package/dist/esm/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/cjs/JaypieSsoGroups.d.ts +0 -121
- package/dist/esm/JaypieSsoGroups.d.ts +0 -121
- /package/dist/cjs/__tests__/{JaypieSsoGroups.spec.d.ts → JaypieDnsRecord.spec.d.ts} +0 -0
- /package/dist/{esm/__tests__/JaypieSsoGroups.spec.d.ts → cjs/__tests__/JaypieSsoPermissions.spec.d.ts} +0 -0
package/dist/esm/index.js
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
|
+
import { CDK as CDK$2, ConfigurationError, mergeDomain, isValidSubdomain, isValidHostname } from '@jaypie/cdk';
|
|
2
|
+
export { CDK } from '@jaypie/cdk';
|
|
1
3
|
import { Construct } from 'constructs';
|
|
2
4
|
import * as cdk from 'aws-cdk-lib';
|
|
3
5
|
import { Tags, Stack, Duration, RemovalPolicy, Fn, CfnOutput, SecretValue } from 'aws-cdk-lib';
|
|
4
6
|
import * as acm from 'aws-cdk-lib/aws-certificatemanager';
|
|
5
7
|
import * as apiGateway from 'aws-cdk-lib/aws-apigateway';
|
|
6
8
|
import * as route53 from 'aws-cdk-lib/aws-route53';
|
|
7
|
-
import { HostedZone } from 'aws-cdk-lib/aws-route53';
|
|
9
|
+
import { TxtRecord, NsRecord, MxRecord, CnameRecord, ARecord, RecordTarget, HostedZone } from 'aws-cdk-lib/aws-route53';
|
|
8
10
|
import * as route53Targets from 'aws-cdk-lib/aws-route53-targets';
|
|
9
|
-
import { CDK as CDK$2, ConfigurationError, mergeDomain, isValidSubdomain, isValidHostname } from '@jaypie/cdk';
|
|
10
11
|
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
|
|
11
12
|
import { DatadogLambda } from 'datadog-cdk-constructs-v2';
|
|
12
13
|
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
14
|
+
import * as logDestinations from 'aws-cdk-lib/aws-logs-destinations';
|
|
13
15
|
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
14
16
|
import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
|
|
15
17
|
import * as sqs from 'aws-cdk-lib/aws-sqs';
|
|
16
18
|
import * as lambdaEventSources from 'aws-cdk-lib/aws-lambda-event-sources';
|
|
17
|
-
import {
|
|
19
|
+
import { Role, FederatedPrincipal, PolicyStatement, Effect, ServicePrincipal, ManagedPolicy } from 'aws-cdk-lib/aws-iam';
|
|
18
20
|
import { LogGroup, RetentionDays, FilterPattern } from 'aws-cdk-lib/aws-logs';
|
|
19
|
-
import
|
|
21
|
+
import { CfnPermissionSet, CfnAssignment } from 'aws-cdk-lib/aws-sso';
|
|
22
|
+
import { CfnApplication } from 'aws-cdk-lib/aws-sam';
|
|
23
|
+
import { ConfigurationError as ConfigurationError$1 } from '@jaypie/errors';
|
|
20
24
|
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
|
|
21
25
|
import * as origins from 'aws-cdk-lib/aws-cloudfront-origins';
|
|
22
26
|
|
|
@@ -215,6 +219,33 @@ function jaypieLambdaEnv(options = {}) {
|
|
|
215
219
|
return environment;
|
|
216
220
|
}
|
|
217
221
|
|
|
222
|
+
const DEFAULT_FUNCTION_NAME$1 = "DatadogForwarderFunction";
|
|
223
|
+
// Cache to store resolved functions
|
|
224
|
+
// Using nested structure to support multiple functions per scope with automatic GC
|
|
225
|
+
const functionCache = new WeakMap();
|
|
226
|
+
function resolveDatadogForwarderFunction(scope, options) {
|
|
227
|
+
const { import: importValue, name } = options || {};
|
|
228
|
+
const functionName = name || DEFAULT_FUNCTION_NAME$1;
|
|
229
|
+
const importKey = importValue || CDK$2.IMPORT.DATADOG_LOG_FORWARDER;
|
|
230
|
+
// Create a cache key based on name and import
|
|
231
|
+
const cacheKey = `${functionName}:${importKey}`;
|
|
232
|
+
// Get or create scope cache
|
|
233
|
+
let scopeCache = functionCache.get(scope);
|
|
234
|
+
if (!scopeCache) {
|
|
235
|
+
scopeCache = new Map();
|
|
236
|
+
functionCache.set(scope, scopeCache);
|
|
237
|
+
}
|
|
238
|
+
// Return cached function if it exists
|
|
239
|
+
const cachedFunction = scopeCache.get(cacheKey);
|
|
240
|
+
if (cachedFunction) {
|
|
241
|
+
return cachedFunction;
|
|
242
|
+
}
|
|
243
|
+
// Create and cache the function
|
|
244
|
+
const func = lambda.Function.fromFunctionArn(scope, functionName, cdk.Fn.importValue(importKey));
|
|
245
|
+
scopeCache.set(cacheKey, func);
|
|
246
|
+
return func;
|
|
247
|
+
}
|
|
248
|
+
|
|
218
249
|
function resolveDatadogLayers(scope, options = {}) {
|
|
219
250
|
const { datadogApiKeyArn, uniqueId } = options;
|
|
220
251
|
let resolvedRegion = Stack.of(scope).region || "us-east-1";
|
|
@@ -234,6 +265,35 @@ function resolveDatadogLayers(scope, options = {}) {
|
|
|
234
265
|
return [datadogNodeLayer, datadogExtensionLayer];
|
|
235
266
|
}
|
|
236
267
|
|
|
268
|
+
const DEFAULT_FUNCTION_NAME = "DatadogForwarderFunction";
|
|
269
|
+
// Cache to store resolved logging destinations
|
|
270
|
+
// Using nested structure to support multiple destinations per scope with automatic GC
|
|
271
|
+
const destinationCache = new WeakMap();
|
|
272
|
+
function resolveDatadogLoggingDestination(scope, options) {
|
|
273
|
+
const { import: importValue, name } = options || {};
|
|
274
|
+
// Create a cache key based on name and import (same as forwarder function)
|
|
275
|
+
const functionName = name || DEFAULT_FUNCTION_NAME;
|
|
276
|
+
const importKey = importValue || CDK$2.IMPORT.DATADOG_LOG_FORWARDER;
|
|
277
|
+
const cacheKey = `${functionName}:${importKey}`;
|
|
278
|
+
// Get or create scope cache
|
|
279
|
+
let scopeCache = destinationCache.get(scope);
|
|
280
|
+
if (!scopeCache) {
|
|
281
|
+
scopeCache = new Map();
|
|
282
|
+
destinationCache.set(scope, scopeCache);
|
|
283
|
+
}
|
|
284
|
+
// Return cached destination if it exists
|
|
285
|
+
const cachedDestination = scopeCache.get(cacheKey);
|
|
286
|
+
if (cachedDestination) {
|
|
287
|
+
return cachedDestination;
|
|
288
|
+
}
|
|
289
|
+
// Resolve the Datadog forwarder function
|
|
290
|
+
const datadogForwarderFunction = resolveDatadogForwarderFunction(scope, options);
|
|
291
|
+
// Create and cache the logging destination
|
|
292
|
+
const datadogLoggingDestination = new logDestinations.LambdaDestination(datadogForwarderFunction);
|
|
293
|
+
scopeCache.set(cacheKey, datadogLoggingDestination);
|
|
294
|
+
return datadogLoggingDestination;
|
|
295
|
+
}
|
|
296
|
+
|
|
237
297
|
function resolveHostedZone(scope, { name = "HostedZone", zone = process.env.CDK_ENV_HOSTED_ZONE, } = {}) {
|
|
238
298
|
if (!zone) {
|
|
239
299
|
throw new ConfigurationError("No `zone` provided. Set CDK_ENV_HOSTED_ZONE to use environment zone");
|
|
@@ -407,6 +467,11 @@ class JaypieApiGateway extends Construct {
|
|
|
407
467
|
applyRemovalPolicy(policy) {
|
|
408
468
|
this._api.applyRemovalPolicy(policy);
|
|
409
469
|
}
|
|
470
|
+
get restApiRef() {
|
|
471
|
+
return {
|
|
472
|
+
restApiId: this._api.restApiId,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
410
475
|
}
|
|
411
476
|
|
|
412
477
|
class JaypieStack extends Stack {
|
|
@@ -588,7 +653,10 @@ class JaypieLambda extends Construct {
|
|
|
588
653
|
return this._reference.resourceArnsForGrantInvoke;
|
|
589
654
|
}
|
|
590
655
|
get functionRef() {
|
|
591
|
-
return
|
|
656
|
+
return {
|
|
657
|
+
functionArn: this._reference.functionArn,
|
|
658
|
+
functionName: this._reference.functionName,
|
|
659
|
+
};
|
|
592
660
|
}
|
|
593
661
|
addEventSource(source) {
|
|
594
662
|
this._reference.addEventSource(source);
|
|
@@ -950,7 +1018,7 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
|
950
1018
|
get policy() {
|
|
951
1019
|
return this._bucket.policy;
|
|
952
1020
|
}
|
|
953
|
-
addEventNotification(event, dest, filters) {
|
|
1021
|
+
addEventNotification(event, dest, ...filters) {
|
|
954
1022
|
this._bucket.addEventNotification(event, dest, ...filters);
|
|
955
1023
|
}
|
|
956
1024
|
addObjectCreatedNotification(dest, ...filters) {
|
|
@@ -968,9 +1036,6 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
|
968
1036
|
enableEventBridgeNotification() {
|
|
969
1037
|
this._bucket.enableEventBridgeNotification();
|
|
970
1038
|
}
|
|
971
|
-
grant(grantee, ...actions) {
|
|
972
|
-
return this._bucket.grant(grantee, ...actions);
|
|
973
|
-
}
|
|
974
1039
|
grantDelete(grantee, objectsKeyPattern) {
|
|
975
1040
|
return this._bucket.grantDelete(grantee, objectsKeyPattern);
|
|
976
1041
|
}
|
|
@@ -1013,54 +1078,17 @@ class JaypieBucketQueuedLambda extends JaypieQueuedLambda {
|
|
|
1013
1078
|
virtualHostedUrlForObject(key, options) {
|
|
1014
1079
|
return this._bucket.virtualHostedUrlForObject(key, options);
|
|
1015
1080
|
}
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
return this._bucket.metricAllRequests(props);
|
|
1019
|
-
}
|
|
1020
|
-
metricBucketSizeBytes(props) {
|
|
1021
|
-
return this._bucket.metricBucketSizeBytes(props);
|
|
1022
|
-
}
|
|
1023
|
-
metricDeleteRequests(props) {
|
|
1024
|
-
return this._bucket.metricDeleteRequests(props);
|
|
1025
|
-
}
|
|
1026
|
-
metricDownloadBytes(props) {
|
|
1027
|
-
return this._bucket.metricDownloadBytes(props);
|
|
1028
|
-
}
|
|
1029
|
-
metricFirstByteLatency(props) {
|
|
1030
|
-
return this._bucket.metricFirstByteLatency(props);
|
|
1031
|
-
}
|
|
1032
|
-
metricGetRequests(props) {
|
|
1033
|
-
return this._bucket.metricGetRequests(props);
|
|
1034
|
-
}
|
|
1035
|
-
metricHeadRequests(props) {
|
|
1036
|
-
return this._bucket.metricHeadRequests(props);
|
|
1037
|
-
}
|
|
1038
|
-
metricHttpRequests(props) {
|
|
1039
|
-
return this._bucket.metricHttpRequests(props);
|
|
1040
|
-
}
|
|
1041
|
-
metricListRequests(props) {
|
|
1042
|
-
return this._bucket.metricListRequests(props);
|
|
1043
|
-
}
|
|
1044
|
-
metricNumberOfObjects(props) {
|
|
1045
|
-
return this._bucket.metricNumberOfObjects(props);
|
|
1046
|
-
}
|
|
1047
|
-
metricPostRequests(props) {
|
|
1048
|
-
return this._bucket.metricPostRequests(props);
|
|
1049
|
-
}
|
|
1050
|
-
metricPutRequests(props) {
|
|
1051
|
-
return this._bucket.metricPutRequests(props);
|
|
1052
|
-
}
|
|
1053
|
-
metricSelectRequests(props) {
|
|
1054
|
-
return this._bucket.metricSelectRequests(props);
|
|
1055
|
-
}
|
|
1056
|
-
metricSelectScannedBytes(props) {
|
|
1057
|
-
return this._bucket.metricSelectScannedBytes(props);
|
|
1081
|
+
grantReplicationPermission(identity, props) {
|
|
1082
|
+
return this._bucket.grantReplicationPermission(identity, props);
|
|
1058
1083
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1084
|
+
addReplicationPolicy(policy) {
|
|
1085
|
+
this._bucket.addReplicationPolicy(policy);
|
|
1061
1086
|
}
|
|
1062
|
-
|
|
1063
|
-
return
|
|
1087
|
+
get bucketRef() {
|
|
1088
|
+
return {
|
|
1089
|
+
bucketArn: this._bucket.bucketArn,
|
|
1090
|
+
bucketName: this._bucket.bucketName,
|
|
1091
|
+
};
|
|
1064
1092
|
}
|
|
1065
1093
|
// Override applyRemovalPolicy to apply to all resources
|
|
1066
1094
|
applyRemovalPolicy(policy) {
|
|
@@ -1214,6 +1242,164 @@ class JaypieDatadogSecret extends JaypieEnvSecret {
|
|
|
1214
1242
|
}
|
|
1215
1243
|
}
|
|
1216
1244
|
|
|
1245
|
+
class JaypieDnsRecord extends Construct {
|
|
1246
|
+
constructor(scope, id, props) {
|
|
1247
|
+
super(scope, id);
|
|
1248
|
+
const { comment, recordName, type, values } = props;
|
|
1249
|
+
const ttl = props.ttl || cdk.Duration.seconds(CDK$2.DNS.CONFIG.TTL);
|
|
1250
|
+
// Resolve the hosted zone (supports both string and IHostedZone)
|
|
1251
|
+
const zone = resolveHostedZone(scope, {
|
|
1252
|
+
name: `${id}HostedZone`,
|
|
1253
|
+
zone: props.zone,
|
|
1254
|
+
});
|
|
1255
|
+
// Common properties for all record types
|
|
1256
|
+
const baseProps = {
|
|
1257
|
+
comment,
|
|
1258
|
+
recordName,
|
|
1259
|
+
ttl,
|
|
1260
|
+
zone,
|
|
1261
|
+
};
|
|
1262
|
+
// Create the appropriate record based on type
|
|
1263
|
+
switch (type) {
|
|
1264
|
+
case CDK$2.DNS.RECORD.A: {
|
|
1265
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
1266
|
+
throw new ConfigurationError("A record requires at least one IP address");
|
|
1267
|
+
}
|
|
1268
|
+
this.record = new ARecord(this, "Record", {
|
|
1269
|
+
...baseProps,
|
|
1270
|
+
target: RecordTarget.fromIpAddresses(...values),
|
|
1271
|
+
});
|
|
1272
|
+
break;
|
|
1273
|
+
}
|
|
1274
|
+
case CDK$2.DNS.RECORD.CNAME: {
|
|
1275
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
1276
|
+
throw new ConfigurationError("CNAME record requires a domain name");
|
|
1277
|
+
}
|
|
1278
|
+
this.record = new CnameRecord(this, "Record", {
|
|
1279
|
+
...baseProps,
|
|
1280
|
+
domainName: values[0],
|
|
1281
|
+
});
|
|
1282
|
+
break;
|
|
1283
|
+
}
|
|
1284
|
+
case CDK$2.DNS.RECORD.MX: {
|
|
1285
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
1286
|
+
throw new ConfigurationError("MX record requires at least one mail server");
|
|
1287
|
+
}
|
|
1288
|
+
this.record = new MxRecord(this, "Record", {
|
|
1289
|
+
...baseProps,
|
|
1290
|
+
values: values,
|
|
1291
|
+
});
|
|
1292
|
+
break;
|
|
1293
|
+
}
|
|
1294
|
+
case CDK$2.DNS.RECORD.NS: {
|
|
1295
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
1296
|
+
throw new ConfigurationError("NS record requires at least one name server");
|
|
1297
|
+
}
|
|
1298
|
+
this.record = new NsRecord(this, "Record", {
|
|
1299
|
+
...baseProps,
|
|
1300
|
+
values: values,
|
|
1301
|
+
});
|
|
1302
|
+
break;
|
|
1303
|
+
}
|
|
1304
|
+
case CDK$2.DNS.RECORD.TXT: {
|
|
1305
|
+
if (!Array.isArray(values) || values.length === 0) {
|
|
1306
|
+
throw new ConfigurationError("TXT record requires at least one value");
|
|
1307
|
+
}
|
|
1308
|
+
this.record = new TxtRecord(this, "Record", {
|
|
1309
|
+
...baseProps,
|
|
1310
|
+
values: values,
|
|
1311
|
+
});
|
|
1312
|
+
break;
|
|
1313
|
+
}
|
|
1314
|
+
default:
|
|
1315
|
+
throw new ConfigurationError(`Unsupported DNS record type: ${type}. Supported types: A, CNAME, MX, NS, TXT`);
|
|
1316
|
+
}
|
|
1317
|
+
// Add standard tags to the DNS record
|
|
1318
|
+
cdk.Tags.of(this.record).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.INFRASTRUCTURE);
|
|
1319
|
+
cdk.Tags.of(this.record).add(CDK$2.TAG.ROLE, CDK$2.ROLE.NETWORKING);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
class JaypieGitHubDeployRole extends Construct {
|
|
1324
|
+
constructor(scope, id, props) {
|
|
1325
|
+
super(scope, id);
|
|
1326
|
+
const { accountId, oidcProviderArn = Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, } = props;
|
|
1327
|
+
// Resolve repoRestriction from props or environment variables
|
|
1328
|
+
let repoRestriction = propsRepoRestriction;
|
|
1329
|
+
if (!repoRestriction) {
|
|
1330
|
+
const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
|
|
1331
|
+
if (!envRepo) {
|
|
1332
|
+
throw new ConfigurationError("No repoRestriction provided. Set repoRestriction prop, CDK_ENV_REPO, or PROJECT_REPO environment variable");
|
|
1333
|
+
}
|
|
1334
|
+
// Extract organization from owner/repo format and create org-wide restriction
|
|
1335
|
+
const organization = envRepo.split("/")[0];
|
|
1336
|
+
repoRestriction = `repo:${organization}/*:*`;
|
|
1337
|
+
}
|
|
1338
|
+
// Create the IAM role
|
|
1339
|
+
this._role = new Role(this, "GitHubActionsRole", {
|
|
1340
|
+
assumedBy: new FederatedPrincipal(oidcProviderArn, {
|
|
1341
|
+
StringLike: {
|
|
1342
|
+
"token.actions.githubusercontent.com:sub": repoRestriction,
|
|
1343
|
+
},
|
|
1344
|
+
}, "sts:AssumeRoleWithWebIdentity"),
|
|
1345
|
+
maxSessionDuration: Duration.hours(1),
|
|
1346
|
+
path: "/",
|
|
1347
|
+
});
|
|
1348
|
+
Tags.of(this._role).add(CDK$2.TAG.ROLE, CDK$2.ROLE.DEPLOY);
|
|
1349
|
+
// Allow the role to access the GitHub OIDC provider
|
|
1350
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1351
|
+
actions: ["sts:AssumeRoleWithWebIdentity"],
|
|
1352
|
+
resources: [`arn:aws:iam::${accountId}:oidc-provider/*`],
|
|
1353
|
+
}));
|
|
1354
|
+
// Allow the role to deploy CDK apps
|
|
1355
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1356
|
+
actions: [
|
|
1357
|
+
"cloudformation:CreateStack",
|
|
1358
|
+
"cloudformation:DeleteStack",
|
|
1359
|
+
"cloudformation:DescribeStackEvents",
|
|
1360
|
+
"cloudformation:DescribeStackResource",
|
|
1361
|
+
"cloudformation:DescribeStackResources",
|
|
1362
|
+
"cloudformation:DescribeStacks",
|
|
1363
|
+
"cloudformation:GetTemplate",
|
|
1364
|
+
"cloudformation:SetStackPolicy",
|
|
1365
|
+
"cloudformation:UpdateStack",
|
|
1366
|
+
"cloudformation:ValidateTemplate",
|
|
1367
|
+
"iam:PassRole",
|
|
1368
|
+
"route53:ListHostedZones*",
|
|
1369
|
+
"s3:GetObject",
|
|
1370
|
+
"s3:ListBucket",
|
|
1371
|
+
],
|
|
1372
|
+
effect: Effect.ALLOW,
|
|
1373
|
+
resources: ["*"],
|
|
1374
|
+
}));
|
|
1375
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1376
|
+
actions: ["iam:PassRole", "sts:AssumeRole"],
|
|
1377
|
+
effect: Effect.ALLOW,
|
|
1378
|
+
resources: [
|
|
1379
|
+
"arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*",
|
|
1380
|
+
"arn:aws:iam::*:role/cdk-hnb659fds-file-publishing-*",
|
|
1381
|
+
"arn:aws:iam::*:role/cdk-readOnlyRole",
|
|
1382
|
+
],
|
|
1383
|
+
}));
|
|
1384
|
+
// Export the ARN of the role
|
|
1385
|
+
if (output !== false) {
|
|
1386
|
+
const outputId = typeof output === "string" ? output : "GitHubActionsRoleArn";
|
|
1387
|
+
new CfnOutput(this, outputId, {
|
|
1388
|
+
value: this._role.roleArn,
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
}
|
|
1392
|
+
get role() {
|
|
1393
|
+
return this._role;
|
|
1394
|
+
}
|
|
1395
|
+
get roleArn() {
|
|
1396
|
+
return this._role.roleArn;
|
|
1397
|
+
}
|
|
1398
|
+
get roleName() {
|
|
1399
|
+
return this._role.roleName;
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1217
1403
|
class JaypieExpressLambda extends JaypieLambda {
|
|
1218
1404
|
constructor(scope, id, props) {
|
|
1219
1405
|
super(scope, id, {
|
|
@@ -1229,11 +1415,12 @@ const SERVICE = {
|
|
|
1229
1415
|
};
|
|
1230
1416
|
class JaypieHostedZone extends Construct {
|
|
1231
1417
|
/**
|
|
1232
|
-
* Create a new hosted zone with query logging
|
|
1418
|
+
* Create a new hosted zone with query logging and optional DNS records
|
|
1233
1419
|
*/
|
|
1234
1420
|
constructor(scope, id, props) {
|
|
1235
1421
|
super(scope, id);
|
|
1236
|
-
const {
|
|
1422
|
+
const { zoneName, project } = props;
|
|
1423
|
+
const destination = props.destination ?? true;
|
|
1237
1424
|
const service = props.service || CDK$2.SERVICE.INFRASTRUCTURE;
|
|
1238
1425
|
// Create the log group
|
|
1239
1426
|
this.logGroup = new LogGroup(this, "LogGroup", {
|
|
@@ -1250,10 +1437,13 @@ class JaypieHostedZone extends Construct {
|
|
|
1250
1437
|
}
|
|
1251
1438
|
// Grant Route 53 permissions to write to the log group
|
|
1252
1439
|
this.logGroup.grantWrite(new ServicePrincipal(SERVICE.ROUTE53));
|
|
1253
|
-
// Add destination
|
|
1254
|
-
if (destination) {
|
|
1440
|
+
// Add destination based on configuration
|
|
1441
|
+
if (destination !== false) {
|
|
1442
|
+
const lambdaDestination = destination === true
|
|
1443
|
+
? resolveDatadogLoggingDestination(scope)
|
|
1444
|
+
: destination;
|
|
1255
1445
|
this.logGroup.addSubscriptionFilter("DatadogLambdaDestination", {
|
|
1256
|
-
destination,
|
|
1446
|
+
destination: lambdaDestination,
|
|
1257
1447
|
filterPattern: FilterPattern.allEvents(),
|
|
1258
1448
|
});
|
|
1259
1449
|
}
|
|
@@ -1268,6 +1458,21 @@ class JaypieHostedZone extends Construct {
|
|
|
1268
1458
|
if (project) {
|
|
1269
1459
|
cdk.Tags.of(this.hostedZone).add(CDK$2.TAG.PROJECT, project);
|
|
1270
1460
|
}
|
|
1461
|
+
// Create DNS records if provided
|
|
1462
|
+
this.dnsRecords = [];
|
|
1463
|
+
if (props.records) {
|
|
1464
|
+
props.records.forEach((recordConfig, index) => {
|
|
1465
|
+
const { id, ...recordProps } = recordConfig;
|
|
1466
|
+
// Generate a default ID if not provided
|
|
1467
|
+
const recordId = id ||
|
|
1468
|
+
`${recordProps.type}${recordProps.recordName ? `-${recordProps.recordName}` : ""}-${index}`;
|
|
1469
|
+
const dnsRecord = new JaypieDnsRecord(this, recordId, {
|
|
1470
|
+
...recordProps,
|
|
1471
|
+
zone: this.hostedZone,
|
|
1472
|
+
});
|
|
1473
|
+
this.dnsRecords.push(dnsRecord);
|
|
1474
|
+
});
|
|
1475
|
+
}
|
|
1271
1476
|
}
|
|
1272
1477
|
}
|
|
1273
1478
|
|
|
@@ -1316,276 +1521,348 @@ class JaypieOpenAiSecret extends JaypieEnvSecret {
|
|
|
1316
1521
|
}
|
|
1317
1522
|
|
|
1318
1523
|
/**
|
|
1319
|
-
*
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1524
|
+
* JaypieSsoPermissions Construct
|
|
1525
|
+
*
|
|
1526
|
+
* Creates and manages AWS IAM Identity Center (SSO) permission sets and assignments
|
|
1527
|
+
*
|
|
1528
|
+
* @example
|
|
1529
|
+
* const permissionSets = new JaypieSsoPermissions(this, "PermissionSets", {
|
|
1530
|
+
* iamIdentityCenterArn: "arn:aws:sso:::instance/...",
|
|
1531
|
+
* administratorGroupId: "b4c8b438-4031-7000-782d-5046945fb956",
|
|
1532
|
+
* analystGroupId: "2488f4e8-d061-708e-abe1-c315f0e30005",
|
|
1533
|
+
* developerGroupId: "b438a4f8-e0e1-707c-c6e8-21841daf9ad1",
|
|
1534
|
+
* administratorAccountAssignments: {
|
|
1535
|
+
* "211125635435": ["Administrator", "Analyst", "Developer"],
|
|
1536
|
+
* "381492033431": ["Administrator", "Analyst"],
|
|
1537
|
+
* },
|
|
1538
|
+
* analystAccountAssignments: {
|
|
1539
|
+
* "211125635435": ["Analyst", "Developer"],
|
|
1540
|
+
* "381492033431": [],
|
|
1541
|
+
* },
|
|
1542
|
+
* developerAccountAssignments: {
|
|
1543
|
+
* "211125635435": ["Analyst", "Developer"],
|
|
1544
|
+
* "381492033431": [],
|
|
1545
|
+
* },
|
|
1546
|
+
* });
|
|
1331
1547
|
*/
|
|
1332
|
-
class
|
|
1548
|
+
class JaypieSsoPermissions extends Construct {
|
|
1333
1549
|
constructor(scope, id, props) {
|
|
1334
1550
|
super(scope, id);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
//
|
|
1343
|
-
this.
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1551
|
+
const { iamIdentityCenterArn, administratorGroupId, analystGroupId, developerGroupId, administratorAccountAssignments, analystAccountAssignments, developerAccountAssignments, } = props;
|
|
1552
|
+
if (!iamIdentityCenterArn) {
|
|
1553
|
+
// If no IAM Identity Center ARN provided, skip SSO setup
|
|
1554
|
+
return;
|
|
1555
|
+
}
|
|
1556
|
+
//
|
|
1557
|
+
// Permission Sets
|
|
1558
|
+
//
|
|
1559
|
+
this.administratorPermissionSet = new CfnPermissionSet(this, "AdministratorPermissionSet", {
|
|
1560
|
+
// Required
|
|
1561
|
+
instanceArn: iamIdentityCenterArn,
|
|
1562
|
+
name: "Administrator",
|
|
1563
|
+
// Optional
|
|
1564
|
+
description: "Unrestricted access",
|
|
1565
|
+
inlinePolicy: {
|
|
1566
|
+
Version: "2012-10-17",
|
|
1567
|
+
Statement: [
|
|
1568
|
+
{
|
|
1569
|
+
Effect: "Allow",
|
|
1570
|
+
Action: [
|
|
1571
|
+
"aws-portal:ViewUsage",
|
|
1572
|
+
"aws-portal:ViewBilling",
|
|
1573
|
+
"budgets:*",
|
|
1574
|
+
"cur:DescribeReportDefinitions",
|
|
1575
|
+
"cur:PutReportDefinition",
|
|
1576
|
+
"cur:DeleteReportDefinition",
|
|
1577
|
+
"cur:ModifyReportDefinition",
|
|
1578
|
+
],
|
|
1579
|
+
Resource: "*",
|
|
1580
|
+
},
|
|
1581
|
+
],
|
|
1582
|
+
},
|
|
1583
|
+
managedPolicies: [
|
|
1584
|
+
ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess")
|
|
1585
|
+
.managedPolicyArn,
|
|
1586
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1587
|
+
],
|
|
1588
|
+
sessionDuration: Duration.hours(1).toIsoString(),
|
|
1589
|
+
tags: [
|
|
1353
1590
|
{
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
"aws-portal:*",
|
|
1357
|
-
"budgets:*",
|
|
1358
|
-
"ce:*",
|
|
1359
|
-
"cost-optimization-hub:*",
|
|
1360
|
-
],
|
|
1361
|
-
Resource: "*",
|
|
1591
|
+
key: CDK$2.TAG.SERVICE,
|
|
1592
|
+
value: CDK$2.SERVICE.SSO,
|
|
1362
1593
|
},
|
|
1363
|
-
],
|
|
1364
|
-
};
|
|
1365
|
-
// Merge with any additional policy statements provided for administrators
|
|
1366
|
-
const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.administrators);
|
|
1367
|
-
const permissionSet = new sso.CfnPermissionSet(this, "AdministratorPermissionSet", {
|
|
1368
|
-
instanceArn: this.instanceArn,
|
|
1369
|
-
name: PermissionSetType.ADMINISTRATOR,
|
|
1370
|
-
description: "Full administrative access to all AWS services and resources",
|
|
1371
|
-
sessionDuration: Duration.hours(8).toIsoString(),
|
|
1372
|
-
managedPolicies: ["arn:aws:iam::aws:policy/AdministratorAccess"],
|
|
1373
|
-
inlinePolicy: mergedPolicy,
|
|
1374
|
-
});
|
|
1375
|
-
Tags.of(permissionSet).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1376
|
-
this.permissionSets[PermissionSetType.ADMINISTRATOR] = permissionSet;
|
|
1377
|
-
}
|
|
1378
|
-
/**
|
|
1379
|
-
* Creates the Analyst permission set with ReadOnlyAccess policy
|
|
1380
|
-
* and limited write access
|
|
1381
|
-
*/
|
|
1382
|
-
createAnalystPermissionSet() {
|
|
1383
|
-
const defaultInlinePolicy = {
|
|
1384
|
-
Version: "2012-10-17",
|
|
1385
|
-
Statement: [
|
|
1386
1594
|
{
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
"aws-portal:ViewBilling",
|
|
1390
|
-
"aws-portal:ViewAccount",
|
|
1391
|
-
"budgets:ViewBudget",
|
|
1392
|
-
"cloudwatch:PutDashboard",
|
|
1393
|
-
"cloudwatch:PutMetricData",
|
|
1394
|
-
"s3:PutObject",
|
|
1395
|
-
"s3:GetObject",
|
|
1396
|
-
"s3:ListBucket",
|
|
1397
|
-
],
|
|
1398
|
-
Resource: "*",
|
|
1595
|
+
key: CDK$2.TAG.ROLE,
|
|
1596
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1399
1597
|
},
|
|
1400
1598
|
],
|
|
1401
|
-
};
|
|
1402
|
-
// Merge with any additional policy statements provided for analysts
|
|
1403
|
-
const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.analysts);
|
|
1404
|
-
const permissionSet = new sso.CfnPermissionSet(this, "AnalystPermissionSet", {
|
|
1405
|
-
instanceArn: this.instanceArn,
|
|
1406
|
-
name: PermissionSetType.ANALYST,
|
|
1407
|
-
description: "Read-only access with billing visibility and limited write access",
|
|
1408
|
-
sessionDuration: Duration.hours(4).toIsoString(),
|
|
1409
|
-
managedPolicies: ["arn:aws:iam::aws:policy/ReadOnlyAccess"],
|
|
1410
|
-
inlinePolicy: mergedPolicy,
|
|
1411
1599
|
});
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1600
|
+
this.analystPermissionSet = new CfnPermissionSet(this, "AnalystPermissionSet", {
|
|
1601
|
+
// Required
|
|
1602
|
+
instanceArn: iamIdentityCenterArn,
|
|
1603
|
+
name: "Analyst",
|
|
1604
|
+
// Optional
|
|
1605
|
+
description: "Read-only access; may expand to limited write access",
|
|
1606
|
+
inlinePolicy: {
|
|
1607
|
+
Version: "2012-10-17",
|
|
1608
|
+
Statement: [
|
|
1609
|
+
{
|
|
1610
|
+
Effect: "Allow",
|
|
1611
|
+
Action: [
|
|
1612
|
+
"aws-portal:ViewUsage",
|
|
1613
|
+
"aws-portal:ViewBilling",
|
|
1614
|
+
"budgets:Describe*",
|
|
1615
|
+
"budgets:View*",
|
|
1616
|
+
"ce:Get*",
|
|
1617
|
+
"ce:List*",
|
|
1618
|
+
"cloudformation:Describe*",
|
|
1619
|
+
"cloudformation:Get*",
|
|
1620
|
+
"cloudformation:List*",
|
|
1621
|
+
"cloudwatch:BatchGet*",
|
|
1622
|
+
"cloudwatch:Get*",
|
|
1623
|
+
"cloudwatch:List*",
|
|
1624
|
+
"cost-optimization-hub:Get*",
|
|
1625
|
+
"cost-optimization-hub:List*",
|
|
1626
|
+
"ec2:Describe*",
|
|
1627
|
+
"ec2:Get*",
|
|
1628
|
+
"ec2:List*",
|
|
1629
|
+
"ec2:Search*",
|
|
1630
|
+
"iam:Get*",
|
|
1631
|
+
"iam:List*",
|
|
1632
|
+
"iam:PassRole",
|
|
1633
|
+
"lambda:Get*",
|
|
1634
|
+
"lambda:List*",
|
|
1635
|
+
"logs:Describe*",
|
|
1636
|
+
"logs:Get*",
|
|
1637
|
+
"logs:List*",
|
|
1638
|
+
"pipes:Describe*",
|
|
1639
|
+
"pipes:List*",
|
|
1640
|
+
"s3:Get*",
|
|
1641
|
+
"s3:List*",
|
|
1642
|
+
"secretsmanager:GetRandomPassword",
|
|
1643
|
+
"secretsmanager:GetResourcePolicy",
|
|
1644
|
+
"secretsmanager:List*",
|
|
1645
|
+
"securityhub:Describe*",
|
|
1646
|
+
"securityhub:Get*",
|
|
1647
|
+
"securityhub:List*",
|
|
1648
|
+
"servicecatalog:Describe*",
|
|
1649
|
+
"sns:Get*",
|
|
1650
|
+
"sns:List*",
|
|
1651
|
+
"sqs:Get*",
|
|
1652
|
+
"sqs:List*",
|
|
1653
|
+
"states:Describe*",
|
|
1654
|
+
"states:Get*",
|
|
1655
|
+
"states:List*",
|
|
1656
|
+
"tag:*",
|
|
1657
|
+
"xray:*",
|
|
1658
|
+
],
|
|
1659
|
+
Resource: "*",
|
|
1660
|
+
},
|
|
1661
|
+
],
|
|
1662
|
+
},
|
|
1663
|
+
managedPolicies: [
|
|
1664
|
+
ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
1665
|
+
.managedPolicyArn,
|
|
1666
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1667
|
+
ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
1668
|
+
.managedPolicyArn,
|
|
1669
|
+
],
|
|
1670
|
+
sessionDuration: Duration.hours(12).toIsoString(),
|
|
1671
|
+
tags: [
|
|
1423
1672
|
{
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
"cloudwatch:*",
|
|
1427
|
-
"logs:*",
|
|
1428
|
-
"lambda:*",
|
|
1429
|
-
"apigateway:*",
|
|
1430
|
-
"dynamodb:*",
|
|
1431
|
-
"s3:*",
|
|
1432
|
-
"sns:*",
|
|
1433
|
-
"sqs:*",
|
|
1434
|
-
"events:*",
|
|
1435
|
-
"ecr:*",
|
|
1436
|
-
"ecs:*",
|
|
1437
|
-
"codebuild:*",
|
|
1438
|
-
],
|
|
1439
|
-
Resource: "*",
|
|
1673
|
+
key: CDK$2.TAG.SERVICE,
|
|
1674
|
+
value: CDK$2.SERVICE.SSO,
|
|
1440
1675
|
},
|
|
1441
1676
|
{
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
"iam:*User*",
|
|
1445
|
-
"iam:*Role*",
|
|
1446
|
-
"iam:*Policy*",
|
|
1447
|
-
"organizations:*",
|
|
1448
|
-
"account:*",
|
|
1449
|
-
],
|
|
1450
|
-
Resource: "*",
|
|
1677
|
+
key: CDK$2.TAG.ROLE,
|
|
1678
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1451
1679
|
},
|
|
1452
1680
|
],
|
|
1453
|
-
};
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
description: "
|
|
1460
|
-
|
|
1681
|
+
});
|
|
1682
|
+
this.developerPermissionSet = new CfnPermissionSet(this, "DeveloperPermissionSet", {
|
|
1683
|
+
// Required
|
|
1684
|
+
instanceArn: iamIdentityCenterArn,
|
|
1685
|
+
name: "Developer",
|
|
1686
|
+
// Optional
|
|
1687
|
+
description: "Administrative access with limited restrictions",
|
|
1688
|
+
inlinePolicy: {
|
|
1689
|
+
Version: "2012-10-17",
|
|
1690
|
+
Statement: [
|
|
1691
|
+
{
|
|
1692
|
+
Effect: "Allow",
|
|
1693
|
+
Action: [
|
|
1694
|
+
"budgets:*",
|
|
1695
|
+
"ce:*",
|
|
1696
|
+
"cloudformation:*",
|
|
1697
|
+
"cloudwatch:*",
|
|
1698
|
+
"cost-optimization-hub:*",
|
|
1699
|
+
"ec2:*",
|
|
1700
|
+
"iam:Get*",
|
|
1701
|
+
"iam:List*",
|
|
1702
|
+
"iam:PassRole",
|
|
1703
|
+
"lambda:*",
|
|
1704
|
+
"logs:*",
|
|
1705
|
+
"pipes:*",
|
|
1706
|
+
"s3:*",
|
|
1707
|
+
"secretsmanager:*",
|
|
1708
|
+
"securityhub:*",
|
|
1709
|
+
"servicecatalog:*",
|
|
1710
|
+
"sns:*",
|
|
1711
|
+
"sqs:*",
|
|
1712
|
+
"states:*",
|
|
1713
|
+
"tag:*",
|
|
1714
|
+
"xray:*",
|
|
1715
|
+
],
|
|
1716
|
+
Resource: "*",
|
|
1717
|
+
},
|
|
1718
|
+
],
|
|
1719
|
+
},
|
|
1461
1720
|
managedPolicies: [
|
|
1462
|
-
"
|
|
1721
|
+
ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
1722
|
+
.managedPolicyArn,
|
|
1723
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1724
|
+
ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
1725
|
+
.managedPolicyArn,
|
|
1726
|
+
ManagedPolicy.fromAwsManagedPolicyName("job-function/SystemAdministrator").managedPolicyArn,
|
|
1727
|
+
],
|
|
1728
|
+
sessionDuration: Duration.hours(4).toIsoString(),
|
|
1729
|
+
tags: [
|
|
1730
|
+
{
|
|
1731
|
+
key: CDK$2.TAG.SERVICE,
|
|
1732
|
+
value: CDK$2.SERVICE.SSO,
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
key: CDK$2.TAG.ROLE,
|
|
1736
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1737
|
+
},
|
|
1463
1738
|
],
|
|
1464
|
-
inlinePolicy: mergedPolicy,
|
|
1465
1739
|
});
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1740
|
+
// Map permission set names to their ARNs and labels
|
|
1741
|
+
const permissionSetMap = {
|
|
1742
|
+
Administrator: {
|
|
1743
|
+
arn: this.administratorPermissionSet.attrPermissionSetArn,
|
|
1744
|
+
label: "Administrator",
|
|
1745
|
+
},
|
|
1746
|
+
Analyst: {
|
|
1747
|
+
arn: this.analystPermissionSet.attrPermissionSetArn,
|
|
1748
|
+
label: "Analyst",
|
|
1749
|
+
},
|
|
1750
|
+
Developer: {
|
|
1751
|
+
arn: this.developerPermissionSet.attrPermissionSetArn,
|
|
1752
|
+
label: "Developer",
|
|
1753
|
+
},
|
|
1754
|
+
};
|
|
1755
|
+
//
|
|
1756
|
+
// Assignments
|
|
1757
|
+
//
|
|
1758
|
+
// Helper function to create assignments for a group
|
|
1759
|
+
const createAssignments = (groupId, accountAssignments) => {
|
|
1760
|
+
if (!groupId || !accountAssignments) {
|
|
1761
|
+
return; // Skip if group ID or assignments not provided
|
|
1762
|
+
}
|
|
1763
|
+
Object.keys(accountAssignments).forEach((accountId) => {
|
|
1764
|
+
const permissionSetNames = accountAssignments[accountId];
|
|
1765
|
+
permissionSetNames.forEach((permissionSetName) => {
|
|
1766
|
+
const permissionSet = permissionSetMap[permissionSetName];
|
|
1767
|
+
if (!permissionSet) {
|
|
1768
|
+
throw new ConfigurationError(`Unknown permission set: ${permissionSetName}. Valid options: ${Object.keys(permissionSetMap).join(", ")}`);
|
|
1769
|
+
}
|
|
1770
|
+
const accountAssignment = new CfnAssignment(this, `AccountAssignment-${accountId}-${permissionSet.label}Role-${groupId}Group`, {
|
|
1771
|
+
// Required
|
|
1772
|
+
instanceArn: iamIdentityCenterArn,
|
|
1773
|
+
permissionSetArn: permissionSet.arn,
|
|
1774
|
+
principalId: groupId,
|
|
1775
|
+
principalType: CDK$2.PRINCIPAL_TYPE.GROUP,
|
|
1776
|
+
targetId: accountId,
|
|
1777
|
+
targetType: CDK$2.TARGET_TYPE.AWS_ACCOUNT,
|
|
1778
|
+
});
|
|
1779
|
+
Tags.of(accountAssignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1780
|
+
Tags.of(accountAssignment).add(CDK$2.TAG.ROLE, CDK$2.ROLE.SECURITY);
|
|
1781
|
+
});
|
|
1782
|
+
});
|
|
1783
|
+
};
|
|
1784
|
+
// Create assignments for each group
|
|
1785
|
+
createAssignments(administratorGroupId, administratorAccountAssignments);
|
|
1786
|
+
createAssignments(analystGroupId, analystAccountAssignments);
|
|
1787
|
+
createAssignments(developerGroupId, developerAccountAssignments);
|
|
1474
1788
|
}
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
//
|
|
1792
|
+
//
|
|
1793
|
+
// Constants
|
|
1794
|
+
//
|
|
1795
|
+
const DEFAULT_APPLICATION_ID = "arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync";
|
|
1796
|
+
const DEFAULT_APPLICATION_VERSION = "2.3.3";
|
|
1797
|
+
const DEFAULT_GOOGLE_GROUP_MATCH = "name:AWS*";
|
|
1798
|
+
//
|
|
1799
|
+
//
|
|
1800
|
+
// Class
|
|
1801
|
+
//
|
|
1802
|
+
class JaypieSsoSyncApplication extends Construct {
|
|
1803
|
+
constructor(scope, id = "SSOSyncApplication", props = {}) {
|
|
1804
|
+
super(scope, id);
|
|
1805
|
+
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;
|
|
1806
|
+
// Resolve all values from props or environment variables
|
|
1807
|
+
const resolvedGoogleAdminEmail = googleAdminEmail || process.env[googleAdminEmailEnvKey];
|
|
1808
|
+
const resolvedGoogleCredentials = googleCredentials || process.env[googleCredentialsEnvKey];
|
|
1809
|
+
const resolvedGoogleGroupMatch = googleGroupMatch ||
|
|
1810
|
+
process.env[googleGroupMatchEnvKey] ||
|
|
1811
|
+
DEFAULT_GOOGLE_GROUP_MATCH;
|
|
1812
|
+
const resolvedIdentityStoreId = identityStoreId || process.env[identityStoreIdEnvKey];
|
|
1813
|
+
const resolvedScimEndpointAccessToken = scimEndpointAccessToken || process.env[scimEndpointAccessTokenEnvKey];
|
|
1814
|
+
const resolvedScimEndpointUrl = scimEndpointUrl || process.env[scimEndpointUrlEnvKey];
|
|
1815
|
+
const resolvedSemanticVersion = semanticVersion ||
|
|
1816
|
+
process.env[semanticVersionEnvKey] ||
|
|
1817
|
+
DEFAULT_APPLICATION_VERSION;
|
|
1818
|
+
// Validate required parameters
|
|
1819
|
+
const missingParams = [];
|
|
1820
|
+
if (!resolvedGoogleAdminEmail) {
|
|
1821
|
+
missingParams.push(`googleAdminEmail or ${googleAdminEmailEnvKey} environment variable`);
|
|
1485
1822
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
//
|
|
1503
|
-
this.
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
...props.accountMap.operations,
|
|
1518
|
-
...props.accountMap.production,
|
|
1519
|
-
...props.accountMap.sandbox,
|
|
1520
|
-
...props.accountMap.security,
|
|
1521
|
-
...props.accountMap.stage,
|
|
1522
|
-
];
|
|
1523
|
-
// Create assignments for each account
|
|
1524
|
-
allAccounts.forEach((accountId, index) => {
|
|
1525
|
-
const assignment = new sso.CfnAssignment(this, `AdministratorAssignment${index}`, {
|
|
1526
|
-
instanceArn: this.instanceArn,
|
|
1527
|
-
permissionSetArn: administratorPermissionSet.attrPermissionSetArn,
|
|
1528
|
-
principalId: administratorGroup,
|
|
1529
|
-
principalType: "GROUP",
|
|
1530
|
-
targetId: accountId,
|
|
1531
|
-
targetType: "AWS_ACCOUNT",
|
|
1532
|
-
});
|
|
1533
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1534
|
-
Tags.of(assignment).add("Group", "administrators");
|
|
1823
|
+
if (!resolvedGoogleCredentials) {
|
|
1824
|
+
missingParams.push(`googleCredentials or ${googleCredentialsEnvKey} environment variable`);
|
|
1825
|
+
}
|
|
1826
|
+
if (!resolvedIdentityStoreId) {
|
|
1827
|
+
missingParams.push(`identityStoreId or ${identityStoreIdEnvKey} environment variable`);
|
|
1828
|
+
}
|
|
1829
|
+
if (!resolvedScimEndpointAccessToken) {
|
|
1830
|
+
missingParams.push(`scimEndpointAccessToken or ${scimEndpointAccessTokenEnvKey} environment variable`);
|
|
1831
|
+
}
|
|
1832
|
+
if (!resolvedScimEndpointUrl) {
|
|
1833
|
+
missingParams.push(`scimEndpointUrl or ${scimEndpointUrlEnvKey} environment variable`);
|
|
1834
|
+
}
|
|
1835
|
+
if (missingParams.length > 0) {
|
|
1836
|
+
throw new ConfigurationError$1(`JaypieSsoSyncApplication missing required configuration: ${missingParams.join(", ")}`);
|
|
1837
|
+
}
|
|
1838
|
+
// Create the SSO Sync Application
|
|
1839
|
+
// Type assertion is safe because we validated all required values above
|
|
1840
|
+
this._application = new CfnApplication(this, "Application", {
|
|
1841
|
+
location: {
|
|
1842
|
+
applicationId: ssoSyncApplicationId,
|
|
1843
|
+
semanticVersion: resolvedSemanticVersion,
|
|
1844
|
+
},
|
|
1845
|
+
parameters: {
|
|
1846
|
+
GoogleAdminEmail: resolvedGoogleAdminEmail,
|
|
1847
|
+
GoogleCredentials: resolvedGoogleCredentials,
|
|
1848
|
+
GoogleGroupMatch: resolvedGoogleGroupMatch,
|
|
1849
|
+
IdentityStoreID: resolvedIdentityStoreId,
|
|
1850
|
+
Region: Stack.of(this).region,
|
|
1851
|
+
SCIMEndpointAccessToken: resolvedScimEndpointAccessToken,
|
|
1852
|
+
SCIMEndpointUrl: resolvedScimEndpointUrl,
|
|
1853
|
+
},
|
|
1535
1854
|
});
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
// Analysts get access to development, management, sandbox, and stage accounts
|
|
1544
|
-
const analystAccounts = [
|
|
1545
|
-
...props.accountMap.development,
|
|
1546
|
-
...props.accountMap.management,
|
|
1547
|
-
...props.accountMap.sandbox,
|
|
1548
|
-
...props.accountMap.stage,
|
|
1549
|
-
];
|
|
1550
|
-
// Create assignments for each account
|
|
1551
|
-
analystAccounts.forEach((accountId, index) => {
|
|
1552
|
-
const assignment = new sso.CfnAssignment(this, `AnalystAssignment${index}`, {
|
|
1553
|
-
instanceArn: this.instanceArn,
|
|
1554
|
-
permissionSetArn: analystPermissionSet.attrPermissionSetArn,
|
|
1555
|
-
principalId: analystGroup,
|
|
1556
|
-
principalType: "GROUP",
|
|
1557
|
-
targetId: accountId,
|
|
1558
|
-
targetType: "AWS_ACCOUNT",
|
|
1559
|
-
});
|
|
1560
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1561
|
-
Tags.of(assignment).add("Group", "analysts");
|
|
1855
|
+
// Add tags
|
|
1856
|
+
const defaultTags = {
|
|
1857
|
+
[CDK$2.TAG.ROLE]: CDK$2.ROLE.SECURITY,
|
|
1858
|
+
};
|
|
1859
|
+
const allTags = { ...defaultTags, ...tags };
|
|
1860
|
+
Object.entries(allTags).forEach(([key, value]) => {
|
|
1861
|
+
Tags.of(this._application).add(key, value);
|
|
1562
1862
|
});
|
|
1563
1863
|
}
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
*/
|
|
1567
|
-
assignDeveloperPermissions(props) {
|
|
1568
|
-
const developerGroup = props.groupMap.developers;
|
|
1569
|
-
const developerPermissionSet = this.permissionSets[PermissionSetType.DEVELOPER];
|
|
1570
|
-
// Developers get access to development, sandbox, and stage accounts
|
|
1571
|
-
const developerAccounts = [
|
|
1572
|
-
...props.accountMap.development,
|
|
1573
|
-
...props.accountMap.sandbox,
|
|
1574
|
-
...props.accountMap.stage,
|
|
1575
|
-
];
|
|
1576
|
-
// Create assignments for each account
|
|
1577
|
-
developerAccounts.forEach((accountId, index) => {
|
|
1578
|
-
const assignment = new sso.CfnAssignment(this, `DeveloperAssignment${index}`, {
|
|
1579
|
-
instanceArn: this.instanceArn,
|
|
1580
|
-
permissionSetArn: developerPermissionSet.attrPermissionSetArn,
|
|
1581
|
-
principalId: developerGroup,
|
|
1582
|
-
principalType: "GROUP",
|
|
1583
|
-
targetId: accountId,
|
|
1584
|
-
targetType: "AWS_ACCOUNT",
|
|
1585
|
-
});
|
|
1586
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1587
|
-
Tags.of(assignment).add("Group", "developers");
|
|
1588
|
-
});
|
|
1864
|
+
get application() {
|
|
1865
|
+
return this._application;
|
|
1589
1866
|
}
|
|
1590
1867
|
}
|
|
1591
1868
|
|
|
@@ -1847,7 +2124,13 @@ class JaypieWebDeploymentBucket extends Construct {
|
|
|
1847
2124
|
applyRemovalPolicy(policy) {
|
|
1848
2125
|
this.bucket.applyRemovalPolicy(policy);
|
|
1849
2126
|
}
|
|
2127
|
+
get bucketRef() {
|
|
2128
|
+
return {
|
|
2129
|
+
bucketArn: this.bucket.bucketArn,
|
|
2130
|
+
bucketName: this.bucket.bucketName,
|
|
2131
|
+
};
|
|
2132
|
+
}
|
|
1850
2133
|
}
|
|
1851
2134
|
|
|
1852
|
-
export { JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieDatadogSecret, JaypieEnvSecret, JaypieExpressLambda, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieOpenAiSecret, JaypieQueuedLambda,
|
|
2135
|
+
export { JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieDatadogSecret, JaypieDnsRecord, JaypieEnvSecret, JaypieExpressLambda, JaypieGitHubDeployRole, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieOpenAiSecret, JaypieQueuedLambda, JaypieSsoPermissions, JaypieSsoSyncApplication, JaypieStack, JaypieTraceSigningKeySecret, JaypieWebDeploymentBucket, addDatadogLayers, constructEnvName, constructStackName, constructTagger, envHostname, isEnv, isProductionEnv, isSandboxEnv, jaypieLambdaEnv, resolveDatadogForwarderFunction, resolveDatadogLayers, resolveDatadogLoggingDestination, resolveHostedZone, resolveParamsAndSecrets };
|
|
1853
2136
|
//# sourceMappingURL=index.js.map
|