@caelo-cms/provisioning 0.11.9 → 0.11.10
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/admin-domain.d.ts +10 -1
- package/dist/admin-domain.d.ts.map +1 -1
- package/dist/admin-domain.js +13 -3
- package/dist/admin-domain.js.map +1 -1
- package/dist/adopt-existing.d.ts +6 -1
- package/dist/adopt-existing.d.ts.map +1 -1
- package/dist/adopt-existing.js +86 -0
- package/dist/adopt-existing.js.map +1 -1
- package/dist/agent/command.d.ts +20 -0
- package/dist/agent/command.d.ts.map +1 -1
- package/dist/agent/command.js +32 -9
- package/dist/agent/command.js.map +1 -1
- package/dist/agent/run.d.ts +2 -0
- package/dist/agent/run.d.ts.map +1 -1
- package/dist/agent/run.js +5 -1
- package/dist/agent/run.js.map +1 -1
- package/dist/agent-db.js +44 -2
- package/dist/aws-task-roles.d.ts +4 -2
- package/dist/aws-task-roles.d.ts.map +1 -1
- package/dist/aws-task-roles.js +4 -1
- package/dist/aws-task-roles.js.map +1 -1
- package/dist/caddy.d.ts +21 -4
- package/dist/caddy.d.ts.map +1 -1
- package/dist/caddy.js +27 -3
- package/dist/caddy.js.map +1 -1
- package/dist/cli.js +12 -3
- package/dist/cli.js.map +1 -1
- package/dist/cloudsql-tls.d.ts +63 -0
- package/dist/cloudsql-tls.d.ts.map +1 -0
- package/dist/cloudsql-tls.js +289 -0
- package/dist/cloudsql-tls.js.map +1 -0
- package/dist/compose.d.ts +29 -6
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +95 -23
- package/dist/compose.js.map +1 -1
- package/dist/converge-checkpoint.d.ts +1 -0
- package/dist/converge-checkpoint.d.ts.map +1 -1
- package/dist/converge-checkpoint.js +8 -1
- package/dist/converge-checkpoint.js.map +1 -1
- package/dist/converge-job-gcp.d.ts.map +1 -1
- package/dist/converge-job-gcp.js +2 -11
- package/dist/converge-job-gcp.js.map +1 -1
- package/dist/deployed-release.d.ts +4 -1
- package/dist/deployed-release.d.ts.map +1 -1
- package/dist/deployed-release.js +18 -8
- package/dist/deployed-release.js.map +1 -1
- package/dist/gcp-names.d.ts +21 -0
- package/dist/gcp-names.d.ts.map +1 -1
- package/dist/gcp-names.js +24 -0
- package/dist/gcp-names.js.map +1 -1
- package/dist/gcp-url-map.d.ts.map +1 -1
- package/dist/gcp-url-map.js +6 -2
- package/dist/gcp-url-map.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infra-contract.d.ts +1 -1
- package/dist/infra-contract.d.ts.map +1 -1
- package/dist/infra-contract.js +24 -1
- package/dist/infra-contract.js.map +1 -1
- package/dist/install-state.d.ts +6 -0
- package/dist/install-state.d.ts.map +1 -1
- package/dist/install-state.js +17 -4
- package/dist/install-state.js.map +1 -1
- package/dist/lifecycle.d.ts.map +1 -1
- package/dist/lifecycle.js +17 -8
- package/dist/lifecycle.js.map +1 -1
- package/dist/mcp-auth-proxy-setup.d.ts +48 -0
- package/dist/mcp-auth-proxy-setup.d.ts.map +1 -0
- package/dist/mcp-auth-proxy-setup.js +280 -0
- package/dist/mcp-auth-proxy-setup.js.map +1 -0
- package/dist/release-manifest.d.ts +25 -1
- package/dist/release-manifest.d.ts.map +1 -1
- package/dist/release-manifest.js +36 -3
- package/dist/release-manifest.js.map +1 -1
- package/dist/remote-mcp.d.ts +55 -18
- package/dist/remote-mcp.d.ts.map +1 -1
- package/dist/remote-mcp.js +307 -77
- package/dist/remote-mcp.js.map +1 -1
- package/dist/runtime-secrets.d.ts +9 -0
- package/dist/runtime-secrets.d.ts.map +1 -1
- package/dist/runtime-secrets.js +21 -10
- package/dist/runtime-secrets.js.map +1 -1
- package/dist/seal-key-rotation.d.ts +7 -7
- package/dist/seal-key-rotation.d.ts.map +1 -1
- package/dist/seal-key-rotation.js +22 -22
- package/dist/seal-key-rotation.js.map +1 -1
- package/dist/self-hosted-db-tls.d.ts +37 -0
- package/dist/self-hosted-db-tls.d.ts.map +1 -0
- package/dist/self-hosted-db-tls.js +220 -0
- package/dist/self-hosted-db-tls.js.map +1 -0
- package/dist/self-hosted-release.d.ts +3 -1
- package/dist/self-hosted-release.d.ts.map +1 -1
- package/dist/self-hosted-release.js +33 -9
- package/dist/self-hosted-release.js.map +1 -1
- package/dist/self-hosted-roles.d.ts +34 -0
- package/dist/self-hosted-roles.d.ts.map +1 -1
- package/dist/self-hosted-roles.js +52 -0
- package/dist/self-hosted-roles.js.map +1 -1
- package/dist/self-hosted-start.d.ts +0 -21
- package/dist/self-hosted-start.d.ts.map +1 -1
- package/dist/self-hosted-start.js +39 -1
- package/dist/self-hosted-start.js.map +1 -1
- package/dist/self-hosted-upgrade.d.ts +15 -6
- package/dist/self-hosted-upgrade.d.ts.map +1 -1
- package/dist/self-hosted-upgrade.js +72 -23
- package/dist/self-hosted-upgrade.js.map +1 -1
- package/dist/stack-contract.d.ts +170 -25
- package/dist/stack-contract.d.ts.map +1 -1
- package/dist/stack-contract.js +314 -37
- package/dist/stack-contract.js.map +1 -1
- package/dist/stack-converge.d.ts +31 -0
- package/dist/stack-converge.d.ts.map +1 -1
- package/dist/stack-converge.js +71 -30
- package/dist/stack-converge.js.map +1 -1
- package/dist/upgrade/app-roll.d.ts +25 -4
- package/dist/upgrade/app-roll.d.ts.map +1 -1
- package/dist/upgrade/app-roll.js +63 -17
- package/dist/upgrade/app-roll.js.map +1 -1
- package/dist/upgrade/converge.d.ts.map +1 -1
- package/dist/upgrade/converge.js +99 -12
- package/dist/upgrade/converge.js.map +1 -1
- package/dist/upgrade/health.d.ts +31 -7
- package/dist/upgrade/health.d.ts.map +1 -1
- package/dist/upgrade/health.js +41 -17
- package/dist/upgrade/health.js.map +1 -1
- package/dist/upgrade/image-forms.d.ts +1 -1
- package/dist/upgrade/image-forms.d.ts.map +1 -1
- package/dist/upgrade/image-forms.js +24 -7
- package/dist/upgrade/image-forms.js.map +1 -1
- package/dist/upgrade/release-images.d.ts +12 -3
- package/dist/upgrade/release-images.d.ts.map +1 -1
- package/dist/upgrade/release-images.js +13 -4
- package/dist/upgrade/release-images.js.map +1 -1
- package/dist/upgrade/upgrade.d.ts +13 -3
- package/dist/upgrade/upgrade.d.ts.map +1 -1
- package/dist/upgrade/upgrade.js +34 -2
- package/dist/upgrade/upgrade.js.map +1 -1
- package/dist/upgrader-gcp.d.ts +12 -0
- package/dist/upgrader-gcp.d.ts.map +1 -1
- package/dist/upgrader-gcp.js +49 -1
- package/dist/upgrader-gcp.js.map +1 -1
- package/dist/upgrader-iam-preflight.d.ts.map +1 -1
- package/dist/upgrader-iam-preflight.js +6 -1
- package/dist/upgrader-iam-preflight.js.map +1 -1
- package/dist/upgrader-job.d.ts +1 -1
- package/dist/upgrader-job.d.ts.map +1 -1
- package/dist/upgrader-job.js +20 -14
- package/dist/upgrader-job.js.map +1 -1
- package/dist/upgrader-records.d.ts +1 -1
- package/dist/upgrader-records.d.ts.map +1 -1
- package/dist/upgrader-records.js +26 -7
- package/dist/upgrader-records.js.map +1 -1
- package/dist/upgrader-setup.d.ts.map +1 -1
- package/dist/upgrader-setup.js +10 -5
- package/dist/upgrader-setup.js.map +1 -1
- package/dist/wizards/gcp-cost.d.ts.map +1 -1
- package/dist/wizards/gcp-cost.js +22 -7
- package/dist/wizards/gcp-cost.js.map +1 -1
- package/dist/wizards/gcp.d.ts.map +1 -1
- package/dist/wizards/gcp.js +43 -17
- package/dist/wizards/gcp.js.map +1 -1
- package/package.json +2 -2
- package/src/admin-domain.test.ts +9 -8
- package/src/admin-domain.ts +13 -3
- package/src/admin-memory.test.ts +1 -0
- package/src/adopt-existing.test.ts +39 -0
- package/src/adopt-existing.ts +83 -1
- package/src/agent/command.test.ts +49 -1
- package/src/agent/command.ts +36 -9
- package/src/agent/run.test.ts +19 -0
- package/src/agent/run.ts +11 -2
- package/src/aws-task-roles.ts +5 -2
- package/src/caddy-redirects.docker.test.ts +2 -0
- package/src/caddy-redirects.test.ts +3 -0
- package/src/caddy-validate.test.ts +7 -1
- package/src/caddy.test.ts +39 -1
- package/src/caddy.ts +36 -4
- package/src/checkpoint-secrets.test.ts +14 -6
- package/src/cli.ts +12 -1
- package/src/cloudsql-tls.test.ts +225 -0
- package/src/cloudsql-tls.ts +352 -0
- package/src/compose.ts +125 -24
- package/src/converge-checkpoint.ts +8 -1
- package/src/converge-job-gcp.ts +2 -11
- package/src/database-tls-builders.test.ts +55 -0
- package/src/deployed-release.test.ts +104 -40
- package/src/deployed-release.ts +30 -9
- package/src/gateway-env-isolation.test.ts +10 -5
- package/src/gcp-names.ts +31 -0
- package/src/gcp-url-map.test.ts +6 -8
- package/src/gcp-url-map.ts +6 -2
- package/src/index.test.ts +7 -1
- package/src/index.ts +1 -0
- package/src/infra-contract.test.ts +5 -3
- package/src/infra-contract.ts +24 -1
- package/src/install-state.ts +26 -4
- package/src/lifecycle.ts +20 -11
- package/src/mcp-auth-proxy-setup.test.ts +305 -0
- package/src/mcp-auth-proxy-setup.ts +374 -0
- package/src/mcp-iap-stacks.test.ts +1 -1
- package/src/media-volume.test.ts +1 -1
- package/src/operator-access-stacks.test.ts +1 -1
- package/src/operator-access.test.ts +5 -4
- package/src/pool-budget-stacks.test.ts +1 -1
- package/src/release-manifest.test.ts +25 -0
- package/src/release-manifest.ts +59 -4
- package/src/remote-mcp-stack-config.test.ts +19 -9
- package/src/remote-mcp.test.ts +252 -57
- package/src/remote-mcp.ts +336 -77
- package/src/runtime-secrets.test.ts +20 -7
- package/src/runtime-secrets.ts +50 -9
- package/src/seal-key-rotation.test.ts +2 -2
- package/src/seal-key-rotation.ts +25 -25
- package/src/self-hosted-compose.test.ts +108 -5
- package/src/self-hosted-db-tls.test.ts +111 -0
- package/src/self-hosted-db-tls.ts +287 -0
- package/src/self-hosted-release-resolve.test.ts +71 -0
- package/src/self-hosted-release.ts +41 -11
- package/src/self-hosted-roles.test.ts +54 -0
- package/src/self-hosted-roles.ts +58 -0
- package/src/self-hosted-start.test.ts +34 -2
- package/src/self-hosted-start.ts +20 -2
- package/src/self-hosted-upgrade.test.ts +103 -14
- package/src/self-hosted-upgrade.ts +115 -29
- package/src/stack-contract-parity.test.ts +79 -12
- package/src/stack-contract.test.ts +169 -29
- package/src/stack-contract.ts +362 -42
- package/src/stack-converge-secrets.test.ts +26 -13
- package/src/stack-converge.test.ts +199 -26
- package/src/stack-converge.ts +92 -30
- package/src/state-store.test.ts +2 -1
- package/src/upgrade/app-roll.ts +97 -19
- package/src/upgrade/converge.ts +120 -11
- package/src/upgrade/health.test.ts +63 -25
- package/src/upgrade/health.ts +54 -22
- package/src/upgrade/image-forms.test.ts +34 -0
- package/src/upgrade/image-forms.ts +23 -8
- package/src/upgrade/release-images.test.ts +5 -1
- package/src/upgrade/release-images.ts +22 -6
- package/src/upgrade/upgrade.test.ts +353 -44
- package/src/upgrade/upgrade.ts +55 -6
- package/src/upgrader-gcp.ts +65 -3
- package/src/upgrader-iam-preflight.test.ts +19 -0
- package/src/upgrader-iam-preflight.ts +6 -0
- package/src/upgrader-job.test.ts +101 -27
- package/src/upgrader-job.ts +27 -14
- package/src/upgrader-records.test.ts +97 -12
- package/src/upgrader-records.ts +28 -11
- package/src/upgrader-setup.test.ts +2 -0
- package/src/upgrader-setup.ts +10 -4
- package/src/wizards/gcp-cost.test.ts +50 -0
- package/src/wizards/gcp-cost.ts +24 -7
- package/src/wizards/gcp.ts +55 -14
- package/stacks/aws/index.ts +32 -14
- package/stacks/azure/index.ts +57 -18
- package/stacks/gcp/index.ts +83 -23
- package/stacks/gcp-firebase/index.ts +162 -33
- package/stacks/self-hosted/README.md +2 -1
- package/stacks/self-hosted/index.ts +11 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
2
|
+
/**
|
|
3
|
+
* #1338 (gateway hardening L6) — verify-full TLS between the self-hosted
|
|
4
|
+
* Compose services and their Postgres.
|
|
5
|
+
*
|
|
6
|
+
* The admin and the gateway reach Postgres over the Compose network as
|
|
7
|
+
* `postgres:5432`. With `sslmode=verify-full` they need a server
|
|
8
|
+
* certificate for exactly that host name, signed by a CA they trust. No
|
|
9
|
+
* public CA issues a certificate for `postgres`, so every install makes its
|
|
10
|
+
* own: an ECDSA P-256 CA, generated once and kept in `.caelo/postgres-tls/`
|
|
11
|
+
* (like the install's other secrets in `.caelo/`), and a server certificate
|
|
12
|
+
* it signs. The CA certificate is mounted read-only into the admin and the
|
|
13
|
+
* gateway at shared `SELF_HOSTED_CA_FILE`; the server key only into
|
|
14
|
+
* Postgres.
|
|
15
|
+
*
|
|
16
|
+
* Generated with `node:crypto` and a minimal DER encoder below, so an
|
|
17
|
+
* install needs neither openssl on the host nor a new dependency (§3).
|
|
18
|
+
* Postgres reads ECDSA keys; Bun's TLS verifies the chain and the host.
|
|
19
|
+
*
|
|
20
|
+
* Re-runs keep what exists (the CA never changes once made, so no client
|
|
21
|
+
* ever needs a new trust anchor); a server certificate that is missing,
|
|
22
|
+
* does not chain to the CA, does not name `postgres`, or expires within a
|
|
23
|
+
* year is re-issued from the stored CA key.
|
|
24
|
+
*/
|
|
25
|
+
import { createHash, createPrivateKey, generateKeyPairSync, randomBytes, sign, X509Certificate, } from "node:crypto";
|
|
26
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
27
|
+
import { join } from "node:path";
|
|
28
|
+
/** The directory under `.caelo/` that holds the install's database TLS files. */
|
|
29
|
+
export const SELF_HOSTED_TLS_DIR = "postgres-tls";
|
|
30
|
+
/** The host name the services dial Postgres by on the Compose network. */
|
|
31
|
+
export const SELF_HOSTED_DB_HOST = "postgres";
|
|
32
|
+
/** File names inside {@link SELF_HOSTED_TLS_DIR}. */
|
|
33
|
+
export const SELF_HOSTED_TLS_FILES = {
|
|
34
|
+
caCert: "ca.crt",
|
|
35
|
+
caKey: "ca.key",
|
|
36
|
+
serverCert: "server.crt",
|
|
37
|
+
serverKey: "server.key",
|
|
38
|
+
};
|
|
39
|
+
const YEAR_MS = 365 * 24 * 3600 * 1000;
|
|
40
|
+
const CA_VALIDITY_YEARS = 30;
|
|
41
|
+
const SERVER_VALIDITY_YEARS = 10;
|
|
42
|
+
/** A server certificate closer than this to its end is re-issued. */
|
|
43
|
+
const RENEW_BEFORE_MS = YEAR_MS;
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Minimal DER (X.690) — only what an X.509 v3 certificate needs.
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
function derLength(n) {
|
|
48
|
+
if (n < 0x80)
|
|
49
|
+
return Buffer.from([n]);
|
|
50
|
+
const bytes = [];
|
|
51
|
+
for (let v = n; v > 0; v = Math.floor(v / 256))
|
|
52
|
+
bytes.unshift(v & 0xff);
|
|
53
|
+
return Buffer.from([0x80 | bytes.length, ...bytes]);
|
|
54
|
+
}
|
|
55
|
+
function tlv(tag, value) {
|
|
56
|
+
return Buffer.concat([Buffer.from([tag]), derLength(value.length), value]);
|
|
57
|
+
}
|
|
58
|
+
const seq = (...items) => tlv(0x30, Buffer.concat(items));
|
|
59
|
+
const set = (...items) => tlv(0x31, Buffer.concat(items));
|
|
60
|
+
const explicit = (n, inner) => tlv(0xa0 + n, inner);
|
|
61
|
+
const octets = (b) => tlv(0x04, b);
|
|
62
|
+
/** A BIT STRING; `unused` trailing bits of the last byte (DER: minimal for named bits). */
|
|
63
|
+
const bitString = (b, unused = 0) => tlv(0x03, Buffer.concat([Buffer.from([unused]), b]));
|
|
64
|
+
const utf8 = (s) => tlv(0x0c, Buffer.from(s, "utf8"));
|
|
65
|
+
const bool = (v) => tlv(0x01, Buffer.from([v ? 0xff : 0]));
|
|
66
|
+
function integer(b) {
|
|
67
|
+
let v = b;
|
|
68
|
+
while (v.length > 1 && v[0] === 0 && (v[1] ?? 0) < 0x80)
|
|
69
|
+
v = v.subarray(1);
|
|
70
|
+
if ((v[0] ?? 0) >= 0x80)
|
|
71
|
+
v = Buffer.concat([Buffer.from([0]), v]);
|
|
72
|
+
return tlv(0x02, v);
|
|
73
|
+
}
|
|
74
|
+
function oid(dotted) {
|
|
75
|
+
const parts = dotted.split(".").map(Number);
|
|
76
|
+
const out = [40 * (parts[0] ?? 0) + (parts[1] ?? 0)];
|
|
77
|
+
for (const p of parts.slice(2)) {
|
|
78
|
+
const chunk = [p & 0x7f];
|
|
79
|
+
for (let v = Math.floor(p / 128); v > 0; v = Math.floor(v / 128))
|
|
80
|
+
chunk.unshift(0x80 | (v & 0x7f));
|
|
81
|
+
out.push(...chunk);
|
|
82
|
+
}
|
|
83
|
+
return tlv(0x06, Buffer.from(out));
|
|
84
|
+
}
|
|
85
|
+
/** UTCTime until 2049, GeneralizedTime from 2050 (RFC 5280 §4.1.2.5). */
|
|
86
|
+
function time(d) {
|
|
87
|
+
const iso = d.toISOString().replace(/[-:T]/g, "").slice(0, 14);
|
|
88
|
+
return d.getUTCFullYear() < 2050
|
|
89
|
+
? tlv(0x17, Buffer.from(`${iso.slice(2)}Z`))
|
|
90
|
+
: tlv(0x18, Buffer.from(`${iso}Z`));
|
|
91
|
+
}
|
|
92
|
+
const ECDSA_SHA256 = seq(oid("1.2.840.10045.4.3.2"));
|
|
93
|
+
const name = (cn) => seq(set(seq(oid("2.5.4.3"), utf8(cn))));
|
|
94
|
+
const extension = (id, critical, value) => seq(oid(id), ...(critical ? [bool(true)] : []), octets(value));
|
|
95
|
+
function certificatePem(spec) {
|
|
96
|
+
const spki = spec.publicKey.export({ type: "spki", format: "der" });
|
|
97
|
+
const exts = [
|
|
98
|
+
extension("2.5.29.19", true, spec.ca ? seq(bool(true)) : seq()),
|
|
99
|
+
// keyCertSign + cRLSign for the CA; digitalSignature for the server.
|
|
100
|
+
extension("2.5.29.15", true, spec.ca ? bitString(Buffer.from([0x06]), 1) : bitString(Buffer.from([0x80]), 7)),
|
|
101
|
+
...(spec.ca
|
|
102
|
+
? []
|
|
103
|
+
: [
|
|
104
|
+
extension("2.5.29.37", false, seq(oid("1.3.6.1.5.5.7.3.1"))),
|
|
105
|
+
extension("2.5.29.17", false, seq(...(spec.dnsNames ?? []).map((n) => tlv(0x82, Buffer.from(n, "ascii"))))),
|
|
106
|
+
]),
|
|
107
|
+
];
|
|
108
|
+
const tbs = seq(explicit(0, integer(Buffer.from([2]))), integer(Buffer.concat([Buffer.from([0x01]), randomBytes(15)])), ECDSA_SHA256, name(spec.issuer), seq(time(spec.notBefore), time(spec.notAfter)), name(spec.subject), spki, explicit(3, seq(...exts)));
|
|
109
|
+
const signature = sign("sha256", tbs, { key: spec.signingKey, dsaEncoding: "der" });
|
|
110
|
+
const der = seq(tbs, ECDSA_SHA256, bitString(signature));
|
|
111
|
+
const b64 = der.toString("base64").replace(/.{64}/g, "$&\n").replace(/\n$/, "");
|
|
112
|
+
return `-----BEGIN CERTIFICATE-----\n${b64}\n-----END CERTIFICATE-----\n`;
|
|
113
|
+
}
|
|
114
|
+
function newKeyPair() {
|
|
115
|
+
return generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
116
|
+
}
|
|
117
|
+
/** A server certificate for {@link SELF_HOSTED_DB_HOST}, signed by the CA. */
|
|
118
|
+
function issueServer(ca, now) {
|
|
119
|
+
const server = newKeyPair();
|
|
120
|
+
const caSubject = new X509Certificate(ca.cert).subject.replace(/^CN=/, "");
|
|
121
|
+
return {
|
|
122
|
+
serverCert: certificatePem({
|
|
123
|
+
subject: SELF_HOSTED_DB_HOST,
|
|
124
|
+
issuer: caSubject,
|
|
125
|
+
publicKey: server.publicKey,
|
|
126
|
+
signingKey: ca.key,
|
|
127
|
+
notBefore: new Date(now.getTime() - 3600 * 1000),
|
|
128
|
+
notAfter: new Date(now.getTime() + SERVER_VALIDITY_YEARS * YEAR_MS),
|
|
129
|
+
ca: false,
|
|
130
|
+
dnsNames: [SELF_HOSTED_DB_HOST],
|
|
131
|
+
}),
|
|
132
|
+
serverKey: server.privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/** A fresh CA and a server certificate it signed. */
|
|
136
|
+
export function generateDatabaseTls(now = new Date()) {
|
|
137
|
+
const ca = newKeyPair();
|
|
138
|
+
const caCert = certificatePem({
|
|
139
|
+
subject: "Caelo self-hosted database CA",
|
|
140
|
+
issuer: "Caelo self-hosted database CA",
|
|
141
|
+
publicKey: ca.publicKey,
|
|
142
|
+
signingKey: ca.privateKey,
|
|
143
|
+
notBefore: new Date(now.getTime() - 3600 * 1000),
|
|
144
|
+
notAfter: new Date(now.getTime() + CA_VALIDITY_YEARS * YEAR_MS),
|
|
145
|
+
ca: true,
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
caCert,
|
|
149
|
+
caKey: ca.privateKey.export({ type: "pkcs8", format: "pem" }).toString(),
|
|
150
|
+
...issueServer({ cert: caCert, key: ca.privateKey }, now),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Why `serverCert` must be re-issued, or null when it is fine. */
|
|
154
|
+
export function serverCertProblem(caCert, serverCert, now) {
|
|
155
|
+
try {
|
|
156
|
+
const ca = new X509Certificate(caCert);
|
|
157
|
+
const server = new X509Certificate(serverCert);
|
|
158
|
+
if (!server.verify(ca.publicKey))
|
|
159
|
+
return "it is not signed by the install's CA";
|
|
160
|
+
if (server.checkHost(SELF_HOSTED_DB_HOST) !== SELF_HOSTED_DB_HOST) {
|
|
161
|
+
return `it does not name ${SELF_HOSTED_DB_HOST}`;
|
|
162
|
+
}
|
|
163
|
+
if (Date.parse(server.validTo) - now.getTime() < RENEW_BEFORE_MS) {
|
|
164
|
+
return `it expires ${server.validTo}`;
|
|
165
|
+
}
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
catch (e) {
|
|
169
|
+
return `it does not parse (${e instanceof Error ? e.message : String(e)})`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Make sure `<caeloDir>/postgres-tls/` holds the install's CA and a valid
|
|
174
|
+
* server certificate; returns what it did (empty when nothing changed).
|
|
175
|
+
* The CA is created once and never replaced.
|
|
176
|
+
*/
|
|
177
|
+
export function ensureSelfHostedDbTls(caeloDir, now = new Date()) {
|
|
178
|
+
const dir = join(caeloDir, SELF_HOSTED_TLS_DIR);
|
|
179
|
+
const path = (f) => join(dir, SELF_HOSTED_TLS_FILES[f]);
|
|
180
|
+
// The CA key and the server key are secrets; the certificates are not,
|
|
181
|
+
// but every container reads them through a bind mount, so 0644.
|
|
182
|
+
const write = (f, content) => writeFileSync(path(f), content, { mode: f.endsWith("Key") ? 0o600 : 0o644 });
|
|
183
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
184
|
+
const done = [];
|
|
185
|
+
if (!existsSync(path("caCert")) || !existsSync(path("caKey"))) {
|
|
186
|
+
if (existsSync(path("caCert")) !== existsSync(path("caKey"))) {
|
|
187
|
+
throw new Error(`${dir} holds only half of the database CA (${SELF_HOSTED_TLS_FILES.caCert} / ${SELF_HOSTED_TLS_FILES.caKey}). Restore the missing file from your backup of .caelo/, or delete both to make a new CA (every service is re-created with it on the next \`cms-provision up\`).`);
|
|
188
|
+
}
|
|
189
|
+
const files = generateDatabaseTls(now);
|
|
190
|
+
for (const f of Object.keys(SELF_HOSTED_TLS_FILES)) {
|
|
191
|
+
write(f, files[f]);
|
|
192
|
+
}
|
|
193
|
+
done.push(`created the install's database CA and the server certificate for ${SELF_HOSTED_DB_HOST}`);
|
|
194
|
+
return done;
|
|
195
|
+
}
|
|
196
|
+
const caCert = readFileSync(path("caCert"), "utf8");
|
|
197
|
+
const problem = existsSync(path("serverCert"))
|
|
198
|
+
? serverCertProblem(caCert, readFileSync(path("serverCert"), "utf8"), now)
|
|
199
|
+
: "it is missing";
|
|
200
|
+
if (problem === null && existsSync(path("serverKey")))
|
|
201
|
+
return done;
|
|
202
|
+
const key = createPrivateKey(readFileSync(path("caKey"), "utf8"));
|
|
203
|
+
const issued = issueServer({ cert: caCert, key }, now);
|
|
204
|
+
write("serverCert", issued.serverCert);
|
|
205
|
+
write("serverKey", issued.serverKey);
|
|
206
|
+
done.push(`re-issued the database server certificate (${problem ?? "its key was missing"})`);
|
|
207
|
+
return done;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* SHA-256 (hex) of the install's database server certificate, which the
|
|
211
|
+
* Compose file carries on the Postgres service so a renewed certificate
|
|
212
|
+
* recreates it (compose.ts `dbTlsServerCertSha256`).
|
|
213
|
+
*
|
|
214
|
+
* @throws when the certificate is missing: call {@link ensureSelfHostedDbTls} first.
|
|
215
|
+
*/
|
|
216
|
+
export function selfHostedDbTlsServerCertSha256(caeloDir) {
|
|
217
|
+
const cert = readFileSync(join(caeloDir, SELF_HOSTED_TLS_DIR, SELF_HOSTED_TLS_FILES.serverCert));
|
|
218
|
+
return createHash("sha256").update(cert).digest("hex");
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=self-hosted-db-tls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-hosted-db-tls.js","sourceRoot":"","sources":["../src/self-hosted-db-tls.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,8 @@ export interface SelfHostedRelease {
|
|
|
46
46
|
readonly images: {
|
|
47
47
|
readonly admin: string;
|
|
48
48
|
readonly gateway: string;
|
|
49
|
+
/** #1328 — absent in records of releases from before the MCP-Auth-Proxy. */
|
|
50
|
+
readonly "mcp-auth-proxy"?: string;
|
|
49
51
|
};
|
|
50
52
|
readonly installedAt: string;
|
|
51
53
|
/** Newest last; capped at {@link HISTORY_LIMIT}. */
|
|
@@ -78,7 +80,7 @@ export type VerifiedRelease = {
|
|
|
78
80
|
readonly error: string;
|
|
79
81
|
};
|
|
80
82
|
/**
|
|
81
|
-
* Resolve
|
|
83
|
+
* Resolve every release image of `tag` (RELEASE_SERVICES) in GHCR to digests,
|
|
82
84
|
* then cosign-verify each digest against the Caelo release workflow
|
|
83
85
|
* identity (unless `skipVerify`, the escape hatch for forks). The returned
|
|
84
86
|
* references are digest-pinned, so what was verified is exactly what runs.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-release.d.ts","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAiC,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"self-hosted-release.d.ts","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* `.caelo/release.json` is the install metadata for self-hosted (the cloud
|
|
7
7
|
* providers keep theirs in `~/.caelo-<id>/install.json`): the release
|
|
8
|
-
* version, the digest-pinned
|
|
9
|
-
*
|
|
8
|
+
* version, the digest-pinned image references the Compose file runs (admin,
|
|
9
|
+
* gateway, and since #1328 the MCP-Auth-Proxy), and a short history of installs/upgrades/rollbacks. It holds no
|
|
10
10
|
* secrets (config.json does), so it is safe to read from tooling and
|
|
11
11
|
* backups; writes refuse secret material like install.json's do.
|
|
12
12
|
*
|
|
@@ -52,7 +52,16 @@ export function releasePath(caeloDir) {
|
|
|
52
52
|
}
|
|
53
53
|
/** The images of a recorded release, as the Compose generator takes them. */
|
|
54
54
|
export function releaseImages(release) {
|
|
55
|
-
return { mode: "release",
|
|
55
|
+
return { mode: "release", ...release.images };
|
|
56
|
+
}
|
|
57
|
+
/** The image references of `images`, as release.json stores them. */
|
|
58
|
+
function recordedImages(images) {
|
|
59
|
+
const proxy = images["mcp-auth-proxy"];
|
|
60
|
+
return {
|
|
61
|
+
admin: images.admin,
|
|
62
|
+
gateway: images.gateway,
|
|
63
|
+
...(proxy !== undefined ? { "mcp-auth-proxy": proxy } : {}),
|
|
64
|
+
};
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
58
67
|
* The install's recorded release, or null when none is recorded (a dev-mode
|
|
@@ -66,14 +75,16 @@ export function readRelease(caeloDir) {
|
|
|
66
75
|
const raw = JSON.parse(readFileSync(path, "utf8"));
|
|
67
76
|
const admin = raw.images?.admin ?? "";
|
|
68
77
|
const gateway = raw.images?.gateway ?? "";
|
|
78
|
+
const proxy = raw.images?.["mcp-auth-proxy"];
|
|
69
79
|
if (typeof raw.version !== "string" ||
|
|
70
80
|
!ghcrImageDigest("admin", admin) ||
|
|
71
|
-
!ghcrImageDigest("gateway", gateway)
|
|
81
|
+
!ghcrImageDigest("gateway", gateway) ||
|
|
82
|
+
(proxy !== undefined && !ghcrImageDigest("mcp-auth-proxy", proxy))) {
|
|
72
83
|
throw new Error(`${path} is malformed (needs version + digest-pinned ghcr.io/caelo-cms images); fix it or re-run \`${selfCommand("upgrade", "--version", "<x.y.z>")}\`.`);
|
|
73
84
|
}
|
|
74
85
|
return {
|
|
75
86
|
version: raw.version,
|
|
76
|
-
images: { admin, gateway },
|
|
87
|
+
images: { admin, gateway, ...(proxy !== undefined ? { "mcp-auth-proxy": proxy } : {}) },
|
|
77
88
|
installedAt: raw.installedAt ?? "",
|
|
78
89
|
history: Array.isArray(raw.history) ? raw.history : [],
|
|
79
90
|
};
|
|
@@ -87,7 +98,7 @@ export function recordRelease(caeloDir, next, entry, now = new Date()) {
|
|
|
87
98
|
const at = now.toISOString();
|
|
88
99
|
const record = {
|
|
89
100
|
version: next.version,
|
|
90
|
-
images:
|
|
101
|
+
images: recordedImages(next.images),
|
|
91
102
|
installedAt: prior && prior.version === next.version && entry.outcome === "rolled-back"
|
|
92
103
|
? prior.installedAt
|
|
93
104
|
: at,
|
|
@@ -102,7 +113,7 @@ export function recordRollback(caeloDir, current, attempted, detail, now = new D
|
|
|
102
113
|
recordRelease(caeloDir, { version: current.version, images: releaseImages(current) }, { from: current.version, to: attempted, outcome: "rolled-back", detail }, now);
|
|
103
114
|
}
|
|
104
115
|
/**
|
|
105
|
-
* Resolve
|
|
116
|
+
* Resolve every release image of `tag` (RELEASE_SERVICES) in GHCR to digests,
|
|
106
117
|
* then cosign-verify each digest against the Caelo release workflow
|
|
107
118
|
* identity (unless `skipVerify`, the escape hatch for forks). The returned
|
|
108
119
|
* references are digest-pinned, so what was verified is exactly what runs.
|
|
@@ -112,6 +123,14 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
112
123
|
for (const service of RELEASE_SERVICES) {
|
|
113
124
|
deps.onProgress?.(`Resolving ${GHCR_REGISTRY}/${GHCR_NAMESPACE}/${service}:${tag}`);
|
|
114
125
|
const r = await resolveRegistryDigest(GHCR_REGISTRY, `${GHCR_NAMESPACE}/${service}`, tag, deps.fetchImpl);
|
|
126
|
+
if (!r.ok && r.notFound && service === "mcp-auth-proxy") {
|
|
127
|
+
// #1328 — releases from before the MCP-Auth-Proxy ship no image of it,
|
|
128
|
+
// and they stay installable and rollback targets: their Compose file
|
|
129
|
+
// simply has no proxy (ReleaseImages models the absence). Only a
|
|
130
|
+
// registry verdict that the tag does not exist means that; an outage
|
|
131
|
+
// still fails below, never silently installs a release without it.
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
115
134
|
if (!r.ok) {
|
|
116
135
|
return {
|
|
117
136
|
ok: false,
|
|
@@ -121,10 +140,12 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
121
140
|
}
|
|
122
141
|
refs[service] = ghcrImageRef(service, r.digest);
|
|
123
142
|
}
|
|
143
|
+
const proxy = refs["mcp-auth-proxy"];
|
|
124
144
|
const images = {
|
|
125
145
|
mode: "release",
|
|
126
146
|
admin: refs.admin ?? "",
|
|
127
147
|
gateway: refs.gateway ?? "",
|
|
148
|
+
...(proxy ? { "mcp-auth-proxy": proxy } : {}),
|
|
128
149
|
};
|
|
129
150
|
if (deps.skipVerify)
|
|
130
151
|
return { ok: true, images };
|
|
@@ -138,12 +159,15 @@ export async function resolveVerifiedRelease(tag, deps) {
|
|
|
138
159
|
};
|
|
139
160
|
}
|
|
140
161
|
for (const service of RELEASE_SERVICES) {
|
|
162
|
+
const ref = images[service];
|
|
163
|
+
if (ref === undefined)
|
|
164
|
+
continue;
|
|
141
165
|
deps.onProgress?.(`Verifying the signature of ${service}`);
|
|
142
|
-
const v = await deps.runner.run(cosignVerifyArgv(
|
|
166
|
+
const v = await deps.runner.run(cosignVerifyArgv(ref));
|
|
143
167
|
if (v.exitCode !== 0) {
|
|
144
168
|
return {
|
|
145
169
|
ok: false,
|
|
146
|
-
error: `cosign verify FAILED for ${
|
|
170
|
+
error: `cosign verify FAILED for ${ref}: its signature does not match the Caelo release workflow.\n` +
|
|
147
171
|
"Either the registry was compromised, the image is a fork's, or sigstore had an outage (retry).\n" +
|
|
148
172
|
`cosign: ${v.stderr.trim().slice(0, 500)}`,
|
|
149
173
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-release.js","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAEnC;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,YAAY,EAAsB,MAAM,cAAc,CAAC;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,gBAAgB,
|
|
1
|
+
{"version":3,"file":"self-hosted-release.js","sourceRoot":"","sources":["../src/self-hosted-release.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,31 @@ import type { RolePasswords } from "./compose.js";
|
|
|
24
24
|
* append events, write the heartbeat (0270) and its own audit rows.
|
|
25
25
|
*/
|
|
26
26
|
export declare const AGENT_DB_ROLE = "caelo_agent";
|
|
27
|
+
/**
|
|
28
|
+
* #1338 (gateway hardening H3) — what bounds public_role, the gateway's
|
|
29
|
+
* login, on the database: at most this many connections, no statement or
|
|
30
|
+
* idle transaction that runs away, little sort memory per query. The same
|
|
31
|
+
* values as packages/migrations/src/bootstrap.sh and the cms_admin
|
|
32
|
+
* migration that sets them where admin_role may (Cloud SQL); the role audit
|
|
33
|
+
* (packages/migrations role-audit.ts) refuses an install without them.
|
|
34
|
+
* Self-hosted admin_role has no CREATEROLE, so the superuser applies them
|
|
35
|
+
* here — on the volume's first start (bootstrap.sh), on every `up`, and
|
|
36
|
+
* before the migrations of every upgrade ({@link publicRoleLimitsScript}).
|
|
37
|
+
*/
|
|
38
|
+
export declare const PUBLIC_ROLE_LIMITS: {
|
|
39
|
+
readonly connectionLimit: 30;
|
|
40
|
+
readonly statementTimeout: "5s";
|
|
41
|
+
readonly idleInTransactionSessionTimeout: "15s";
|
|
42
|
+
readonly workMem: "1MB";
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* The psql script (superuser) that applies only {@link PUBLIC_ROLE_LIMITS}.
|
|
46
|
+
* The self-hosted upgrade runs it BEFORE the migrations: their role audit
|
|
47
|
+
* refuses public_role without the limits, and the full convergence must
|
|
48
|
+
* wait until after them (it drops roles a migration retired). Fails when
|
|
49
|
+
* public_role does not exist — the install's roles were never created.
|
|
50
|
+
*/
|
|
51
|
+
export declare function publicRoleLimitsScript(): string;
|
|
27
52
|
/**
|
|
28
53
|
* The psql script (run as the superuser, connected to any database) that
|
|
29
54
|
* brings roles and databases to the configured state.
|
|
@@ -47,6 +72,15 @@ export type SuperuserPsql = (script: string) => Promise<{
|
|
|
47
72
|
exitCode: number;
|
|
48
73
|
stderr: string;
|
|
49
74
|
}>;
|
|
75
|
+
/**
|
|
76
|
+
* Apply {@link publicRoleLimitsScript} through the running Postgres
|
|
77
|
+
* container. Unlike {@link convergeSelfHostedRoles} a stopped database is a
|
|
78
|
+
* failure: the upgrade runs it right before migrations that need it.
|
|
79
|
+
*/
|
|
80
|
+
export declare function applyPublicRoleLimits(deps: {
|
|
81
|
+
readonly probe: () => Promise<boolean>;
|
|
82
|
+
readonly psql: SuperuserPsql;
|
|
83
|
+
}): Promise<ConvergeOutcome>;
|
|
50
84
|
export type ConvergeOutcome = {
|
|
51
85
|
readonly ok: true;
|
|
52
86
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-roles.d.ts","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOlD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"self-hosted-roles.d.ts","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAOlD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAM3C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAaX;;;;;;GAMG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAkDD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAS9F;AASD;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAqBnF;AAED,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9F;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B,GAAG,OAAO,CAAC,eAAe,CAAC,CAO3B;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE;AACvB,+EAA+E;GAC7E;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,aAAa,EACxB,IAAI,EAAE;IACJ,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC,GACA,OAAO,CAAC,eAAe,CAAC,CAO1B;AAED,+DAA+D;AAC/D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACxF;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,UAAU,CAoBtF"}
|
|
@@ -12,6 +12,43 @@ function literal(s) {
|
|
|
12
12
|
export const AGENT_DB_ROLE = "caelo_agent";
|
|
13
13
|
/** The application roles bootstrap.sh and the convergence create. */
|
|
14
14
|
const APP_ROLES = ["admin_role", "public_role"];
|
|
15
|
+
/**
|
|
16
|
+
* #1338 (gateway hardening H3) — what bounds public_role, the gateway's
|
|
17
|
+
* login, on the database: at most this many connections, no statement or
|
|
18
|
+
* idle transaction that runs away, little sort memory per query. The same
|
|
19
|
+
* values as packages/migrations/src/bootstrap.sh and the cms_admin
|
|
20
|
+
* migration that sets them where admin_role may (Cloud SQL); the role audit
|
|
21
|
+
* (packages/migrations role-audit.ts) refuses an install without them.
|
|
22
|
+
* Self-hosted admin_role has no CREATEROLE, so the superuser applies them
|
|
23
|
+
* here — on the volume's first start (bootstrap.sh), on every `up`, and
|
|
24
|
+
* before the migrations of every upgrade ({@link publicRoleLimitsScript}).
|
|
25
|
+
*/
|
|
26
|
+
export const PUBLIC_ROLE_LIMITS = {
|
|
27
|
+
connectionLimit: 30,
|
|
28
|
+
statementTimeout: "5s",
|
|
29
|
+
idleInTransactionSessionTimeout: "15s",
|
|
30
|
+
workMem: "1MB",
|
|
31
|
+
};
|
|
32
|
+
/** The statements that apply {@link PUBLIC_ROLE_LIMITS} (idempotent). */
|
|
33
|
+
function publicRoleLimitsSql() {
|
|
34
|
+
const l = PUBLIC_ROLE_LIMITS;
|
|
35
|
+
return [
|
|
36
|
+
`ALTER ROLE public_role CONNECTION LIMIT ${l.connectionLimit};`,
|
|
37
|
+
`ALTER ROLE public_role SET statement_timeout = '${l.statementTimeout}';`,
|
|
38
|
+
`ALTER ROLE public_role SET idle_in_transaction_session_timeout = '${l.idleInTransactionSessionTimeout}';`,
|
|
39
|
+
`ALTER ROLE public_role SET work_mem = '${l.workMem}';`,
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The psql script (superuser) that applies only {@link PUBLIC_ROLE_LIMITS}.
|
|
44
|
+
* The self-hosted upgrade runs it BEFORE the migrations: their role audit
|
|
45
|
+
* refuses public_role without the limits, and the full convergence must
|
|
46
|
+
* wait until after them (it drops roles a migration retired). Fails when
|
|
47
|
+
* public_role does not exist — the install's roles were never created.
|
|
48
|
+
*/
|
|
49
|
+
export function publicRoleLimitsScript() {
|
|
50
|
+
return ["\\set ON_ERROR_STOP on", ...publicRoleLimitsSql(), ""].join("\n");
|
|
51
|
+
}
|
|
15
52
|
/**
|
|
16
53
|
* The convergence SQL (psql, as the superuser, connected to any database).
|
|
17
54
|
* `password` renders each role's password; `agent` adds the agent's login.
|
|
@@ -23,6 +60,7 @@ function convergenceSql(password, agent) {
|
|
|
23
60
|
`SELECT 'CREATE ROLE ${role} NOINHERIT LOGIN' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${role}') \\gexec`,
|
|
24
61
|
`ALTER ROLE ${role} WITH LOGIN PASSWORD ${password(role)};`,
|
|
25
62
|
]),
|
|
63
|
+
...publicRoleLimitsSql(),
|
|
26
64
|
// The upgrader's role (migration 0267 creates it only with CREATEROLE,
|
|
27
65
|
// which the self-hosted admin_role lacks).
|
|
28
66
|
"SELECT 'CREATE ROLE platform_updater NOLOGIN' WHERE NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'platform_updater') \\gexec",
|
|
@@ -104,6 +142,20 @@ ${variables}
|
|
|
104
142
|
${convergenceSql((role) => `:'${role}_pw'`, opts.agent)}CAELO_SQL
|
|
105
143
|
`;
|
|
106
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Apply {@link publicRoleLimitsScript} through the running Postgres
|
|
147
|
+
* container. Unlike {@link convergeSelfHostedRoles} a stopped database is a
|
|
148
|
+
* failure: the upgrade runs it right before migrations that need it.
|
|
149
|
+
*/
|
|
150
|
+
export async function applyPublicRoleLimits(deps) {
|
|
151
|
+
if (!(await deps.probe())) {
|
|
152
|
+
return { ok: false, reachable: false, error: "the Postgres container is not running" };
|
|
153
|
+
}
|
|
154
|
+
const r = await deps.psql(publicRoleLimitsScript());
|
|
155
|
+
if (r.exitCode === 0)
|
|
156
|
+
return { ok: true };
|
|
157
|
+
return { ok: false, reachable: true, error: r.stderr.trim() || `psql exited ${r.exitCode}` };
|
|
158
|
+
}
|
|
107
159
|
/**
|
|
108
160
|
* Apply {@link roleConvergenceScript}. `probe` says whether the database is
|
|
109
161
|
* up; when it is not, nothing is attempted and the caller decides whether
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-roles.js","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"AAAA,mCAAmC;AAuBnC,4BAA4B;AAC5B,SAAS,OAAO,CAAC,CAAS;IACxB,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAC;AAE3C,qEAAqE;AACrE,MAAM,SAAS,GAAG,CAAC,YAAY,EAAE,aAAa,CAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"self-hosted-roles.js","sourceRoot":"","sources":["../src/self-hosted-roles.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Start (or converge) a self-hosted Compose install — what `init` and `up`
|
|
3
|
-
* run after writing `.caelo/`, so one command ends with a serving install
|
|
4
|
-
* (CLAUDE.md §11.C, issue #707) instead of printing steps to copy.
|
|
5
|
-
*
|
|
6
|
-
* Order, and why:
|
|
7
|
-
* 1. pull every image, with the progress on the terminal (the admin image
|
|
8
|
-
* is large; a silent multi-minute step reads as a hang);
|
|
9
|
-
* 2. start Postgres and wait for its health check — on a fresh volume its
|
|
10
|
-
* first start runs bootstrap.sh (roles + databases);
|
|
11
|
-
* 3. apply the migrations with the install's admin image;
|
|
12
|
-
* 4. start everything (`--remove-orphans` drops services an older Compose
|
|
13
|
-
* file had, e.g. the pgBackRest sidecar);
|
|
14
|
-
* 5. health-check the admin (`/_caelo/health` proves the DB pool and its
|
|
15
|
-
* role) and the gateway;
|
|
16
|
-
* 6. reload Caddy — Compose does not restart a running Caddy when only
|
|
17
|
-
* its bind-mounted Caddyfile changed, so a re-run `up` would otherwise
|
|
18
|
-
* keep serving the old vhosts.
|
|
19
|
-
* Every step converges, so a re-run after a failure picks up where it
|
|
20
|
-
* stopped.
|
|
21
|
-
*/
|
|
22
1
|
import type { HostRunner } from "./self-hosted-release.js";
|
|
23
2
|
export interface StartDeps {
|
|
24
3
|
readonly caeloDir: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-hosted-start.d.ts","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"self-hosted-start.d.ts","sourceRoot":"","sources":["../src/self-hosted-start.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAI3D,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,QAAQ,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,oEAAoE;IACpE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,MAAM,WAAW,GACnB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAA;CAAE,GACrB;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/E,KAAK,UAAU,GAAG,MAAM,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEjF,sGAAsG;AACtG,wBAAsB,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC,CA+D3E;AAED,gFAAgF;AAChF,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBtD"}
|