@jaypie/constructs 1.1.49 → 1.1.51
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 +14 -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 +96 -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 +592 -355
- 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 +14 -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 +96 -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 +585 -356
- 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,166 @@ 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 { oidcProviderArn = Fn.importValue(CDK$2.IMPORT.OIDC_PROVIDER), output = true, repoRestriction: propsRepoRestriction, } = props;
|
|
1327
|
+
// Extract account ID from the scope
|
|
1328
|
+
const accountId = Stack.of(this).account;
|
|
1329
|
+
// Resolve repoRestriction from props or environment variables
|
|
1330
|
+
let repoRestriction = propsRepoRestriction;
|
|
1331
|
+
if (!repoRestriction) {
|
|
1332
|
+
const envRepo = process.env.CDK_ENV_REPO || process.env.PROJECT_REPO;
|
|
1333
|
+
if (!envRepo) {
|
|
1334
|
+
throw new ConfigurationError("No repoRestriction provided. Set repoRestriction prop, CDK_ENV_REPO, or PROJECT_REPO environment variable");
|
|
1335
|
+
}
|
|
1336
|
+
// Extract organization from owner/repo format and create org-wide restriction
|
|
1337
|
+
const organization = envRepo.split("/")[0];
|
|
1338
|
+
repoRestriction = `repo:${organization}/*:*`;
|
|
1339
|
+
}
|
|
1340
|
+
// Create the IAM role
|
|
1341
|
+
this._role = new Role(this, "GitHubActionsRole", {
|
|
1342
|
+
assumedBy: new FederatedPrincipal(oidcProviderArn, {
|
|
1343
|
+
StringLike: {
|
|
1344
|
+
"token.actions.githubusercontent.com:sub": repoRestriction,
|
|
1345
|
+
},
|
|
1346
|
+
}, "sts:AssumeRoleWithWebIdentity"),
|
|
1347
|
+
maxSessionDuration: Duration.hours(1),
|
|
1348
|
+
path: "/",
|
|
1349
|
+
});
|
|
1350
|
+
Tags.of(this._role).add(CDK$2.TAG.ROLE, CDK$2.ROLE.DEPLOY);
|
|
1351
|
+
// Allow the role to access the GitHub OIDC provider
|
|
1352
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1353
|
+
actions: ["sts:AssumeRoleWithWebIdentity"],
|
|
1354
|
+
resources: [`arn:aws:iam::${accountId}:oidc-provider/*`],
|
|
1355
|
+
}));
|
|
1356
|
+
// Allow the role to deploy CDK apps
|
|
1357
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1358
|
+
actions: [
|
|
1359
|
+
"cloudformation:CreateStack",
|
|
1360
|
+
"cloudformation:DeleteStack",
|
|
1361
|
+
"cloudformation:DescribeStackEvents",
|
|
1362
|
+
"cloudformation:DescribeStackResource",
|
|
1363
|
+
"cloudformation:DescribeStackResources",
|
|
1364
|
+
"cloudformation:DescribeStacks",
|
|
1365
|
+
"cloudformation:GetTemplate",
|
|
1366
|
+
"cloudformation:SetStackPolicy",
|
|
1367
|
+
"cloudformation:UpdateStack",
|
|
1368
|
+
"cloudformation:ValidateTemplate",
|
|
1369
|
+
"iam:PassRole",
|
|
1370
|
+
"route53:ListHostedZones*",
|
|
1371
|
+
"s3:GetObject",
|
|
1372
|
+
"s3:ListBucket",
|
|
1373
|
+
],
|
|
1374
|
+
effect: Effect.ALLOW,
|
|
1375
|
+
resources: ["*"],
|
|
1376
|
+
}));
|
|
1377
|
+
this._role.addToPolicy(new PolicyStatement({
|
|
1378
|
+
actions: ["iam:PassRole", "sts:AssumeRole"],
|
|
1379
|
+
effect: Effect.ALLOW,
|
|
1380
|
+
resources: [
|
|
1381
|
+
"arn:aws:iam::*:role/cdk-hnb659fds-deploy-role-*",
|
|
1382
|
+
"arn:aws:iam::*:role/cdk-hnb659fds-file-publishing-*",
|
|
1383
|
+
"arn:aws:iam::*:role/cdk-readOnlyRole",
|
|
1384
|
+
],
|
|
1385
|
+
}));
|
|
1386
|
+
// Export the ARN of the role
|
|
1387
|
+
if (output !== false) {
|
|
1388
|
+
const outputId = typeof output === "string" ? output : "GitHubActionsRoleArn";
|
|
1389
|
+
new CfnOutput(this, outputId, {
|
|
1390
|
+
value: this._role.roleArn,
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
get role() {
|
|
1395
|
+
return this._role;
|
|
1396
|
+
}
|
|
1397
|
+
get roleArn() {
|
|
1398
|
+
return this._role.roleArn;
|
|
1399
|
+
}
|
|
1400
|
+
get roleName() {
|
|
1401
|
+
return this._role.roleName;
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1217
1405
|
class JaypieExpressLambda extends JaypieLambda {
|
|
1218
1406
|
constructor(scope, id, props) {
|
|
1219
1407
|
super(scope, id, {
|
|
@@ -1229,11 +1417,12 @@ const SERVICE = {
|
|
|
1229
1417
|
};
|
|
1230
1418
|
class JaypieHostedZone extends Construct {
|
|
1231
1419
|
/**
|
|
1232
|
-
* Create a new hosted zone with query logging
|
|
1420
|
+
* Create a new hosted zone with query logging and optional DNS records
|
|
1233
1421
|
*/
|
|
1234
1422
|
constructor(scope, id, props) {
|
|
1235
1423
|
super(scope, id);
|
|
1236
|
-
const {
|
|
1424
|
+
const { zoneName, project } = props;
|
|
1425
|
+
const destination = props.destination ?? true;
|
|
1237
1426
|
const service = props.service || CDK$2.SERVICE.INFRASTRUCTURE;
|
|
1238
1427
|
// Create the log group
|
|
1239
1428
|
this.logGroup = new LogGroup(this, "LogGroup", {
|
|
@@ -1250,10 +1439,13 @@ class JaypieHostedZone extends Construct {
|
|
|
1250
1439
|
}
|
|
1251
1440
|
// Grant Route 53 permissions to write to the log group
|
|
1252
1441
|
this.logGroup.grantWrite(new ServicePrincipal(SERVICE.ROUTE53));
|
|
1253
|
-
// Add destination
|
|
1254
|
-
if (destination) {
|
|
1442
|
+
// Add destination based on configuration
|
|
1443
|
+
if (destination !== false) {
|
|
1444
|
+
const lambdaDestination = destination === true
|
|
1445
|
+
? resolveDatadogLoggingDestination(scope)
|
|
1446
|
+
: destination;
|
|
1255
1447
|
this.logGroup.addSubscriptionFilter("DatadogLambdaDestination", {
|
|
1256
|
-
destination,
|
|
1448
|
+
destination: lambdaDestination,
|
|
1257
1449
|
filterPattern: FilterPattern.allEvents(),
|
|
1258
1450
|
});
|
|
1259
1451
|
}
|
|
@@ -1268,6 +1460,21 @@ class JaypieHostedZone extends Construct {
|
|
|
1268
1460
|
if (project) {
|
|
1269
1461
|
cdk.Tags.of(this.hostedZone).add(CDK$2.TAG.PROJECT, project);
|
|
1270
1462
|
}
|
|
1463
|
+
// Create DNS records if provided
|
|
1464
|
+
this.dnsRecords = [];
|
|
1465
|
+
if (props.records) {
|
|
1466
|
+
props.records.forEach((recordConfig, index) => {
|
|
1467
|
+
const { id, ...recordProps } = recordConfig;
|
|
1468
|
+
// Generate a default ID if not provided
|
|
1469
|
+
const recordId = id ||
|
|
1470
|
+
`${recordProps.type}${recordProps.recordName ? `-${recordProps.recordName}` : ""}-${index}`;
|
|
1471
|
+
const dnsRecord = new JaypieDnsRecord(this, recordId, {
|
|
1472
|
+
...recordProps,
|
|
1473
|
+
zone: this.hostedZone,
|
|
1474
|
+
});
|
|
1475
|
+
this.dnsRecords.push(dnsRecord);
|
|
1476
|
+
});
|
|
1477
|
+
}
|
|
1271
1478
|
}
|
|
1272
1479
|
}
|
|
1273
1480
|
|
|
@@ -1316,333 +1523,349 @@ class JaypieOpenAiSecret extends JaypieEnvSecret {
|
|
|
1316
1523
|
}
|
|
1317
1524
|
|
|
1318
1525
|
/**
|
|
1319
|
-
*
|
|
1526
|
+
* JaypieSsoPermissions Construct
|
|
1527
|
+
*
|
|
1528
|
+
* Creates and manages AWS IAM Identity Center (SSO) permission sets and assignments
|
|
1529
|
+
*
|
|
1530
|
+
* @example
|
|
1531
|
+
* const permissionSets = new JaypieSsoPermissions(this, "PermissionSets", {
|
|
1532
|
+
* iamIdentityCenterArn: "arn:aws:sso:::instance/...",
|
|
1533
|
+
* administratorGroupId: "b4c8b438-4031-7000-782d-5046945fb956",
|
|
1534
|
+
* analystGroupId: "2488f4e8-d061-708e-abe1-c315f0e30005",
|
|
1535
|
+
* developerGroupId: "b438a4f8-e0e1-707c-c6e8-21841daf9ad1",
|
|
1536
|
+
* administratorAccountAssignments: {
|
|
1537
|
+
* "211125635435": ["Administrator", "Analyst", "Developer"],
|
|
1538
|
+
* "381492033431": ["Administrator", "Analyst"],
|
|
1539
|
+
* },
|
|
1540
|
+
* analystAccountAssignments: {
|
|
1541
|
+
* "211125635435": ["Analyst", "Developer"],
|
|
1542
|
+
* "381492033431": [],
|
|
1543
|
+
* },
|
|
1544
|
+
* developerAccountAssignments: {
|
|
1545
|
+
* "211125635435": ["Analyst", "Developer"],
|
|
1546
|
+
* "381492033431": [],
|
|
1547
|
+
* },
|
|
1548
|
+
* });
|
|
1320
1549
|
*/
|
|
1321
|
-
|
|
1322
|
-
(function (PermissionSetType) {
|
|
1323
|
-
PermissionSetType["ADMINISTRATOR"] = "Administrator";
|
|
1324
|
-
PermissionSetType["ANALYST"] = "Analyst";
|
|
1325
|
-
PermissionSetType["DEVELOPER"] = "Developer";
|
|
1326
|
-
})(PermissionSetType || (PermissionSetType = {}));
|
|
1327
|
-
/**
|
|
1328
|
-
* Construct to simplify AWS SSO group management.
|
|
1329
|
-
* This construct encapsulates the complexity of creating permission sets
|
|
1330
|
-
* and assigning them to groups across multiple AWS accounts.
|
|
1331
|
-
*/
|
|
1332
|
-
class JaypieSsoGroups extends Construct {
|
|
1550
|
+
class JaypieSsoPermissions extends Construct {
|
|
1333
1551
|
constructor(scope, id, props) {
|
|
1334
1552
|
super(scope, id);
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
//
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1553
|
+
const { iamIdentityCenterArn: iamIdentityCenterArnProp, administratorGroupId, analystGroupId, developerGroupId, administratorAccountAssignments, analystAccountAssignments, developerAccountAssignments, } = props;
|
|
1554
|
+
const iamIdentityCenterArn = iamIdentityCenterArnProp || process.env.CDK_ENV_IAM_IDENTITY_CENTER_ARN;
|
|
1555
|
+
if (!iamIdentityCenterArn) {
|
|
1556
|
+
// If no IAM Identity Center ARN provided, skip SSO setup
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
//
|
|
1560
|
+
// Permission Sets
|
|
1561
|
+
//
|
|
1562
|
+
this.administratorPermissionSet = new CfnPermissionSet(this, "AdministratorPermissionSet", {
|
|
1563
|
+
// Required
|
|
1564
|
+
instanceArn: iamIdentityCenterArn,
|
|
1565
|
+
name: "Administrator",
|
|
1566
|
+
// Optional
|
|
1567
|
+
description: "Unrestricted access",
|
|
1568
|
+
inlinePolicy: {
|
|
1569
|
+
Version: "2012-10-17",
|
|
1570
|
+
Statement: [
|
|
1571
|
+
{
|
|
1572
|
+
Effect: "Allow",
|
|
1573
|
+
Action: [
|
|
1574
|
+
"aws-portal:ViewUsage",
|
|
1575
|
+
"aws-portal:ViewBilling",
|
|
1576
|
+
"budgets:*",
|
|
1577
|
+
"cur:DescribeReportDefinitions",
|
|
1578
|
+
"cur:PutReportDefinition",
|
|
1579
|
+
"cur:DeleteReportDefinition",
|
|
1580
|
+
"cur:ModifyReportDefinition",
|
|
1581
|
+
],
|
|
1582
|
+
Resource: "*",
|
|
1583
|
+
},
|
|
1584
|
+
],
|
|
1585
|
+
},
|
|
1586
|
+
managedPolicies: [
|
|
1587
|
+
ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess")
|
|
1588
|
+
.managedPolicyArn,
|
|
1589
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1590
|
+
],
|
|
1591
|
+
sessionDuration: Duration.hours(1).toIsoString(),
|
|
1592
|
+
tags: [
|
|
1353
1593
|
{
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
"aws-portal:*",
|
|
1357
|
-
"budgets:*",
|
|
1358
|
-
"ce:*",
|
|
1359
|
-
"cost-optimization-hub:*",
|
|
1360
|
-
"cur:*",
|
|
1361
|
-
],
|
|
1362
|
-
Resource: "*",
|
|
1594
|
+
key: CDK$2.TAG.SERVICE,
|
|
1595
|
+
value: CDK$2.SERVICE.SSO,
|
|
1363
1596
|
},
|
|
1364
|
-
],
|
|
1365
|
-
};
|
|
1366
|
-
// Merge with any additional policy statements provided for administrators
|
|
1367
|
-
const mergedPolicy = this.mergeInlinePolicies(defaultInlinePolicy, this.props?.inlinePolicyStatements?.administrators);
|
|
1368
|
-
const permissionSet = new sso.CfnPermissionSet(this, "AdministratorPermissionSet", {
|
|
1369
|
-
instanceArn: this.instanceArn,
|
|
1370
|
-
name: PermissionSetType.ADMINISTRATOR,
|
|
1371
|
-
description: "Full administrative access to all AWS services and resources",
|
|
1372
|
-
sessionDuration: Duration.hours(8).toIsoString(),
|
|
1373
|
-
managedPolicies: ["arn:aws:iam::aws:policy/AdministratorAccess"],
|
|
1374
|
-
inlinePolicy: mergedPolicy,
|
|
1375
|
-
});
|
|
1376
|
-
Tags.of(permissionSet).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1377
|
-
this.permissionSets[PermissionSetType.ADMINISTRATOR] = permissionSet;
|
|
1378
|
-
}
|
|
1379
|
-
/**
|
|
1380
|
-
* Creates the Analyst permission set with ReadOnlyAccess policy
|
|
1381
|
-
* and limited write access
|
|
1382
|
-
*/
|
|
1383
|
-
createAnalystPermissionSet() {
|
|
1384
|
-
const defaultInlinePolicy = {
|
|
1385
|
-
Version: "2012-10-17",
|
|
1386
|
-
Statement: [
|
|
1387
1597
|
{
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
"aws-portal:ViewUsage",
|
|
1391
|
-
"aws-portal:ViewBilling",
|
|
1392
|
-
"budgets:Describe*",
|
|
1393
|
-
"budgets:View*",
|
|
1394
|
-
"ce:Get*",
|
|
1395
|
-
"ce:List*",
|
|
1396
|
-
"cloudformation:Describe*",
|
|
1397
|
-
"cloudformation:Get*",
|
|
1398
|
-
"cloudformation:List*",
|
|
1399
|
-
"cloudwatch:BatchGet*",
|
|
1400
|
-
"cloudwatch:Get*",
|
|
1401
|
-
"cloudwatch:List*",
|
|
1402
|
-
"cost-optimization-hub:Get*",
|
|
1403
|
-
"cost-optimization-hub:List*",
|
|
1404
|
-
"ec2:Describe*",
|
|
1405
|
-
"ec2:Get*",
|
|
1406
|
-
"ec2:List*",
|
|
1407
|
-
"ec2:Search*",
|
|
1408
|
-
"iam:Get*",
|
|
1409
|
-
"iam:List*",
|
|
1410
|
-
"iam:PassRole",
|
|
1411
|
-
"lambda:Get*",
|
|
1412
|
-
"lambda:List*",
|
|
1413
|
-
"logs:Describe*",
|
|
1414
|
-
"logs:Get*",
|
|
1415
|
-
"logs:List*",
|
|
1416
|
-
"pipes:Describe*",
|
|
1417
|
-
"pipes:List*",
|
|
1418
|
-
"s3:Get*",
|
|
1419
|
-
"s3:List*",
|
|
1420
|
-
"secretsmanager:GetRandomPassword",
|
|
1421
|
-
"secretsmanager:GetResourcePolicy",
|
|
1422
|
-
"secretsmanager:List*",
|
|
1423
|
-
"securityhub:Describe*",
|
|
1424
|
-
"securityhub:Get*",
|
|
1425
|
-
"securityhub:List*",
|
|
1426
|
-
"servicecatalog:Describe*",
|
|
1427
|
-
"sns:Get*",
|
|
1428
|
-
"sns:List*",
|
|
1429
|
-
"sqs:Get*",
|
|
1430
|
-
"sqs:List*",
|
|
1431
|
-
"states:Describe*",
|
|
1432
|
-
"states:Get*",
|
|
1433
|
-
"states:List*",
|
|
1434
|
-
"tag:*",
|
|
1435
|
-
"xray:*",
|
|
1436
|
-
],
|
|
1437
|
-
Resource: "*",
|
|
1598
|
+
key: CDK$2.TAG.ROLE,
|
|
1599
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1438
1600
|
},
|
|
1439
1601
|
],
|
|
1440
|
-
};
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
description: "Read-only access
|
|
1447
|
-
|
|
1602
|
+
});
|
|
1603
|
+
this.analystPermissionSet = new CfnPermissionSet(this, "AnalystPermissionSet", {
|
|
1604
|
+
// Required
|
|
1605
|
+
instanceArn: iamIdentityCenterArn,
|
|
1606
|
+
name: "Analyst",
|
|
1607
|
+
// Optional
|
|
1608
|
+
description: "Read-only access; may expand to limited write access",
|
|
1609
|
+
inlinePolicy: {
|
|
1610
|
+
Version: "2012-10-17",
|
|
1611
|
+
Statement: [
|
|
1612
|
+
{
|
|
1613
|
+
Effect: "Allow",
|
|
1614
|
+
Action: [
|
|
1615
|
+
"aws-portal:ViewUsage",
|
|
1616
|
+
"aws-portal:ViewBilling",
|
|
1617
|
+
"budgets:Describe*",
|
|
1618
|
+
"budgets:View*",
|
|
1619
|
+
"ce:Get*",
|
|
1620
|
+
"ce:List*",
|
|
1621
|
+
"cloudformation:Describe*",
|
|
1622
|
+
"cloudformation:Get*",
|
|
1623
|
+
"cloudformation:List*",
|
|
1624
|
+
"cloudwatch:BatchGet*",
|
|
1625
|
+
"cloudwatch:Get*",
|
|
1626
|
+
"cloudwatch:List*",
|
|
1627
|
+
"cost-optimization-hub:Get*",
|
|
1628
|
+
"cost-optimization-hub:List*",
|
|
1629
|
+
"ec2:Describe*",
|
|
1630
|
+
"ec2:Get*",
|
|
1631
|
+
"ec2:List*",
|
|
1632
|
+
"ec2:Search*",
|
|
1633
|
+
"iam:Get*",
|
|
1634
|
+
"iam:List*",
|
|
1635
|
+
"iam:PassRole",
|
|
1636
|
+
"lambda:Get*",
|
|
1637
|
+
"lambda:List*",
|
|
1638
|
+
"logs:Describe*",
|
|
1639
|
+
"logs:Get*",
|
|
1640
|
+
"logs:List*",
|
|
1641
|
+
"pipes:Describe*",
|
|
1642
|
+
"pipes:List*",
|
|
1643
|
+
"s3:Get*",
|
|
1644
|
+
"s3:List*",
|
|
1645
|
+
"secretsmanager:GetRandomPassword",
|
|
1646
|
+
"secretsmanager:GetResourcePolicy",
|
|
1647
|
+
"secretsmanager:List*",
|
|
1648
|
+
"securityhub:Describe*",
|
|
1649
|
+
"securityhub:Get*",
|
|
1650
|
+
"securityhub:List*",
|
|
1651
|
+
"servicecatalog:Describe*",
|
|
1652
|
+
"sns:Get*",
|
|
1653
|
+
"sns:List*",
|
|
1654
|
+
"sqs:Get*",
|
|
1655
|
+
"sqs:List*",
|
|
1656
|
+
"states:Describe*",
|
|
1657
|
+
"states:Get*",
|
|
1658
|
+
"states:List*",
|
|
1659
|
+
"tag:*",
|
|
1660
|
+
"xray:*",
|
|
1661
|
+
],
|
|
1662
|
+
Resource: "*",
|
|
1663
|
+
},
|
|
1664
|
+
],
|
|
1665
|
+
},
|
|
1448
1666
|
managedPolicies: [
|
|
1449
1667
|
ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
1450
1668
|
.managedPolicyArn,
|
|
1669
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1451
1670
|
ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
1452
1671
|
.managedPolicyArn,
|
|
1453
1672
|
],
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
Tags.of(permissionSet).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1457
|
-
this.permissionSets[PermissionSetType.ANALYST] = permissionSet;
|
|
1458
|
-
}
|
|
1459
|
-
/**
|
|
1460
|
-
* Creates the Developer permission set with SystemAdministrator policy
|
|
1461
|
-
* and expanded write access
|
|
1462
|
-
*/
|
|
1463
|
-
createDeveloperPermissionSet() {
|
|
1464
|
-
const defaultInlinePolicy = {
|
|
1465
|
-
Version: "2012-10-17",
|
|
1466
|
-
Statement: [
|
|
1673
|
+
sessionDuration: Duration.hours(12).toIsoString(),
|
|
1674
|
+
tags: [
|
|
1467
1675
|
{
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
"budgets:*",
|
|
1471
|
-
"ce:*",
|
|
1472
|
-
"cloudformation:*",
|
|
1473
|
-
"cloudwatch:*",
|
|
1474
|
-
"cost-optimization-hub:*",
|
|
1475
|
-
"ec2:*",
|
|
1476
|
-
"iam:Get*",
|
|
1477
|
-
"iam:List*",
|
|
1478
|
-
"iam:PassRole",
|
|
1479
|
-
"lambda:*",
|
|
1480
|
-
"logs:*",
|
|
1481
|
-
"pipes:*",
|
|
1482
|
-
"s3:*",
|
|
1483
|
-
"secretsmanager:*",
|
|
1484
|
-
"securityhub:*",
|
|
1485
|
-
"servicecatalog:*",
|
|
1486
|
-
"sns:*",
|
|
1487
|
-
"sqs:*",
|
|
1488
|
-
"states:*",
|
|
1489
|
-
"tag:*",
|
|
1490
|
-
"xray:*",
|
|
1491
|
-
],
|
|
1492
|
-
Resource: "*",
|
|
1676
|
+
key: CDK$2.TAG.SERVICE,
|
|
1677
|
+
value: CDK$2.SERVICE.SSO,
|
|
1493
1678
|
},
|
|
1494
1679
|
{
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
"iam:*User*",
|
|
1498
|
-
"iam:*Role*",
|
|
1499
|
-
"iam:*Policy*",
|
|
1500
|
-
"organizations:*",
|
|
1501
|
-
"account:*",
|
|
1502
|
-
],
|
|
1503
|
-
Resource: "*",
|
|
1680
|
+
key: CDK$2.TAG.ROLE,
|
|
1681
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1504
1682
|
},
|
|
1505
1683
|
],
|
|
1506
|
-
};
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
description: "
|
|
1513
|
-
|
|
1684
|
+
});
|
|
1685
|
+
this.developerPermissionSet = new CfnPermissionSet(this, "DeveloperPermissionSet", {
|
|
1686
|
+
// Required
|
|
1687
|
+
instanceArn: iamIdentityCenterArn,
|
|
1688
|
+
name: "Developer",
|
|
1689
|
+
// Optional
|
|
1690
|
+
description: "Administrative access with limited restrictions",
|
|
1691
|
+
inlinePolicy: {
|
|
1692
|
+
Version: "2012-10-17",
|
|
1693
|
+
Statement: [
|
|
1694
|
+
{
|
|
1695
|
+
Effect: "Allow",
|
|
1696
|
+
Action: [
|
|
1697
|
+
"budgets:*",
|
|
1698
|
+
"ce:*",
|
|
1699
|
+
"cloudformation:*",
|
|
1700
|
+
"cloudwatch:*",
|
|
1701
|
+
"cost-optimization-hub:*",
|
|
1702
|
+
"ec2:*",
|
|
1703
|
+
"iam:Get*",
|
|
1704
|
+
"iam:List*",
|
|
1705
|
+
"iam:PassRole",
|
|
1706
|
+
"lambda:*",
|
|
1707
|
+
"logs:*",
|
|
1708
|
+
"pipes:*",
|
|
1709
|
+
"s3:*",
|
|
1710
|
+
"secretsmanager:*",
|
|
1711
|
+
"securityhub:*",
|
|
1712
|
+
"servicecatalog:*",
|
|
1713
|
+
"sns:*",
|
|
1714
|
+
"sqs:*",
|
|
1715
|
+
"states:*",
|
|
1716
|
+
"tag:*",
|
|
1717
|
+
"xray:*",
|
|
1718
|
+
],
|
|
1719
|
+
Resource: "*",
|
|
1720
|
+
},
|
|
1721
|
+
],
|
|
1722
|
+
},
|
|
1514
1723
|
managedPolicies: [
|
|
1515
1724
|
ManagedPolicy.fromAwsManagedPolicyName("AmazonQDeveloperAccess")
|
|
1516
1725
|
.managedPolicyArn,
|
|
1726
|
+
ManagedPolicy.fromAwsManagedPolicyName("AWSManagementConsoleBasicUserAccess").managedPolicyArn,
|
|
1517
1727
|
ManagedPolicy.fromAwsManagedPolicyName("ReadOnlyAccess")
|
|
1518
1728
|
.managedPolicyArn,
|
|
1519
1729
|
ManagedPolicy.fromAwsManagedPolicyName("job-function/SystemAdministrator").managedPolicyArn,
|
|
1520
1730
|
],
|
|
1521
|
-
|
|
1731
|
+
sessionDuration: Duration.hours(4).toIsoString(),
|
|
1732
|
+
tags: [
|
|
1733
|
+
{
|
|
1734
|
+
key: CDK$2.TAG.SERVICE,
|
|
1735
|
+
value: CDK$2.SERVICE.SSO,
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
key: CDK$2.TAG.ROLE,
|
|
1739
|
+
value: CDK$2.ROLE.SECURITY,
|
|
1740
|
+
},
|
|
1741
|
+
],
|
|
1522
1742
|
});
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1743
|
+
// Map permission set names to their ARNs and labels
|
|
1744
|
+
const permissionSetMap = {
|
|
1745
|
+
Administrator: {
|
|
1746
|
+
arn: this.administratorPermissionSet.attrPermissionSetArn,
|
|
1747
|
+
label: "Administrator",
|
|
1748
|
+
},
|
|
1749
|
+
Analyst: {
|
|
1750
|
+
arn: this.analystPermissionSet.attrPermissionSetArn,
|
|
1751
|
+
label: "Analyst",
|
|
1752
|
+
},
|
|
1753
|
+
Developer: {
|
|
1754
|
+
arn: this.developerPermissionSet.attrPermissionSetArn,
|
|
1755
|
+
label: "Developer",
|
|
1756
|
+
},
|
|
1757
|
+
};
|
|
1758
|
+
//
|
|
1759
|
+
// Assignments
|
|
1760
|
+
//
|
|
1761
|
+
// Helper function to create assignments for a group
|
|
1762
|
+
const createAssignments = (groupId, accountAssignments) => {
|
|
1763
|
+
if (!groupId || !accountAssignments) {
|
|
1764
|
+
return; // Skip if group ID or assignments not provided
|
|
1765
|
+
}
|
|
1766
|
+
Object.keys(accountAssignments).forEach((accountId) => {
|
|
1767
|
+
const permissionSetNames = accountAssignments[accountId];
|
|
1768
|
+
permissionSetNames.forEach((permissionSetName) => {
|
|
1769
|
+
const permissionSet = permissionSetMap[permissionSetName];
|
|
1770
|
+
if (!permissionSet) {
|
|
1771
|
+
throw new ConfigurationError(`Unknown permission set: ${permissionSetName}. Valid options: ${Object.keys(permissionSetMap).join(", ")}`);
|
|
1772
|
+
}
|
|
1773
|
+
const accountAssignment = new CfnAssignment(this, `AccountAssignment-${accountId}-${permissionSet.label}Role-${groupId}Group`, {
|
|
1774
|
+
// Required
|
|
1775
|
+
instanceArn: iamIdentityCenterArn,
|
|
1776
|
+
permissionSetArn: permissionSet.arn,
|
|
1777
|
+
principalId: groupId,
|
|
1778
|
+
principalType: CDK$2.PRINCIPAL_TYPE.GROUP,
|
|
1779
|
+
targetId: accountId,
|
|
1780
|
+
targetType: CDK$2.TARGET_TYPE.AWS_ACCOUNT,
|
|
1781
|
+
});
|
|
1782
|
+
Tags.of(accountAssignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1783
|
+
Tags.of(accountAssignment).add(CDK$2.TAG.ROLE, CDK$2.ROLE.SECURITY);
|
|
1784
|
+
});
|
|
1785
|
+
});
|
|
1786
|
+
};
|
|
1787
|
+
// Create assignments for each group
|
|
1788
|
+
createAssignments(administratorGroupId, administratorAccountAssignments);
|
|
1789
|
+
createAssignments(analystGroupId, analystAccountAssignments);
|
|
1790
|
+
createAssignments(developerGroupId, developerAccountAssignments);
|
|
1531
1791
|
}
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
//
|
|
1795
|
+
//
|
|
1796
|
+
// Constants
|
|
1797
|
+
//
|
|
1798
|
+
const DEFAULT_APPLICATION_ID = "arn:aws:serverlessrepo:us-east-2:004480582608:applications/SSOSync";
|
|
1799
|
+
const DEFAULT_APPLICATION_VERSION = "2.3.3";
|
|
1800
|
+
const DEFAULT_GOOGLE_GROUP_MATCH = "name:AWS*";
|
|
1801
|
+
//
|
|
1802
|
+
//
|
|
1803
|
+
// Class
|
|
1804
|
+
//
|
|
1805
|
+
class JaypieSsoSyncApplication extends Construct {
|
|
1806
|
+
constructor(scope, id = "SsoSyncApplication", props = {}) {
|
|
1807
|
+
super(scope, id);
|
|
1808
|
+
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;
|
|
1809
|
+
// Resolve all values from props or environment variables
|
|
1810
|
+
const resolvedGoogleAdminEmail = googleAdminEmail || process.env[googleAdminEmailEnvKey];
|
|
1811
|
+
const resolvedGoogleCredentials = googleCredentials || process.env[googleCredentialsEnvKey];
|
|
1812
|
+
const resolvedGoogleGroupMatch = googleGroupMatch ||
|
|
1813
|
+
process.env[googleGroupMatchEnvKey] ||
|
|
1814
|
+
DEFAULT_GOOGLE_GROUP_MATCH;
|
|
1815
|
+
const resolvedIdentityStoreId = identityStoreId || process.env[identityStoreIdEnvKey];
|
|
1816
|
+
const resolvedScimEndpointAccessToken = scimEndpointAccessToken || process.env[scimEndpointAccessTokenEnvKey];
|
|
1817
|
+
const resolvedScimEndpointUrl = scimEndpointUrl || process.env[scimEndpointUrlEnvKey];
|
|
1818
|
+
const resolvedSemanticVersion = semanticVersion ||
|
|
1819
|
+
process.env[semanticVersionEnvKey] ||
|
|
1820
|
+
DEFAULT_APPLICATION_VERSION;
|
|
1821
|
+
// Validate required parameters
|
|
1822
|
+
const missingParams = [];
|
|
1823
|
+
if (!resolvedGoogleAdminEmail) {
|
|
1824
|
+
missingParams.push(`googleAdminEmail or ${googleAdminEmailEnvKey} environment variable`);
|
|
1542
1825
|
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
//
|
|
1560
|
-
this.
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
...props.accountMap.operations,
|
|
1575
|
-
...props.accountMap.production,
|
|
1576
|
-
...props.accountMap.sandbox,
|
|
1577
|
-
...props.accountMap.security,
|
|
1578
|
-
...props.accountMap.stage,
|
|
1579
|
-
];
|
|
1580
|
-
// Create assignments for each account
|
|
1581
|
-
allAccounts.forEach((accountId, index) => {
|
|
1582
|
-
const assignment = new sso.CfnAssignment(this, `AdministratorAssignment${index}`, {
|
|
1583
|
-
instanceArn: this.instanceArn,
|
|
1584
|
-
permissionSetArn: administratorPermissionSet.attrPermissionSetArn,
|
|
1585
|
-
principalId: administratorGroup,
|
|
1586
|
-
principalType: "GROUP",
|
|
1587
|
-
targetId: accountId,
|
|
1588
|
-
targetType: "AWS_ACCOUNT",
|
|
1589
|
-
});
|
|
1590
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1591
|
-
Tags.of(assignment).add("Group", "administrators");
|
|
1826
|
+
if (!resolvedGoogleCredentials) {
|
|
1827
|
+
missingParams.push(`googleCredentials or ${googleCredentialsEnvKey} environment variable`);
|
|
1828
|
+
}
|
|
1829
|
+
if (!resolvedIdentityStoreId) {
|
|
1830
|
+
missingParams.push(`identityStoreId or ${identityStoreIdEnvKey} environment variable`);
|
|
1831
|
+
}
|
|
1832
|
+
if (!resolvedScimEndpointAccessToken) {
|
|
1833
|
+
missingParams.push(`scimEndpointAccessToken or ${scimEndpointAccessTokenEnvKey} environment variable`);
|
|
1834
|
+
}
|
|
1835
|
+
if (!resolvedScimEndpointUrl) {
|
|
1836
|
+
missingParams.push(`scimEndpointUrl or ${scimEndpointUrlEnvKey} environment variable`);
|
|
1837
|
+
}
|
|
1838
|
+
if (missingParams.length > 0) {
|
|
1839
|
+
throw new ConfigurationError$1(`JaypieSsoSyncApplication missing required configuration: ${missingParams.join(", ")}`);
|
|
1840
|
+
}
|
|
1841
|
+
// Create the SSO Sync Application
|
|
1842
|
+
// Type assertion is safe because we validated all required values above
|
|
1843
|
+
this._application = new CfnApplication(this, "Application", {
|
|
1844
|
+
location: {
|
|
1845
|
+
applicationId: ssoSyncApplicationId,
|
|
1846
|
+
semanticVersion: resolvedSemanticVersion,
|
|
1847
|
+
},
|
|
1848
|
+
parameters: {
|
|
1849
|
+
GoogleAdminEmail: resolvedGoogleAdminEmail,
|
|
1850
|
+
GoogleCredentials: resolvedGoogleCredentials,
|
|
1851
|
+
GoogleGroupMatch: resolvedGoogleGroupMatch,
|
|
1852
|
+
IdentityStoreID: resolvedIdentityStoreId,
|
|
1853
|
+
Region: Stack.of(this).region,
|
|
1854
|
+
SCIMEndpointAccessToken: resolvedScimEndpointAccessToken,
|
|
1855
|
+
SCIMEndpointUrl: resolvedScimEndpointUrl,
|
|
1856
|
+
},
|
|
1592
1857
|
});
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
// Analysts get access to development, management, sandbox, and stage accounts
|
|
1601
|
-
const analystAccounts = [
|
|
1602
|
-
...props.accountMap.development,
|
|
1603
|
-
...props.accountMap.management,
|
|
1604
|
-
...props.accountMap.sandbox,
|
|
1605
|
-
...props.accountMap.stage,
|
|
1606
|
-
];
|
|
1607
|
-
// Create assignments for each account
|
|
1608
|
-
analystAccounts.forEach((accountId, index) => {
|
|
1609
|
-
const assignment = new sso.CfnAssignment(this, `AnalystAssignment${index}`, {
|
|
1610
|
-
instanceArn: this.instanceArn,
|
|
1611
|
-
permissionSetArn: analystPermissionSet.attrPermissionSetArn,
|
|
1612
|
-
principalId: analystGroup,
|
|
1613
|
-
principalType: "GROUP",
|
|
1614
|
-
targetId: accountId,
|
|
1615
|
-
targetType: "AWS_ACCOUNT",
|
|
1616
|
-
});
|
|
1617
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1618
|
-
Tags.of(assignment).add("Group", "analysts");
|
|
1858
|
+
// Add tags
|
|
1859
|
+
const defaultTags = {
|
|
1860
|
+
[CDK$2.TAG.ROLE]: CDK$2.ROLE.SECURITY,
|
|
1861
|
+
};
|
|
1862
|
+
const allTags = { ...defaultTags, ...tags };
|
|
1863
|
+
Object.entries(allTags).forEach(([key, value]) => {
|
|
1864
|
+
Tags.of(this._application).add(key, value);
|
|
1619
1865
|
});
|
|
1620
1866
|
}
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
*/
|
|
1624
|
-
assignDeveloperPermissions(props) {
|
|
1625
|
-
const developerGroup = props.groupMap.developers;
|
|
1626
|
-
const developerPermissionSet = this.permissionSets[PermissionSetType.DEVELOPER];
|
|
1627
|
-
// Developers get access to development, sandbox, and stage accounts
|
|
1628
|
-
const developerAccounts = [
|
|
1629
|
-
...props.accountMap.development,
|
|
1630
|
-
...props.accountMap.sandbox,
|
|
1631
|
-
...props.accountMap.stage,
|
|
1632
|
-
];
|
|
1633
|
-
// Create assignments for each account
|
|
1634
|
-
developerAccounts.forEach((accountId, index) => {
|
|
1635
|
-
const assignment = new sso.CfnAssignment(this, `DeveloperAssignment${index}`, {
|
|
1636
|
-
instanceArn: this.instanceArn,
|
|
1637
|
-
permissionSetArn: developerPermissionSet.attrPermissionSetArn,
|
|
1638
|
-
principalId: developerGroup,
|
|
1639
|
-
principalType: "GROUP",
|
|
1640
|
-
targetId: accountId,
|
|
1641
|
-
targetType: "AWS_ACCOUNT",
|
|
1642
|
-
});
|
|
1643
|
-
Tags.of(assignment).add(CDK$2.TAG.SERVICE, CDK$2.SERVICE.SSO);
|
|
1644
|
-
Tags.of(assignment).add("Group", "developers");
|
|
1645
|
-
});
|
|
1867
|
+
get application() {
|
|
1868
|
+
return this._application;
|
|
1646
1869
|
}
|
|
1647
1870
|
}
|
|
1648
1871
|
|
|
@@ -1904,7 +2127,13 @@ class JaypieWebDeploymentBucket extends Construct {
|
|
|
1904
2127
|
applyRemovalPolicy(policy) {
|
|
1905
2128
|
this.bucket.applyRemovalPolicy(policy);
|
|
1906
2129
|
}
|
|
2130
|
+
get bucketRef() {
|
|
2131
|
+
return {
|
|
2132
|
+
bucketArn: this.bucket.bucketArn,
|
|
2133
|
+
bucketName: this.bucket.bucketName,
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
1907
2136
|
}
|
|
1908
2137
|
|
|
1909
|
-
export { JaypieApiGateway, JaypieAppStack, JaypieBucketQueuedLambda, JaypieDatadogSecret, JaypieEnvSecret, JaypieExpressLambda, JaypieHostedZone, JaypieInfrastructureStack, JaypieLambda, JaypieMongoDbSecret, JaypieOpenAiSecret, JaypieQueuedLambda,
|
|
2138
|
+
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 };
|
|
1910
2139
|
//# sourceMappingURL=index.js.map
|