Skip to content

Commit

Permalink
add the ability to configure sslrootcert, sslkey and sslrootcert (#653)
Browse files Browse the repository at this point in the history
* style: add missing line breaks

* feat: add the ability to configure sslrootcert, sslkey and sslrootcert (#652)

* feat: add the ability to configure sslrootcert, sslkey and sslrootcert (#652)

* style: apply eslint fixes

* chore: add cspell exceptions for ssl

* docs: add changeset

* docs: elaborate on supported dsn parameters

* docs: elaborate on supported dsn parameters

* fix: remove explicit default

* refactor: move test SSLs to a package

* lint

* test: add framework for testing ssl
  • Loading branch information
gajus authored Jan 3, 2025
1 parent 6e52354 commit 960bf89
Show file tree
Hide file tree
Showing 33 changed files with 1,582 additions and 593 deletions.
5 changes: 5 additions & 0 deletions .changeset/angry-buses-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"slonik": minor
---

add the ability to configure sslrootcert, sslkey and sslrootcert
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm run lint && npm run test && npm run build
npm run lint
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,10 @@ Supported parameters:
|---|---|---|
|`application_name`|[`application_name`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-APPLICATION-NAME)||
|`options`|[`options`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-OPTIONS)||
|`sslmode`|[`sslmode`](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) (supported values: `disable`, `no-verify`, `require`)|`disable`|
|`sslcert`|The location of the [certificate](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-CLIENTCERT).|-|
|`sslkey`|The location of the [certificate](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-CLIENTCERT).|-|
|`sslmode`|[`sslmode`](https://www.postgresql.org/docs/current/libpq-ssl.html#LIBPQ-SSL-PROTECTION) (supported values: `disable`, `no-verify`, `require`)|`disable`|
|`sslrootcert`|The location of the [root certificate]((https://www.postgresql.org/docs/current/libpq-ssl.html#LIBQ-SSL-CERTIFICATES)) file.||
Note that unless listed above, other [libpq parameters](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS) are not supported.
Expand Down Expand Up @@ -2591,6 +2594,8 @@ import {
parseDsn('postgresql://foo@localhost/bar?application_name=baz');
```
See [supported parameters](#connection-uri).
### <code>stringifyDsn</code>
```ts
Expand Down
4 changes: 3 additions & 1 deletion cspell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ words:
- kuizinas
- plpgsql
- roarr
- slonik
- slonik
- sslcert
- sslrootcert
1 change: 1 addition & 0 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
],
"ignoreDependencies": [
"@changesets/cli",
"@slonik/test-ssls",
"husky"
],
"project": [
Expand Down
2 changes: 1 addition & 1 deletion packages/driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@types/node": "^22.9.0",
"ava": "^6.1.3",
"cspell": "^8.16.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"nyc": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/errors/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@types/node": "^22.9.0",
"ava": "^6.1.3",
"cspell": "^8.16.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"nyc": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.6.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"dependencies": {
"eslint-config-canonical": "^44.3.28"
"eslint-config-canonical": "^44.3.33"
},
"main": "./index.cjs",
"name": "@slonik/eslint-config",
Expand Down
2 changes: 1 addition & 1 deletion packages/pg-driver/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@types/pg": "^8.11.10",
"ava": "^6.1.3",
"cspell": "^8.16.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"nyc": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/slonik-dataloaders/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"devDependencies": {
"@slonik/eslint-config": "workspace:^",
"@slonik/types": "^46.2.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"slonik": "^46.2.0",
"typescript": "^5.6.3",
"vitest": "^2.1.8"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"devDependencies": {
"@slonik/eslint-config": "workspace:^",
"ava": "^6.1.3",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"slonik": "^46.2.0",
"ts-node": "^10.4.0",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/slonik-interceptor-query-cache/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"devDependencies": {
"@slonik/eslint-config": "workspace:^",
"ava": "^6.1.3",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"slonik": "^46.2.0",
"ts-node": "^10.4.0",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/slonik-interceptor-query-logging/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"devDependencies": {
"@slonik/eslint-config": "workspace:^",
"ava": "^6.1.3",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"slonik": "^46.2.0",
"ts-node": "^10.4.0",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/slonik-sql-tag-raw/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"devDependencies": {
"@slonik/eslint-config": "workspace:^",
"ava": "^6.1.3",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"slonik": "^46.2.0",
"ts-node": "^10.4.0",
"typescript": "^5.6.3"
Expand Down
2 changes: 1 addition & 1 deletion packages/slonik/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"@types/sinon": "^10.0.20",
"ava": "^6.1.3",
"cspell": "^8.16.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"expect-type": "^0.15.0",
"get-port": "^5.1.1",
"nyc": "^15.1.0",
Expand Down
113 changes: 113 additions & 0 deletions packages/slonik/src/integration.test/ssl.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/* eslint-disable no-console */

import { createPool, sql } from '..';
import test from 'ava';
import getPort from 'get-port';
import { execSync, spawn } from 'node:child_process';
import { randomUUID } from 'node:crypto';
import { setTimeout } from 'node:timers/promises';

export const startTestContainer = async () => {
const dockerContainerName = `slonik-test-${randomUUID()}`;

const servicePort = await getPort();

const dockerArgs = [
'run',
'--name',
dockerContainerName,
'--rm',
'-e',
'POSTGRES_HOST_AUTH_METHOD=trust',
'-p',
servicePort + ':5432',
// see packages/test-ssls/README.md
'slonik-ssl-test',
'-N 1000',
];

const dockerProcess = spawn('docker', dockerArgs);

dockerProcess.on('error', (error) => {
console.error(error);
});

dockerProcess.stdout.on('data', (data) => {
console.log(data.toString());
});

dockerProcess.stderr.on('data', (data) => {
console.error(data.toString());
});

dockerProcess.on('exit', (code) => {
console.log(`Docker process exited with code ${code}`);
});

await new Promise((resolve) => {
dockerProcess.stdout.on('data', (data) => {
if (
data
.toString()
.includes('database system is ready to accept connections')
) {
resolve(undefined);
}
});
});

await setTimeout(1_000);

const terminate = () => {
execSync(`docker kill ${dockerContainerName}`);
};

return {
servicePort,
terminate,
};
};

test('makes a connection using SSL', async (t) => {
const { servicePort, terminate } = await startTestContainer();

try {
const searchParameters = new URLSearchParams();

// TODO figure out how to test sslmode=require
// We are now getting an error: SELF_SIGNED_CERT_IN_CHAIN
searchParameters.set('sslmode', 'no-verify');

searchParameters.set(
'sslrootcert',
require.resolve('@slonik/test-ssls/root.crt'),
);
searchParameters.set(
'sslcert',
require.resolve('@slonik/test-ssls/slonik.crt'),
);
searchParameters.set(
'sslkey',
require.resolve('@slonik/test-ssls/slonik.key'),
);

const pool = await createPool(
`postgresql://postgres@localhost:${servicePort}/postgres?${searchParameters}`,
);

const result = await pool.one(sql.unsafe`
SELECT ssl
FROM pg_stat_ssl
JOIN pg_stat_activity
ON pg_stat_ssl.pid = pg_stat_activity.pid;
`);

t.deepEqual(result, {
ssl: true,
});

await pool.end();
} finally {
terminate();
}
});
2 changes: 1 addition & 1 deletion packages/sql-tag/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
"@types/node": "^22.9.0",
"ava": "^6.1.3",
"cspell": "^8.16.0",
"eslint": "^9.14.0",
"eslint": "^9.16.0",
"nyc": "^15.1.0",
"ts-node": "^10.9.1",
"typescript": "^5.6.3",
Expand Down
22 changes: 22 additions & 0 deletions packages/test-ssls/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM postgres:16

RUN mkdir -p /etc/postgresql/certs && chown postgres:postgres /etc/postgresql/certs

# Copy the SSL certificates into the container
COPY root.crt /etc/postgresql/certs/root.crt
COPY slonik.key /etc/postgresql/certs/server.key
COPY slonik.crt /etc/postgresql/certs/server.crt


RUN chmod 600 /etc/postgresql/certs/server.key && \
chmod 644 /etc/postgresql/certs/server.crt /etc/postgresql/certs/root.crt && \
chown postgres:postgres /etc/postgresql/certs/*

RUN echo "ssl = on" >> /usr/share/postgresql/postgresql.conf.sample && \
echo "ssl_cert_file = '/etc/postgresql/certs/server.crt'" >> /usr/share/postgresql/postgresql.conf.sample && \
echo "ssl_key_file = '/etc/postgresql/certs/server.key'" >> /usr/share/postgresql/postgresql.conf.sample && \
echo "ssl_ca_file = '/etc/postgresql/certs/root.crt'" >> /usr/share/postgresql/postgresql.conf.sample

EXPOSE 5432

USER postgres
30 changes: 30 additions & 0 deletions packages/test-ssls/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Test SSLs

SSLs used for testing Slonik.

## Generating SSL certificates

```bash
# Generate a Root Certificate (CA)
openssl genrsa -out root.key 2048
openssl req -x509 -new -nodes -key root.key -sha256 -days 365 -out root.crt -subj "/C=US/ST=State/L=City/O=Organization/OU=OrgUnit/CN=RootCA"

# Generate a Client Key
openssl genrsa -out slonik.key 2048

# Create a Certificate Signing Request (CSR) for the Client
openssl req -new -key slonik.key -out slonik.csr -subj "/C=US/ST=State/L=City/O=Organization/OU=OrgUnit/CN=Client"

# Sign the Client Certificate with the Root Certificate
openssl x509 -req -in slonik.csr -CA root.crt -CAkey root.key -CAcreateserial -out slonik.crt -days 365 -sha256

# Verify the Certificates
openssl verify -CAfile root.crt slonik.crt
```

## Running PostgreSQL with SSL

```bash
docker build -t slonik-ssl-test .
docker run --name slonik-ssl-test --rm -it -e POSTGRES_PASSWORD=postgres -p 5433:5432 slonik-ssl-test
```
21 changes: 21 additions & 0 deletions packages/test-ssls/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"author": {
"email": "[email protected]",
"name": "Gajus Kuizinas",
"url": "http://gajus.com"
},
"description": "SSLs used for testing Slonik.",
"engines": {
"node": ">=18"
},
"license": "BSD-3-Clause",
"name": "@slonik/test-ssls",
"peerDependencies": {
"zod": "^3"
},
"repository": {
"type": "git",
"url": "https://github.com/gajus/slonik"
},
"version": "46.2.0"
}
22 changes: 22 additions & 0 deletions packages/test-ssls/root.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDrTCCApWgAwIBAgIUCeW/D1et8Kai9cSz5UKmkyAcXVMwDQYJKoZIhvcNAQEL
BQAwZjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5
MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNV
BAMMBlJvb3RDQTAeFw0yNDEyMDMxODQ4NTdaFw0yNTEyMDMxODQ4NTdaMGYxCzAJ
BgNVBAYTAlVTMQ4wDAYDVQQIDAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UE
CgwMT3JnYW5pemF0aW9uMRAwDgYDVQQLDAdPcmdVbml0MQ8wDQYDVQQDDAZSb290
Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCjqsgWUe2h2lJmrLIw
/fOvSSsgIeH6fgnal3KoWrY0J4Brsx7jHqKcyWiVEeRche9MxuBbt8smyU4jUX+S
eWx3fhK4couXB4JvK+vJAwVUF5yGWCcd1j+4BYFtMjo+I5crpQwmCGt+9kg+5t32
pr2oxcL5wjBQ9ILYbsnSgiS9V6/nWeIafc1xgY3irsrjXNgtKjBS/a8Xdw16Axn5
07Ys8C4bckGVSsQSo3oLvoMYPKk3vCAYsuQuTsPsmmhtAYm/VeyXYCX4liJ7Wyi7
uhZLnJ/LCpOkJzYzcLedueUplrh6BNtSet+Q7xQD3HrATDZWQHqNkSfYef3Vk1EM
svWhAgMBAAGjUzBRMB0GA1UdDgQWBBSdZ57li7aqScAYPVX7EReccnfhzjAfBgNV
HSMEGDAWgBSdZ57li7aqScAYPVX7EReccnfhzjAPBgNVHRMBAf8EBTADAQH/MA0G
CSqGSIb3DQEBCwUAA4IBAQB4kvYFaIcA3ZklmdzSYQuBvSwD93o39mSI7OCgJ4Du
vD9vGRDXBptveV9yGBirHtQdOJrtSXJeeA2CsoGgapHNLzeNasVRO773R4gem+F5
aImKUQVDvanEfVCCoUH5hBPSsO98sZPolk2p0Td2VKZJ4/NYWICI7vKVEfNkqmC/
4nzt2QZIkz0jG7H3Y8dqbAoL7zCJnziOBS4HxlOwbgCDHgog9kQPeMrJJuRdR1SK
7xSMwff2UQMkpL5Rib7nXBHL8jTWqB8WwcrsiiEfWHxFgOOIUjKGfqnGvSbn+9ME
U++l+xOA1HdOerXOZ9pFmaCPuAwPBy0o8qtuX1Y+6ueh
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions packages/test-ssls/root.key
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCjqsgWUe2h2lJm
rLIw/fOvSSsgIeH6fgnal3KoWrY0J4Brsx7jHqKcyWiVEeRche9MxuBbt8smyU4j
UX+SeWx3fhK4couXB4JvK+vJAwVUF5yGWCcd1j+4BYFtMjo+I5crpQwmCGt+9kg+
5t32pr2oxcL5wjBQ9ILYbsnSgiS9V6/nWeIafc1xgY3irsrjXNgtKjBS/a8Xdw16
Axn507Ys8C4bckGVSsQSo3oLvoMYPKk3vCAYsuQuTsPsmmhtAYm/VeyXYCX4liJ7
Wyi7uhZLnJ/LCpOkJzYzcLedueUplrh6BNtSet+Q7xQD3HrATDZWQHqNkSfYef3V
k1EMsvWhAgMBAAECggEADaeq2vCJ8XuGwsnncglLYqqpnkbav5dIGNnoNzNI9AVU
Wb1PjJEamGyAvRM0PiNEibTRX4Wa6EkFARMEdZg2Maqt7X/3tSmWEH1rG3xqM4+8
FO9XkCM3HLzaMAiamGLyyAbqAmWocPwjn0U2wU88ZU+JSro7ZWheXv1bTvoMY6mX
iqhtfjsmoTFR7qR2sG/VM3S85rwB9pUUuvPah+j/g9UGwgQ3+uqlHptJTW5JW4BT
87OALr2c1Dzfy2Y8PuNUrKeD4Brm3IFHh3LzzpR5VYUxhU6zltMkA14NNozKHH8G
3VIizEze2HJXXF1hlB/sTP8ULD12qq0sgLalfprWgwKBgQDUrs7MG70gEL1s7Yz7
CqFo2EOd8m2//oTyN1zYCSlcmro80eF9eEOOljNFjuhrgMX8/tv/lIgAeUQ8kfaD
xMLuaJYSmTZn05jju9UIFr+u1r4HMqqGimSnT+l+m/0kZb6ORJqakuPAs7iwDv1D
ZdisRsmEXvNbvZ9+TsIf5dmbowKBgQDFAFCWAdgB8ODSt2vdTdN+WNwZR8qS2/gn
qneeWVgbhybQ0PHMltKZFRLUB568/5y3MS8J3ivsjiPxORnBAaB0xq15PDODkfRb
DCj/8o1ls3kw/+3VJH6Hj6n/cg5/7Cw4RPWC5DPxVUeRCKpIKUKB5OtervMPPrd8
CzsOZmv96wKBgHhXzYXqsDIjprurEtm94yUrMd9+nKFFyD4yG2PWk0Pl/TmK3Ned
JETbMnnKajLiM6V7JErS5b224GiRgvZ+cHpsTXaKoSFQtrMtxlYEYUPyGKaEAb+N
MXUGn61XYH6m35MquHx8X0jbqMZeROpNB7Q7fa1b+MHRYx0aPXfFHEOXAoGAZ8oi
quWNyHf/+wRn79Bw/MAUNb19HKKHu140Z1jq8pXh/WIYApHzonNX2B2rpCeHiXyA
K9LBkX/Rr+VFjEovH1cNTjJJcagT9WQStcY0eMB1uTsdMo5nm0Q1bD/LI9pp8btj
HfLc6ujjK6ZFEH+saoMQ/nFt3TpNsSy5kHylqMECgYBfYLzB2enk2Och5J9JXqrH
mJ3Fn+ftbfrKuH18usbpmBkILuuExNQTW/TPPYfu2OAUQZkTZspg1sOStvjfNoxb
RN2croyq6SnLnKB3Iie5Phat8v2CUJ2ztXpdTHgwWUXH8BfAA9SM9GGAtp407pAW
cEvc+//nwJb0A/jm+77Vkg==
-----END PRIVATE KEY-----
1 change: 1 addition & 0 deletions packages/test-ssls/root.srl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
43559C920011918D75D5CF4B9694FCBC9CB9F3B9
Loading

0 comments on commit 960bf89

Please sign in to comment.