L’objectif

Établir une connexion chiffrée entre le backend d’une application Nodejs et une base de données PostgreSQL distante hébergé chez Scaleway.

Le contexte

Un backend Nodejs d’une application NuxtJS doit se connecter à une base de données PostgreSQL distante.
La base de données est une DBaaS (Database as a Service) fourni pas Scaleway.
Langage utilisé : TypeScript mais ce qui suit est aussi valable pour JavaScript.
Librairies utilisées : pg. npm install pg
Si vous utilisez TypeScript n’oubliez pas les déclarations de types npm install --save @types/pg

La réalisation

La première étape consiste à récupérer le certificat SSL du serveur PostgreSQL.
Ce certificat est fourni par Scaleway, vous pouvez le télécharger depuis l’interface web de gestion de votre compte Scaleway :

DBAAS PostgreSQL Scaleway

Vous allez obtenir le certificat SSL au format PEM.

Dans la mesure où toute la configuration de notre backend est faite via un fichier .env, la premiere question qui se pose est de savoir comment incorporer ce certificat dans notre fichier .env.

Il y a deux solutions :

  • Enregistrer le fichier .pem sur le disque, configurer le chemin d’accès dans le fichier .env et le charger, au niveau de notre backend, via un readFileSync('./cert.pem')
  • Mettre directement le certificat dans le fichier .env.

Le problème de la première solution est que le chemin d’accès au fichier peut varier d’un environnement à l’autre.
On va donc utiliser la seconde solution, la seule petite contrainte, c’est que l’on ne peut définir une variable multi-line dans le fichier .env, on va donc remplacer tous les sauts de ligne par des \n :

# postgresql
ATT_DB_HOST=rw-5ad02df9-xxxxxxxxxxxxxx.rdb.fr-par.scw.cloud
ATT_DB_PORT=26257
ATT_DB_USER='myuser'
ATT_DB_PASSWORD='mypassword'
ATT_DB_NAME='mydb'
ATT_DB_SSL_CA="-----BEGIN CERTIFICATE-----\nMIID....\n-----END CERTIFICATE-----"

Au niveau de notre backend, on va donc utiliser process.env.ATT_DB_SSL_CA qui contient le certificat SSL :

const port: number = parseInt(process.env.ATT_DB_PORT || '5432')
this.pool = new Pool({
    user: process.env.ATT_DB_USER,
    password: process.env.ATT_DB_PASSWORD,
    host: process.env.ATT_DB_HOST,
    port,
    database: process.env.ATT_DB_NAME,
    ssl: {
        rejectUnauthorized: true,
        ca: process.env.ATT_DB_SSL_CA
    }
})

Attention si vous utilisez l’IP de votre serveur et pas son nom d’hôte, vous allez avoir une erreur SSL, dans ces conditions le nom défini dans le certificat ne matche pas :

Hostname/IP does not match certificate's altnames

Si vous tenez absolument à utiliser, l’IP, ce que je ne vous conseille pas du tout, car la connexion sera moins sécurisée, passez rejectUnauthorized: à false dans le constructeur de la classe Pool.

Une dernière chose Scaleway vous permet de limiter les accès à votre base de données en fonction des IPs des clients qui se connectent. Pensez à utiliser cette option ;)