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

Enable configuration of API_SECRET as a Docker secret #8300

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
Changes from 1 commit
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
Next Next commit
add support for passing API_SECRET to a container via a file
swebster committed Oct 1, 2024
commit fc2893a8fea8d00921ae277e993fd2cae13edf2e
2 changes: 1 addition & 1 deletion lib/server/enclave.js
Original file line number Diff line number Diff line change
@@ -44,7 +44,7 @@ const init = function init () {
}

enclave.isApiKeySet = function isApiKeySet () {
return isApiKeySet;
return apiKeySet;
}

enclave.isApiKey = function isApiKey (keyValue) {
27 changes: 19 additions & 8 deletions lib/server/env.js
Original file line number Diff line number Diff line change
@@ -77,22 +77,19 @@ function setSSL () {
env.secureCspReportOnly = readENVTruthy("SECURE_CSP_REPORT_ONLY", false);
}

// A little ugly, but we don't want to read the secret into a var
function setAPISecret () {
var useSecret = (readENV('API_SECRET') && readENV('API_SECRET').length > 0);
// if no value is provided as an environment variable, try to read it from a file
const apiSecret = readENV('API_SECRET') || readEnvFile('API_SECRET_FILE');
//TODO: should we clear API_SECRET from process env?
env.api_secret = null;
// if a passphrase was provided, get the hex digest to mint a single token
if (useSecret) {
if (readENV('API_SECRET').length < consts.MIN_PASSPHRASE_LENGTH) {
if (apiSecret && apiSecret.length > 0) {
if (apiSecret.length < consts.MIN_PASSPHRASE_LENGTH) {
var msg = ['API_SECRET should be at least', consts.MIN_PASSPHRASE_LENGTH, 'characters'].join(' ');
console.error(msg);
env.err.push({ desc: msg });
} else {

const apiSecret = readENV('API_SECRET');
delete process.env.API_SECRET;

env.enclave.setApiKey(apiSecret);
var testresult = stringEntropy(apiSecret);

@@ -108,7 +105,6 @@ function setAPISecret () {
env.notifies.push({ persistent: true, title: 'Security issue', message: 'MongoDB password and API_SECRET match. This is a really bad idea. Please change both and do not reuse passwords across the system.' });
}
}

}
}
}
@@ -185,6 +181,21 @@ function readENVTruthy (varName, defaultValue) {
return value;
}

function readEnvFile(varName) {
let value = null;
const fileName = readENV(varName);

if (fileName && fileName.length > 0) {
try {
value = fs.readFileSync(fileName);
} catch (error) {
env.err.push({ desc: `Unable to read ${varName}: ${error.message}` });
}
}

return value;
}

function findExtendedSettings (envs) {
var extended = {};

63 changes: 63 additions & 0 deletions tests/env.test.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,71 @@
'use strict';

require('should');
const fs = require('fs');
const os = require('os');
const path = require('path');

describe('env', function () {
function writeTempFile(fileName, data) {
const fullPath = path.join(os.tmpdir(), fileName);
fs.writeFileSync(fullPath, data);
return fullPath;
}

it('should not set the API key without API_SECRET or API_SECRET_FILE', function () {
delete process.env.API_SECRET;
var env = require( '../lib/server/env' )();
env.enclave.isApiKeySet().should.equal(false);
});

it('should read the API key from API_SECRET_FILE if it is valid', function () {
const apiSecretFile = 'this is another pass phrase';
const hashFile = 'c79c6db1070da3537d0162e60647b0a588769f8d';
process.env.API_SECRET_FILE = writeTempFile('api_secret_file', apiSecretFile);

var env = require( '../lib/server/env' )();
env.enclave.isApiKeySet().should.equal(true);
env.enclave.isApiKey(hashFile).should.equal(true);

fs.rmSync(process.env.API_SECRET_FILE);
delete process.env.API_SECRET_FILE;
});

it('should raise an error when API_SECRET_FILE does not exist', function () {
const nonexistentPath = path.join(os.tmpdir(), 'api_secret_file');
process.env.API_SECRET_FILE = nonexistentPath;

var env = require( '../lib/server/env' )();
env.enclave.isApiKeySet().should.equal(false);
env.err.length.should.equal(1);

const error = env.err.pop();
error.should.have.property('desc');
error.desc.should.match(/API_SECRET_FILE/);
error.desc.should.match(/no such file or directory/);

delete process.env.API_SECRET_FILE;
});

it('should use API_SECRET when API_SECRET_FILE is also specified', function () {
const apiSecretEnv = 'this is my long pass phrase';
const hashEnv = 'b723e97aa97846eb92d5264f084b2823f57c4aa1';
process.env.API_SECRET = apiSecretEnv;

const apiSecretFile = 'this is another pass phrase';
const hashFile = 'c79c6db1070da3537d0162e60647b0a588769f8d';
process.env.API_SECRET_FILE = writeTempFile('api_secret_file', apiSecretFile);

var env = require( '../lib/server/env' )();
env.enclave.isApiKeySet().should.equal(true);
env.enclave.isApiKey(hashEnv).should.equal(true);
env.enclave.isApiKey(hashFile).should.equal(false);

fs.rmSync(process.env.API_SECRET_FILE);
delete process.env.API_SECRET_FILE;
delete process.env.API_SECRET;
});

it( 'show the right plugins', function () {
process.env.SHOW_PLUGINS = 'iob';
process.env.ENABLE = 'iob cob';