Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add the ability to configure sslrootcert, sslkey and sslrootcert #653

Merged
merged 14 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading