@fjall/components-infrastructure 0.102.0 → 1.1.0
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/lib/lambda-assets/cert-generator/asset/index.js +17948 -0
- package/dist/lib/lambda-assets/cert-generator/asset/package.json +4 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +37 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.js +120 -19
- package/dist/lib/patterns/aws/clickhouseTls/index.d.ts +1 -0
- package/dist/lib/patterns/aws/clickhouseTls/index.js +1 -0
- package/dist/lib/patterns/aws/clickhouseTls/types.d.ts +48 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +21 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.js +21 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +2 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +2 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +21 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.js +48 -3
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +1 -1
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +1 -1
- package/dist/lib/resources/aws/secrets/index.d.ts +2 -0
- package/dist/lib/resources/aws/secrets/index.js +2 -0
- package/dist/lib/resources/aws/secrets/tlsCaSecret.d.ts +13 -0
- package/dist/lib/resources/aws/secrets/tlsCaSecret.js +15 -0
- package/dist/lib/resources/aws/secrets/tlsServerSecret.d.ts +15 -0
- package/dist/lib/resources/aws/secrets/tlsServerSecret.js +17 -0
- package/dist/lib/resources/aws/utilities/index.d.ts +1 -0
- package/dist/lib/resources/aws/utilities/index.js +1 -0
- package/dist/lib/resources/aws/utilities/tlsCertGenerator.d.ts +33 -0
- package/dist/lib/resources/aws/utilities/tlsCertGenerator.js +67 -0
- package/package.json +7 -5
- package/dist/lib/config/aws/__t17fixture.js +0 -3
- package/dist/lib/config/aws/__t17fixtureType.d.ts +0 -2
- package/dist/lib/config/aws/__t17fixtureType.js +0 -1
- package/dist/lib/config/aws/eventBus.d.ts +0 -7
- package/dist/lib/config/aws/eventBus.js +0 -21
- package/dist/lib/config/aws/identityCenterGroupMembership.d.ts +0 -10
- package/dist/lib/config/aws/identityCenterGroupMembership.js +0 -102
- package/dist/lib/config/aws/securityBaseline.d.ts +0 -15
- package/dist/lib/config/aws/securityBaseline.js +0 -27
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +0 -1
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +0 -4
- package/dist/lib/patterns/aws/managedIdentityCenter.d.ts +0 -4
- package/dist/lib/patterns/aws/managedIdentityCenter.js +0 -19
- package/dist/lib/patterns/aws/subdomainHostedZone.d.ts +0 -9
- package/dist/lib/patterns/aws/subdomainHostedZone.js +0 -34
- package/dist/lib/resources/aws/analytics/clickhouse.d.ts +0 -15
- package/dist/lib/resources/aws/analytics/clickhouse.js +0 -310
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +0 -49
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +0 -140
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +0 -73
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +0 -89
- package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.d.ts +0 -13
- package/dist/lib/resources/aws/analytics/clickhouseSecurityGroup.js +0 -28
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +0 -59
- package/dist/lib/resources/aws/analytics/clickhouseTypes.js +0 -1
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +0 -6
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +0 -299
- package/dist/lib/resources/aws/analytics/index.d.ts +0 -4
- package/dist/lib/resources/aws/analytics/index.js +0 -2
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +0 -2
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +0 -11
- package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +0 -7
- package/dist/lib/resources/aws/messaging/defaultEventBus.js +0 -21
- package/dist/lib/resources/aws/networking/domain.d.ts +0 -13
- package/dist/lib/resources/aws/networking/domain.js +0 -100
- package/dist/lib/synth_dump.d.ts +0 -1
- package/dist/lib/synth_dump.js +0 -42
- package/dist/lib/utils/bastionFactory.d.ts +0 -10
- package/dist/lib/utils/bastionFactory.js +0 -29
- package/dist/lib/utils/constructMap.d.ts +0 -33
- package/dist/lib/utils/constructMap.js +0 -154
- package/dist/lib/utils/dnsRecords.d.ts +0 -4
- package/dist/lib/utils/dnsRecords.js +0 -104
- /package/dist/lib/{config/aws/__t17fixture.d.ts → patterns/aws/clickhouseTls/types.js} +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RemovalPolicy } from "aws-cdk-lib";
|
|
2
|
+
import { Secret } from "./secret.js";
|
|
3
|
+
/**
|
|
4
|
+
* ClickHouse TLS server cert + key (JSON: `{ cert, key }`). Retained on
|
|
5
|
+
* delete so cert material survives accidental stack teardown; the private
|
|
6
|
+
* key only leaves Secrets Manager via ECS executionRole + the TLS init
|
|
7
|
+
* container that materialises it onto the shared volume.
|
|
8
|
+
*/
|
|
9
|
+
export class TlsServerSecret extends Secret {
|
|
10
|
+
constructor(scope, id, props) {
|
|
11
|
+
super(scope, id, {
|
|
12
|
+
secretName: `fjall-${props.appName}-clickhouse-tls-server`,
|
|
13
|
+
description: "ClickHouse TLS server cert + key (JSON: { cert, key })"
|
|
14
|
+
});
|
|
15
|
+
this.secret.applyRemovalPolicy(RemovalPolicy.RETAIN);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Construct } from "constructs";
|
|
2
|
+
import { TlsCaSecret } from "../secrets/tlsCaSecret.js";
|
|
3
|
+
import { TlsServerSecret } from "../secrets/tlsServerSecret.js";
|
|
4
|
+
export interface TlsCertGeneratorProps {
|
|
5
|
+
/** Drives the deterministic Secrets Manager names of the two cert secrets. */
|
|
6
|
+
readonly appName: string;
|
|
7
|
+
/**
|
|
8
|
+
* Hostname embedded as CN + SAN dns entry on the leaf cert. Typically the
|
|
9
|
+
* Cloud Map SRV name the ClickHouse service answers on.
|
|
10
|
+
*/
|
|
11
|
+
readonly hostname: string;
|
|
12
|
+
/** CA cert validity in years (default 10). Bumping forces re-issuance on next deploy. */
|
|
13
|
+
readonly caValidityYears?: number;
|
|
14
|
+
/** Leaf cert validity in years (default 5). Bumping forces re-issuance on next deploy. */
|
|
15
|
+
readonly leafValidityYears?: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Custom-resource Lambda that mints a self-signed CA + leaf cert on stack
|
|
19
|
+
* deploy and persists them to Secrets Manager. The CA secret carries the
|
|
20
|
+
* raw PEM (public — clients pin against it); the server secret carries a
|
|
21
|
+
* JSON `{ cert, key }` payload consumed by the TLS init container.
|
|
22
|
+
*
|
|
23
|
+
* `caCertSha256` is exposed for downstream consumers to wire into their
|
|
24
|
+
* container `environment` block as `CA_CERT_SHA256` — its CFN value
|
|
25
|
+
* changes whenever the cert regenerates, forcing task-def replacement so
|
|
26
|
+
* services pick up the new trust anchor.
|
|
27
|
+
*/
|
|
28
|
+
export declare class TlsCertGenerator extends Construct {
|
|
29
|
+
readonly caSecret: TlsCaSecret;
|
|
30
|
+
readonly serverSecret: TlsServerSecret;
|
|
31
|
+
readonly caCertSha256: string;
|
|
32
|
+
constructor(scope: Construct, id: string, props: TlsCertGeneratorProps);
|
|
33
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { dirname, join } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { Duration, Stack } from "aws-cdk-lib";
|
|
4
|
+
import { Effect, PolicyStatement } from "aws-cdk-lib/aws-iam";
|
|
5
|
+
import { Runtime } from "aws-cdk-lib/aws-lambda";
|
|
6
|
+
import { Construct } from "constructs";
|
|
7
|
+
import { TlsCaSecret } from "../secrets/tlsCaSecret.js";
|
|
8
|
+
import { TlsServerSecret } from "../secrets/tlsServerSecret.js";
|
|
9
|
+
import { CustomResource } from "./customResource.js";
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
/**
|
|
12
|
+
* Resolves relative to the compiled location too — the build step copies
|
|
13
|
+
* the asset directory into dist/lib/lambda-assets/cert-generator/asset/,
|
|
14
|
+
* mirroring the source tree, so the same relative walk works post-build.
|
|
15
|
+
*/
|
|
16
|
+
const LAMBDA_ASSET_DIR = join(__dirname, "../../../lambda-assets/cert-generator/asset");
|
|
17
|
+
const DEFAULT_CA_VALIDITY_YEARS = 10;
|
|
18
|
+
const DEFAULT_LEAF_VALIDITY_YEARS = 5;
|
|
19
|
+
const LAMBDA_TIMEOUT = Duration.minutes(2);
|
|
20
|
+
/**
|
|
21
|
+
* Custom-resource Lambda that mints a self-signed CA + leaf cert on stack
|
|
22
|
+
* deploy and persists them to Secrets Manager. The CA secret carries the
|
|
23
|
+
* raw PEM (public — clients pin against it); the server secret carries a
|
|
24
|
+
* JSON `{ cert, key }` payload consumed by the TLS init container.
|
|
25
|
+
*
|
|
26
|
+
* `caCertSha256` is exposed for downstream consumers to wire into their
|
|
27
|
+
* container `environment` block as `CA_CERT_SHA256` — its CFN value
|
|
28
|
+
* changes whenever the cert regenerates, forcing task-def replacement so
|
|
29
|
+
* services pick up the new trust anchor.
|
|
30
|
+
*/
|
|
31
|
+
export class TlsCertGenerator extends Construct {
|
|
32
|
+
caSecret;
|
|
33
|
+
serverSecret;
|
|
34
|
+
caCertSha256;
|
|
35
|
+
constructor(scope, id, props) {
|
|
36
|
+
super(scope, id);
|
|
37
|
+
this.caSecret = new TlsCaSecret(this, "Ca", { appName: props.appName });
|
|
38
|
+
this.serverSecret = new TlsServerSecret(this, "Server", {
|
|
39
|
+
appName: props.appName
|
|
40
|
+
});
|
|
41
|
+
const stack = Stack.of(this);
|
|
42
|
+
const caSecretArnPattern = `arn:${stack.partition}:secretsmanager:${stack.region}:${stack.account}:secret:fjall-${props.appName}-clickhouse-tls-ca-*`;
|
|
43
|
+
const serverSecretArnPattern = `arn:${stack.partition}:secretsmanager:${stack.region}:${stack.account}:secret:fjall-${props.appName}-clickhouse-tls-server-*`;
|
|
44
|
+
const writePolicy = new PolicyStatement({
|
|
45
|
+
effect: Effect.ALLOW,
|
|
46
|
+
actions: ["secretsmanager:PutSecretValue"],
|
|
47
|
+
resources: [caSecretArnPattern, serverSecretArnPattern]
|
|
48
|
+
});
|
|
49
|
+
const cr = new CustomResource(this, "Generator", {
|
|
50
|
+
runtime: Runtime.NODEJS_22_X,
|
|
51
|
+
timeout: LAMBDA_TIMEOUT,
|
|
52
|
+
codePath: LAMBDA_ASSET_DIR,
|
|
53
|
+
handler: "index.handler",
|
|
54
|
+
lambdaDescription: `${id} ClickHouse TLS cert generator`,
|
|
55
|
+
roleDescription: `Execution role for ${id} cert generator (PutSecretValue on two cert secrets)`,
|
|
56
|
+
inlinePolicy: [writePolicy],
|
|
57
|
+
properties: {
|
|
58
|
+
caSecretArn: this.caSecret.secret.secretArn,
|
|
59
|
+
serverSecretArn: this.serverSecret.secret.secretArn,
|
|
60
|
+
hostname: props.hostname,
|
|
61
|
+
caValidityYears: String(props.caValidityYears ?? DEFAULT_CA_VALIDITY_YEARS),
|
|
62
|
+
leafValidityYears: String(props.leafValidityYears ?? DEFAULT_LEAF_VALIDITY_YEARS)
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
this.caCertSha256 = cr.resource.getAttString("CaCertSha256");
|
|
66
|
+
}
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fjall/components-infrastructure",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"scripts": {
|
|
34
34
|
"clean": "rm -rf ./dist",
|
|
35
35
|
"clean:node": "rm -rf ./node_modules",
|
|
36
|
-
"build": "
|
|
36
|
+
"build:cert-gen-lambda": "node lib/lambda-assets/cert-generator/src/build.mjs",
|
|
37
|
+
"build": "npm run build:cert-gen-lambda && tsc && cp -r lib/layers dist/lib/layers && mkdir -p dist/lib/lambda-assets/cert-generator/asset && cp lib/lambda-assets/cert-generator/asset/index.js dist/lib/lambda-assets/cert-generator/asset/index.js && cp lib/lambda-assets/cert-generator/asset/package.json dist/lib/lambda-assets/cert-generator/asset/package.json && cp lib/resources/aws/compute/lifecycleHookLambda.source.cjs dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs && cp lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs && cp lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs",
|
|
37
38
|
"watch": "tsc -w",
|
|
38
39
|
"watch:only": "tsc -w",
|
|
39
40
|
"test": "vitest run",
|
|
@@ -49,6 +50,7 @@
|
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@aws-sdk/client-elastic-load-balancing-v2": "^3.1045.0",
|
|
53
|
+
"@peculiar/x509": "1.14.0",
|
|
52
54
|
"@types/aws-lambda": "^8.10.161",
|
|
53
55
|
"@types/node": "^25.6.0",
|
|
54
56
|
"@types/uuid": "^11.0.0",
|
|
@@ -61,8 +63,8 @@
|
|
|
61
63
|
},
|
|
62
64
|
"dependencies": {
|
|
63
65
|
"@aws-sdk/client-organizations": "^3.1038.0",
|
|
64
|
-
"@fjall/generator": "^
|
|
65
|
-
"@fjall/util": "^
|
|
66
|
+
"@fjall/generator": "^1.1.0",
|
|
67
|
+
"@fjall/util": "^1.1.0",
|
|
66
68
|
"constructs": "^10.0.0",
|
|
67
69
|
"uuid": "^14.0.0"
|
|
68
70
|
},
|
|
@@ -77,5 +79,5 @@
|
|
|
77
79
|
"engines": {
|
|
78
80
|
"node": ">=18.0.0"
|
|
79
81
|
},
|
|
80
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "437ec726425bd7610b83a57c12c1a4e1980bbb01"
|
|
81
83
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { CfnOutput } from "aws-cdk-lib";
|
|
2
|
-
import { Construct } from "constructs";
|
|
3
|
-
export declare class DefaultEventBus extends Construct {
|
|
4
|
-
readonly defaultEventBusName: CfnOutput;
|
|
5
|
-
readonly defaultEventBusArn: CfnOutput;
|
|
6
|
-
constructor(scope: Construct, id: string);
|
|
7
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CfnOutput } from "aws-cdk-lib";
|
|
2
|
-
import * as Events from "aws-cdk-lib/aws-events";
|
|
3
|
-
import { Construct } from "constructs";
|
|
4
|
-
export class DefaultEventBus extends Construct {
|
|
5
|
-
defaultEventBusName;
|
|
6
|
-
defaultEventBusArn;
|
|
7
|
-
constructor(scope, id) {
|
|
8
|
-
super(scope, id);
|
|
9
|
-
const eventBridge = Events.EventBus.fromEventBusName(this, "defaultEventBus", "default");
|
|
10
|
-
this.defaultEventBusName = new CfnOutput(this, "defaultEventBusName", {
|
|
11
|
-
key: `defaultEventBusName`,
|
|
12
|
-
value: eventBridge.eventBusName,
|
|
13
|
-
exportName: "defaultEventBusName"
|
|
14
|
-
});
|
|
15
|
-
this.defaultEventBusArn = new CfnOutput(this, "defaultEventBusArn", {
|
|
16
|
-
key: `defaultEventBusArn`,
|
|
17
|
-
value: eventBridge.eventBusArn,
|
|
18
|
-
exportName: "defaultEventBusArn"
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { NestedStack, type StackProps } from "aws-cdk-lib";
|
|
2
|
-
import { type Construct } from "constructs";
|
|
3
|
-
interface IdentityCenterGroupMembershipProps extends StackProps {
|
|
4
|
-
groupName: string;
|
|
5
|
-
groupMembers: string[];
|
|
6
|
-
}
|
|
7
|
-
export declare class IdentityCenterGroupMembership extends NestedStack {
|
|
8
|
-
constructor(scope: Construct, id: string, props: IdentityCenterGroupMembershipProps);
|
|
9
|
-
}
|
|
10
|
-
export {};
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { Fn, NestedStack } from "aws-cdk-lib";
|
|
2
|
-
import * as customResources from "aws-cdk-lib/custom-resources";
|
|
3
|
-
import { AwsCustomResource } from "../../resources/aws/utilities/awsCustomResource.js";
|
|
4
|
-
const IDENTITY_STORE_SERVICE = "identityStore";
|
|
5
|
-
const IDENTITY_CENTER_USERS_RESOURCE_TYPE = "Custom::IdentityCenterUsers";
|
|
6
|
-
// TODO: This requires a deletion and recreation to update
|
|
7
|
-
export class IdentityCenterGroupMembership extends NestedStack {
|
|
8
|
-
constructor(scope, id, props) {
|
|
9
|
-
super(scope, id);
|
|
10
|
-
const identityStoreId = Fn.importValue("identityStoreId");
|
|
11
|
-
const groupId = Fn.importValue(`${props.groupName}GroupId`);
|
|
12
|
-
for (const member of props.groupMembers) {
|
|
13
|
-
const memberSuffix = (member.split("@")[0] ?? member)
|
|
14
|
-
.split(/[^a-zA-Z0-9]/)
|
|
15
|
-
.filter((part) => part.length > 0)
|
|
16
|
-
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
17
|
-
.join("") +
|
|
18
|
-
props.groupName.charAt(0).toUpperCase() +
|
|
19
|
-
props.groupName.slice(1);
|
|
20
|
-
const listUsersCall = {
|
|
21
|
-
service: IDENTITY_STORE_SERVICE,
|
|
22
|
-
action: "listUsers",
|
|
23
|
-
parameters: {
|
|
24
|
-
IdentityStoreId: identityStoreId,
|
|
25
|
-
Filters: [
|
|
26
|
-
{
|
|
27
|
-
AttributePath: "UserName",
|
|
28
|
-
AttributeValue: member
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
physicalResourceId: customResources.PhysicalResourceId.of(`listUsers${memberSuffix}`)
|
|
33
|
-
};
|
|
34
|
-
const listUser = new AwsCustomResource(this, `ListUsersResource${memberSuffix}`, {
|
|
35
|
-
onCreate: listUsersCall,
|
|
36
|
-
onUpdate: listUsersCall
|
|
37
|
-
});
|
|
38
|
-
const userId = listUser.getResponseField("Users.0.UserId");
|
|
39
|
-
const groupMembershipId = new AwsCustomResource(this, `CreateGroupMembershipResource${memberSuffix}`, {
|
|
40
|
-
onCreate: {
|
|
41
|
-
service: IDENTITY_STORE_SERVICE,
|
|
42
|
-
action: "createGroupMembership",
|
|
43
|
-
parameters: {
|
|
44
|
-
GroupId: groupId,
|
|
45
|
-
IdentityStoreId: identityStoreId,
|
|
46
|
-
MemberId: {
|
|
47
|
-
UserId: userId
|
|
48
|
-
}
|
|
49
|
-
},
|
|
50
|
-
physicalResourceId: customResources.PhysicalResourceId.of(`createGroupMembership${memberSuffix}`)
|
|
51
|
-
},
|
|
52
|
-
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
53
|
-
});
|
|
54
|
-
const refreshMembership = new AwsCustomResource(this, `RefreshMembershipResource${memberSuffix}`, {
|
|
55
|
-
onUpdate: {
|
|
56
|
-
service: IDENTITY_STORE_SERVICE,
|
|
57
|
-
action: "deleteGroupMembership",
|
|
58
|
-
parameters: {
|
|
59
|
-
IdentityStoreId: identityStoreId,
|
|
60
|
-
MembershipId: groupMembershipId.getResponseField("MembershipId")
|
|
61
|
-
},
|
|
62
|
-
physicalResourceId: customResources.PhysicalResourceId.of(`refreshGroupMembership${memberSuffix}`)
|
|
63
|
-
},
|
|
64
|
-
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
65
|
-
});
|
|
66
|
-
const recreateMembership = new AwsCustomResource(this, `RecreateGroupMembershipResource${memberSuffix}`, {
|
|
67
|
-
onUpdate: {
|
|
68
|
-
service: IDENTITY_STORE_SERVICE,
|
|
69
|
-
action: "createGroupMembership",
|
|
70
|
-
parameters: {
|
|
71
|
-
GroupId: groupId,
|
|
72
|
-
IdentityStoreId: identityStoreId,
|
|
73
|
-
MemberId: {
|
|
74
|
-
UserId: userId
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
physicalResourceId: customResources.PhysicalResourceId.of(`recreateGroupMembership${memberSuffix}`),
|
|
78
|
-
// createGroupMembership throws ConflictException when the
|
|
79
|
-
// membership already exists — keeps onUpdate idempotent.
|
|
80
|
-
ignoreErrorCodesMatching: "ConflictException"
|
|
81
|
-
},
|
|
82
|
-
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
83
|
-
});
|
|
84
|
-
refreshMembership.node.addDependency(recreateMembership);
|
|
85
|
-
const deleteMembership = new AwsCustomResource(this, `DeleteGroupMembershipResource${memberSuffix}`, {
|
|
86
|
-
onDelete: {
|
|
87
|
-
service: IDENTITY_STORE_SERVICE,
|
|
88
|
-
action: "deleteGroupMembership",
|
|
89
|
-
parameters: {
|
|
90
|
-
IdentityStoreId: identityStoreId,
|
|
91
|
-
MembershipId: groupMembershipId.getResponseField("MembershipId")
|
|
92
|
-
},
|
|
93
|
-
// deleteGroupMembership throws ResourceNotFoundException when
|
|
94
|
-
// the membership is already gone — keeps onDelete idempotent.
|
|
95
|
-
ignoreErrorCodesMatching: "ResourceNotFoundException"
|
|
96
|
-
},
|
|
97
|
-
resourceType: IDENTITY_CENTER_USERS_RESOURCE_TYPE
|
|
98
|
-
});
|
|
99
|
-
deleteMembership.node.addDependency(groupMembershipId);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Construct } from "constructs";
|
|
2
|
-
export interface SecurityBaselineProps {
|
|
3
|
-
/** Controls which services are instantiated. "off" creates nothing. */
|
|
4
|
-
level: "off" | "baseline" | "compliance";
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Convenience orchestrator for per-account security services.
|
|
8
|
-
* Instantiates child constructs based on the selected level.
|
|
9
|
-
*
|
|
10
|
-
* Does NOT include ConfigRulePreset -- Config Rules are applied independently
|
|
11
|
-
* at the Account stack level with environment-aware presets.
|
|
12
|
-
*/
|
|
13
|
-
export declare class SecurityBaseline extends Construct {
|
|
14
|
-
constructor(scope: Construct, id: string, props: SecurityBaselineProps);
|
|
15
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { Construct } from "constructs";
|
|
2
|
-
import { GuardDutyDetector } from "./guardDutyDetector.js";
|
|
3
|
-
import { SecurityHubHub } from "./securityHubHub.js";
|
|
4
|
-
import { ConfigRecorder } from "./configRecorder.js";
|
|
5
|
-
import { AccountAccessAnalyser } from "./accessAnalyser.js";
|
|
6
|
-
import { InspectorEnablement } from "./inspectorEnablement.js";
|
|
7
|
-
/**
|
|
8
|
-
* Convenience orchestrator for per-account security services.
|
|
9
|
-
* Instantiates child constructs based on the selected level.
|
|
10
|
-
*
|
|
11
|
-
* Does NOT include ConfigRulePreset -- Config Rules are applied independently
|
|
12
|
-
* at the Account stack level with environment-aware presets.
|
|
13
|
-
*/
|
|
14
|
-
export class SecurityBaseline extends Construct {
|
|
15
|
-
constructor(scope, id, props) {
|
|
16
|
-
super(scope, id);
|
|
17
|
-
if (props.level === "off")
|
|
18
|
-
return;
|
|
19
|
-
new GuardDutyDetector(this, "GuardDuty");
|
|
20
|
-
new SecurityHubHub(this, "SecurityHub");
|
|
21
|
-
new ConfigRecorder(this, "Config");
|
|
22
|
-
new AccountAccessAnalyser(this, "AccessAnalyser");
|
|
23
|
-
if (props.level === "compliance") {
|
|
24
|
-
new InspectorEnablement(this, "Inspector");
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { Stack } from "aws-cdk-lib";
|
|
2
|
-
import * as fs from "fs";
|
|
3
|
-
import App from "../../app.js";
|
|
4
|
-
import { IdentityCenterGroupMembership } from "../../config/aws/identityCenterGroupMembership.js";
|
|
5
|
-
export class ManagedIdentityCenter extends Stack {
|
|
6
|
-
constructor(id) {
|
|
7
|
-
super(App.getInstance(), id);
|
|
8
|
-
const configFile = fs.readFileSync("../identity-center-config.json", {
|
|
9
|
-
encoding: "utf8"
|
|
10
|
-
});
|
|
11
|
-
const identityCenterConfig = JSON.parse(configFile);
|
|
12
|
-
identityCenterConfig.forEach((config) => {
|
|
13
|
-
new IdentityCenterGroupMembership(this, `Managed${config.group}Group`, {
|
|
14
|
-
groupName: config.group,
|
|
15
|
-
groupMembers: config.members
|
|
16
|
-
});
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { Stack } from "aws-cdk-lib";
|
|
2
|
-
export interface subdomainHostedZoneProps {
|
|
3
|
-
delegatedZone: string;
|
|
4
|
-
parentHostedZoneName: string;
|
|
5
|
-
parentAccountName: string;
|
|
6
|
-
}
|
|
7
|
-
export declare class SubdomainHostedZone extends Stack {
|
|
8
|
-
constructor(id: string, props: subdomainHostedZoneProps);
|
|
9
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import * as route53 from "aws-cdk-lib/aws-route53";
|
|
2
|
-
import { CfnOutput, Stack } from "aws-cdk-lib";
|
|
3
|
-
import { Role } from "../../resources/aws/iam/index.js";
|
|
4
|
-
import getAccountId from "../../utils/getAccountId.js";
|
|
5
|
-
import App from "../../app.js";
|
|
6
|
-
export class SubdomainHostedZone extends Stack {
|
|
7
|
-
constructor(id, props) {
|
|
8
|
-
super(App.getInstance(), id);
|
|
9
|
-
// DelegationRoleArn
|
|
10
|
-
const delegationRoleArn = Stack.of(this).formatArn({
|
|
11
|
-
account: getAccountId(props.parentAccountName),
|
|
12
|
-
region: "",
|
|
13
|
-
resource: "role",
|
|
14
|
-
resourceName: `${props.parentHostedZoneName.split(".", 1)}DelegateHostedZoneRole`,
|
|
15
|
-
service: "iam"
|
|
16
|
-
});
|
|
17
|
-
// Delegate Hosted Zone Role
|
|
18
|
-
const hostedZoneDelegationRole = Role.fromRoleArn(this, "hostedZoneDelegationRole", delegationRoleArn);
|
|
19
|
-
// Subdomains
|
|
20
|
-
const delegatedHostedZone = new route53.HostedZone(this, `${props.delegatedZone}HostedZone`, {
|
|
21
|
-
zoneName: props.delegatedZone
|
|
22
|
-
});
|
|
23
|
-
new route53.CrossAccountZoneDelegationRecord(this, `${props.delegatedZone}DelegationRole`, {
|
|
24
|
-
delegationRole: hostedZoneDelegationRole,
|
|
25
|
-
delegatedZone: delegatedHostedZone,
|
|
26
|
-
parentHostedZoneName: props.parentHostedZoneName
|
|
27
|
-
});
|
|
28
|
-
new CfnOutput(this, `${props.delegatedZone.split(".").join("")}HostedZoneId`, {
|
|
29
|
-
key: `${props.delegatedZone.split(".").join("")}HostedZoneId`,
|
|
30
|
-
value: delegatedHostedZone.hostedZoneId,
|
|
31
|
-
exportName: `${props.delegatedZone.split(".").join("")}HostedZoneId`
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Connections, type IConnectable } from "aws-cdk-lib/aws-ec2";
|
|
2
|
-
import { Construct } from "constructs";
|
|
3
|
-
import type { ClickHouseProps, ClickHouseOutputs } from "./clickhouseTypes.js";
|
|
4
|
-
/**
|
|
5
|
-
* ClickHouse analytics infrastructure.
|
|
6
|
-
*
|
|
7
|
-
* Creates a single-node ClickHouse instance on ECS EC2 with a dedicated
|
|
8
|
-
* gp3 EBS volume for data persistence. Designed for analytical workloads
|
|
9
|
-
* (cost aggregation, deployment metrics, audit logs) rather than OLTP.
|
|
10
|
-
*/
|
|
11
|
-
export default class ClickHouse extends Construct implements IConnectable {
|
|
12
|
-
readonly connections: Connections;
|
|
13
|
-
readonly outputs: ClickHouseOutputs;
|
|
14
|
-
constructor(scope: Construct, id: string, props: ClickHouseProps);
|
|
15
|
-
}
|