Skip to content

Commit 3514106

Browse files
committed
feat: allow setting ssl root cert
1 parent 7e7d114 commit 3514106

File tree

9 files changed

+922
-690
lines changed

9 files changed

+922
-690
lines changed

package-lock.json

+717-671
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+10-9
Original file line numberDiff line numberDiff line change
@@ -56,28 +56,29 @@
5656
]
5757
},
5858
"dependencies": {
59-
"@sinclair/typebox": "^0.25.1",
60-
"pg": "^8.7.1",
61-
"pg-format": "^1.0.4",
62-
"pgsql-parser": "^13.3.0",
63-
"postgres-array": "^3.0.1",
64-
"prettier": "^2.6.0",
65-
"prettier-plugin-sql": "^0.13.0",
66-
"pino": "^8.6.1",
6759
"@fastify/cors": "^8.2.0",
6860
"@fastify/swagger": "^8.2.1",
6961
"@fastify/type-provider-typebox": "^2.4.0",
62+
"@sinclair/typebox": "^0.25.1",
7063
"crypto-js": "^4.0.0",
7164
"fastify": "^4.8.1",
7265
"fastify-metrics": "^10.0.0",
73-
"pg-connection-string": "^2.5.0"
66+
"pg": "^8.7.1",
67+
"pg-connection-string": "^2.5.0",
68+
"pg-format": "^1.0.4",
69+
"pgsql-parser": "^13.3.0",
70+
"pino": "^8.6.1",
71+
"postgres-array": "^3.0.1",
72+
"prettier": "^2.6.0",
73+
"prettier-plugin-sql": "^0.13.0"
7474
},
7575
"devDependencies": {
7676
"@types/crypto-js": "^4.1.1",
7777
"@types/jest": "^29.2.4",
7878
"@types/node": "^16.18.3",
7979
"@types/pg": "^8.6.5",
8080
"@types/pg-format": "^1.0.1",
81+
"@types/prettier": "^2.7.3",
8182
"cpy-cli": "^4.1.0",
8283
"jest": "^29.3.1",
8384
"nodemon": "^2.0.20",

src/server/constants.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,27 @@ export const CRYPTO_KEY = (await getSecret('CRYPTO_KEY')) || 'SAMPLE_KEY'
77
const PG_META_DB_HOST = process.env.PG_META_DB_HOST || 'localhost'
88
const PG_META_DB_NAME = process.env.PG_META_DB_NAME || 'postgres'
99
const PG_META_DB_USER = process.env.PG_META_DB_USER || 'postgres'
10-
const PG_META_DB_PORT = Number(process.env.PG_META_DB_PORT) || 5432
10+
const PG_META_DB_PORT = process.env.PG_META_DB_PORT || '5432'
1111
const PG_META_DB_PASSWORD = (await getSecret('PG_META_DB_PASSWORD')) || 'postgres'
1212
const PG_META_DB_SSL_MODE = process.env.PG_META_DB_SSL_MODE || 'disable'
13+
const PG_META_DB_SSL_ROOT_CERT_PATH = process.env.PG_META_DB_SSL_ROOT_CERT_PATH
1314

1415
const PG_CONN_TIMEOUT_SECS = Number(process.env.PG_CONN_TIMEOUT_SECS || 15)
1516

16-
export const PG_CONNECTION =
17-
process.env.PG_META_DB_URL ||
18-
`postgres://${PG_META_DB_USER}:${encodeURIComponent(
19-
PG_META_DB_PASSWORD
20-
)}@${PG_META_DB_HOST}:${PG_META_DB_PORT}/${PG_META_DB_NAME}?sslmode=${PG_META_DB_SSL_MODE}`
17+
export let PG_CONNECTION = process.env.PG_META_DB_URL
18+
if (!PG_CONNECTION) {
19+
const pgConn = new URL('postgresql://')
20+
pgConn.hostname = PG_META_DB_HOST
21+
pgConn.port = PG_META_DB_PORT
22+
pgConn.username = PG_META_DB_USER
23+
pgConn.password = PG_META_DB_PASSWORD
24+
pgConn.pathname = encodeURIComponent(PG_META_DB_NAME)
25+
pgConn.searchParams.set('sslmode', PG_META_DB_SSL_MODE)
26+
if (PG_META_DB_SSL_ROOT_CERT_PATH) {
27+
pgConn.searchParams.set('sslrootcert', PG_META_DB_SSL_ROOT_CERT_PATH)
28+
}
29+
PG_CONNECTION = `${pgConn}`
30+
}
2131

2232
export const EXPORT_DOCS = process.argv[2] === 'docs' && process.argv[3] === 'export'
2333
export const GENERATE_TYPES =

test/db/Dockerfile

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
FROM supabase/postgres:14.1.0
2+
3+
COPY --chown=postgres:postgres --chmod=600 server.key server.crt /var/lib/postgresql/

test/db/docker-compose.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
services:
22
db:
3-
image: supabase/postgres:14.1.0
3+
build: .
44
ports:
55
- 5432:5432
66
volumes:
7-
- .:/docker-entrypoint-initdb.d
8-
environment:
7+
- .:/docker-entrypoint-initdb.d
8+
environment:
99
POSTGRES_PASSWORD: postgres
10-
command: postgres -c config_file=/etc/postgresql/postgresql.conf
10+
command: postgres -c config_file=/etc/postgresql/postgresql.conf -c ssl=on -c ssl_cert_file=/var/lib/postgresql/server.crt -c ssl_key_file=/var/lib/postgresql/server.key

test/db/server.crt

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
Certificate:
2+
Data:
3+
Version: 3 (0x2)
4+
Serial Number:
5+
41:a3:0e:d5:2f:07:82:95:c1:cc:c8:62:02:04:eb:7b:25:dc:3e:6b
6+
Signature Algorithm: sha256WithRSAEncryption
7+
Issuer: CN = localhost
8+
Validity
9+
Not Before: Aug 2 10:31:43 2023 GMT
10+
Not After : Jul 30 10:31:43 2033 GMT
11+
Subject: CN = localhost
12+
Subject Public Key Info:
13+
Public Key Algorithm: rsaEncryption
14+
Public-Key: (2048 bit)
15+
Modulus:
16+
00:d6:4a:ec:0d:40:a8:b1:cd:e8:e9:16:41:a9:6b:
17+
ed:7f:c4:ee:4e:b6:4e:83:5a:7c:37:81:8c:fd:90:
18+
07:da:57:d3:1b:91:2f:77:6d:a1:b0:38:48:08:03:
19+
1f:77:91:6a:91:39:54:06:87:20:33:c2:d9:20:e4:
20+
06:15:f9:59:fb:0e:db:2e:a0:81:c0:6c:47:f6:bc:
21+
00:0f:07:9a:36:a8:4c:c3:62:97:51:31:53:53:51:
22+
2a:d6:ff:ca:e6:cf:b2:8e:d7:89:ae:2b:a4:15:ed:
23+
7c:35:8e:5b:26:84:b1:4d:13:7a:3e:32:a3:56:53:
24+
c1:e8:98:f2:4a:03:56:53:2e:db:c7:96:7e:d2:df:
25+
ea:e5:d7:c2:35:93:61:0d:af:0c:c0:2e:b4:b2:a2:
26+
b1:5a:8b:38:fa:e6:1c:c7:1e:20:d8:0e:b2:97:f2:
27+
82:6b:4a:1f:27:8c:c1:e4:63:df:42:9a:e3:6c:46:
28+
74:46:fb:f5:0e:12:d4:b9:12:ce:dc:22:dd:f0:5c:
29+
6e:e3:31:4f:1a:fa:de:31:15:ec:2a:9b:6c:ea:67:
30+
bf:67:f7:13:44:ba:01:4a:dd:76:32:a8:59:82:13:
31+
81:f2:48:6d:f4:5d:f0:70:a1:7b:f0:be:46:3e:65:
32+
36:ee:f3:2e:39:00:52:2a:00:f3:d3:83:c9:55:56:
33+
dd:93
34+
Exponent: 65537 (0x10001)
35+
X509v3 extensions:
36+
X509v3 Subject Key Identifier:
37+
79:57:F3:18:B8:6B:FB:64:39:B0:E8:CC:24:18:ED:C0:C1:37:E2:0D
38+
X509v3 Authority Key Identifier:
39+
79:57:F3:18:B8:6B:FB:64:39:B0:E8:CC:24:18:ED:C0:C1:37:E2:0D
40+
X509v3 Basic Constraints: critical
41+
CA:TRUE
42+
Signature Algorithm: sha256WithRSAEncryption
43+
Signature Value:
44+
2b:d1:37:75:b5:92:9a:c9:ed:45:a6:46:ac:97:93:b9:bf:c0:
45+
f3:7f:47:c3:bd:fd:bd:6b:58:ad:49:79:9d:31:18:3c:b9:94:
46+
4b:aa:ca:49:c9:04:c4:71:1f:62:9b:ce:3f:5a:24:ec:82:68:
47+
a7:74:45:dd:b1:02:8a:f0:f2:4f:7f:3d:28:94:b0:5b:47:51:
48+
f3:12:a5:ce:1b:32:9f:f8:c6:6a:61:c6:99:4c:f6:99:9e:44:
49+
e4:e9:01:0c:45:1c:a4:5f:f3:69:2e:3d:a7:5d:62:ab:fb:e4:
50+
ea:d2:56:0f:56:df:00:5d:fa:9e:62:2a:77:00:cd:cd:b4:d8:
51+
b6:47:4b:84:73:85:3e:eb:4c:3e:2b:67:46:84:b1:22:1a:04:
52+
47:02:ca:a0:74:a5:97:28:89:56:aa:c6:4a:ce:97:9b:14:14:
53+
96:d7:26:60:38:fd:ec:ae:7d:ea:47:68:16:1c:ee:47:19:10:
54+
69:6a:25:67:71:ac:0b:f0:4a:b0:b3:e6:9b:5f:89:e8:e7:64:
55+
f7:92:37:0c:72:8c:d0:32:c5:10:79:c1:2e:22:05:65:50:db:
56+
d8:0e:bf:b6:d9:f1:7b:88:82:0e:be:06:9b:8c:96:e2:53:03:
57+
1f:de:86:39:d8:7e:4b:48:bb:11:d9:5d:41:68:82:49:e4:2b:
58+
33:79:1b:78
59+
-----BEGIN CERTIFICATE-----
60+
MIIDCTCCAfGgAwIBAgIUQaMO1S8HgpXBzMhiAgTreyXcPmswDQYJKoZIhvcNAQEL
61+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDgwMjEwMzE0M1oXDTMzMDcz
62+
MDEwMzE0M1owFDESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEF
63+
AAOCAQ8AMIIBCgKCAQEA1krsDUCosc3o6RZBqWvtf8TuTrZOg1p8N4GM/ZAH2lfT
64+
G5Evd22hsDhICAMfd5FqkTlUBocgM8LZIOQGFflZ+w7bLqCBwGxH9rwADweaNqhM
65+
w2KXUTFTU1Eq1v/K5s+yjteJriukFe18NY5bJoSxTRN6PjKjVlPB6JjySgNWUy7b
66+
x5Z+0t/q5dfCNZNhDa8MwC60sqKxWos4+uYcxx4g2A6yl/KCa0ofJ4zB5GPfQprj
67+
bEZ0Rvv1DhLUuRLO3CLd8Fxu4zFPGvreMRXsKpts6me/Z/cTRLoBSt12MqhZghOB
68+
8kht9F3wcKF78L5GPmU27vMuOQBSKgDz04PJVVbdkwIDAQABo1MwUTAdBgNVHQ4E
69+
FgQUeVfzGLhr+2Q5sOjMJBjtwME34g0wHwYDVR0jBBgwFoAUeVfzGLhr+2Q5sOjM
70+
JBjtwME34g0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAK9E3
71+
dbWSmsntRaZGrJeTub/A839Hw739vWtYrUl5nTEYPLmUS6rKSckExHEfYpvOP1ok
72+
7IJop3RF3bECivDyT389KJSwW0dR8xKlzhsyn/jGamHGmUz2mZ5E5OkBDEUcpF/z
73+
aS49p11iq/vk6tJWD1bfAF36nmIqdwDNzbTYtkdLhHOFPutMPitnRoSxIhoERwLK
74+
oHSllyiJVqrGSs6XmxQUltcmYDj97K596kdoFhzuRxkQaWolZ3GsC/BKsLPmm1+J
75+
6Odk95I3DHKM0DLFEHnBLiIFZVDb2A6/ttnxe4iCDr4Gm4yW4lMDH96GOdh+S0i7
76+
EdldQWiCSeQrM3kbeA==
77+
-----END CERTIFICATE-----

test/db/server.key

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDWSuwNQKixzejp
3+
FkGpa+1/xO5Otk6DWnw3gYz9kAfaV9MbkS93baGwOEgIAx93kWqROVQGhyAzwtkg
4+
5AYV+Vn7DtsuoIHAbEf2vAAPB5o2qEzDYpdRMVNTUSrW/8rmz7KO14muK6QV7Xw1
5+
jlsmhLFNE3o+MqNWU8HomPJKA1ZTLtvHln7S3+rl18I1k2ENrwzALrSyorFaizj6
6+
5hzHHiDYDrKX8oJrSh8njMHkY99CmuNsRnRG+/UOEtS5Es7cIt3wXG7jMU8a+t4x
7+
Fewqm2zqZ79n9xNEugFK3XYyqFmCE4HySG30XfBwoXvwvkY+ZTbu8y45AFIqAPPT
8+
g8lVVt2TAgMBAAECggEAHXE9I3OpzzF3pGbEGMSqZJlTFgoi7sCE5pTBy/4jsL0g
9+
/92fxEHngDBgvTETUWNFCApKCtI6phdJq8+IgoZi9YU3Wh2qwMcKetJJE8eQnvKF
10+
XCb0nAQx6vWbnt9AKnGI7+qZ5mM6moSplyt68eeIpgqyC0+mdMWck8TygnbDlTlP
11+
W+lfAZoCnrPDe6ptKTKtSy3AdGteAKk0pdaiUPHjtMdtOMwXCcHQkKopVIstfAib
12+
mvg2/3djn5OnYBmhOINIAZvNSoVr/s9I/yZc8V3z2/lPoLDRmEjCgIGba4zkG0Sr
13+
oaHdxJz8eTuSPwI+jcjto3gPkBdL2658l4JLxXYgQQKBgQD+VWv+jJsB01ijZsI9
14+
cV1aS6bqyb5sJEc1EFOZtkUYEr0RB6ww4FrRY7uryMPjXf+y47RvGsev0GvWkpRZ
15+
ijzGmfeqHMm9y+hjVxJ64nNOvxzpuVWG0s3JOBDnVY/4RmnW1qghlAI0QkwU7EHl
16+
O4ql3QS5PQEzudhNpQltDHmL4QKBgQDXsleHOzf32HCFR3EWAy+rosuiianGu3LI
17+
2toAX0NxCSkNCPHksfcEryoyrgKLCSzNoBtQMQkvk9sgbQfRLPZi3Lcng+wzjBEv
18+
4uR/a2xdOwnCMCYc9KMjnVukhf5WZ+hJBc49lCqJtc4Mhl89icgrXxUG8YwqUqNK
19+
qb9YMCH38wKBgE3JOnpj7pSkWxu+tfGs1mxjbu2oPkE85zpnf+onQQKX2JN40UUx
20+
mRUpd6CWirLjcOz5j5nbiu9Ow2yg8BZinSvwszqoC1utHaokW1aSI8oV0XX6ZRoT
21+
JzU/nIvkM2AvyPcYN9vtNK9fB33utEiz6TfJXUR6T//N+0XkD/n2MsaBAoGBALDY
22+
A3NYVhbaWcasQEdv7VGnc5WbkJrjbMTIyhur/ztZ61JIlyqNzp0EkHBkwqkDqLwe
23+
HMaurX1YmDwJqHMTjh6YH4JCYxIQMLc2K2lcxcfac7HGkDkFSgwVI+HMCi8Fmijk
24+
nadXJ1koufsC4Gsv3/HPTwoWWHkKr96zNbI0JGWJAoGAFFw+fjx4gI+VDayf4NMd
25+
feIpDF6O2uB9uKbTyNJjYoj9Jh0NkSHccgVb+j5BvnxBmAJHrMEr6Cz3bnlKlK0a
26+
1+Oqyq8MaYRLk6J/xMGSUcfa3uRC5svq0s8ebbl84Kt23IW9NU+YycVnMzysMLsH
27+
xn4VooZdfd3oNm2lpYURz3I=
28+
-----END PRIVATE KEY-----

test/index.test.ts

+1
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ import './server/column-privileges'
2020
import './server/materialized-views'
2121
import './server/table-privileges'
2222
import './server/typegen'
23+
import './server/ssl'

test/server/ssl.ts

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import CryptoJS from 'crypto-js'
2+
import path from 'path'
3+
import { fileURLToPath } from 'url'
4+
import { app } from './utils'
5+
import { CRYPTO_KEY } from '../../src/server/constants'
6+
7+
// @ts-ignore: Harmless type error on import.meta.
8+
const cwd = path.dirname(fileURLToPath(import.meta.url))
9+
const SSL_ROOT_CERT_PATH = path.join(cwd, '../db/server.crt')
10+
11+
test('query with no ssl', async () => {
12+
const res = await app.inject({
13+
method: 'POST',
14+
path: '/query',
15+
headers: {
16+
'x-connection-encrypted': CryptoJS.AES.encrypt(
17+
'postgresql://postgres:postgres@localhost:5432/postgres',
18+
CRYPTO_KEY
19+
).toString(),
20+
},
21+
payload: { query: 'select 1;' },
22+
})
23+
expect(res.json()).toMatchInlineSnapshot(`
24+
[
25+
{
26+
"?column?": 1,
27+
},
28+
]
29+
`)
30+
})
31+
32+
test('query with ssl w/o root cert', async () => {
33+
const res = await app.inject({
34+
method: 'POST',
35+
path: '/query',
36+
headers: {
37+
'x-connection-encrypted': CryptoJS.AES.encrypt(
38+
'postgresql://postgres:postgres@localhost:5432/postgres?sslmode=verify-full',
39+
CRYPTO_KEY
40+
).toString(),
41+
},
42+
payload: { query: 'select 1;' },
43+
})
44+
expect(res.json()?.error).toMatch(/^self[ -]signed certificate$/)
45+
})
46+
47+
test('query with ssl with root cert', async () => {
48+
const res = await app.inject({
49+
method: 'POST',
50+
path: '/query',
51+
headers: {
52+
'x-connection-encrypted': CryptoJS.AES.encrypt(
53+
`postgresql://postgres:postgres@localhost:5432/postgres?sslmode=verify-full&sslrootcert=${SSL_ROOT_CERT_PATH}`,
54+
CRYPTO_KEY
55+
).toString(),
56+
},
57+
payload: { query: 'select 1;' },
58+
})
59+
expect(res.json()).toMatchInlineSnapshot(`
60+
[
61+
{
62+
"?column?": 1,
63+
},
64+
]
65+
`)
66+
})

0 commit comments

Comments
 (0)