Skip to content

Commit

Permalink
feat: added tls config
Browse files Browse the repository at this point in the history
Signed-off-by: Avinash <avinash.kumar.cs92@gmail.com>
  • Loading branch information
Avinash committed Mar 8, 2024
1 parent 956dd28 commit bf90dbd
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 8 deletions.
82 changes: 82 additions & 0 deletions backend/src/config/database.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { registerAs } from '@nestjs/config';
import * as fs from 'fs';
import * as Joi from 'joi';

import { DatabaseType } from './database-type.enum';
Expand All @@ -18,10 +19,41 @@ export interface DatabaseConfig {
type: DatabaseType;
}

const getSecret = (path?: string) => {
if (path && fs.existsSync(path)) {
return fs.readFileSync(path, 'utf8');
}
};

const postgresTlsSchema = Joi.object({
ca: Joi.string().label('HD_PG_SSL_CA_PATH'),
rejectUnauthorized: Joi.boolean()
.default(false)
.label('HD_DATABASE_SSL_REJECT_UNAUTHORIZED')
.optional(),
key: Joi.string().label('HD_PG_SSL_KEY_PATH').optional(),
cert: Joi.string().label('HD_PG_SSL_CERT_PATH').optional(),
});

const sqlTlsSchema = Joi.object({
rejectUnauthorized: Joi.boolean()
.default(true)
.label('HD_DATABASE_SSL_REJECT_UNAUTHORIZED')
.optional(),
ca: Joi.string().label('HD_DATABASE_SSL_CA'),
cert: Joi.string().label('HD_DATABASE_SSL_CERT'),
key: Joi.string().label('HD_DATABASE_SSL_KEY').optional(),
ciphers: Joi.string().label('HD_DATABASE_SSL_CIPHERS').optional(),
maxVersion: Joi.string().label('HD_DATABASE_SSL_MAX_VERSION').optional(),
minVersion: Joi.string().label('HD_DATABASE_SSL_MIN_VERSION').optional(),
passphrase: Joi.string().label('HD_DATABASE_SSL_PASSPHRASE').optional(),
});

const databaseSchema = Joi.object({
type: Joi.string()
.valid(...Object.values(DatabaseType))
.label('HD_DATABASE_TYPE'),
needsSSL: Joi.string().valid('0', '1').label('HD_DATABASE_SSL'),

// This is the database name, except for SQLite,
// where it is the path to the database file.
Expand All @@ -46,8 +78,56 @@ const databaseSchema = Joi.object({
then: Joi.number(),
otherwise: Joi.optional(),
}).label('HD_DATABASE_PORT'),
ssl: Joi.when('needsSSL', {
is: Joi.valid('1'),
then: Joi.required(),
otherwise: Joi.optional(),
}).when('type', {
is: Joi.valid(DatabaseType.MARIADB, DatabaseType.MYSQL),
then: sqlTlsSchema,
otherwise: Joi.when('type', {
is: Joi.invalid(DatabaseType.SQLITE),
then: postgresTlsSchema,
otherwise: Joi.optional(),
}),
}),
});

const getTlsConfig = (dbType: DatabaseType, needsSSL: boolean) => {
if (!needsSSL) return;

const postgresTlsConfig = dbType === DatabaseType.POSTGRES && {
ssl: {
ca: getSecret(process.env.HD_PG_SSL_CA_PATH),
rejectUnauthorized: process.env.HD_PG_SSL_REJECT_UNAUTHORIZED === 'true',
key: getSecret(process.env.HD_PG_SSL_KEY_PATH),
cert: getSecret(process.env.HD_PG_SSL_CERT_PATH),
},
};

const sqlTlsConfig = [DatabaseType.MARIADB, DatabaseType.MYSQL].includes(
dbType,
) && {
ssl: {
ca: getSecret(process.env.HD_SQL_SSL_CA_PATH),
key: getSecret(process.env.HD_SQL_SSL_KEY_PATH),
cert: getSecret(process.env.HD_SQL_SSL_CERT_PATH),
rejectUnauthorized: process.env.HD_SQL_SSL_REJECT_UNAUTHORIZED === 'true',
ciphers: process.env.HD_SQL_SSL_CIPHERS,
maxVersion: process.env.HD_SQL_SSL_MAX_VERSION,
minVersion: process.env.HD_SQL_SSL_MIN_VERSION,
passphrase: process.env.HD_SQL_SSL_PASSPHRASE,
},
};

return sqlTlsConfig || postgresTlsConfig;
};

const dbType = process.env.HD_DATABASE_TYPE;
const needsSSL = process.env.HD_DATABASE_SSL === '1';

const tlsConfig = getTlsConfig(dbType as DatabaseType, needsSSL);

export default registerAs('databaseConfig', () => {
const databaseConfig = databaseSchema.validate(
{
Expand All @@ -57,6 +137,8 @@ export default registerAs('databaseConfig', () => {
database: process.env.HD_DATABASE_NAME,
host: process.env.HD_DATABASE_HOST,
port: parseOptionalNumber(process.env.HD_DATABASE_PORT),
needsSSL: process.env.HD_DATABASE_SSL ?? '0',
...tlsConfig,
},
{
abortEarly: false,
Expand Down
59 changes: 51 additions & 8 deletions docs/content/references/config/database.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,55 @@ We officially support and test these databases:
- MariaDB

<!-- markdownlint-disable proper-names -->
| environment variable | default | example | description |
|-----------------------|---------|---------------------|--------------------------------------------------------------------------------------------|
| `HD_DATABASE_TYPE` | - | `postgres` | The database type you want to use. This can be `postgres`, `mysql`, `mariadb` or `sqlite`. |
| `HD_DATABASE_NAME` | - | `hedgedoc` | The name of the database to use. When using SQLite, this is the path to the database file. |
| `HD_DATABASE_HOST` | - | `db.example.com` | The host, where the database runs. *Only if you're **not** using `sqlite`.* |
| `HD_DATABASE_PORT` | - | `5432` | The port, where the database runs. *Only if you're **not** using `sqlite`.* |
| `HD_DATABASE_USER` | - | `hedgedoc` | The user that logs in the database. *Only if you're **not** using `sqlite`.* |
| `HD_DATABASE_PASS` | - | `password` | The password to log into the database. *Only if you're **not** using `sqlite`.* |

| environment variable | default | example | description |
| -------------------- | ------- | ---------------- | ------------------------------------------------------------------------------------------ |
| `HD_DATABASE_TYPE` | - | `postgres` | The database type you want to use. This can be `postgres`, `mysql`, `mariadb` or `sqlite`. |
| `HD_DATABASE_NAME` | - | `hedgedoc` | The name of the database to use. When using SQLite, this is the path to the database file. |
| `HD_DATABASE_HOST` | - | `db.example.com` | The host, where the database runs. _Only if you're **not** using `sqlite`._ |
| `HD_DATABASE_PORT` | - | `5432` | The port, where the database runs. _Only if you're **not** using `sqlite`._ |
| `HD_DATABASE_USER` | - | `hedgedoc` | The user that logs in the database. _Only if you're **not** using `sqlite`._ |
| `HD_DATABASE_PASS` | - | `password` | The password to log into the database. _Only if you're **not** using `sqlite`._ |
| `HD_DATABASE_SSL` | '0' | `1` | Pass this value when SSL/TLS configuration is needed |

<!-- markdownlint-enable proper-names -->

### SSL/TLS configuration for postgres database

**Note:** `HD_DATABASE_SSL='1'` should be added in .env else following SSL/TLS config will not work

<!-- markdownlint-disable proper-names -->

| environment variable | default | example | description |
| ------------------------------- | ------- | ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `HD_PG_SSL_CA_PATH` | - | ./root.crt | The path of SSL/TLS certificate authority (CA) certificate needed for establishing secure database connections. |
| `HD_PG_SSL_CERT_PATH` | - | ./postgresql.crt | The path for the file that is going to be used for SSL/TLS handshake. |
| `HD_PG_SSL_REJECT_UNAUTHORIZED` | 'true' | 'false' | If true fail the ssl handshake if supplied CAs and hostname doesn't match the server certificate |
| `HD_PG_SSL_KEY_PATH` | - | './key.pem' | This is passed as the key option to [SSL key option](https://node-postgres.com/features/ssl#self-signed-cert) |

This CA certificate serves as the anchor for verifying the validity of the certificate chain. Ensure that the provided CA certificate is trusted by the database server to establish secure connections.

<!-- markdownlint-enable proper-names -->

### SSL/TLS configuration for mysql/mariaDB database

**Note:** `HD_DATABASE_SSL='1'` should be added in .env else following SSL/TLS config will not work

<!-- markdownlint-disable proper-names -->

| environment variable | default | example | description |
| -------------------------------- | ------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `HD_SQL_SSL_CA_PATH` | - | ./mysql-ca.crt | The path of SSL/TLS certificate authority (CA) certificate needed for establishing secure database connections |
| `HD_SQL_SSL_CERT_PATH` | - | ./mysql-cert.crt | The path for client certificate to use in the SSL handshake. |
| `HD_SQL_SSL_REJECT_UNAUTHORIZED` | 'true' | 'false' | If true server certificate will be verified against the list of supplied CAs. |
| `HD_SQL_SSL_KEY_PATH` | - | ./key.pem | This is passed as the key option to [SSL key option](https://github.com/mysqljs/mysql?tab=readme-ov-file#ssl-options) |
| `HD_DATABASE_SSL_CIPHERS` | - | 'TLS_AES_256...' | The ciphers to use to use in the SSL handshake instead of the default ones for Node.js. |
| `HD_DATABASE_SSL_MAX_VERSION` | - | 'TLSv1.3' | This is passed as the maxVersion option for [SSL max_version](https://github.com/mysqljs/mysql?tab=readme-ov-file#ssl-options) |
| `HD_DATABASE_SSL_MIN_VERSION` | - | 'TLSv1.3' | This is passed as the minVersion option for [SSL max_version](https://github.com/mysqljs/mysql?tab=readme-ov-file#ssl-options) |
| `HD_DATABASE_SSL_PASSPHRASE` | - | 'XSX@W...' | Shared passphrase used for a single private key and/or a PFX.This is passed as the passphrase option for [SSL max_version](https://github.com/mysqljs/mysql?tab=readme-ov-file#ssl-options) |

This CA certificate serves as the anchor for verifying the validity of the certificate chain. Ensure that the provided CA certificate is trusted by the database server to establish secure connections.

Check full description for [mysql TLS](https://github.com/mysqljs/mysql?tab=readme-ov-file#ssl-options)

<!-- markdownlint-enable proper-names -->

0 comments on commit bf90dbd

Please sign in to comment.