fix: disable PostgreSQL TLS for refusing RDS endpoint
This commit is contained in:
@@ -39,13 +39,20 @@ assert(goApi.includes("name: zhinian-go-runtime"), "Go API must consume the Go r
|
||||
assert(goApi.includes("name: zhinian-go-auth"), "Go API must own the browser session signing Secret");
|
||||
assert(!goApi.includes("name: zhinian-web-auth"), "Go API must not reference the removed Web auth Secret");
|
||||
assert(goApi.includes("name: zhinian-go-bootstrap"), "Go API must receive bootstrap administrator credentials");
|
||||
assert(goApi.includes("secretName: zhinian-rds-ca"), "Go API must mount the optional RDS CA used by DATABASE_URL");
|
||||
assert(!goApi.includes("DATABASE_SSL_MODE"), "Go API must keep database TLS inside DATABASE_URL");
|
||||
assert(!goApi.includes("DATABASE_CA_CERT_PATH"), "Go API must keep database TLS inside DATABASE_URL");
|
||||
assert(!goApi.includes("rds-ca"), "Go API must not mount an RDS CA when PostgreSQL TLS is disabled");
|
||||
assert(!goApi.includes("/etc/zhinian/rds"), "Go API must not retain the removed RDS CA path");
|
||||
assert(!/\bTLS\b/i.test(goApi), "Go API manifest must not retain PostgreSQL TLS configuration");
|
||||
assert(!goApi.includes("DATABASE_SSL_MODE"), "Go API must not receive a separate database SSL mode");
|
||||
assert(!goApi.includes("DATABASE_CA_CERT_PATH"), "Go API must not receive a database CA path");
|
||||
|
||||
const secrets = read("secrets.example.yaml");
|
||||
assert(secrets.includes("name: zhinian-go-auth"), "Example secrets must name Go as the session Secret owner");
|
||||
assert(!secrets.includes("name: zhinian-web-auth"), "Example secrets must not retain the removed Web auth Secret");
|
||||
assert(!secrets.includes("zhinian-rds-ca"), "Example secrets must not define the removed RDS CA Secret");
|
||||
assert(!secrets.includes("sslrootcert"), "Example DATABASE_URL values must not reference an RDS CA");
|
||||
assert(!secrets.includes("verify-full"), "Example DATABASE_URL values must not request TLS");
|
||||
assert(!/\bTLS\b/i.test(secrets), "Example secrets must not retain PostgreSQL TLS configuration");
|
||||
assert((secrets.match(/sslmode=disable/g) ?? []).length === 2, "Migration and Go DATABASE_URL examples must disable TLS");
|
||||
|
||||
const namespace = read("namespace.yaml");
|
||||
assert(namespace.includes("kind: Namespace"), "namespace.yaml must define a Namespace");
|
||||
@@ -131,6 +138,9 @@ assert(
|
||||
deploymentDocs.includes("Pod 重建或滚动升级同样会永久丢失上传文件和生成结果"),
|
||||
"Deployment docs must disclose emptyDir data loss across Go Pod replacement",
|
||||
);
|
||||
assert(deploymentDocs.includes("不使用 TLS"), "Deployment docs must disclose plaintext PostgreSQL transport");
|
||||
assert(!deploymentDocs.includes("sslrootcert"), "Deployment docs must not instruct operators to mount an RDS CA");
|
||||
assert(!deploymentDocs.includes("verify-full"), "Deployment docs must not instruct operators to enable PostgreSQL TLS");
|
||||
|
||||
const gitIgnore = readRepository(".gitignore");
|
||||
assert(
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import pg from "pg";
|
||||
|
||||
const { Pool } = pg;
|
||||
@@ -14,8 +13,14 @@ export function createPostgresPool({ env = process.env, applicationName = "zhini
|
||||
if (!connectionString) throw new Error("DATABASE_URL is required when ZHINIAN_DATA_BACKEND=postgres");
|
||||
const parsed = assertConnectionStringContract(connectionString);
|
||||
|
||||
for (const key of [...parsed.searchParams.keys()]) {
|
||||
if (["sslmode", "sslrootcert"].includes(key.toLowerCase())) parsed.searchParams.delete(key);
|
||||
}
|
||||
parsed.searchParams.set("sslmode", "disable");
|
||||
|
||||
const config = {
|
||||
connectionString,
|
||||
connectionString: parsed.toString(),
|
||||
ssl: false,
|
||||
max: positiveInteger(env, "DATABASE_POOL_MAX", 10),
|
||||
idleTimeoutMillis: nonNegativeInteger(env, "DATABASE_IDLE_TIMEOUT_MS", 30_000),
|
||||
connectionTimeoutMillis: positiveInteger(env, "DATABASE_CONNECTION_TIMEOUT_MS", 10_000),
|
||||
@@ -23,21 +28,6 @@ export function createPostgresPool({ env = process.env, applicationName = "zhini
|
||||
application_name: applicationName
|
||||
};
|
||||
|
||||
const sslMode = parsed.searchParams.get("sslmode")?.trim().toLowerCase() || "verify-full";
|
||||
if (sslMode === "verify-full") {
|
||||
const caPath = parsed.searchParams.get("sslrootcert")?.trim();
|
||||
config.ssl = {
|
||||
...(caPath ? { ca: readFileSync(caPath, "utf8") } : {}),
|
||||
rejectUnauthorized: true
|
||||
};
|
||||
} else if (sslMode !== "disable") {
|
||||
throw new Error("DATABASE_URL sslmode must be 'disable' or 'verify-full'");
|
||||
}
|
||||
|
||||
parsed.searchParams.delete("sslmode");
|
||||
parsed.searchParams.delete("sslrootcert");
|
||||
config.connectionString = parsed.toString();
|
||||
|
||||
return new Pool(config);
|
||||
}
|
||||
|
||||
@@ -66,7 +56,7 @@ function assertConnectionStringContract(connectionString) {
|
||||
const unsupportedSSLParameters = sslParameters.filter((key) => !["sslmode", "sslrootcert"].includes(key.toLowerCase()));
|
||||
if (unsupportedSSLParameters.length > 0) {
|
||||
throw new Error(
|
||||
`DATABASE_URL contains unsupported SSL query parameters (${unsupportedSSLParameters.join(", ")}); use sslmode and optional sslrootcert`
|
||||
`DATABASE_URL contains unsupported SSL query parameters (${unsupportedSSLParameters.join(", ")}); PostgreSQL transport is forced to sslmode=disable`
|
||||
);
|
||||
}
|
||||
const sslMode = parsed.searchParams.get("sslmode")?.trim().toLowerCase();
|
||||
|
||||
Reference in New Issue
Block a user