@fjall/components-infrastructure 0.96.0 → 0.99.1
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/app.d.ts +68 -1
- package/dist/lib/app.js +113 -4
- package/dist/lib/config/aws/__t17fixture.d.ts +1 -0
- package/dist/lib/config/aws/__t17fixture.js +3 -0
- package/dist/lib/config/aws/__t17fixtureType.d.ts +2 -0
- package/dist/lib/config/aws/__t17fixtureType.js +1 -0
- package/dist/lib/config/aws/alarmTopic.js +8 -4
- package/dist/lib/config/aws/cloudTrail.js +1 -1
- package/dist/lib/config/aws/disasterRecovery.js +11 -16
- package/dist/lib/config/aws/ecrDefaultImage.d.ts +0 -1
- package/dist/lib/config/aws/ecrDefaultImage.js +13 -23
- package/dist/lib/config/aws/identityCenter.d.ts +10 -3
- package/dist/lib/config/aws/identityCenter.js +101 -37
- package/dist/lib/config/aws/identityCenterGroupMembership.js +8 -2
- package/dist/lib/config/aws/identityCenterMembership.d.ts +11 -0
- package/dist/lib/config/aws/identityCenterMembership.js +61 -0
- package/dist/lib/config/aws/index.d.ts +1 -1
- package/dist/lib/config/aws/index.js +1 -1
- package/dist/lib/config/aws/ipam.js +6 -11
- package/dist/lib/config/aws/oidcConnector.js +5 -1
- package/dist/lib/config/aws/scpPreset.js +4 -1
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.d.ts +1 -0
- package/dist/lib/patterns/aws/_eslint_test_tmp/leak.js +4 -0
- package/dist/lib/patterns/aws/account.js +2 -4
- package/dist/lib/patterns/aws/apexDomainPattern.js +10 -10
- package/dist/lib/patterns/aws/bastionFactory.d.ts +10 -0
- package/dist/lib/patterns/aws/bastionFactory.js +29 -0
- package/dist/lib/patterns/aws/buildkite.d.ts +2 -2
- package/dist/lib/patterns/aws/buildkite.js +51 -97
- package/dist/lib/patterns/aws/cdn.js +1 -1
- package/dist/lib/patterns/aws/clickhouseDatabase.d.ts +172 -0
- package/dist/lib/patterns/aws/clickhouseDatabase.js +600 -0
- package/dist/lib/patterns/aws/compute.d.ts +4 -6
- package/dist/lib/patterns/aws/compute.js +7 -13
- package/dist/lib/patterns/aws/computeEcs.d.ts +93 -5
- package/dist/lib/patterns/aws/computeEcs.js +867 -37
- package/dist/lib/patterns/aws/computeEcsTypes.d.ts +528 -25
- package/dist/lib/patterns/aws/computeEcsTypes.js +10 -0
- package/dist/lib/patterns/aws/computeLambda.d.ts +0 -5
- package/dist/lib/patterns/aws/computeLambda.js +1 -2
- package/dist/lib/patterns/aws/database.d.ts +50 -8
- package/dist/lib/patterns/aws/database.js +183 -27
- package/dist/lib/patterns/aws/domain.js +6 -4
- package/dist/lib/patterns/aws/index.d.ts +1 -0
- package/dist/lib/patterns/aws/index.js +1 -0
- package/dist/lib/patterns/aws/interfaces/compute.d.ts +7 -1
- package/dist/lib/patterns/aws/interfaces/database.d.ts +187 -8
- package/dist/lib/patterns/aws/interfaces/database.js +17 -3
- package/dist/lib/patterns/aws/interfaces/index.d.ts +2 -1
- package/dist/lib/patterns/aws/interfaces/index.js +3 -1
- package/dist/lib/patterns/aws/interfaces/messaging.d.ts +7 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.d.ts +47 -0
- package/dist/lib/patterns/aws/interfaces/migrationContributor.js +9 -0
- package/dist/lib/patterns/aws/messaging.d.ts +66 -10
- package/dist/lib/patterns/aws/messaging.js +115 -20
- package/dist/lib/patterns/aws/network.js +16 -7
- package/dist/lib/patterns/aws/organisation.d.ts +4 -0
- package/dist/lib/patterns/aws/organisation.js +22 -4
- package/dist/lib/patterns/aws/storage.d.ts +1 -2
- package/dist/lib/patterns/aws/storage.js +3 -2
- package/dist/lib/patterns/aws/vpcPeer.js +3 -1
- package/dist/lib/resources/aws/analytics/clickhouse.js +18 -9
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.d.ts +24 -9
- package/dist/lib/resources/aws/analytics/clickhouseAlarms.js +61 -10
- package/dist/lib/resources/aws/analytics/clickhouseConstants.d.ts +3 -3
- package/dist/lib/resources/aws/analytics/clickhouseConstants.js +3 -3
- package/dist/lib/resources/aws/analytics/clickhouseTypes.d.ts +7 -1
- package/dist/lib/resources/aws/analytics/clickhouseUserData.d.ts +1 -1
- package/dist/lib/resources/aws/analytics/clickhouseUserData.js +53 -3
- package/dist/lib/resources/aws/base/awsStack.js +4 -2
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.d.ts +2 -0
- package/dist/lib/resources/aws/compute/__tmp__/regression-shape.js +11 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.d.ts +52 -0
- package/dist/lib/resources/aws/compute/asgInlineLifecycleHook.js +60 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.d.ts +8 -0
- package/dist/lib/resources/aws/compute/blockDeviceVolume.js +10 -0
- package/dist/lib/resources/aws/compute/ec2.d.ts +132 -12
- package/dist/lib/resources/aws/compute/ec2.js +163 -23
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.d.ts +41 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationHandler.js +194 -0
- package/dist/lib/resources/aws/compute/ec2GracefulTerminationLambda.source.cjs +458 -0
- package/dist/lib/resources/aws/compute/ecs.d.ts +27 -1
- package/dist/lib/resources/aws/compute/ecs.js +42 -2
- package/dist/lib/resources/aws/compute/ecsConstants.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsConstants.js +16 -0
- package/dist/lib/resources/aws/compute/ecsImages.js +32 -20
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.d.ts +96 -0
- package/dist/lib/resources/aws/compute/ecsLifecycleHookMigration.js +113 -0
- package/dist/lib/resources/aws/compute/ecsNetworking.d.ts +2 -1
- package/dist/lib/resources/aws/compute/ecsNetworking.js +18 -6
- package/dist/lib/resources/aws/compute/ecsServiceFactory.d.ts +13 -4
- package/dist/lib/resources/aws/compute/ecsServiceFactory.js +155 -33
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.d.ts +31 -1
- package/dist/lib/resources/aws/compute/ecsTaskDefinition.js +102 -6
- package/dist/lib/resources/aws/compute/ecsTypes.d.ts +173 -13
- package/dist/lib/resources/aws/compute/ecsValidation.d.ts +9 -0
- package/dist/lib/resources/aws/compute/ecsValidation.js +63 -0
- package/dist/lib/resources/aws/compute/index.d.ts +2 -0
- package/dist/lib/resources/aws/compute/index.js +2 -0
- package/dist/lib/resources/aws/compute/lambda.d.ts +7 -13
- package/dist/lib/resources/aws/compute/lambda.js +30 -38
- package/dist/lib/resources/aws/compute/lifecycleHookLambda.source.cjs +192 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.d.ts +104 -0
- package/dist/lib/resources/aws/compute/persistentDataVolume.js +245 -0
- package/dist/lib/resources/aws/compute/persistentDataVolumeLambda.source.cjs +398 -0
- package/dist/lib/resources/aws/compute/samApplication.d.ts +15 -0
- package/dist/lib/resources/aws/compute/samApplication.js +27 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.d.ts +159 -0
- package/dist/lib/resources/aws/database/clickhouseConstants.js +181 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.d.ts +71 -0
- package/dist/lib/resources/aws/database/clickhouseSchemas.js +157 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.d.ts +14 -0
- package/dist/lib/resources/aws/database/clickhouseSecurityGroup.js +23 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.d.ts +69 -0
- package/dist/lib/resources/aws/database/clickhouseUserData.js +371 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.d.ts +56 -0
- package/dist/lib/resources/aws/database/clickhouseXmlRenderer.js +112 -0
- package/dist/lib/resources/aws/database/rdsAurora.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsAurora.js +42 -32
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.d.ts +15 -2
- package/dist/lib/resources/aws/database/rdsAuroraGlobal.js +39 -43
- package/dist/lib/resources/aws/database/rdsDefaults.d.ts +6 -0
- package/dist/lib/resources/aws/database/rdsDefaults.js +7 -1
- package/dist/lib/resources/aws/database/rdsHelpers.d.ts +3 -3
- package/dist/lib/resources/aws/database/rdsHelpers.js +1 -0
- package/dist/lib/resources/aws/database/rdsInstance.d.ts +8 -1
- package/dist/lib/resources/aws/database/rdsInstance.js +51 -34
- package/dist/lib/resources/aws/database/rdsProxyOutput.d.ts +1 -1
- package/dist/lib/resources/aws/database/rdsProxyOutput.js +1 -1
- package/dist/lib/resources/aws/iam/delegationRole.js +1 -1
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.d.ts +9 -0
- package/dist/lib/resources/aws/iam/identityCenter/groupMembership.js +12 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/index.js +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.d.ts +1 -0
- package/dist/lib/resources/aws/iam/identityCenter/permissionSet.js +1 -0
- package/dist/lib/resources/aws/logging/logGroup.d.ts +0 -8
- package/dist/lib/resources/aws/logging/logGroup.js +0 -11
- package/dist/lib/resources/aws/messaging/defaultEventBus.d.ts +7 -0
- package/dist/lib/resources/aws/messaging/defaultEventBus.js +21 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.d.ts +96 -0
- package/dist/lib/resources/aws/messaging/eventBridgeRule.js +110 -0
- package/dist/lib/resources/aws/messaging/eventTargets.d.ts +84 -0
- package/dist/lib/resources/aws/messaging/eventTargets.js +152 -0
- package/dist/lib/resources/aws/messaging/eventbridge.d.ts +25 -2
- package/dist/lib/resources/aws/messaging/eventbridge.js +22 -10
- package/dist/lib/resources/aws/messaging/index.d.ts +5 -0
- package/dist/lib/resources/aws/messaging/index.js +2 -0
- package/dist/lib/resources/aws/messaging/schedule.d.ts +118 -0
- package/dist/lib/resources/aws/messaging/schedule.js +64 -0
- package/dist/lib/resources/aws/messaging/sns.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/sqs.d.ts +2 -1
- package/dist/lib/resources/aws/messaging/subscription.d.ts +112 -0
- package/dist/lib/resources/aws/messaging/subscription.js +67 -0
- package/dist/lib/resources/aws/messaging/utils.d.ts +6 -0
- package/dist/lib/resources/aws/messaging/utils.js +10 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.d.ts +60 -0
- package/dist/lib/resources/aws/monitoring/clickhouseAlarms.js +139 -0
- package/dist/lib/resources/aws/monitoring/index.d.ts +2 -0
- package/dist/lib/resources/aws/monitoring/index.js +2 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.d.ts +47 -0
- package/dist/lib/resources/aws/monitoring/scheduleAlarms.js +106 -0
- package/dist/lib/resources/aws/networking/crossAccountDelegationRecord.js +6 -4
- package/dist/lib/resources/aws/networking/crossAccountReturnRoutes.js +17 -13
- package/dist/lib/resources/aws/networking/dnsRecord/dnsRecordBase.js +7 -5
- package/dist/lib/resources/aws/networking/domainCertificate.d.ts +2 -2
- package/dist/lib/resources/aws/networking/domainCertificate.js +6 -4
- package/dist/lib/resources/aws/networking/hostedZone.js +6 -5
- package/dist/lib/resources/aws/networking/serviceDiscovery.d.ts +96 -0
- package/dist/lib/resources/aws/networking/serviceDiscovery.js +96 -0
- package/dist/lib/resources/aws/networking/vpc.d.ts +4 -1
- package/dist/lib/resources/aws/networking/vpc.js +4 -1
- package/dist/lib/resources/aws/networking/vpcPeeringConnection.js +21 -3
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.d.ts +16 -5
- package/dist/lib/resources/aws/organisation/costAllocationTagActivator.js +17 -3
- package/dist/lib/resources/aws/organisation/index.d.ts +1 -1
- package/dist/lib/resources/aws/organisation/organisationPolicy.d.ts +2 -0
- package/dist/lib/resources/aws/organisation/organisationPolicy.js +3 -2
- package/dist/lib/resources/aws/secrets/secret.d.ts +7 -0
- package/dist/lib/resources/aws/secrets/secret.js +4 -3
- package/dist/lib/resources/aws/storage/bucketDeployment.d.ts +16 -0
- package/dist/lib/resources/aws/storage/bucketDeployment.js +17 -0
- package/dist/lib/resources/aws/storage/ecr.js +5 -5
- package/dist/lib/resources/aws/storage/index.d.ts +1 -0
- package/dist/lib/resources/aws/storage/index.js +1 -0
- package/dist/lib/resources/aws/storage/s3.js +10 -3
- package/dist/lib/resources/aws/utilities/customResource.js +18 -9
- package/dist/lib/synth_dump.d.ts +1 -0
- package/dist/lib/synth_dump.js +42 -0
- package/dist/lib/utils/cdkContext.d.ts +2 -0
- package/dist/lib/utils/cdkContext.js +4 -2
- package/dist/lib/utils/connections.js +6 -0
- package/dist/lib/utils/connector.d.ts +12 -0
- package/dist/lib/utils/costAllocationTags.d.ts +9 -0
- package/dist/lib/utils/costAllocationTags.js +11 -1
- package/dist/lib/utils/databaseTypes.d.ts +14 -0
- package/dist/lib/utils/getConfig.d.ts +2 -0
- package/dist/lib/utils/getConfig.js +2 -0
- package/dist/lib/utils/index.d.ts +1 -0
- package/dist/lib/utils/index.js +1 -0
- package/dist/lib/utils/manifestWriter.d.ts +6 -89
- package/dist/lib/utils/manifestWriter.js +36 -23
- package/dist/lib/utils/migrationVersionResolvers.d.ts +2 -0
- package/dist/lib/utils/migrationVersionResolvers.js +2 -0
- package/dist/lib/utils/orgConfigParser.js +2 -1
- package/dist/lib/utils/resolveAlertsTopic.d.ts +14 -0
- package/dist/lib/utils/resolveAlertsTopic.js +30 -0
- package/dist/lib/utils/validationLogger.js +6 -3
- package/package.json +22 -19
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/** Database name created at ClickHouse bootstrap; consumed by BACKUP DATABASE,
|
|
2
|
+
* OPTIMIZE TABLE, and the DatabaseName CfnOutput so all four sites share one source. */
|
|
3
|
+
export const CLICKHOUSE_DATABASE_NAME = "analytics";
|
|
4
|
+
/** Default EC2 instance type for ClickHouse (Graviton3 — fixed-spec cores).
|
|
5
|
+
*
|
|
6
|
+
* `m7g.medium` (1 vCPU sustained, 4 GiB) chosen over `t4g.medium` (2 vCPU
|
|
7
|
+
* burst, 4 GiB) because CH's steady-state merge/scan/aggregation profile is
|
|
8
|
+
* not bursty — burst credits run out under the per-5min metrics ingest plus
|
|
9
|
+
* the OPTIMIZE FINAL sidecar, leaving the box throttled at baseline (10–20%
|
|
10
|
+
* of 2 vCPU) for the rest of the hour. Graviton3 is also ~25% faster on
|
|
11
|
+
* columnar scans than Graviton2.
|
|
12
|
+
*
|
|
13
|
+
* Settings are tuned for 1 vCPU sustained (max_threads=1 across all profiles,
|
|
14
|
+
* max_concurrent_queries=4) — see clickhouseUserData.ts. Bumping to a larger
|
|
15
|
+
* instance MUST be paired with raising those thread/concurrency caps.
|
|
16
|
+
*
|
|
17
|
+
* Next size up: `m7g.large` (2 vCPU, 8 GiB) for sustained workloads, or
|
|
18
|
+
* `r7g.medium` (1 vCPU, 8 GiB) when memory-bound. Set via
|
|
19
|
+
* `clickhouseInstanceType` CDK context or the `instanceType` prop, no code
|
|
20
|
+
* change needed (see clickhouseDatabase.ts:162). */
|
|
21
|
+
export const DEFAULT_CLICKHOUSE_INSTANCE_TYPE = "m7g.medium";
|
|
22
|
+
/** ClickHouse container image. Explicit `docker.io/` prefix is required so
|
|
23
|
+
* string-form consumers in `ecsImages.ts#getContainerImage()` route through
|
|
24
|
+
* `ContainerImage.fromRegistry(...)` instead of the ECR-repo fallback (which
|
|
25
|
+
* would otherwise append a service-tag suffix and produce a double-colon
|
|
26
|
+
* malformed image reference).
|
|
27
|
+
*
|
|
28
|
+
* Pin the full patch (not the floating `26.3`) so prod and local containers
|
|
29
|
+
* always run the same digest. The floating tag bit us once when CH 26.3.10
|
|
30
|
+
* tightened config.xml validation overnight while local Docker caches still
|
|
31
|
+
* held the prior patch — keep this pin in lockstep with
|
|
32
|
+
* `webapp/docker-compose.yaml`.
|
|
33
|
+
*
|
|
34
|
+
* Default Ubuntu (glibc) variant chosen over `-alpine` (musl): musl's
|
|
35
|
+
* threading/NPTL implementation is materially slower under CH's per-merge
|
|
36
|
+
* / per-query-stage thread fan-out, and musl's 128 KB default thread stack
|
|
37
|
+
* has a recurring history of stack-overflow incidents on deep query plans.
|
|
38
|
+
* Image size is ~250 MB larger but irrelevant on a single-instance EC2 ASG
|
|
39
|
+
* that pulls once per launch. Upstream CH CI runs its full perf + stress
|
|
40
|
+
* matrix on the Ubuntu build; Alpine is community-tier coverage. */
|
|
41
|
+
export const CLICKHOUSE_IMAGE = "docker.io/clickhouse/clickhouse-server:26.3.10.60";
|
|
42
|
+
/** EBS volume configuration. */
|
|
43
|
+
export const CLICKHOUSE_EBS_VOLUME_SIZE_GB = 80;
|
|
44
|
+
export const CLICKHOUSE_EBS_IOPS = 3000;
|
|
45
|
+
export const CLICKHOUSE_EBS_THROUGHPUT_MBPS = 125;
|
|
46
|
+
/** ECS task resource allocation. m7g.medium ships with 4 GB; reserve 1 GB
|
|
47
|
+
* for the host (kernel + ECS agent + cloudwatch agent + IMDS) and give
|
|
48
|
+
* ClickHouse the remaining 3 GB. Stays right when bumping to m7g.large
|
|
49
|
+
* (8 GB) — raise this value in lockstep, or fall back to deriving from
|
|
50
|
+
* the instance type if we ever support multiple sizes. */
|
|
51
|
+
export const CLICKHOUSE_TASK_MEMORY_MIB = 3072;
|
|
52
|
+
/** ClickHouse ports. */
|
|
53
|
+
export const CLICKHOUSE_HTTP_PORT = 8123;
|
|
54
|
+
export const CLICKHOUSE_NATIVE_PORT = 9000;
|
|
55
|
+
export const CLICKHOUSE_PROMETHEUS_PORT = 9363;
|
|
56
|
+
/** EBS device name for the data volume (must match user data script). */
|
|
57
|
+
export const CLICKHOUSE_EBS_DEVICE_NAME = "/dev/xvdf";
|
|
58
|
+
/** EBS mount path on the EC2 host. */
|
|
59
|
+
export const CLICKHOUSE_DATA_MOUNT_PATH = "/mnt/clickhouse-data";
|
|
60
|
+
/** Secrets Manager path prefix. */
|
|
61
|
+
export const CLICKHOUSE_SECRETS_PREFIX = "fjall/clickhouse";
|
|
62
|
+
/** Canonical Secrets Manager secret name for a ClickHouse user.
|
|
63
|
+
* Two sites compute this name and they MUST match:
|
|
64
|
+
* (a) the secret mint inside `createClickHouseUserSecret(...)` in
|
|
65
|
+
* `clickhouseDatabase.ts` — calls this helper directly;
|
|
66
|
+
* (b) the SSM live-reload script that fetches the admin password via
|
|
67
|
+
* `aws secretsmanager get-secret-value --secret-id` — also calls
|
|
68
|
+
* this helper directly.
|
|
69
|
+
* Drift between the two would silently break the live-reload path post-
|
|
70
|
+
* deploy on a users.d S3 change (no compile or test signal). */
|
|
71
|
+
export function clickHouseUserSecretName(userName) {
|
|
72
|
+
return `${CLICKHOUSE_SECRETS_PREFIX}/${userName.replace(/_/g, "-")}-password`;
|
|
73
|
+
}
|
|
74
|
+
/** ECS-injected env var name carrying a user's plaintext password.
|
|
75
|
+
* Canonical source is `@fjall/util/migration § userPasswordEnvName` — re-exported
|
|
76
|
+
* here so the construct-side import chain stays unchanged while the runner
|
|
77
|
+
* (`webapp/scripts/migration-runner.mjs`) and any future consumer share a single
|
|
78
|
+
* declaration. Coupled values per `.claude/rules/code-quality.md § "Coupled values:
|
|
79
|
+
* shared source at 2 occurrences"`. */
|
|
80
|
+
export { userPasswordEnvName } from "@fjall/util/migration";
|
|
81
|
+
/** Env var name carrying the SHA-256 of a user's plaintext password.
|
|
82
|
+
* The container entrypoint wrapper derives this name from the
|
|
83
|
+
* `USER_<NAME>_PASSWORD` env var injected by ECS `secretsImport`, then
|
|
84
|
+
* resolves `<password_sha256_hex from_env="..."/>` directives in
|
|
85
|
+
* `users.d/fjall.xml` against it at server start. */
|
|
86
|
+
export function userSha256EnvName(userName) {
|
|
87
|
+
return `USER_${userName.toUpperCase()}_SHA256`;
|
|
88
|
+
}
|
|
89
|
+
/** Canonical bash pipeline that hashes a ClickHouse user password.
|
|
90
|
+
* Invoked from the container entrypoint wrapper
|
|
91
|
+
* (`buildClickHouseEntrypointWrapper`) to derive `USER_<NAME>_SHA256` from
|
|
92
|
+
* the ECS-injected plaintext at server start.
|
|
93
|
+
* @param plaintextShellRef A quoted bash reference to the plaintext
|
|
94
|
+
* password (e.g. `"\${!var}"` for the wrapper's indirect deref). */
|
|
95
|
+
export function clickHousePasswordSha256Snippet(plaintextShellRef) {
|
|
96
|
+
return `printf '%s' ${plaintextShellRef} | sha256sum | awk '{print $1}'`;
|
|
97
|
+
}
|
|
98
|
+
/** Tag identifying ClickHouse server ASG instances.
|
|
99
|
+
* Three sites carry this pair and they MUST match: (a) the `tags:` map on
|
|
100
|
+
* the ClickHouse EC2 instance (threaded through to ASG instance tags),
|
|
101
|
+
* (b) the SSM `Targets: [{ Key: "tag:<key>", Values: ["<value>"] }]` filter
|
|
102
|
+
* on the live-reload `AwsCustomResource`, and (c) the synth snapshot tests
|
|
103
|
+
* pinning the relationship. Drift between (a) and (b) silently routes the
|
|
104
|
+
* reload command to zero instances — the `InvocationDoesNotExist` failure
|
|
105
|
+
* is already suppressed by `ignoreErrorCodesMatching`, so the misroute
|
|
106
|
+
* emits no signal. */
|
|
107
|
+
export const CLICKHOUSE_SERVER_ROLE_TAG = {
|
|
108
|
+
key: "ClickHouseRole",
|
|
109
|
+
value: "server"
|
|
110
|
+
};
|
|
111
|
+
/** Shared secret generation options (all ClickHouse users share the same policy). */
|
|
112
|
+
export const CLICKHOUSE_SECRET_OPTIONS = {
|
|
113
|
+
excludePunctuation: true,
|
|
114
|
+
passwordLength: 32
|
|
115
|
+
};
|
|
116
|
+
/** Health check configuration. */
|
|
117
|
+
export const CLICKHOUSE_HEALTH_CHECK = {
|
|
118
|
+
INTERVAL_SECONDS: 30,
|
|
119
|
+
TIMEOUT_SECONDS: 5,
|
|
120
|
+
RETRIES: 3,
|
|
121
|
+
START_PERIOD_SECONDS: 120
|
|
122
|
+
};
|
|
123
|
+
/** Container stop timeout in seconds. ECS waits this long after SIGTERM
|
|
124
|
+
* before sending SIGKILL. ClickHouse needs the longer-than-default window
|
|
125
|
+
* (CDK default: 30s) to flush in-progress merges, finish writing parts,
|
|
126
|
+
* and close the data directory cleanly — premature SIGKILL on a 1 vCPU
|
|
127
|
+
* m7g.medium under merge load risks `max_suspicious_broken_parts` on the
|
|
128
|
+
* next start. ECS upper bound is 120s. */
|
|
129
|
+
export const CLICKHOUSE_STOP_TIMEOUT_SECONDS = 90;
|
|
130
|
+
/** OPTIMIZE TABLE FINAL schedule.
|
|
131
|
+
* RMT tables carry min_age_to_force_merge_seconds=600 so the engine already merges
|
|
132
|
+
* old parts within 10 min; this task is a safety net for MVs (no engine-level setting)
|
|
133
|
+
* and for ReplacingMergeTree dedup under skewed write patterns. 6 hours is sufficient. */
|
|
134
|
+
export const OPTIMISE_FINAL_SCHEDULE = "rate(6 hours)";
|
|
135
|
+
/** Tables requiring periodic OPTIMIZE FINAL (ReplacingMergeTree only).
|
|
136
|
+
* Keep in sync with REPLACING_MERGE_TREE_TABLES in
|
|
137
|
+
* webapp/app/.server/lib/clickhouse/tenantQuery/tableConstants.ts (auto-FINAL). */
|
|
138
|
+
export const REPLACING_MERGE_TREE_TABLES = [
|
|
139
|
+
"application_metrics",
|
|
140
|
+
"cost_records",
|
|
141
|
+
"log_fingerprints",
|
|
142
|
+
"insights",
|
|
143
|
+
"asset_inventory"
|
|
144
|
+
];
|
|
145
|
+
/** Subdirectory on the EBS volume for server config files (must match CDK volume mount). */
|
|
146
|
+
export const CLICKHOUSE_CONFIG_SUBDIR = "server-config.d";
|
|
147
|
+
/** Subdirectory on the EBS volume for users config files (must match CDK volume mount). */
|
|
148
|
+
export const CLICKHOUSE_USERS_SUBDIR = "server-users.d";
|
|
149
|
+
/** Cloud Map service name (resolves to `clickhouse.<appName>.local` via the per-app namespace registered by `App.getInstance().registerService(...)`). */
|
|
150
|
+
export const CLICKHOUSE_CLOUDMAP_SERVICE_NAME = "clickhouse";
|
|
151
|
+
/** ECS container name for the ClickHouse server task. Threaded through both
|
|
152
|
+
* the `addContainer` call site and the SSM reload script (which uses
|
|
153
|
+
* `docker ps --filter "label=com.amazonaws.ecs.container-name=<name>"` to
|
|
154
|
+
* locate the running container). Drift between the two sites turns the
|
|
155
|
+
* live-reload path into a silent no-op without any compile/test signal,
|
|
156
|
+
* so this lives as a single source of truth. */
|
|
157
|
+
export const CLICKHOUSE_SERVER_CONTAINER_NAME = "clickhouse";
|
|
158
|
+
/** Materialised views that benefit from periodic OPTIMIZE to reduce part count at read time.
|
|
159
|
+
* These are not ReplacingMergeTree (no dedup needed) but un-merged parts force
|
|
160
|
+
* read-time aggregation which degrades query performance. */
|
|
161
|
+
export const OPTIMISE_MV_TABLES = [
|
|
162
|
+
"metrics_hourly_mv",
|
|
163
|
+
"metrics_daily_mv",
|
|
164
|
+
"response_time_quantiles_hourly_mv",
|
|
165
|
+
"deployment_duration_quantiles_daily_mv",
|
|
166
|
+
"log_severity_hourly_mv",
|
|
167
|
+
"compliance_score_daily_mv",
|
|
168
|
+
"ai_usage_daily_mv",
|
|
169
|
+
"finding_daily_aggregate",
|
|
170
|
+
"insight_pattern_dismissals"
|
|
171
|
+
];
|
|
172
|
+
/** Resource allocation for the lightweight optimise task. */
|
|
173
|
+
export const OPTIMISE_TASK_MEMORY_MIB = 256;
|
|
174
|
+
export const OPTIMISE_TASK_CPU_UNITS = 256;
|
|
175
|
+
/** Automated backup schedule (daily 03:00 UTC — low-traffic window). */
|
|
176
|
+
export const BACKUP_SCHEDULE = "cron(0 3 * * ? *)";
|
|
177
|
+
/** Resource allocation for the backup task (lightweight — clickhouse-client only). */
|
|
178
|
+
export const BACKUP_TASK_MEMORY_MIB = 256;
|
|
179
|
+
export const BACKUP_TASK_CPU_UNITS = 256;
|
|
180
|
+
/** Backup object expiration: 14 days (retains 14 daily snapshots). */
|
|
181
|
+
export const BACKUP_RETENTION_DAYS = 14;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Schema-admin user — the framework's bootstrap-privileged identity that
|
|
4
|
+
* customer SQL runs as. Owns DDL, schema migrations, GRANTs. Rendered into
|
|
5
|
+
* `users.d/fjall.xml` with `<access_management>1</access_management>` so it
|
|
6
|
+
* can manage GRANT / CREATE USER from SQL.
|
|
7
|
+
*
|
|
8
|
+
* The `profile` field names a key in the construct's `profiles:` prop (or
|
|
9
|
+
* `ClickHouseDefaultProfiles` if omitted) and is bound directly in the XML
|
|
10
|
+
* `<user><profile>…</profile></user>` block — not via the migration helper.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ClickHouseSchemaAdminSchema: z.ZodObject<{
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
profile: z.ZodString;
|
|
15
|
+
}, z.core.$strict>;
|
|
16
|
+
export type ClickHouseSchemaAdmin = z.infer<typeof ClickHouseSchemaAdminSchema>;
|
|
17
|
+
/**
|
|
18
|
+
* Managed-password workload user name. The framework mints a secret, grants
|
|
19
|
+
* IAM read on it, and the migration helper issues `CREATE USER … IDENTIFIED
|
|
20
|
+
* WITH sha256_password …` at runtime. Profile binding is NOT performed by
|
|
21
|
+
* the framework — customer SQL applies `ALTER USER <name> SETTINGS PROFILE
|
|
22
|
+
* <profile>` alongside their GRANTs.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ManagedPasswordNameSchema: z.ZodString;
|
|
25
|
+
export type ManagedPasswordName = z.infer<typeof ManagedPasswordNameSchema>;
|
|
26
|
+
/**
|
|
27
|
+
* Per-profile resource-cap shape. Field names mirror the ClickHouse XML
|
|
28
|
+
* element names (snake_case at the wire; camelCase here for TS ergonomics).
|
|
29
|
+
* Every field is `.optional()` — a profile may declare any subset.
|
|
30
|
+
*
|
|
31
|
+
* `renderUsersXml` maps each present field to the snake_case XML element
|
|
32
|
+
* via `camelToSnakeCase`. Unknown fields are rejected by `.strict()` so a
|
|
33
|
+
* typo at the consumer doesn't silently ship a no-op profile.
|
|
34
|
+
*/
|
|
35
|
+
export declare const ProfileSpecSchema: z.ZodObject<{
|
|
36
|
+
maxThreads: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
maxInsertThreads: z.ZodOptional<z.ZodNumber>;
|
|
38
|
+
maxConcurrentQueriesForUser: z.ZodOptional<z.ZodNumber>;
|
|
39
|
+
maxMemoryUsage: z.ZodOptional<z.ZodNumber>;
|
|
40
|
+
maxMemoryUsageForUser: z.ZodOptional<z.ZodNumber>;
|
|
41
|
+
maxExecutionTime: z.ZodOptional<z.ZodNumber>;
|
|
42
|
+
maxRowsToRead: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
maxBytesBeforeExternalSort: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
maxBytesBeforeExternalGroupBy: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
logQueriesMinQueryDurationMs: z.ZodOptional<z.ZodNumber>;
|
|
46
|
+
optimizeMoveToPrewhere: z.ZodOptional<z.ZodBoolean>;
|
|
47
|
+
useQueryConditionCache: z.ZodOptional<z.ZodBoolean>;
|
|
48
|
+
useSkipIndexesIfFinal: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
applyRowPolicyAfterFinal: z.ZodOptional<z.ZodBoolean>;
|
|
50
|
+
applyPrewhereAfterFinal: z.ZodOptional<z.ZodBoolean>;
|
|
51
|
+
doNotMergeAcrossPartitionsSelectFinal: z.ZodOptional<z.ZodBoolean>;
|
|
52
|
+
asyncInsert: z.ZodOptional<z.ZodBoolean>;
|
|
53
|
+
waitForAsyncInsert: z.ZodOptional<z.ZodBoolean>;
|
|
54
|
+
asyncInsertMaxDataSize: z.ZodOptional<z.ZodNumber>;
|
|
55
|
+
asyncInsertBusyTimeoutMinMs: z.ZodOptional<z.ZodNumber>;
|
|
56
|
+
asyncInsertBusyTimeoutMaxMs: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
asyncInsertUseAdaptiveBusyTimeout: z.ZodOptional<z.ZodBoolean>;
|
|
58
|
+
asyncInsertDeduplicate: z.ZodOptional<z.ZodBoolean>;
|
|
59
|
+
inputFormatParallelParsing: z.ZodOptional<z.ZodBoolean>;
|
|
60
|
+
outputFormatParallelFormatting: z.ZodOptional<z.ZodBoolean>;
|
|
61
|
+
queryPlanOptimizeLazyMaterialization: z.ZodOptional<z.ZodBoolean>;
|
|
62
|
+
materializeTtlAfterModify: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
}, z.core.$strict>;
|
|
64
|
+
export type ProfileSpec = z.infer<typeof ProfileSpecSchema>;
|
|
65
|
+
/**
|
|
66
|
+
* Re-exported for the construct's Stage 1 validation. Profile keys MUST
|
|
67
|
+
* match the same lowercase snake_case shape as user names — they emit as
|
|
68
|
+
* XML element names with no escaping.
|
|
69
|
+
*/
|
|
70
|
+
export declare const PROFILE_NAME_PATTERN: RegExp;
|
|
71
|
+
export declare const ClickHouseDefaultProfiles: Readonly<Record<string, Readonly<ProfileSpec>>>;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** ClickHouse user/profile name pattern — lowercase snake_case, leading
|
|
3
|
+
* letter only. Shared by `ClickHouseUserSchema.name` and the per-profile
|
|
4
|
+
* key regex applied inside `ClickHouseDatabase`'s construct-time validation
|
|
5
|
+
* (Stage 1). Keeps the XML element names emit-safe (no escaping needed). */
|
|
6
|
+
const NAME_PATTERN = /^[a-z][a-z0-9_]*$/;
|
|
7
|
+
/**
|
|
8
|
+
* Schema-admin user — the framework's bootstrap-privileged identity that
|
|
9
|
+
* customer SQL runs as. Owns DDL, schema migrations, GRANTs. Rendered into
|
|
10
|
+
* `users.d/fjall.xml` with `<access_management>1</access_management>` so it
|
|
11
|
+
* can manage GRANT / CREATE USER from SQL.
|
|
12
|
+
*
|
|
13
|
+
* The `profile` field names a key in the construct's `profiles:` prop (or
|
|
14
|
+
* `ClickHouseDefaultProfiles` if omitted) and is bound directly in the XML
|
|
15
|
+
* `<user><profile>…</profile></user>` block — not via the migration helper.
|
|
16
|
+
*/
|
|
17
|
+
export const ClickHouseSchemaAdminSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
name: z
|
|
20
|
+
.string()
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(63)
|
|
23
|
+
.regex(NAME_PATTERN, "Must be lowercase snake_case"),
|
|
24
|
+
profile: z.string().min(1)
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
/**
|
|
28
|
+
* Managed-password workload user name. The framework mints a secret, grants
|
|
29
|
+
* IAM read on it, and the migration helper issues `CREATE USER … IDENTIFIED
|
|
30
|
+
* WITH sha256_password …` at runtime. Profile binding is NOT performed by
|
|
31
|
+
* the framework — customer SQL applies `ALTER USER <name> SETTINGS PROFILE
|
|
32
|
+
* <profile>` alongside their GRANTs.
|
|
33
|
+
*/
|
|
34
|
+
export const ManagedPasswordNameSchema = z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(63)
|
|
38
|
+
.regex(NAME_PATTERN, "Must be lowercase snake_case");
|
|
39
|
+
/**
|
|
40
|
+
* Per-profile resource-cap shape. Field names mirror the ClickHouse XML
|
|
41
|
+
* element names (snake_case at the wire; camelCase here for TS ergonomics).
|
|
42
|
+
* Every field is `.optional()` — a profile may declare any subset.
|
|
43
|
+
*
|
|
44
|
+
* `renderUsersXml` maps each present field to the snake_case XML element
|
|
45
|
+
* via `camelToSnakeCase`. Unknown fields are rejected by `.strict()` so a
|
|
46
|
+
* typo at the consumer doesn't silently ship a no-op profile.
|
|
47
|
+
*/
|
|
48
|
+
export const ProfileSpecSchema = z
|
|
49
|
+
.object({
|
|
50
|
+
maxThreads: z.number().int().positive().optional(),
|
|
51
|
+
maxInsertThreads: z.number().int().positive().optional(),
|
|
52
|
+
maxConcurrentQueriesForUser: z.number().int().positive().optional(),
|
|
53
|
+
maxMemoryUsage: z.number().int().positive().optional(),
|
|
54
|
+
maxMemoryUsageForUser: z.number().int().positive().optional(),
|
|
55
|
+
maxExecutionTime: z.number().int().positive().optional(),
|
|
56
|
+
maxRowsToRead: z.number().int().positive().optional(),
|
|
57
|
+
maxBytesBeforeExternalSort: z.number().int().positive().optional(),
|
|
58
|
+
maxBytesBeforeExternalGroupBy: z.number().int().positive().optional(),
|
|
59
|
+
logQueriesMinQueryDurationMs: z.number().int().nonnegative().optional(),
|
|
60
|
+
optimizeMoveToPrewhere: z.boolean().optional(),
|
|
61
|
+
useQueryConditionCache: z.boolean().optional(),
|
|
62
|
+
useSkipIndexesIfFinal: z.boolean().optional(),
|
|
63
|
+
applyRowPolicyAfterFinal: z.boolean().optional(),
|
|
64
|
+
applyPrewhereAfterFinal: z.boolean().optional(),
|
|
65
|
+
doNotMergeAcrossPartitionsSelectFinal: z.boolean().optional(),
|
|
66
|
+
asyncInsert: z.boolean().optional(),
|
|
67
|
+
waitForAsyncInsert: z.boolean().optional(),
|
|
68
|
+
asyncInsertMaxDataSize: z.number().int().positive().optional(),
|
|
69
|
+
asyncInsertBusyTimeoutMinMs: z.number().int().nonnegative().optional(),
|
|
70
|
+
asyncInsertBusyTimeoutMaxMs: z.number().int().nonnegative().optional(),
|
|
71
|
+
asyncInsertUseAdaptiveBusyTimeout: z.boolean().optional(),
|
|
72
|
+
asyncInsertDeduplicate: z.boolean().optional(),
|
|
73
|
+
inputFormatParallelParsing: z.boolean().optional(),
|
|
74
|
+
outputFormatParallelFormatting: z.boolean().optional(),
|
|
75
|
+
queryPlanOptimizeLazyMaterialization: z.boolean().optional(),
|
|
76
|
+
materializeTtlAfterModify: z.boolean().optional()
|
|
77
|
+
})
|
|
78
|
+
.strict();
|
|
79
|
+
/**
|
|
80
|
+
* Re-exported for the construct's Stage 1 validation. Profile keys MUST
|
|
81
|
+
* match the same lowercase snake_case shape as user names — they emit as
|
|
82
|
+
* XML element names with no escaping.
|
|
83
|
+
*/
|
|
84
|
+
export const PROFILE_NAME_PATTERN = NAME_PATTERN;
|
|
85
|
+
/**
|
|
86
|
+
* Four workload-class default profiles. Cap values lifted byte-for-byte
|
|
87
|
+
* from the pre-Phase-4b inline `<app_writer>` / `<audit_writer>` /
|
|
88
|
+
* `<backup_reader>` / `<schema_admin>` blocks at
|
|
89
|
+
* `clickhouseUserData.ts:296-382` — zero behavioural drift from the
|
|
90
|
+
* pre-4b prod resource caps.
|
|
91
|
+
*
|
|
92
|
+
* Frozen via `Object.freeze` on the outer record AND each sub-object so
|
|
93
|
+
* a consumer cannot mutate the defaults in place. Pass your own
|
|
94
|
+
* `profiles:` map to the construct to extend / override; never mutate
|
|
95
|
+
* this constant.
|
|
96
|
+
*/
|
|
97
|
+
const _ClickHouseDefaultProfilesRaw = {
|
|
98
|
+
high_throughput_ingest: {
|
|
99
|
+
maxThreads: 1,
|
|
100
|
+
maxInsertThreads: 1,
|
|
101
|
+
maxConcurrentQueriesForUser: 2,
|
|
102
|
+
logQueriesMinQueryDurationMs: 100,
|
|
103
|
+
optimizeMoveToPrewhere: true,
|
|
104
|
+
useQueryConditionCache: true,
|
|
105
|
+
useSkipIndexesIfFinal: true,
|
|
106
|
+
applyRowPolicyAfterFinal: true,
|
|
107
|
+
applyPrewhereAfterFinal: true,
|
|
108
|
+
doNotMergeAcrossPartitionsSelectFinal: true,
|
|
109
|
+
asyncInsert: true,
|
|
110
|
+
waitForAsyncInsert: true,
|
|
111
|
+
asyncInsertMaxDataSize: 10000000,
|
|
112
|
+
asyncInsertBusyTimeoutMinMs: 50,
|
|
113
|
+
asyncInsertBusyTimeoutMaxMs: 2000,
|
|
114
|
+
asyncInsertUseAdaptiveBusyTimeout: true,
|
|
115
|
+
asyncInsertDeduplicate: true,
|
|
116
|
+
inputFormatParallelParsing: false,
|
|
117
|
+
outputFormatParallelFormatting: false,
|
|
118
|
+
queryPlanOptimizeLazyMaterialization: true,
|
|
119
|
+
maxMemoryUsage: 1610612736,
|
|
120
|
+
maxMemoryUsageForUser: 2147483648,
|
|
121
|
+
maxBytesBeforeExternalSort: 536870912,
|
|
122
|
+
maxBytesBeforeExternalGroupBy: 536870912,
|
|
123
|
+
maxExecutionTime: 30,
|
|
124
|
+
maxRowsToRead: 10000000
|
|
125
|
+
},
|
|
126
|
+
audit_append: {
|
|
127
|
+
maxThreads: 1,
|
|
128
|
+
maxInsertThreads: 1,
|
|
129
|
+
maxConcurrentQueriesForUser: 2,
|
|
130
|
+
maxMemoryUsage: 500000000,
|
|
131
|
+
maxExecutionTime: 10,
|
|
132
|
+
asyncInsert: true,
|
|
133
|
+
waitForAsyncInsert: true
|
|
134
|
+
},
|
|
135
|
+
read_only: {
|
|
136
|
+
maxThreads: 1,
|
|
137
|
+
maxConcurrentQueriesForUser: 1,
|
|
138
|
+
maxMemoryUsage: 1000000000,
|
|
139
|
+
maxExecutionTime: 3600
|
|
140
|
+
},
|
|
141
|
+
ddl_admin: {
|
|
142
|
+
maxThreads: 1,
|
|
143
|
+
maxConcurrentQueriesForUser: 1,
|
|
144
|
+
maxMemoryUsage: 1000000000,
|
|
145
|
+
maxExecutionTime: 1800
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export const ClickHouseDefaultProfiles = Object.freeze({
|
|
149
|
+
high_throughput_ingest: Object.freeze({
|
|
150
|
+
..._ClickHouseDefaultProfilesRaw.high_throughput_ingest
|
|
151
|
+
}),
|
|
152
|
+
audit_append: Object.freeze({
|
|
153
|
+
..._ClickHouseDefaultProfilesRaw.audit_append
|
|
154
|
+
}),
|
|
155
|
+
read_only: Object.freeze({ ..._ClickHouseDefaultProfilesRaw.read_only }),
|
|
156
|
+
ddl_admin: Object.freeze({ ..._ClickHouseDefaultProfilesRaw.ddl_admin })
|
|
157
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
2
|
+
import type { Construct } from "constructs";
|
|
3
|
+
import { SecurityGroup } from "../networking/securityGroup.js";
|
|
4
|
+
/**
|
|
5
|
+
* Create the ClickHouse security group.
|
|
6
|
+
*
|
|
7
|
+
* No consumer ingress rules are added here — consumer ingress flows through
|
|
8
|
+
* the connector contract (`ISecurityGroupConnector` + `additionalTcpPorts`)
|
|
9
|
+
* so the SG is consumer-agnostic and reusable across compute consumers.
|
|
10
|
+
*
|
|
11
|
+
* Self-referencing native-port ingress is kept so the optimise/backup
|
|
12
|
+
* scheduled tasks (which share this SG) can reach the ClickHouse server.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createClickHouseSecurityGroup(scope: Construct, vpc: IVpc, nativePort: number): SecurityGroup;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Peer, Port } from "aws-cdk-lib/aws-ec2";
|
|
2
|
+
import { SecurityGroup } from "../networking/securityGroup.js";
|
|
3
|
+
/**
|
|
4
|
+
* Create the ClickHouse security group.
|
|
5
|
+
*
|
|
6
|
+
* No consumer ingress rules are added here — consumer ingress flows through
|
|
7
|
+
* the connector contract (`ISecurityGroupConnector` + `additionalTcpPorts`)
|
|
8
|
+
* so the SG is consumer-agnostic and reusable across compute consumers.
|
|
9
|
+
*
|
|
10
|
+
* Self-referencing native-port ingress is kept so the optimise/backup
|
|
11
|
+
* scheduled tasks (which share this SG) can reach the ClickHouse server.
|
|
12
|
+
*/
|
|
13
|
+
export function createClickHouseSecurityGroup(scope, vpc, nativePort) {
|
|
14
|
+
const sg = new SecurityGroup(scope, "ClickHouseSecurityGroup", {
|
|
15
|
+
vpc,
|
|
16
|
+
description: "Security group for ClickHouse analytics instance",
|
|
17
|
+
allowAllOutbound: false
|
|
18
|
+
});
|
|
19
|
+
sg.addIngressRule(sg, Port.tcp(nativePort), "ClickHouse native protocol from sidecar tasks (self-referencing)");
|
|
20
|
+
sg.addEgressRule(Peer.anyIpv4(), Port.tcp(443), "HTTPS to AWS service endpoints (S3, Secrets Manager, IMDS)");
|
|
21
|
+
sg.addEgressRule(sg, Port.tcp(nativePort), "ClickHouse native protocol for sidecar tasks");
|
|
22
|
+
return sg;
|
|
23
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { ClickHouseSchemaAdmin, ProfileSpec } from "./clickhouseSchemas.js";
|
|
2
|
+
/**
|
|
3
|
+
* Options for {@link buildClickHouseUserData}.
|
|
4
|
+
*
|
|
5
|
+
* Per design D27 + D12: Cloudflare R2 is dropped; cold storage targets S3
|
|
6
|
+
* with IAM-only auth via `<use_environment_credentials>true</use_environment_credentials>`.
|
|
7
|
+
* Zero env-var access keys are injected into the rendered config.
|
|
8
|
+
*/
|
|
9
|
+
export interface BuildClickHouseUserDataOptions {
|
|
10
|
+
/** S3 bucket name for `BACKUP DATABASE TO S3`; pre-authenticated via IAM. */
|
|
11
|
+
backupBucketName: string;
|
|
12
|
+
/** AWS region of the backup bucket. */
|
|
13
|
+
backupBucketRegion: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional S3 cold-tier configuration.
|
|
16
|
+
* When omitted, single-tier hot storage on the EC2 EBS volume is used.
|
|
17
|
+
*/
|
|
18
|
+
coldTier?: {
|
|
19
|
+
bucketName: string;
|
|
20
|
+
region: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export declare function generateServerConfigXml(options: BuildClickHouseUserDataOptions): string;
|
|
24
|
+
export interface GenerateUsersConfigXmlOptions {
|
|
25
|
+
schemaAdmin: ClickHouseSchemaAdmin;
|
|
26
|
+
profiles: Record<string, ProfileSpec>;
|
|
27
|
+
vpcCidr: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Construct-side thin wrapper around `renderUsersXml`. Always emits the
|
|
31
|
+
* prod shape: loopback-only `<default>` user, `from_env=` sha256 password
|
|
32
|
+
* directives. The container entrypoint wrapper (see
|
|
33
|
+
* `buildClickHouseEntrypointWrapper`) resolves the `USER_<NAME>_SHA256` env
|
|
34
|
+
* vars at server start from `sha256sum` of each ECS-injected plaintext.
|
|
35
|
+
*
|
|
36
|
+
* TODO secondary CIDRs: props.vpc.vpcCidrBlock returns only the primary CIDR.
|
|
37
|
+
* BYOC consumers with multi-CIDR VPCs need a per-CIDR `<ip>` emitter — see
|
|
38
|
+
* designs/2026-05-12-clickhouse-construct-leak-fixes.md § "Phase 1.5".
|
|
39
|
+
*/
|
|
40
|
+
export declare function generateUsersConfigXml(options: GenerateUsersConfigXmlOptions): string;
|
|
41
|
+
/**
|
|
42
|
+
* Build the EC2 user-data script that bootstraps ClickHouse on the ASG instance.
|
|
43
|
+
*
|
|
44
|
+
* Per design D27 + D12: cold-storage and backups authenticate to S3 via IAM
|
|
45
|
+
* (the EC2 instance role's grants), not via env-var access keys. The rendered
|
|
46
|
+
* output contains zero `R2_*` / `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`
|
|
47
|
+
* references — `<use_environment_credentials>true</use_environment_credentials>`
|
|
48
|
+
* tells ClickHouse to use the IMDS-derived credentials instead.
|
|
49
|
+
*/
|
|
50
|
+
export declare function buildClickHouseUserData(options: BuildClickHouseUserDataOptions): string;
|
|
51
|
+
/**
|
|
52
|
+
* Build the bash wrapper executed as the CH container's entrypoint.
|
|
53
|
+
*
|
|
54
|
+
* The CH server reads `users.d/fjall.xml`, which carries
|
|
55
|
+
* `<password_sha256_hex from_env="USER_<NAME>_SHA256"/>` directives, and
|
|
56
|
+
* resolves those `from_env=` lookups against the server process's
|
|
57
|
+
* environment at startup. ECS injects the plaintext password for each user
|
|
58
|
+
* as `USER_<NAME>_PASSWORD` via `secretsImport`; this wrapper derives the
|
|
59
|
+
* matching `USER_<NAME>_SHA256` env var (via the same SHA-256 pipeline as
|
|
60
|
+
* the EC2 user-data loop in `buildClickHouseUserData()`) and then `exec`s
|
|
61
|
+
* the stock CH entrypoint so the server inherits the derived vars after
|
|
62
|
+
* the gosu privilege drop.
|
|
63
|
+
*
|
|
64
|
+
* Pure-bash iteration via `${!USER_@}` avoids spawning `env`/`grep` and
|
|
65
|
+
* guarantees only ECS-injected secrets are considered. The `case` filter
|
|
66
|
+
* skips any future `USER_*_HOST`/`USER_*_PORT` envs that don't match the
|
|
67
|
+
* password convention.
|
|
68
|
+
*/
|
|
69
|
+
export declare function buildClickHouseEntrypointWrapper(): string;
|