Skip to content

Commit 863f14b

Browse files
authored
fix: use AWS RDS CA bundle for proper SSL verification, simplify client SSL config (#2432)
1 parent 98213f8 commit 863f14b

7 files changed

Lines changed: 17 additions & 116 deletions

File tree

apps/api/Dockerfile.multistage

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,11 @@ RUN groupadd --system nestjs && useradd --system --gid nestjs --create-home nest
8383
WORKDIR /app
8484
RUN chown nestjs:nestjs /app
8585

86-
# Install runtime dependencies
87-
RUN apt-get update && apt-get install -y --no-install-recommends wget && rm -rf /var/lib/apt/lists/*
86+
# Install runtime dependencies + AWS RDS CA certificate bundle
87+
RUN apt-get update && apt-get install -y --no-install-recommends wget && rm -rf /var/lib/apt/lists/* \
88+
&& wget -q -O /usr/local/share/aws-rds-ca-bundle.pem https://truststore.pki.rds.amazonaws.com/global/global-bundle.pem
89+
90+
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/aws-rds-ca-bundle.pem
8891

8992
# Copy built NestJS app
9093
COPY --from=builder --chown=nestjs:nestjs /app/apps/api/dist ./dist

apps/api/prisma/client.ts

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,47 +3,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
33

44
const globalForPrisma = global as unknown as { prisma: PrismaClient };
55

6-
/**
7-
* Derive pg SSL config from the DATABASE_URL.
8-
*
9-
* pg@8+ defaults rejectUnauthorized to true, which rejects AWS RDS Proxy's
10-
* certificate (signed by internal AWS CA, not in Node.js root CA store).
11-
*
12-
* Per PostgreSQL sslmode spec:
13-
* - disable: no SSL
14-
* - require: encrypt, skip certificate verification
15-
* - verify-ca: encrypt + verify CA
16-
* - verify-full: encrypt + verify CA + hostname
17-
*
18-
* When no sslmode is set, we default to SSL with rejectUnauthorized: false
19-
* for non-localhost connections (matches Prisma v6 behavior where the Rust
20-
* engine silently accepted all certificates).
21-
*/
22-
function getSslConfig(url: string): boolean | { rejectUnauthorized: boolean } | undefined {
23-
const sslmodeMatch = url.match(/sslmode=(\w[\w-]*)/);
24-
25-
if (sslmodeMatch) {
26-
switch (sslmodeMatch[1]) {
27-
case 'disable':
28-
return undefined;
29-
case 'require':
30-
case 'no-verify':
31-
return { rejectUnauthorized: false };
32-
case 'verify-ca':
33-
case 'verify-full':
34-
return { rejectUnauthorized: true };
35-
}
36-
}
37-
38-
// No sslmode specified — enable SSL for non-localhost (production default)
39-
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
40-
return isLocalhost ? undefined : { rejectUnauthorized: false };
41-
}
42-
436
function createPrismaClient(): PrismaClient {
447
const url = process.env.DATABASE_URL!;
45-
const ssl = getSslConfig(url);
46-
const adapter = new PrismaPg({ connectionString: url, ssl });
8+
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
9+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
4710
return new PrismaClient({ adapter });
4811
}
4912

apps/app/prisma/client.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
33

44
const globalForPrisma = global as unknown as { prisma: PrismaClient };
55

6-
function getSslConfig(url: string): boolean | { rejectUnauthorized: boolean } | undefined {
7-
const sslmodeMatch = url.match(/sslmode=(\w[\w-]*)/);
8-
if (sslmodeMatch) {
9-
switch (sslmodeMatch[1]) {
10-
case 'disable': return undefined;
11-
case 'require': case 'no-verify': return { rejectUnauthorized: false };
12-
case 'verify-ca': case 'verify-full': return { rejectUnauthorized: true };
13-
}
14-
}
15-
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
16-
return isLocalhost ? undefined : { rejectUnauthorized: false };
17-
}
18-
196
function createPrismaClient(): PrismaClient {
207
const url = process.env.DATABASE_URL!;
21-
const ssl = getSslConfig(url);
22-
const adapter = new PrismaPg({ connectionString: url, ssl });
8+
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
9+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
2310
return new PrismaClient({ adapter });
2411
}
2512

apps/framework-editor/prisma/client.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
33

44
const globalForPrisma = global as unknown as { prisma: PrismaClient };
55

6-
function getSslConfig(url: string): boolean | { rejectUnauthorized: boolean } | undefined {
7-
const sslmodeMatch = url.match(/sslmode=(\w[\w-]*)/);
8-
if (sslmodeMatch) {
9-
switch (sslmodeMatch[1]) {
10-
case 'disable': return undefined;
11-
case 'require': case 'no-verify': return { rejectUnauthorized: false };
12-
case 'verify-ca': case 'verify-full': return { rejectUnauthorized: true };
13-
}
14-
}
15-
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
16-
return isLocalhost ? undefined : { rejectUnauthorized: false };
17-
}
18-
196
function createPrismaClient(): PrismaClient {
207
const url = process.env.DATABASE_URL!;
21-
const ssl = getSslConfig(url);
22-
const adapter = new PrismaPg({ connectionString: url, ssl });
8+
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
9+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
2310
return new PrismaClient({ adapter });
2411
}
2512

apps/portal/prisma/client.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
33

44
const globalForPrisma = global as unknown as { prisma: PrismaClient };
55

6-
function getSslConfig(url: string): boolean | { rejectUnauthorized: boolean } | undefined {
7-
const sslmodeMatch = url.match(/sslmode=(\w[\w-]*)/);
8-
if (sslmodeMatch) {
9-
switch (sslmodeMatch[1]) {
10-
case 'disable': return undefined;
11-
case 'require': case 'no-verify': return { rejectUnauthorized: false };
12-
case 'verify-ca': case 'verify-full': return { rejectUnauthorized: true };
13-
}
14-
}
15-
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
16-
return isLocalhost ? undefined : { rejectUnauthorized: false };
17-
}
18-
196
function createPrismaClient(): PrismaClient {
207
const url = process.env.DATABASE_URL!;
21-
const ssl = getSslConfig(url);
22-
const adapter = new PrismaPg({ connectionString: url, ssl });
8+
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
9+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
2310
return new PrismaClient({ adapter });
2411
}
2512

packages/db/scripts/combine-schemas.js

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -54,23 +54,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
5454
5555
const globalForPrisma = global as unknown as { prisma: PrismaClient };
5656
57-
function getSslConfig(url: string) {
58-
const sslmodeMatch = url.match(/sslmode=(\\w[\\w-]*)/);
59-
if (sslmodeMatch) {
60-
switch (sslmodeMatch[1]) {
61-
case 'disable': return undefined;
62-
case 'require': case 'no-verify': return { rejectUnauthorized: false };
63-
case 'verify-ca': case 'verify-full': return { rejectUnauthorized: true };
64-
}
65-
}
66-
const isLocalhost = /localhost|127\\.0\\.0\\.1|::1/.test(url);
67-
return isLocalhost ? undefined : { rejectUnauthorized: false };
68-
}
69-
7057
function createPrismaClient(): PrismaClient {
7158
const url = process.env.DATABASE_URL!;
72-
const ssl = getSslConfig(url);
73-
const adapter = new PrismaPg({ connectionString: url, ssl });
59+
const isLocalhost = /localhost|127\\.0\\.0\\.1|::1/.test(url);
60+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
7461
return new PrismaClient({ adapter });
7562
}
7663

packages/db/src/client.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,10 @@ import { PrismaPg } from '@prisma/adapter-pg';
33

44
const globalForPrisma = global as unknown as { prisma: PrismaClient };
55

6-
function getSslConfig(url: string): boolean | { rejectUnauthorized: boolean } | undefined {
7-
const sslmodeMatch = url.match(/sslmode=(\w[\w-]*)/);
8-
if (sslmodeMatch) {
9-
switch (sslmodeMatch[1]) {
10-
case 'disable': return undefined;
11-
case 'require': case 'no-verify': return { rejectUnauthorized: false };
12-
case 'verify-ca': case 'verify-full': return { rejectUnauthorized: true };
13-
}
14-
}
15-
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
16-
return isLocalhost ? undefined : { rejectUnauthorized: false };
17-
}
18-
196
function createPrismaClient(): PrismaClient {
207
const url = process.env.DATABASE_URL!;
21-
const ssl = getSslConfig(url);
22-
const adapter = new PrismaPg({ connectionString: url, ssl });
8+
const isLocalhost = /localhost|127\.0\.0\.1|::1/.test(url);
9+
const adapter = new PrismaPg({ connectionString: url, ssl: isLocalhost ? undefined : true });
2310
return new PrismaClient({ adapter });
2411
}
2512

0 commit comments

Comments
 (0)