@tsmx/secure-config
Advanced tools
Comparing version 1.1.2 to 1.2.0
@@ -7,2 +7,3 @@ { | ||
}, | ||
"nullVal": null, | ||
"filestorage": { | ||
@@ -9,0 +10,0 @@ "type": "local", |
{ | ||
"name": "@tsmx/secure-config", | ||
"version": "1.1.2", | ||
"description": "Handling multi-environment JSON configurations with encrypted secrets. Minimalistic, zero deps.", | ||
"version": "1.2.0", | ||
"description": "Secure multi-environment JSON configurations with encrypted secrets.", | ||
"main": "secure-config.js", | ||
@@ -39,4 +39,8 @@ "engines": { | ||
"coveralls": "^3.1.0", | ||
"jest": "^26.1.0" | ||
"jest": "^26.5.3" | ||
}, | ||
"dependencies": { | ||
"@tsmx/json-traverse": "^1.0.2", | ||
"@tsmx/string-crypto": "^1.0.2" | ||
} | ||
} |
@@ -1,2 +0,2 @@ | ||
# [**secure-config**](https://github.com/tsmx/secure-config) | ||
# [**@tsmx/secure-config**](https://github.com/tsmx/secure-config) | ||
@@ -6,27 +6,10 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT) | ||
![node-current (scoped)](https://img.shields.io/node/v/@tsmx/secure-config) | ||
[![Build Status](https://travis-ci.org/tsmx/secure-config.svg?branch=master)](https://travis-ci.org/tsmx/secure-config) | ||
[![Build Status](https://travis-ci.com/tsmx/secure-config.svg?branch=master)](https://travis-ci.org/tsmx/secure-config) | ||
[![Coverage Status](https://coveralls.io/repos/github/tsmx/secure-config/badge.svg?branch=master)](https://coveralls.io/github/tsmx/secure-config?branch=master) | ||
Handling multi-environment configurations with encrypted secrets. | ||
> Secure multi-environment configurations with encrypted secrets. | ||
Benefits: | ||
- No need to "hide" your configuration files from code repos etc. | ||
- The only thing to be kept secret is one key per environment. | ||
- No need to use 3rd party secret stores like GCP KMS, Vault or something | ||
- Pure NodeJS solution, no dependencies | ||
- Uses standard environment variable technique to inject the only secret you need | ||
The cipher used is AES-256-CBC. | ||
## Usage | ||
1. Encrypt your secret configuration values, e.g. by using [secure-config-tool](https://www.npmjs.com/package/@tsmx/secure-config-tool). For more details please see [generating encrypted values](#generating-encrypted-entries). | ||
```bash | ||
[tsmx@localhost ]$ secure-config-tool create --secret MySecretDbUser | ||
ENCRYPTED|50ceed2f97223100fbdf842ecbd4541f|df9ed9002bfc956eb14b1d2f8d960a11 | ||
[tsmx@localhost ]$ secure-config-tool create --secret MySecretDbPass | ||
ENCRYPTED|8fbf6ded36bcb15bd4734b3dc78f2890|7463b2ea8ed2c8d71272ac2e41761a35 | ||
``` | ||
2. Copy & Paste the encrypted values to your JSON configuration file | ||
1. Encrypt sensitive data in your JSON configuration file. For more details please see [generating encrypted values](#generating-encrypted-entries) and [naming conventions](#naming-conventions). | ||
```json | ||
@@ -42,3 +25,3 @@ { | ||
3. Use your configuration in the code | ||
3. Use your configuration in the code. | ||
```js | ||
@@ -54,2 +37,7 @@ const conf = require('@tsmx/secure-config'); | ||
``` | ||
A fully working [example project](https://github.com/tsmx/secure-config-test) is also available on GitHub. | ||
To get all information please also check out the [full documentation](https://tsmx.net/secure-config/). | ||
## Injecting the decryption key | ||
@@ -86,2 +74,4 @@ | ||
More examples are available in the [full documentation](https://tsmx.net/secure-config/). | ||
The key length must be 32 bytes! The value set in `CONFIG_ENCRYPTION_KEY` has to be: | ||
@@ -133,3 +123,3 @@ - a string of 32 characters length, or | ||
## Configuration file name and directory convention | ||
## Naming conventions | ||
@@ -136,0 +126,0 @@ You can have multiple configuration files for different environments or stages. They are distinguished by the environment variable `NODE_ENV`. The basic configuration file name is `config.json` if this variable is not present. If it is present, a configuration file with the name `config-[NODE_ENV].json` |
@@ -1,6 +0,8 @@ | ||
const crypto = require('crypto'); | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const algorithm = 'aes-256-cbc'; | ||
const sc = require('@tsmx/string-crypto'); | ||
const jt = require('@tsmx/json-traverse'); | ||
const prefix = 'ENCRYPTED|'; | ||
function getKey() { | ||
@@ -13,6 +15,6 @@ const hexReg = new RegExp('^[0-9A-F]{64}$', 'i'); | ||
else if (process.env.CONFIG_ENCRYPTION_KEY.toString().length == 32) { | ||
result = Buffer.from(process.env.CONFIG_ENCRYPTION_KEY); | ||
result = process.env.CONFIG_ENCRYPTION_KEY; | ||
} | ||
else if (hexReg.test(process.env.CONFIG_ENCRYPTION_KEY)) { | ||
result = Buffer.from(process.env.CONFIG_ENCRYPTION_KEY, 'hex'); | ||
result = process.env.CONFIG_ENCRYPTION_KEY; | ||
} | ||
@@ -25,27 +27,11 @@ else { | ||
function decryptValue(text, key) { | ||
let input = text.split('|'); | ||
input.shift(); | ||
let iv = Buffer.from(input[0], 'hex'); | ||
let encryptedText = Buffer.from(input[1], 'hex'); | ||
let decipher = crypto.createDecipheriv(algorithm, key, iv); | ||
let decrypted = decipher.update(encryptedText); | ||
decrypted = Buffer.concat([decrypted, decipher.final()]); | ||
return decrypted.toString(); | ||
} | ||
function decryptConfig(conf, key) { | ||
for (var prop in conf) { | ||
if (!Object.prototype.hasOwnProperty.call(conf, prop)) continue; | ||
if (Array.isArray(conf[prop])) { | ||
continue; | ||
} | ||
if (typeof conf[prop] == 'object') { | ||
decryptConfig(conf[prop], key); | ||
} else if (conf[prop] !== null) { | ||
if (conf[prop].toString().startsWith('ENCRYPTED|')) { | ||
conf[prop] = decryptValue(conf[prop].toString(), key); | ||
function decryptConfig(conf, confKey) { | ||
const callbacks = { | ||
processValue: (key, value, level, path, isObjectRoot, isArrayElement, cbSetValue) => { | ||
if(!isArrayElement && value && value.toString().startsWith(prefix)) { | ||
cbSetValue(sc.decrypt(value.toString().substring(prefix.length), { key: confKey })); | ||
} | ||
} | ||
} | ||
}; | ||
jt.traverse(conf, callbacks, true); | ||
return conf; | ||
@@ -68,6 +54,6 @@ } | ||
var conf = require(getConfigPath()); | ||
const key = getKey(); | ||
decryptConfig(conf, key); | ||
let conf = require(getConfigPath()); | ||
let confKey = getKey(); | ||
decryptConfig(conf, confKey); | ||
module.exports = conf; |
@@ -59,2 +59,3 @@ describe('secure-config test suite', () => { | ||
expect(conf.database.password).toBe('dbpass'); | ||
expect(conf.nullVal).toBe(null); | ||
expect(conf.filestorage.type).toBe('local'); | ||
@@ -61,0 +62,0 @@ expect(conf.filestorage.params.folder).toBe('/tmp/storage'); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15889
2
190
153
+ Added@tsmx/json-traverse@^1.0.2
+ Added@tsmx/string-crypto@^1.0.2
+ Added@tsmx/json-traverse@1.0.8(transitive)
+ Added@tsmx/string-crypto@1.0.6(transitive)