@fjall/components-infrastructure 0.102.0 → 2.1.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/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 +45 -2
- package/dist/lib/patterns/aws/clickhouseDatabase.js +156 -32
- 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/patterns/aws/interfaces/database.d.ts +7 -5
- 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 +68 -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/dist/lib/utils/manifestWriter.js +6 -13
- package/package.json +8 -6
- 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
|
@@ -2,8 +2,10 @@ import { Connections, type IConnectable, type IVpc } from "aws-cdk-lib/aws-ec2";
|
|
|
2
2
|
import { type TaskDefinition } from "aws-cdk-lib/aws-ecs";
|
|
3
3
|
import { type IBucket } from "aws-cdk-lib/aws-s3";
|
|
4
4
|
import { Construct } from "constructs";
|
|
5
|
-
import { Secret } from "../../resources/aws/secrets/secret.js";
|
|
5
|
+
import { Secret, type SecretImport } from "../../resources/aws/secrets/secret.js";
|
|
6
6
|
import { type ClickHouseSchemaAdmin, type ProfileSpec } from "../../resources/aws/database/clickhouseSchemas.js";
|
|
7
|
+
import { type ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
8
|
+
import type { ClickHouseTlsOptions } from "./clickhouseTls/index.js";
|
|
7
9
|
import { type ClickHouseMigrationsConfig, type IClickHouseDatabase } from "./interfaces/database.js";
|
|
8
10
|
import { type ISecurityGroupConnector } from "./interfaces/connector.js";
|
|
9
11
|
import { type MigrationContributions } from "./interfaces/migrationContributor.js";
|
|
@@ -104,6 +106,15 @@ export interface ClickHouseDatabaseProps {
|
|
|
104
106
|
* records in `_schema_migrations.ch_version`.
|
|
105
107
|
*/
|
|
106
108
|
migrations?: ClickHouseMigrationsConfig;
|
|
109
|
+
/**
|
|
110
|
+
* TLS configuration. Default: `{ mode: "self-signed" }` — mints an ECDSA
|
|
111
|
+
* P-256 CA + leaf cert at deploy via a Lambda custom resource, stores both
|
|
112
|
+
* PEMs in Secrets Manager, and the EC2 user-data materialises them at boot
|
|
113
|
+
* for the CH server to read. Set `mode: "imported"` to bring your own CA;
|
|
114
|
+
* `mode: "none"` (acknowledgement literal required) opts out of TLS.
|
|
115
|
+
* See ./clickhouseTls/types.ts.
|
|
116
|
+
*/
|
|
117
|
+
tls?: ClickHouseTlsOptions;
|
|
107
118
|
}
|
|
108
119
|
/**
|
|
109
120
|
* ClickHouse analytics database wrapper implementing IClickHouseDatabase.
|
|
@@ -121,6 +132,25 @@ export declare class ClickHouseDatabase extends Construct implements IClickHouse
|
|
|
121
132
|
readonly additionalTcpPorts: number[];
|
|
122
133
|
readonly id: string;
|
|
123
134
|
readonly connections: Connections;
|
|
135
|
+
/**
|
|
136
|
+
* CA cert secret. Self-signed: minted by `TlsCertGenerator`. Imported: the
|
|
137
|
+
* user-supplied ISecret. `undefined` when `tls.mode === "none"`.
|
|
138
|
+
* SecretString shape: raw PEM (single cert, no JSON wrapping).
|
|
139
|
+
*/
|
|
140
|
+
readonly tlsCaSecret: ISecret | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* Server cert + key secret. Self-signed: minted by `TlsCertGenerator`.
|
|
143
|
+
* Imported: the user-supplied ISecret. `undefined` when `tls.mode === "none"`.
|
|
144
|
+
* SecretString shape: JSON `{ "cert": "<leaf-pem>", "key": "<key-pem>" }`.
|
|
145
|
+
*/
|
|
146
|
+
readonly tlsServerSecret: ISecret | undefined;
|
|
147
|
+
/**
|
|
148
|
+
* SHA-256 of the CA cert PEM. CFN token in self-signed mode (from the cert
|
|
149
|
+
* generator custom resource Data attribute). Plain string in imported mode
|
|
150
|
+
* when supplied. `undefined` when `tls.mode === "none"` or when imported
|
|
151
|
+
* without a digest. Surface on consumers as a task-replacement trigger.
|
|
152
|
+
*/
|
|
153
|
+
readonly caCertSha256: string | undefined;
|
|
124
154
|
constructor(scope: Construct, id: string, props: ClickHouseDatabaseProps);
|
|
125
155
|
/**
|
|
126
156
|
* Returns the Fjall `Secret` wrapper for the named user. Throws with a
|
|
@@ -138,7 +168,20 @@ export declare class ClickHouseDatabase extends Construct implements IClickHouse
|
|
|
138
168
|
getHttpPort(): number;
|
|
139
169
|
getNativePort(): number;
|
|
140
170
|
getHostEndpoint(): string;
|
|
141
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Canonical URL for the HTTP(S) interface. Scheme is `https` when TLS is
|
|
173
|
+
* active (default), `http` only when `tls: { mode: "none", … }` is set.
|
|
174
|
+
* Port matches: HTTPS (8443) under TLS, HTTP (8123) otherwise.
|
|
175
|
+
*/
|
|
176
|
+
getUrl(): string;
|
|
177
|
+
/**
|
|
178
|
+
* SecretImport for the CA certificate secret, or `undefined` when TLS is
|
|
179
|
+
* disabled (`tls: { mode: "none", … }`). Consumers wire this into their
|
|
180
|
+
* `secretsImport:` block under `CLICKHOUSE_CA_CERT` so `@fjall/clickhouse`
|
|
181
|
+
* `createFjallClickHouseClient()` picks it up from `process.env`. The secret
|
|
182
|
+
* holds raw PEM (no JSON field) so `field` is `undefined`.
|
|
183
|
+
*/
|
|
184
|
+
getTlsCaCertImport(): SecretImport | undefined;
|
|
142
185
|
getNativeUrl(): string;
|
|
143
186
|
getDatabaseName(): string;
|
|
144
187
|
getBackupBucket(): IBucket;
|
|
@@ -20,7 +20,8 @@ import { buildClickHouseEntrypointWrapper, buildClickHouseUserData, generateUser
|
|
|
20
20
|
import { toPascalCase } from "../../utils/capitaliseString.js";
|
|
21
21
|
import { ClickHouseSchemaAdminSchema, ManagedPasswordNameSchema, ProfileSpecSchema, ClickHouseDefaultProfiles, PROFILE_NAME_PATTERN } from "../../resources/aws/database/clickhouseSchemas.js";
|
|
22
22
|
import { inferAmiHardwareType } from "../../resources/aws/compute/ecsConstants.js";
|
|
23
|
-
import { CLICKHOUSE_DATABASE_NAME, DEFAULT_CLICKHOUSE_INSTANCE_TYPE, CLICKHOUSE_IMAGE, CLICKHOUSE_EBS_VOLUME_SIZE_GB, CLICKHOUSE_EBS_IOPS, CLICKHOUSE_EBS_THROUGHPUT_MBPS, CLICKHOUSE_TASK_MEMORY_MIB, CLICKHOUSE_HTTP_PORT, CLICKHOUSE_NATIVE_PORT, CLICKHOUSE_PROMETHEUS_PORT, CLICKHOUSE_DATA_MOUNT_PATH, CLICKHOUSE_SECRET_OPTIONS, CLICKHOUSE_SERVER_ROLE_TAG, clickHouseUserSecretName, CLICKHOUSE_HEALTH_CHECK, CLICKHOUSE_STOP_TIMEOUT_SECONDS, CLICKHOUSE_EBS_DEVICE_NAME, CLICKHOUSE_CONFIG_SUBDIR, CLICKHOUSE_USERS_SUBDIR, userPasswordEnvName, OPTIMISE_FINAL_SCHEDULE, REPLACING_MERGE_TREE_TABLES, OPTIMISE_MV_TABLES, CLICKHOUSE_CLOUDMAP_SERVICE_NAME, CLICKHOUSE_SERVER_CONTAINER_NAME, OPTIMISE_TASK_MEMORY_MIB, OPTIMISE_TASK_CPU_UNITS, BACKUP_SCHEDULE, BACKUP_TASK_MEMORY_MIB, BACKUP_TASK_CPU_UNITS, BACKUP_RETENTION_DAYS } from "../../resources/aws/database/clickhouseConstants.js";
|
|
23
|
+
import { CLICKHOUSE_DATABASE_NAME, DEFAULT_CLICKHOUSE_INSTANCE_TYPE, CLICKHOUSE_IMAGE, CLICKHOUSE_EBS_VOLUME_SIZE_GB, CLICKHOUSE_EBS_IOPS, CLICKHOUSE_EBS_THROUGHPUT_MBPS, CLICKHOUSE_TASK_MEMORY_MIB, CLICKHOUSE_HTTP_PORT, CLICKHOUSE_HTTPS_PORT, CLICKHOUSE_NATIVE_PORT, CLICKHOUSE_TCP_SECURE_PORT, CLICKHOUSE_TLS_CERT_MOUNT_PATH, CLICKHOUSE_PROMETHEUS_PORT, CLICKHOUSE_DATA_MOUNT_PATH, CLICKHOUSE_SECRET_OPTIONS, CLICKHOUSE_SERVER_ROLE_TAG, clickHouseUserSecretName, CLICKHOUSE_HEALTH_CHECK, CLICKHOUSE_STOP_TIMEOUT_SECONDS, CLICKHOUSE_EBS_DEVICE_NAME, CLICKHOUSE_CONFIG_SUBDIR, CLICKHOUSE_USERS_SUBDIR, userPasswordEnvName, OPTIMISE_FINAL_SCHEDULE, REPLACING_MERGE_TREE_TABLES, OPTIMISE_MV_TABLES, CLICKHOUSE_CLOUDMAP_SERVICE_NAME, CLICKHOUSE_SERVER_CONTAINER_NAME, OPTIMISE_TASK_MEMORY_MIB, OPTIMISE_TASK_CPU_UNITS, BACKUP_SCHEDULE, BACKUP_TASK_MEMORY_MIB, BACKUP_TASK_CPU_UNITS, BACKUP_RETENTION_DAYS } from "../../resources/aws/database/clickhouseConstants.js";
|
|
24
|
+
import { TlsCertGenerator } from "../../resources/aws/utilities/tlsCertGenerator.js";
|
|
24
25
|
import { EcsCompute } from "./computeEcs.js";
|
|
25
26
|
/**
|
|
26
27
|
* Resolve the ECS desired task count for the ClickHouse service.
|
|
@@ -81,9 +82,30 @@ function createClickHouseUserSecret(scope, name) {
|
|
|
81
82
|
export class ClickHouseDatabase extends Construct {
|
|
82
83
|
databaseType = "ClickHouse";
|
|
83
84
|
connectorType = "relational";
|
|
84
|
-
additionalTcpPorts
|
|
85
|
+
additionalTcpPorts;
|
|
85
86
|
id;
|
|
86
87
|
connections;
|
|
88
|
+
/**
|
|
89
|
+
* CA cert secret. Self-signed: minted by `TlsCertGenerator`. Imported: the
|
|
90
|
+
* user-supplied ISecret. `undefined` when `tls.mode === "none"`.
|
|
91
|
+
* SecretString shape: raw PEM (single cert, no JSON wrapping).
|
|
92
|
+
*/
|
|
93
|
+
tlsCaSecret;
|
|
94
|
+
/**
|
|
95
|
+
* Server cert + key secret. Self-signed: minted by `TlsCertGenerator`.
|
|
96
|
+
* Imported: the user-supplied ISecret. `undefined` when `tls.mode === "none"`.
|
|
97
|
+
* SecretString shape: JSON `{ "cert": "<leaf-pem>", "key": "<key-pem>" }`.
|
|
98
|
+
*/
|
|
99
|
+
tlsServerSecret;
|
|
100
|
+
/**
|
|
101
|
+
* SHA-256 of the CA cert PEM. CFN token in self-signed mode (from the cert
|
|
102
|
+
* generator custom resource Data attribute). Plain string in imported mode
|
|
103
|
+
* when supplied. `undefined` when `tls.mode === "none"` or when imported
|
|
104
|
+
* without a digest. Surface on consumers as a task-replacement trigger.
|
|
105
|
+
*/
|
|
106
|
+
caCertSha256;
|
|
107
|
+
#httpPort;
|
|
108
|
+
#nativePort;
|
|
87
109
|
#users;
|
|
88
110
|
#schemaAdmin;
|
|
89
111
|
#managedPasswordNames;
|
|
@@ -157,7 +179,46 @@ export class ClickHouseDatabase extends Construct {
|
|
|
157
179
|
(props.backupRetentionDays < 1 || props.backupRetentionDays > 3650)) {
|
|
158
180
|
throw new Error(`ClickHouseDatabase: backupRetentionDays must be between 1 and 3650; got ${props.backupRetentionDays}.`);
|
|
159
181
|
}
|
|
160
|
-
const
|
|
182
|
+
const tlsOptions = props.tls ?? {
|
|
183
|
+
mode: "self-signed"
|
|
184
|
+
};
|
|
185
|
+
const tlsActive = tlsOptions.mode !== "none";
|
|
186
|
+
const httpPort = tlsActive ? CLICKHOUSE_HTTPS_PORT : CLICKHOUSE_HTTP_PORT;
|
|
187
|
+
const nativePort = tlsActive
|
|
188
|
+
? CLICKHOUSE_TCP_SECURE_PORT
|
|
189
|
+
: CLICKHOUSE_NATIVE_PORT;
|
|
190
|
+
let tlsCaSecret;
|
|
191
|
+
let tlsServerSecret;
|
|
192
|
+
let caCertSha256;
|
|
193
|
+
if (tlsOptions.mode === "self-signed") {
|
|
194
|
+
const namespaceName = App.getInstance().getNamespace().namespaceName;
|
|
195
|
+
const hostname = `${CLICKHOUSE_CLOUDMAP_SERVICE_NAME}.${namespaceName}`;
|
|
196
|
+
const certGen = new TlsCertGenerator(this, "TlsCertGenerator", {
|
|
197
|
+
appName: App.getInstance().getName(),
|
|
198
|
+
hostname,
|
|
199
|
+
...(tlsOptions.caValidityYears !== undefined && {
|
|
200
|
+
caValidityYears: tlsOptions.caValidityYears
|
|
201
|
+
}),
|
|
202
|
+
...(tlsOptions.leafValidityYears !== undefined && {
|
|
203
|
+
leafValidityYears: tlsOptions.leafValidityYears
|
|
204
|
+
})
|
|
205
|
+
});
|
|
206
|
+
tlsCaSecret = certGen.caSecret.secret;
|
|
207
|
+
tlsServerSecret = certGen.serverSecret.secret;
|
|
208
|
+
caCertSha256 = certGen.caCertSha256;
|
|
209
|
+
}
|
|
210
|
+
else if (tlsOptions.mode === "imported") {
|
|
211
|
+
tlsCaSecret = tlsOptions.caCertSecret;
|
|
212
|
+
tlsServerSecret = tlsOptions.serverCertSecret;
|
|
213
|
+
caCertSha256 = tlsOptions.caCertSha256;
|
|
214
|
+
}
|
|
215
|
+
this.tlsCaSecret = tlsCaSecret;
|
|
216
|
+
this.tlsServerSecret = tlsServerSecret;
|
|
217
|
+
this.caCertSha256 = caCertSha256;
|
|
218
|
+
this.additionalTcpPorts = [nativePort];
|
|
219
|
+
this.#httpPort = httpPort;
|
|
220
|
+
this.#nativePort = nativePort;
|
|
221
|
+
const securityGroup = createClickHouseSecurityGroup(this, vpc, nativePort);
|
|
161
222
|
const userSecrets = new Map();
|
|
162
223
|
for (const name of allUserNames) {
|
|
163
224
|
userSecrets.set(name, createClickHouseUserSecret(this, name));
|
|
@@ -200,6 +261,13 @@ export class ClickHouseDatabase extends Construct {
|
|
|
200
261
|
bucketName: coldTierBucket.bucketName,
|
|
201
262
|
region: Stack.of(this).region
|
|
202
263
|
}
|
|
264
|
+
}),
|
|
265
|
+
tlsActive,
|
|
266
|
+
...(tlsActive &&
|
|
267
|
+
tlsCaSecret !== undefined &&
|
|
268
|
+
tlsServerSecret !== undefined && {
|
|
269
|
+
caSecretArn: tlsCaSecret.secretArn,
|
|
270
|
+
serverSecretArn: tlsServerSecret.secretArn
|
|
203
271
|
})
|
|
204
272
|
}));
|
|
205
273
|
// Source.data wraps the content in a zip; the default `extract: true`
|
|
@@ -226,6 +294,15 @@ export class ClickHouseDatabase extends Construct {
|
|
|
226
294
|
...OPTIMISE_MV_TABLES.map((table) => `OPTIMIZE TABLE ${CLICKHOUSE_DATABASE_NAME}.${table}`)
|
|
227
295
|
].join("; ");
|
|
228
296
|
const adminSecret = expectDefined(userSecrets.get(schemaAdmin.name), `schemaAdmin '${schemaAdmin.name}' secret not minted.`);
|
|
297
|
+
const sidecarTlsPreamble = tlsActive
|
|
298
|
+
? `set -eu && printf '%s\\n' "$CLICKHOUSE_CA_CERT" > /tmp/ca.crt && printf '%s' '<?xml version="1.0"?><config><openSSL><client><caConfig>/tmp/ca.crt</caConfig><verificationMode>strict</verificationMode><loadDefaultCAFile>false</loadDefaultCAFile><invalidCertificateHandler><name>RejectCertificateHandler</name></invalidCertificateHandler></client></openSSL></config>' > /tmp/clickhouse-client.xml && `
|
|
299
|
+
: "";
|
|
300
|
+
const sidecarTlsClientArgs = tlsActive
|
|
301
|
+
? " --config-file=/tmp/clickhouse-client.xml --secure"
|
|
302
|
+
: "";
|
|
303
|
+
const sidecarTlsSecrets = tlsActive && tlsCaSecret !== undefined
|
|
304
|
+
? { CLICKHOUSE_CA_CERT: EcsSecret.fromSecretsManager(tlsCaSecret) }
|
|
305
|
+
: {};
|
|
229
306
|
const scheduledTasks = [];
|
|
230
307
|
if (optimiseEnabled) {
|
|
231
308
|
scheduledTasks.push({
|
|
@@ -235,18 +312,13 @@ export class ClickHouseDatabase extends Construct {
|
|
|
235
312
|
cpu: OPTIMISE_TASK_CPU_UNITS,
|
|
236
313
|
memoryLimitMiB: OPTIMISE_TASK_MEMORY_MIB,
|
|
237
314
|
command: [
|
|
238
|
-
"
|
|
239
|
-
"
|
|
240
|
-
clickHouseHost
|
|
241
|
-
"--port",
|
|
242
|
-
String(CLICKHOUSE_NATIVE_PORT),
|
|
243
|
-
"--user",
|
|
244
|
-
schemaAdmin.name,
|
|
245
|
-
"--query",
|
|
246
|
-
`${optimiseQuery};`
|
|
315
|
+
"sh",
|
|
316
|
+
"-c",
|
|
317
|
+
`${sidecarTlsPreamble}clickhouse-client --host ${clickHouseHost} --port ${nativePort} --user ${schemaAdmin.name}${sidecarTlsClientArgs} --query "${optimiseQuery};"`
|
|
247
318
|
],
|
|
248
319
|
secrets: {
|
|
249
|
-
CLICKHOUSE_PASSWORD: EcsSecret.fromSecretsManager(adminSecret.secret, "password")
|
|
320
|
+
CLICKHOUSE_PASSWORD: EcsSecret.fromSecretsManager(adminSecret.secret, "password"),
|
|
321
|
+
...sidecarTlsSecrets
|
|
250
322
|
},
|
|
251
323
|
logRetention: RetentionDays.ONE_WEEK,
|
|
252
324
|
securityGroups: [securityGroup]
|
|
@@ -263,10 +335,11 @@ export class ClickHouseDatabase extends Construct {
|
|
|
263
335
|
"sh",
|
|
264
336
|
"-c",
|
|
265
337
|
// Password via CLICKHOUSE_PASSWORD env, not --password on argv (argv → /proc/<pid>/cmdline).
|
|
266
|
-
|
|
338
|
+
`${sidecarTlsPreamble}STAMP=$(date +%Y%m%d-%H%M%S) && clickhouse-client --host ${clickHouseHost} --port ${nativePort} --user ${schemaAdmin.name}${sidecarTlsClientArgs} --query "BACKUP DATABASE ${CLICKHOUSE_DATABASE_NAME} TO S3('${backupDestUrl}weekly-$STAMP/')"`
|
|
267
339
|
],
|
|
268
340
|
secrets: {
|
|
269
|
-
CLICKHOUSE_PASSWORD: EcsSecret.fromSecretsManager(adminSecret.secret, "password")
|
|
341
|
+
CLICKHOUSE_PASSWORD: EcsSecret.fromSecretsManager(adminSecret.secret, "password"),
|
|
342
|
+
...sidecarTlsSecrets
|
|
270
343
|
},
|
|
271
344
|
logGroup: backupTaskLogGroup,
|
|
272
345
|
securityGroups: [securityGroup]
|
|
@@ -331,12 +404,12 @@ export class ClickHouseDatabase extends Construct {
|
|
|
331
404
|
secretsImport: clickHouseContainerSecrets,
|
|
332
405
|
portMappings: [
|
|
333
406
|
{
|
|
334
|
-
containerPort:
|
|
335
|
-
hostPort:
|
|
407
|
+
containerPort: httpPort,
|
|
408
|
+
hostPort: httpPort
|
|
336
409
|
},
|
|
337
410
|
{
|
|
338
|
-
containerPort:
|
|
339
|
-
hostPort:
|
|
411
|
+
containerPort: nativePort,
|
|
412
|
+
hostPort: nativePort
|
|
340
413
|
},
|
|
341
414
|
{
|
|
342
415
|
containerPort: CLICKHOUSE_PROMETHEUS_PORT,
|
|
@@ -360,12 +433,24 @@ export class ClickHouseDatabase extends Construct {
|
|
|
360
433
|
hostSourcePath: `${CLICKHOUSE_DATA_MOUNT_PATH}/${CLICKHOUSE_USERS_SUBDIR}`,
|
|
361
434
|
mountPath: "/etc/clickhouse-server/users.d",
|
|
362
435
|
readOnly: true
|
|
363
|
-
}
|
|
436
|
+
},
|
|
437
|
+
...(tlsActive
|
|
438
|
+
? [
|
|
439
|
+
{
|
|
440
|
+
name: "clickhouse-certs",
|
|
441
|
+
hostSourcePath: `${CLICKHOUSE_DATA_MOUNT_PATH}/server-certs`,
|
|
442
|
+
mountPath: CLICKHOUSE_TLS_CERT_MOUNT_PATH,
|
|
443
|
+
readOnly: true
|
|
444
|
+
}
|
|
445
|
+
]
|
|
446
|
+
: [])
|
|
364
447
|
],
|
|
365
448
|
healthCheck: {
|
|
366
449
|
command: [
|
|
367
450
|
"CMD-SHELL",
|
|
368
|
-
|
|
451
|
+
tlsActive
|
|
452
|
+
? `wget -q --ca-certificate=${CLICKHOUSE_TLS_CERT_MOUNT_PATH}/ca.crt -O /dev/null https://127.0.0.1:${httpPort}/ping || exit 1`
|
|
453
|
+
: `wget -q -O /dev/null http://127.0.0.1:${httpPort}/ping || exit 1`
|
|
369
454
|
],
|
|
370
455
|
interval: CLICKHOUSE_HEALTH_CHECK.INTERVAL_SECONDS,
|
|
371
456
|
timeout: CLICKHOUSE_HEALTH_CHECK.TIMEOUT_SECONDS,
|
|
@@ -390,6 +475,10 @@ export class ClickHouseDatabase extends Construct {
|
|
|
390
475
|
instanceRole.addManagedPolicy(ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore"));
|
|
391
476
|
backupBucket.grantRead(instanceRole, "config/*");
|
|
392
477
|
adminSecret.secret.grantRead(instanceRole);
|
|
478
|
+
if (tlsCaSecret !== undefined)
|
|
479
|
+
tlsCaSecret.grantRead(instanceRole);
|
|
480
|
+
if (tlsServerSecret !== undefined)
|
|
481
|
+
tlsServerSecret.grantRead(instanceRole);
|
|
393
482
|
const adminSecretName = clickHouseUserSecretName(schemaAdmin.name);
|
|
394
483
|
// Password via CLICKHOUSE_CLIENT_PASSWORD env, not --password on argv
|
|
395
484
|
// (argv → /proc/<pid>/cmdline). `jq -r .password` on an empty pipeline
|
|
@@ -404,7 +493,7 @@ export class ClickHouseDatabase extends Construct {
|
|
|
404
493
|
`ADMIN_PASSWORD=$(aws secretsmanager get-secret-value --secret-id "${adminSecretName}" --query SecretString --output text | jq -r .password)`,
|
|
405
494
|
`if [ -z "$ADMIN_PASSWORD" ] || [ "$ADMIN_PASSWORD" = "null" ]; then echo "fjall:reload:status=failed reason=password-fetch" >&2; exit 1; fi`,
|
|
406
495
|
`mv /var/lib/clickhouse/users.d/fjall.xml.new /var/lib/clickhouse/users.d/fjall.xml`,
|
|
407
|
-
`docker exec -i -e CLICKHOUSE_CLIENT_PASSWORD="$ADMIN_PASSWORD" "$CONTAINER" clickhouse-client --port
|
|
496
|
+
`docker exec -i -e CLICKHOUSE_CLIENT_PASSWORD="$ADMIN_PASSWORD" "$CONTAINER" clickhouse-client${tlsActive ? ` --config-file=${CLICKHOUSE_TLS_CERT_MOUNT_PATH}/client.xml --secure --host localhost` : ""} --port ${nativePort} --user ${schemaAdmin.name} -q "SYSTEM RELOAD USERS"`
|
|
408
497
|
].join("\n");
|
|
409
498
|
const region = Stack.of(this).region;
|
|
410
499
|
const account = Stack.of(this).account;
|
|
@@ -456,15 +545,21 @@ export class ClickHouseDatabase extends Construct {
|
|
|
456
545
|
reloadCustomResource.node.addDependency(usersConfigDeployment);
|
|
457
546
|
this.connections = new Connections({
|
|
458
547
|
securityGroups: [securityGroup],
|
|
459
|
-
defaultPort: Port.tcp(
|
|
548
|
+
defaultPort: Port.tcp(httpPort)
|
|
460
549
|
});
|
|
461
550
|
const declareOutput = (name, value) => {
|
|
462
551
|
const output = new CfnOutput(this, name, { value });
|
|
463
552
|
output.overrideLogicalId(name);
|
|
464
553
|
};
|
|
465
554
|
declareOutput("Endpoint", clickHouseHost);
|
|
466
|
-
declareOutput("HttpPort", String(
|
|
467
|
-
declareOutput("NativePort", String(
|
|
555
|
+
declareOutput("HttpPort", String(httpPort));
|
|
556
|
+
declareOutput("NativePort", String(nativePort));
|
|
557
|
+
if (tlsActive) {
|
|
558
|
+
declareOutput("TlsActive", "true");
|
|
559
|
+
}
|
|
560
|
+
if (caCertSha256 !== undefined) {
|
|
561
|
+
declareOutput("CaCertSha256", caCertSha256);
|
|
562
|
+
}
|
|
468
563
|
declareOutput("DatabaseName", CLICKHOUSE_DATABASE_NAME);
|
|
469
564
|
for (const [name, secret] of userSecrets) {
|
|
470
565
|
declareOutput(`${toPascalCase(name)}SecretArn`, secret.secret.secretArn);
|
|
@@ -497,19 +592,41 @@ export class ClickHouseDatabase extends Construct {
|
|
|
497
592
|
return this.#users.get(name);
|
|
498
593
|
}
|
|
499
594
|
getHttpPort() {
|
|
500
|
-
return
|
|
595
|
+
return this.#httpPort;
|
|
501
596
|
}
|
|
502
597
|
getNativePort() {
|
|
503
|
-
return
|
|
598
|
+
return this.#nativePort;
|
|
504
599
|
}
|
|
505
600
|
getHostEndpoint() {
|
|
506
601
|
return `${CLICKHOUSE_CLOUDMAP_SERVICE_NAME}.${App.getInstance().getNamespace().namespaceName}`;
|
|
507
602
|
}
|
|
508
|
-
|
|
509
|
-
|
|
603
|
+
/**
|
|
604
|
+
* Canonical URL for the HTTP(S) interface. Scheme is `https` when TLS is
|
|
605
|
+
* active (default), `http` only when `tls: { mode: "none", … }` is set.
|
|
606
|
+
* Port matches: HTTPS (8443) under TLS, HTTP (8123) otherwise.
|
|
607
|
+
*/
|
|
608
|
+
getUrl() {
|
|
609
|
+
const scheme = this.tlsCaSecret !== undefined ? "https" : "http";
|
|
610
|
+
return `${scheme}://${this.getHostEndpoint()}:${this.#httpPort}`;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* SecretImport for the CA certificate secret, or `undefined` when TLS is
|
|
614
|
+
* disabled (`tls: { mode: "none", … }`). Consumers wire this into their
|
|
615
|
+
* `secretsImport:` block under `CLICKHOUSE_CA_CERT` so `@fjall/clickhouse`
|
|
616
|
+
* `createFjallClickHouseClient()` picks it up from `process.env`. The secret
|
|
617
|
+
* holds raw PEM (no JSON field) so `field` is `undefined`.
|
|
618
|
+
*/
|
|
619
|
+
getTlsCaCertImport() {
|
|
620
|
+
if (this.tlsCaSecret === undefined)
|
|
621
|
+
return undefined;
|
|
622
|
+
return {
|
|
623
|
+
id: `${this.node.id}TlsCaCertImport`,
|
|
624
|
+
name: this.tlsCaSecret.secretName,
|
|
625
|
+
field: undefined
|
|
626
|
+
};
|
|
510
627
|
}
|
|
511
628
|
getNativeUrl() {
|
|
512
|
-
return `tcp://${this.getHostEndpoint()}:${this
|
|
629
|
+
return `tcp://${this.getHostEndpoint()}:${this.#nativePort}`;
|
|
513
630
|
}
|
|
514
631
|
getDatabaseName() {
|
|
515
632
|
return CLICKHOUSE_DATABASE_NAME;
|
|
@@ -561,12 +678,19 @@ export class ClickHouseDatabase extends Construct {
|
|
|
561
678
|
*/
|
|
562
679
|
getMigrationContributions() {
|
|
563
680
|
const environment = {
|
|
564
|
-
CLICKHOUSE_URL: this.
|
|
681
|
+
CLICKHOUSE_URL: this.getUrl(),
|
|
565
682
|
CLICKHOUSE_DATABASE: this.getDatabaseName()
|
|
566
683
|
};
|
|
567
684
|
const secretsImport = {};
|
|
568
685
|
const adminSecret = this.getUser(this.#schemaAdmin.name);
|
|
569
686
|
secretsImport.SCHEMA_ADMIN_PASSWORD = adminSecret.getImport("password");
|
|
687
|
+
const caCertImport = this.getTlsCaCertImport();
|
|
688
|
+
if (caCertImport !== undefined) {
|
|
689
|
+
secretsImport.CLICKHOUSE_CA_CERT = caCertImport;
|
|
690
|
+
}
|
|
691
|
+
if (this.caCertSha256 !== undefined) {
|
|
692
|
+
environment.CLICKHOUSE_CA_CERT_SHA256 = this.caCertSha256;
|
|
693
|
+
}
|
|
570
694
|
for (const name of this.#managedPasswordNames) {
|
|
571
695
|
const userSecret = this.getUser(name);
|
|
572
696
|
secretsImport[userPasswordEnvName(name)] =
|
|
@@ -606,7 +730,7 @@ export class ClickHouseDatabase extends Construct {
|
|
|
606
730
|
if (container === undefined) {
|
|
607
731
|
throw new Error("ClickHouseDatabase.connectFromTask: task has no default container");
|
|
608
732
|
}
|
|
609
|
-
container.addEnvironment("CLICKHOUSE_URL", this.
|
|
733
|
+
container.addEnvironment("CLICKHOUSE_URL", this.getUrl());
|
|
610
734
|
container.addEnvironment("CLICKHOUSE_DATABASE", CLICKHOUSE_DATABASE_NAME);
|
|
611
735
|
if (opts?.user !== undefined) {
|
|
612
736
|
const userSecret = this.getUser(opts.user);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./types.js";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
|
2
|
+
/**
|
|
3
|
+
* Self-signed mode (default). The construct mints an ECDSA P-256 CA + leaf
|
|
4
|
+
* cert at stack deploy via a custom-resource Lambda. Bumping
|
|
5
|
+
* `caValidityYears` / `leafValidityYears` triggers re-issuance on the next
|
|
6
|
+
* deploy.
|
|
7
|
+
*/
|
|
8
|
+
export interface ClickHouseSelfSignedTls {
|
|
9
|
+
readonly mode: "self-signed";
|
|
10
|
+
readonly caValidityYears?: number;
|
|
11
|
+
readonly leafValidityYears?: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Imported mode. Caller owns the CA + server-cert secrets in Secrets
|
|
15
|
+
* Manager. `serverCertSecret`'s SecretString MUST be JSON of the shape
|
|
16
|
+
* `{ "cert": "<pem>", "key": "<pem>" }`. `caCertSha256` is optional — when
|
|
17
|
+
* supplied the construct surfaces it as a CFN env-var token so consumers
|
|
18
|
+
* can wire it into containers for rotation-triggers-task-replacement
|
|
19
|
+
* parity with self-signed mode. Omit it and rotation requires manual task
|
|
20
|
+
* restart (documented in `aiDocs/patterns/clickhouse-tls-pattern.md § "Imported mode"`).
|
|
21
|
+
*/
|
|
22
|
+
export interface ClickHouseImportedTls {
|
|
23
|
+
readonly mode: "imported";
|
|
24
|
+
readonly caCertSecret: ISecret;
|
|
25
|
+
readonly serverCertSecret: ISecret;
|
|
26
|
+
readonly caCertSha256?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Plaintext escape hatch. Disables TLS entirely. The acknowledgement is a
|
|
30
|
+
* literal-string type so misuse fails at compile time — passing any other
|
|
31
|
+
* string fails `tsc --noEmit`.
|
|
32
|
+
*/
|
|
33
|
+
export interface ClickHouseNoTls {
|
|
34
|
+
readonly mode: "none";
|
|
35
|
+
readonly acknowledgement: "I understand plaintext-only ClickHouse fails SOC2 DP5";
|
|
36
|
+
}
|
|
37
|
+
export type ClickHouseTlsOptions = ClickHouseSelfSignedTls | ClickHouseImportedTls | ClickHouseNoTls;
|
|
38
|
+
/**
|
|
39
|
+
* The resolved TLS surface a `ClickHouseDatabase` carries after dispatch.
|
|
40
|
+
* Every field is `undefined` in `mode: "none"`. `certGeneratorFunction`
|
|
41
|
+
* is `undefined` in `mode: "imported"`. `caCertSha256` is `undefined` in
|
|
42
|
+
* `mode: "none"` AND in `mode: "imported"` unless the caller supplied it.
|
|
43
|
+
*/
|
|
44
|
+
export interface ClickHouseTlsResolved {
|
|
45
|
+
readonly caSecret: ISecret | undefined;
|
|
46
|
+
readonly serverSecret: ISecret | undefined;
|
|
47
|
+
readonly caCertSha256: string | undefined;
|
|
48
|
+
}
|
|
@@ -263,12 +263,14 @@ export interface IClickHouseDatabase extends IDatabase, IConnectable, IMigration
|
|
|
263
263
|
/** Native TCP port (typically 9000). */
|
|
264
264
|
getNativePort(): number;
|
|
265
265
|
/**
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
269
|
-
*
|
|
266
|
+
* Canonical URL for the HTTP(S) interface. Scheme is `https` when TLS is
|
|
267
|
+
* active (default), `http` only when `tls: { mode: "none", … }` is set.
|
|
268
|
+
* Port matches: HTTPS (8443) under TLS, HTTP (8123) otherwise. No
|
|
269
|
+
* credentials in the URL — ClickHouse HTTP uses Basic Auth headers or
|
|
270
|
+
* `X-ClickHouse-User`/`X-ClickHouse-Key` headers. Compose creds at
|
|
271
|
+
* runtime via `getUser(name).getImport(...)`.
|
|
270
272
|
*/
|
|
271
|
-
|
|
273
|
+
getUrl(): string;
|
|
272
274
|
/**
|
|
273
275
|
* Native TCP URL (`tcp://<host>:<nativePort>`).
|
|
274
276
|
* No credentials in the URL — the native protocol handshake carries them.
|
|
@@ -53,6 +53,27 @@ export declare const CLICKHOUSE_TASK_MEMORY_MIB = 3072;
|
|
|
53
53
|
export declare const CLICKHOUSE_HTTP_PORT = 8123;
|
|
54
54
|
export declare const CLICKHOUSE_NATIVE_PORT = 9000;
|
|
55
55
|
export declare const CLICKHOUSE_PROMETHEUS_PORT = 9363;
|
|
56
|
+
/** TLS-mode ClickHouse ports.
|
|
57
|
+
* HTTPS replaces 8123; secure native protocol replaces 9000.
|
|
58
|
+
* See aiDocs/patterns/clickhouse-tls-pattern.md § "The contract". */
|
|
59
|
+
export declare const CLICKHOUSE_HTTPS_PORT = 8443;
|
|
60
|
+
export declare const CLICKHOUSE_TCP_SECURE_PORT = 9440;
|
|
61
|
+
/** Mount path inside the main ClickHouse container for the materialised
|
|
62
|
+
* TLS cert + key. The init container writes to a shared task-scoped volume
|
|
63
|
+
* mounted here read-only on the main container. */
|
|
64
|
+
export declare const CLICKHOUSE_TLS_CERT_MOUNT_PATH = "/etc/clickhouse-server/certs";
|
|
65
|
+
/** Task-scoped Docker volume name shared between the TLS init container
|
|
66
|
+
* (writer) and the main ClickHouse container (reader). */
|
|
67
|
+
export declare const CLICKHOUSE_TLS_CERT_VOLUME_NAME = "tls-certs";
|
|
68
|
+
/** UID:GID the official ClickHouse image runs as. Init container `chown`s
|
|
69
|
+
* the materialised cert files to this UID so the server can read them. */
|
|
70
|
+
export declare const CLICKHOUSE_UID = 101;
|
|
71
|
+
/** Digest-pinned alpine image used by the TLS init container. The init
|
|
72
|
+
* container needs `jq` (extracts `cert`+`key` from the server-cert JSON
|
|
73
|
+
* secret); alpine ships it via `apk add` — but pinning the digest avoids
|
|
74
|
+
* fetching `:latest` on every deploy. Bump in lockstep with renovate
|
|
75
|
+
* alerts; CI verifies the digest resolves. */
|
|
76
|
+
export declare const ALPINE_INIT_CONTAINER_IMAGE = "public.ecr.aws/docker/library/alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d";
|
|
56
77
|
/** EBS device name for the data volume (must match user data script). */
|
|
57
78
|
export declare const CLICKHOUSE_EBS_DEVICE_NAME = "/dev/xvdf";
|
|
58
79
|
/** EBS mount path on the EC2 host. */
|
|
@@ -53,6 +53,27 @@ export const CLICKHOUSE_TASK_MEMORY_MIB = 3072;
|
|
|
53
53
|
export const CLICKHOUSE_HTTP_PORT = 8123;
|
|
54
54
|
export const CLICKHOUSE_NATIVE_PORT = 9000;
|
|
55
55
|
export const CLICKHOUSE_PROMETHEUS_PORT = 9363;
|
|
56
|
+
/** TLS-mode ClickHouse ports.
|
|
57
|
+
* HTTPS replaces 8123; secure native protocol replaces 9000.
|
|
58
|
+
* See aiDocs/patterns/clickhouse-tls-pattern.md § "The contract". */
|
|
59
|
+
export const CLICKHOUSE_HTTPS_PORT = 8443;
|
|
60
|
+
export const CLICKHOUSE_TCP_SECURE_PORT = 9440;
|
|
61
|
+
/** Mount path inside the main ClickHouse container for the materialised
|
|
62
|
+
* TLS cert + key. The init container writes to a shared task-scoped volume
|
|
63
|
+
* mounted here read-only on the main container. */
|
|
64
|
+
export const CLICKHOUSE_TLS_CERT_MOUNT_PATH = "/etc/clickhouse-server/certs";
|
|
65
|
+
/** Task-scoped Docker volume name shared between the TLS init container
|
|
66
|
+
* (writer) and the main ClickHouse container (reader). */
|
|
67
|
+
export const CLICKHOUSE_TLS_CERT_VOLUME_NAME = "tls-certs";
|
|
68
|
+
/** UID:GID the official ClickHouse image runs as. Init container `chown`s
|
|
69
|
+
* the materialised cert files to this UID so the server can read them. */
|
|
70
|
+
export const CLICKHOUSE_UID = 101;
|
|
71
|
+
/** Digest-pinned alpine image used by the TLS init container. The init
|
|
72
|
+
* container needs `jq` (extracts `cert`+`key` from the server-cert JSON
|
|
73
|
+
* secret); alpine ships it via `apk add` — but pinning the digest avoids
|
|
74
|
+
* fetching `:latest` on every deploy. Bump in lockstep with renovate
|
|
75
|
+
* alerts; CI verifies the digest resolves. */
|
|
76
|
+
export const ALPINE_INIT_CONTAINER_IMAGE = "public.ecr.aws/docker/library/alpine:3.20@sha256:beefdbd8a1da6d2915566fde36db9db0b524eb737fc57cd1367effd16dc0d06d";
|
|
56
77
|
/** EBS device name for the data volume (must match user data script). */
|
|
57
78
|
export const CLICKHOUSE_EBS_DEVICE_NAME = "/dev/xvdf";
|
|
58
79
|
/** EBS mount path on the EC2 host. */
|
|
@@ -10,5 +10,7 @@ import { SecurityGroup } from "../networking/securityGroup.js";
|
|
|
10
10
|
*
|
|
11
11
|
* Self-referencing native-port ingress is kept so the optimise/backup
|
|
12
12
|
* scheduled tasks (which share this SG) can reach the ClickHouse server.
|
|
13
|
+
* Under TLS modes, the secure native port (9440) is the self-referencing
|
|
14
|
+
* port; under `mode: "none"` the plaintext native port stays.
|
|
13
15
|
*/
|
|
14
16
|
export declare function createClickHouseSecurityGroup(scope: Construct, vpc: IVpc, nativePort: number): SecurityGroup;
|
|
@@ -9,6 +9,8 @@ import { SecurityGroup } from "../networking/securityGroup.js";
|
|
|
9
9
|
*
|
|
10
10
|
* Self-referencing native-port ingress is kept so the optimise/backup
|
|
11
11
|
* scheduled tasks (which share this SG) can reach the ClickHouse server.
|
|
12
|
+
* Under TLS modes, the secure native port (9440) is the self-referencing
|
|
13
|
+
* port; under `mode: "none"` the plaintext native port stays.
|
|
12
14
|
*/
|
|
13
15
|
export function createClickHouseSecurityGroup(scope, vpc, nativePort) {
|
|
14
16
|
const sg = new SecurityGroup(scope, "ClickHouseSecurityGroup", {
|
|
@@ -19,6 +19,27 @@ export interface BuildClickHouseUserDataOptions {
|
|
|
19
19
|
bucketName: string;
|
|
20
20
|
region: string;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* When true, the server config emits `<https_port>`, `<tcp_port_secure>`,
|
|
24
|
+
* and an `<openSSL><server>` block referencing the cert files materialised
|
|
25
|
+
* at `CLICKHOUSE_TLS_CERT_MOUNT_PATH` by the user-data bootstrap step.
|
|
26
|
+
* Plaintext `<http_port>` is omitted to avoid mixed-protocol exposure.
|
|
27
|
+
* Default: false. When true, `caSecretArn` and `serverSecretArn` MUST be
|
|
28
|
+
* supplied so the bootstrap step can materialise the cert PEMs.
|
|
29
|
+
*/
|
|
30
|
+
tlsActive?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Secrets Manager ARN holding the CA cert as raw PEM. Required when
|
|
33
|
+
* `tlsActive` is true. Fetched at instance boot via the EC2 instance role
|
|
34
|
+
* and written to `${dataMount}/server-certs/ca.crt`.
|
|
35
|
+
*/
|
|
36
|
+
caSecretArn?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Secrets Manager ARN holding the server cert + key as JSON
|
|
39
|
+
* `{ "cert": "<pem>", "key": "<pem>" }`. Required when `tlsActive` is true.
|
|
40
|
+
* Fetched at instance boot and written to `${dataMount}/server-certs/server.{crt,key}`.
|
|
41
|
+
*/
|
|
42
|
+
serverSecretArn?: string;
|
|
22
43
|
}
|
|
23
44
|
export declare function generateServerConfigXml(options: BuildClickHouseUserDataOptions): string;
|
|
24
45
|
export interface GenerateUsersConfigXmlOptions {
|