Add support for "_FILE" environment variables

This commit is contained in:
Jan Oberhauser 2019-08-03 14:06:11 +02:00
parent 1fff6e4d54
commit 13c5f99a7e
4 changed files with 75 additions and 7 deletions

View file

@ -73,6 +73,11 @@ By default n8n uses SQLite to save credentials, past executions and workflows.
n8n however also supports MongoDB and PostgresDB. To use them simply a few
environment variables have to be set.
To avoid passing sensitive information via environment variables "_FILE" may be
appended to the database environment variables (for example "DB_POSTGRESDB_PASSWORD_FILE").
It will then load the data from a file with the given name. That makes it possible to
load data easily from Docker- and Kubernetes-Secrets.
It is important to still persist the data in the `/root/.n8` folder. The reason
is that it contains n8n user data. That is the name of the webhook
(in case) the n8n tunnel gets used and even more important the encryption key

View file

@ -74,6 +74,11 @@ By default n8n uses SQLite to save credentials, past executions and workflows.
n8n however also supports MongoDB and PostgresDB. To use them simply a few
environment variables have to be set.
To avoid passing sensitive information via environment variables "_FILE" may be
appended to the database environment variables (for example "DB_POSTGRESDB_PASSWORD_FILE").
It will then load the data from a file with the given name. That makes it possible to
load data easily from Docker- and Kubernetes-Secrets.
#### Start with MongoDB as Database

View file

@ -1,4 +1,5 @@
import {
GenericHelpers,
IDatabaseCollections,
DatabaseType,
} from './';
@ -31,7 +32,7 @@ export let collections: IDatabaseCollections = {
import * as path from 'path';
export async function init(): Promise<IDatabaseCollections> {
const dbType = config.get('database.type') as DatabaseType;
const dbType = await GenericHelpers.getConfigValue('database.type') as DatabaseType;
const n8nFolder = UserSettings.getUserN8nFolderPath();
let entities;
@ -41,18 +42,18 @@ export async function init(): Promise<IDatabaseCollections> {
entities = MongoDb;
connectionOptions = {
type: 'mongodb',
url: config.get('database.mongodb.connectionUrl') as string,
url: await GenericHelpers.getConfigValue('database.mongodb.connectionUrl') as string,
useNewUrlParser: true,
};
} else if (dbType === 'postgresdb') {
entities = PostgresDb;
connectionOptions = {
type: 'postgres',
database: config.get('database.postgresdb.database'),
host: config.get('database.postgresdb.host'),
password: config.get('database.postgresdb.password'),
port: config.get('database.postgresdb.port'),
username: config.get('database.postgresdb.user'),
database: await GenericHelpers.getConfigValue('database.postgresdb.database') as string,
host: await GenericHelpers.getConfigValue('database.postgresdb.host') as string,
password: await GenericHelpers.getConfigValue('database.postgresdb.password') as string,
port: await GenericHelpers.getConfigValue('database.postgresdb.port') as number,
username: await GenericHelpers.getConfigValue('database.postgresdb.user') as string,
};
} else if (dbType === 'sqlite') {
entities = SQLite;

View file

@ -1,6 +1,12 @@
import * as config from '../config';
import * as express from 'express';
import {
readFile as fsReadFile,
} from 'fs';
import { promisify } from "util";
import { IDataObject } from 'n8n-workflow';
const fsReadFileAsync = promisify(fsReadFile);
/**
* Displays a message to the user
@ -46,3 +52,54 @@ export function getBaseUrl(): string {
export function getSessionId(req: express.Request): string | undefined {
return req.headers.sessionid as string | undefined;
}
/**
* Gets value from config with support for "_FILE" environment variables
*
* @export
* @param {string} configKey The key of the config data to get
* @returns {(Promise<string | boolean | number | undefined>)}
*/
export async function getConfigValue(configKey: string): Promise<string | boolean | number | undefined> {
const configKeyParts = configKey.split('.');
// Get the environment variable
const configSchema = config.getSchema();
let currentSchema = configSchema.properties as IDataObject;
for (const key of configKeyParts) {
if (currentSchema[key] === undefined) {
throw new Error(`Key "${key}" of ConfigKey "${configKey}" does not exist`);
} else if ((currentSchema[key]! as IDataObject).properties === undefined) {
currentSchema = currentSchema[key] as IDataObject;
} else {
currentSchema = (currentSchema[key] as IDataObject).properties as IDataObject;
}
}
// Check if environment variable is defined for config key
if (currentSchema.env === undefined) {
// No environment variable defined, so return value from config
return config.get(configKey);
}
// Check if special file enviroment variable exists
const fileEnvironmentVariable = process.env[currentSchema.env + '_FILE'];
if (fileEnvironmentVariable === undefined) {
// Does not exist, so return value from config
return config.get(configKey);
}
let data;
try {
data = await fsReadFileAsync(fileEnvironmentVariable, 'utf8') as string;
} catch (error) {
if (error.code === 'ENOENT') {
throw new Error(`The file "${fileEnvironmentVariable}" could not be found.`);
}
throw error;
}
return data;
}