From 517f5c141ad53c38991c9417f9822fb596848e2e Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:03:41 +0100 Subject: [PATCH 1/9] feat: add support for using dataFrom --- README.md | 34 +++++++++ lib/backends/kv-backend.js | 87 +++++++++++++++------ lib/backends/kv-backend.test.js | 130 ++++++++++++++++++++++++++------ 3 files changed, 207 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index a376997d..2575b4e1 100644 --- a/README.md +++ b/README.md @@ -242,6 +242,40 @@ secretDescriptor: property: username ``` +alternatively you can use `dataFrom` and get all the values from hello-service/credentials: + +```yml +apiVersion: 'kubernetes-client.io/v1' +kind: ExternalSecret +metadata: + name: hello-service +secretDescriptor: + backendType: secretsManager + # optional: specify role to assume when retrieving the data + roleArn: arn:aws:iam::123456789012:role/test-role + dataFrom: + - hello-service/credentials +``` + +`data` and `dataFrom` can of course be combined, any naming conflicts will use the last defined, with `data` overriding `dataFrom` + +```yml +apiVersion: 'kubernetes-client.io/v1' +kind: ExternalSecret +metadata: + name: hello-service +secretDescriptor: + backendType: secretsManager + # optional: specify role to assume when retrieving the data + roleArn: arn:aws:iam::123456789012:role/test-role + dataFrom: + - hello-service/credentials + data: + - key: hello-service/migration-credentials + name: password + property: password +``` + ## Metrics kubernetes-external-secrets exposes the following metrics over a prometheus endpoint: diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index 676f7020..7319c33b 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -15,20 +15,22 @@ class KVBackend extends AbstractBackend { /** * Fetch Kubernetes secret property values. - * @param {Object[]} secretProperties - Kubernetes secret properties. - * @param {string} secretProperties[].key - Secret key in the backend. - * @param {string} secretProperties[].name - Kubernetes Secret property name. - * @param {string} secretProperties[].property - If the backend secret is an + * @param {Object[]} data - Kubernetes secret properties. + * @param {string} data[].key - Secret key in the backend. + * @param {string} data[].name - Kubernetes Secret property name. + * @param {string} data[].property - If the backend secret is an * object, this is the property name of the value to use. - * @param {string} secretProperties[].roleArn - If the client should assume a role before fetching the secret + * @param {string} roleArn - If the client should assume a role before fetching the secret * @returns {Promise} Promise object representing secret property values. */ - _fetchSecretPropertyValues ({ externalData, roleArn }) { - return Promise.all(externalData.map(async secretProperty => { + _fetchSecretPropertyValues ({ data, roleArn }) { + return Promise.all(data.map(async secretProperty => { this._logger.info(`fetching secret property ${secretProperty.name} with role: ${roleArn || 'no role set'}`) - const value = await this._get({ secretKey: secretProperty.key, roleArn }) + const plainOrObjValue = await this._get({ secretKey: secretProperty.key, roleArn }) + const shouldParseValue = 'property' in secretProperty - if ('property' in secretProperty) { + let value = plainOrObjValue + if (shouldParseValue) { let parsedValue try { parsedValue = JSON.parse(value) @@ -43,10 +45,34 @@ class KVBackend extends AbstractBackend { throw new Error(`Could not find property ${secretProperty.property} in ${secretProperty.key}`) } - return parsedValue[secretProperty.property] + value = parsedValue[secretProperty.property] } - return value + return { [secretProperty.name]: value } + })) + } + + /** + * Fetch Kubernetes secret property values. + * @param {string[]} dataFrom - Array of secret keys in the backend + * @param {string} roleArn - If the client should assume a role before fetching the secret + * @returns {Promise} Promise object representing secret property values. + */ + _fetchSecretPropertyValuesFrom ({ dataFrom, roleArn }) { + return Promise.all(dataFrom.map(async secretKey => { + this._logger.info(`fetching secret property ${secretKey} with role: ${roleArn || 'no role set'}`) + const value = await this._get({ secretKey, roleArn }) + + let parsedValue + try { + parsedValue = JSON.parse(value) + } catch (err) { + this._logger.warn(`Failed to JSON.parse value for '${secretKey}',` + + ` please verify that your secret value is correctly formatted as JSON.`) + return + } + + return parsedValue })) } @@ -62,18 +88,33 @@ class KVBackend extends AbstractBackend { * @param {SecretDescriptor} secretDescriptor - Kubernetes secret descriptor. * @returns {Promise} Promise object representing Kubernetes secret manifest data. */ - async getSecretManifestData ({ secretDescriptor }) { - const data = {} - // Use secretDescriptor.properties to be backwards compatible. - const externalData = secretDescriptor.data || secretDescriptor.properties - const secretPropertyValues = await this._fetchSecretPropertyValues({ - externalData, - roleArn: secretDescriptor.roleArn - }) - externalData.forEach((secretProperty, index) => { - data[secretProperty.name] = (Buffer.from(secretPropertyValues[index], 'utf8')).toString('base64') - }) - return data + async getSecretManifestData ({ + secretDescriptor: { + // Use secretDescriptor.properties to be backwards compatible. + properties = [], + data = properties, + dataFrom = [], + roleArn + } + }) { + const [secretPropertyValues, secretPropertyValuesFrom] = await Promise.all([ + this._fetchSecretPropertyValues({ data, roleArn }), + this._fetchSecretPropertyValuesFrom({ dataFrom, roleArn }) + ]) + + const plainValues = secretPropertyValuesFrom.concat(secretPropertyValues) + .reduce((acc, parsedValue) => ({ + ...acc, + ...parsedValue + }), {}) + + const encodedEntries = Object.entries(plainValues) + .map(([name, plainValue]) => [ + name, + (Buffer.from(`${plainValue}`, 'utf8')).toString('base64') + ]) + + return Object.fromEntries(encodedEntries) } } diff --git a/lib/backends/kv-backend.test.js b/lib/backends/kv-backend.test.js index 21aed287..a4a47395 100644 --- a/lib/backends/kv-backend.test.js +++ b/lib/backends/kv-backend.test.js @@ -30,7 +30,7 @@ describe('SecretsManagerBackend', () => { kvBackend._get.onFirstCall().resolves('{"foo":"bar"}') try { await kvBackend._fetchSecretPropertyValues({ - externalData: [{ + data: [{ key: 'mocked-key', name: 'mocked-name', property: 'oops' @@ -45,19 +45,19 @@ describe('SecretsManagerBackend', () => { it('handles secrets values that are objects', async () => { kvBackend._get.onFirstCall().resolves('{"foo":"bar"}') const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ - externalData: [{ + data: [{ key: 'mocked-key', name: 'mocked-name', property: 'foo' }] }) - expect(secretPropertyValues).to.deep.equal(['bar']) + expect(secretPropertyValues).to.deep.equal([{ 'mocked-name': 'bar' }]) }) it('handles invalid JSON objects', async () => { kvBackend._get.onFirstCall().resolves('{') const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ - externalData: [{ + data: [{ key: 'mocked-key', name: 'mocked-name', property: 'foo' @@ -71,7 +71,7 @@ describe('SecretsManagerBackend', () => { kvBackend._get.onSecondCall().resolves('fakePropertyValue2') const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ - externalData: [{ + data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' }, { @@ -90,7 +90,7 @@ describe('SecretsManagerBackend', () => { secretKey: 'fakePropertyKey2', roleArn: undefined })).to.equal(true) - expect(secretPropertyValues).deep.equals(['fakePropertyValue1', 'fakePropertyValue2']) + expect(secretPropertyValues).deep.equals([{ fakePropertyName1: 'fakePropertyValue1' }, { fakePropertyName2: 'fakePropertyValue2' }]) }) it('fetches secret property values using the specified role', async () => { @@ -98,7 +98,7 @@ describe('SecretsManagerBackend', () => { kvBackend._get.onSecondCall().resolves('fakePropertyValue2') const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ - externalData: [{ + data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' }, { @@ -118,7 +118,7 @@ describe('SecretsManagerBackend', () => { secretKey: 'fakePropertyKey2', roleArn: 'secretDescriptiorRole' })).to.equal(true) - expect(secretPropertyValues).deep.equals(['fakePropertyValue1', 'fakePropertyValue2']) + expect(secretPropertyValues).deep.equals([{ fakePropertyName1: 'fakePropertyValue1' }, { fakePropertyName2: 'fakePropertyValue2' }]) }) }) @@ -139,30 +139,97 @@ describe('SecretsManagerBackend', () => { describe('getSecretManifestData', () => { beforeEach(() => { - kvBackend._fetchSecretPropertyValues = sinon.stub() + kvBackend._fetchSecretPropertyValues = sinon.stub().resolves([]) + kvBackend._fetchSecretPropertyValuesFrom = sinon.stub().resolves([]) }) it('returns secret manifest data', async () => { kvBackend._fetchSecretPropertyValues - .resolves(['fakePropertyValue1', 'fakePropertyValue2']) + .resolves([{ + fakePropertyName0: 'should-be-overriden', + fakePropertyName1: 'fakePropertyValue1' + }, { + fakePropertyName0: 'fakePropertyValue0', + fakePropertyName2: 'fakePropertyValue2' + }]) + kvBackend._fetchSecretPropertyValuesFrom + .resolves([{ + fakePropertyName2: 'should-be-overriden', // Overriden by data + fakePropertyName3: 'fakePropertyValue3', // not overriden + fakePropertyName4: 'should-be-overriden' // Overriden by secondary dataFrom + }, { + fakePropertyName4: 'fakePropertyValue4', + fakePropertyName5: 'fakePropertyValue5' // not overriden + }]) const manifestData = await kvBackend .getSecretManifestData({ - secretDescriptor: { - backendType: 'fakeBackendType', - name: 'fakeSecretName', - properties: [{ + secretDescriptor: { } + }) + + expect(manifestData).deep.equals({ + fakePropertyName0: 'ZmFrZVByb3BlcnR5VmFsdWUw', // base 64 value of fakePropertyValue0 + fakePropertyName1: 'ZmFrZVByb3BlcnR5VmFsdWUx', // base 64 value of fakePropertyValue1 + fakePropertyName2: 'ZmFrZVByb3BlcnR5VmFsdWUy', // base 64 value of fakePropertyValue2 + fakePropertyName3: 'ZmFrZVByb3BlcnR5VmFsdWUz', // base 64 value of fakePropertyValue3 + fakePropertyName4: 'ZmFrZVByb3BlcnR5VmFsdWU0', // base 64 value of fakePropertyValue4 + fakePropertyName5: 'ZmFrZVByb3BlcnR5VmFsdWU1' // base 64 value of fakePropertyValue5 + }) + }) + + it('makes correct calls - with data and role', async () => { + await kvBackend.getSecretManifestData({ + secretDescriptor: { + data: [ + { key: 'fakePropertyKey1', name: 'fakePropertyName1' }, { key: 'fakePropertyKey2', name: 'fakePropertyName2' - }] - } - }) + } + ], + roleArn: 'my-role' + } + }) expect(kvBackend._fetchSecretPropertyValues.calledWith({ - externalData: [{ + data: [{ + key: 'fakePropertyKey1', + name: 'fakePropertyName1' + }, { + key: 'fakePropertyKey2', + name: 'fakePropertyName2' + }], + roleArn: 'my-role' + })).to.equal(true) + + expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + dataFrom: [], + roleArn: 'my-role' + })).to.equal(true) + }) + + it('makes correct calls - with properties and dataFrom', async () => { + await kvBackend.getSecretManifestData({ + secretDescriptor: { + properties: [ + { + key: 'fakePropertyKey1', + name: 'fakePropertyName1' + }, { + key: 'fakePropertyKey2', + name: 'fakePropertyName2' + } + ], + dataFrom: [ + 'fakeDataFromKey1' + ] + } + }) + + expect(kvBackend._fetchSecretPropertyValues.calledWith({ + data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' }, { @@ -171,10 +238,31 @@ describe('SecretsManagerBackend', () => { }], roleArn: undefined })).to.equal(true) - expect(manifestData).deep.equals({ - fakePropertyName1: 'ZmFrZVByb3BlcnR5VmFsdWUx', // base 64 value - fakePropertyName2: 'ZmFrZVByb3BlcnR5VmFsdWUy' // base 64 value + + expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + dataFrom: ['fakeDataFromKey1'], + roleArn: undefined + })).to.equal(true) + }) + it('makes correct calls - with only dataFrom', async () => { + await kvBackend.getSecretManifestData({ + secretDescriptor: { + dataFrom: [ + 'fakeDataFromKey1', + 'fakeDataFromKey2' + ] + } }) + + expect(kvBackend._fetchSecretPropertyValues.calledWith({ + data: [], + roleArn: undefined + })).to.equal(true) + + expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + dataFrom: ['fakeDataFromKey1', 'fakeDataFromKey2'], + roleArn: undefined + })).to.equal(true) }) }) }) From 87817a097a465ab1f3d563a2253de620ab7ebfa4 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:08:18 +0100 Subject: [PATCH 2/9] chore: bump node version --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 0035da14..17b32cb0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:10.15.1-alpine +FROM node:12.13.0-alpine ENV NODE_ENV production ENV NPM_CONFIG_LOGLEVEL info From 84ba3ef80bf6a22eae344ff6ba9f0bd3820015f4 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:12:28 +0100 Subject: [PATCH 3/9] fix: naming, ordering, log msg --- lib/backends/kv-backend.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index 7319c33b..68fde43b 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -60,7 +60,7 @@ class KVBackend extends AbstractBackend { */ _fetchSecretPropertyValuesFrom ({ dataFrom, roleArn }) { return Promise.all(dataFrom.map(async secretKey => { - this._logger.info(`fetching secret property ${secretKey} with role: ${roleArn || 'no role set'}`) + this._logger.info(`fetching secret ${secretKey} with role: ${roleArn || 'no role set'}`) const value = await this._get({ secretKey, roleArn }) let parsedValue @@ -97,12 +97,12 @@ class KVBackend extends AbstractBackend { roleArn } }) { - const [secretPropertyValues, secretPropertyValuesFrom] = await Promise.all([ - this._fetchSecretPropertyValues({ data, roleArn }), - this._fetchSecretPropertyValuesFrom({ dataFrom, roleArn }) + const [dataFromValues, dataValues] = await Promise.all([ + this._fetchSecretPropertyValuesFrom({ dataFrom, roleArn }), + this._fetchSecretPropertyValues({ data, roleArn }) ]) - const plainValues = secretPropertyValuesFrom.concat(secretPropertyValues) + const plainValues = dataFromValues.concat(dataValues) .reduce((acc, parsedValue) => ({ ...acc, ...parsedValue From c6cba5ebf3e0511d22c19c55e1f30c7843ff3225 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:21:22 +0100 Subject: [PATCH 4/9] chore: tests --- lib/backends/kv-backend.js | 2 +- lib/backends/kv-backend.test.js | 71 ++++++++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 3 deletions(-) diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index 68fde43b..e0c6aa1f 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -58,7 +58,7 @@ class KVBackend extends AbstractBackend { * @param {string} roleArn - If the client should assume a role before fetching the secret * @returns {Promise} Promise object representing secret property values. */ - _fetchSecretPropertyValuesFrom ({ dataFrom, roleArn }) { + _fetchDataFromValues ({ dataFrom, roleArn }) { return Promise.all(dataFrom.map(async secretKey => { this._logger.info(`fetching secret ${secretKey} with role: ${roleArn || 'no role set'}`) const value = await this._get({ secretKey, roleArn }) diff --git a/lib/backends/kv-backend.test.js b/lib/backends/kv-backend.test.js index a4a47395..db91b581 100644 --- a/lib/backends/kv-backend.test.js +++ b/lib/backends/kv-backend.test.js @@ -122,6 +122,62 @@ describe('SecretsManagerBackend', () => { }) }) + describe('_fetchDataFromValues', () => { + beforeEach(() => { + kvBackend._get = sinon.stub() + }) + + it('handles secrets values that are objects', async () => { + kvBackend._get.onFirstCall().resolves('{"foo":"bar"}') + const dataFromValues = await kvBackend._fetchDataFromValues({ + dataFrom: ['mocked-key'] + }) + expect(dataFromValues).to.deep.equal([{ foo: 'bar' }]) + }) + + it('handles invalid JSON objects', async () => { + kvBackend._get.onFirstCall().resolves('{') + const dataFromValues = await kvBackend._fetchDataFromValues({ + dataFrom: ['mocked-key'] + }) + expect(dataFromValues).to.deep.equal([undefined]) + }) + + it('disregards plain values', async () => { + kvBackend._get.onFirstCall().resolves('fakePropertyValue1') + + const dataFromValues = await kvBackend._fetchDataFromValues({ + dataFrom: ['fakePropertyKey1'] + }) + + expect(kvBackend._get.calledWith({ + secretKey: 'fakePropertyKey1', + roleArn: undefined + })).to.equal(true) + expect(dataFromValues).deep.equals([undefined]) + }) + + it('fetches secret property values using the specified role', async () => { + kvBackend._get.onFirstCall().resolves('{"fakePropertyName1":"fakePropertyValue1"}') + kvBackend._get.onSecondCall().resolves('{"fakePropertyName2":"fakePropertyValue2"}') + + const dataFromValues = await kvBackend._fetchDataFromValues({ + dataFrom: ['fakePropertyKey1', 'fakePropertyKey2'], + roleArn: 'secretDescriptiorRole' + }) + + expect(kvBackend._get.calledWith({ + secretKey: 'fakePropertyKey1', + roleArn: 'secretDescriptiorRole' + })).to.equal(true) + expect(kvBackend._get.calledWith({ + secretKey: 'fakePropertyKey2', + roleArn: 'secretDescriptiorRole' + })).to.equal(true) + expect(dataFromValues).deep.equals([{ fakePropertyName1: 'fakePropertyValue1' }, { fakePropertyName2: 'fakePropertyValue2' }]) + }) + }) + describe('_get', () => { it('throws an error', () => { let error @@ -151,13 +207,13 @@ describe('SecretsManagerBackend', () => { }, { fakePropertyName0: 'fakePropertyValue0', fakePropertyName2: 'fakePropertyValue2' - }]) + }, undefined]) kvBackend._fetchSecretPropertyValuesFrom .resolves([{ fakePropertyName2: 'should-be-overriden', // Overriden by data fakePropertyName3: 'fakePropertyValue3', // not overriden fakePropertyName4: 'should-be-overriden' // Overriden by secondary dataFrom - }, { + }, undefined, { fakePropertyName4: 'fakePropertyValue4', fakePropertyName5: 'fakePropertyValue5' // not overriden }]) @@ -177,6 +233,16 @@ describe('SecretsManagerBackend', () => { }) }) + it('handles undefined data', async () => { + kvBackend._fetchSecretPropertyValues.resolves([undefined]) + kvBackend._fetchSecretPropertyValuesFrom.resolves([undefined]) + + const manifestData = await kvBackend + .getSecretManifestData({ secretDescriptor: { } }) + + expect(manifestData).deep.equals({}) + }) + it('makes correct calls - with data and role', async () => { await kvBackend.getSecretManifestData({ secretDescriptor: { @@ -244,6 +310,7 @@ describe('SecretsManagerBackend', () => { roleArn: undefined })).to.equal(true) }) + it('makes correct calls - with only dataFrom', async () => { await kvBackend.getSecretManifestData({ secretDescriptor: { From 32ca58238ef9d3e1c058c1e044f3f7d148e9c29a Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:22:23 +0100 Subject: [PATCH 5/9] chore: bump node version in travis --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 83895594..22c30e3e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ language: node_js matrix: fast_finish: true include: - - node_js: '10' + - node_js: '12' # https://github.com/greenkeeperio/greenkeeper-lockfile#npm before_install: # package-lock.json was introduced in npm@5 From 8a3c71b181f7050956dc00e4160a02e6d4d5edb0 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:29:17 +0100 Subject: [PATCH 6/9] fix: renaming everywhere helps.. --- lib/backends/kv-backend.js | 2 +- lib/backends/kv-backend.test.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index e0c6aa1f..fff36dd4 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -98,7 +98,7 @@ class KVBackend extends AbstractBackend { } }) { const [dataFromValues, dataValues] = await Promise.all([ - this._fetchSecretPropertyValuesFrom({ dataFrom, roleArn }), + this._fetchDataFromValues({ dataFrom, roleArn }), this._fetchSecretPropertyValues({ data, roleArn }) ]) diff --git a/lib/backends/kv-backend.test.js b/lib/backends/kv-backend.test.js index db91b581..0bc0c18f 100644 --- a/lib/backends/kv-backend.test.js +++ b/lib/backends/kv-backend.test.js @@ -196,7 +196,7 @@ describe('SecretsManagerBackend', () => { describe('getSecretManifestData', () => { beforeEach(() => { kvBackend._fetchSecretPropertyValues = sinon.stub().resolves([]) - kvBackend._fetchSecretPropertyValuesFrom = sinon.stub().resolves([]) + kvBackend._fetchDataFromValues = sinon.stub().resolves([]) }) it('returns secret manifest data', async () => { @@ -208,7 +208,7 @@ describe('SecretsManagerBackend', () => { fakePropertyName0: 'fakePropertyValue0', fakePropertyName2: 'fakePropertyValue2' }, undefined]) - kvBackend._fetchSecretPropertyValuesFrom + kvBackend._fetchDataFromValues .resolves([{ fakePropertyName2: 'should-be-overriden', // Overriden by data fakePropertyName3: 'fakePropertyValue3', // not overriden @@ -235,7 +235,7 @@ describe('SecretsManagerBackend', () => { it('handles undefined data', async () => { kvBackend._fetchSecretPropertyValues.resolves([undefined]) - kvBackend._fetchSecretPropertyValuesFrom.resolves([undefined]) + kvBackend._fetchDataFromValues.resolves([undefined]) const manifestData = await kvBackend .getSecretManifestData({ secretDescriptor: { } }) @@ -270,7 +270,7 @@ describe('SecretsManagerBackend', () => { roleArn: 'my-role' })).to.equal(true) - expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + expect(kvBackend._fetchDataFromValues.calledWith({ dataFrom: [], roleArn: 'my-role' })).to.equal(true) @@ -305,7 +305,7 @@ describe('SecretsManagerBackend', () => { roleArn: undefined })).to.equal(true) - expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + expect(kvBackend._fetchDataFromValues.calledWith({ dataFrom: ['fakeDataFromKey1'], roleArn: undefined })).to.equal(true) @@ -326,7 +326,7 @@ describe('SecretsManagerBackend', () => { roleArn: undefined })).to.equal(true) - expect(kvBackend._fetchSecretPropertyValuesFrom.calledWith({ + expect(kvBackend._fetchDataFromValues.calledWith({ dataFrom: ['fakeDataFromKey1', 'fakeDataFromKey2'], roleArn: undefined })).to.equal(true) From 4d78c0ad25c9756de9813295e587a4fe267beb83 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 02:35:43 +0100 Subject: [PATCH 7/9] chore: bump node version in engines --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f434989e..863ec43b 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "maintainer": "Jacopo Daeli ", "license": "MIT", "engines": { - "node": ">=10.0.0" + "node": ">=12.0.0" }, "dependencies": { "aws-sdk": "^2.433.0", From fd429c3029095d768a044079d8802eda76e9c700 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 03:12:18 +0100 Subject: [PATCH 8/9] refactor: simplify in fetchDataFromValues --- lib/backends/kv-backend.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index fff36dd4..617b4f2a 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -63,16 +63,12 @@ class KVBackend extends AbstractBackend { this._logger.info(`fetching secret ${secretKey} with role: ${roleArn || 'no role set'}`) const value = await this._get({ secretKey, roleArn }) - let parsedValue try { - parsedValue = JSON.parse(value) + return JSON.parse(value) } catch (err) { this._logger.warn(`Failed to JSON.parse value for '${secretKey}',` + ` please verify that your secret value is correctly formatted as JSON.`) - return } - - return parsedValue })) } From d69b42e11525f5fbfb327ca226b985d58a8aa369 Mon Sep 17 00:00:00 2001 From: Markus Maga Date: Tue, 5 Nov 2019 20:48:54 +0100 Subject: [PATCH 9/9] refactor: rename _fetchSecretPropertyValues to _fetchDataValues --- lib/backends/kv-backend.js | 4 ++-- lib/backends/kv-backend.test.js | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/lib/backends/kv-backend.js b/lib/backends/kv-backend.js index 617b4f2a..302d5fe1 100644 --- a/lib/backends/kv-backend.js +++ b/lib/backends/kv-backend.js @@ -23,7 +23,7 @@ class KVBackend extends AbstractBackend { * @param {string} roleArn - If the client should assume a role before fetching the secret * @returns {Promise} Promise object representing secret property values. */ - _fetchSecretPropertyValues ({ data, roleArn }) { + _fetchDataValues ({ data, roleArn }) { return Promise.all(data.map(async secretProperty => { this._logger.info(`fetching secret property ${secretProperty.name} with role: ${roleArn || 'no role set'}`) const plainOrObjValue = await this._get({ secretKey: secretProperty.key, roleArn }) @@ -95,7 +95,7 @@ class KVBackend extends AbstractBackend { }) { const [dataFromValues, dataValues] = await Promise.all([ this._fetchDataFromValues({ dataFrom, roleArn }), - this._fetchSecretPropertyValues({ data, roleArn }) + this._fetchDataValues({ data, roleArn }) ]) const plainValues = dataFromValues.concat(dataValues) diff --git a/lib/backends/kv-backend.test.js b/lib/backends/kv-backend.test.js index 0bc0c18f..fede2a61 100644 --- a/lib/backends/kv-backend.test.js +++ b/lib/backends/kv-backend.test.js @@ -20,7 +20,7 @@ describe('SecretsManagerBackend', () => { }) }) - describe('_fetchSecretPropertyValues', () => { + describe('_fetchDataValues', () => { beforeEach(() => { // NOTE(jdaeli): overriding abstract method _get kvBackend._get = sinon.stub() @@ -29,7 +29,7 @@ describe('SecretsManagerBackend', () => { it('throws an error if missing a property', async () => { kvBackend._get.onFirstCall().resolves('{"foo":"bar"}') try { - await kvBackend._fetchSecretPropertyValues({ + await kvBackend._fetchDataValues({ data: [{ key: 'mocked-key', name: 'mocked-name', @@ -44,7 +44,7 @@ describe('SecretsManagerBackend', () => { it('handles secrets values that are objects', async () => { kvBackend._get.onFirstCall().resolves('{"foo":"bar"}') - const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ + const secretPropertyValues = await kvBackend._fetchDataValues({ data: [{ key: 'mocked-key', name: 'mocked-name', @@ -56,7 +56,7 @@ describe('SecretsManagerBackend', () => { it('handles invalid JSON objects', async () => { kvBackend._get.onFirstCall().resolves('{') - const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ + const secretPropertyValues = await kvBackend._fetchDataValues({ data: [{ key: 'mocked-key', name: 'mocked-name', @@ -70,7 +70,7 @@ describe('SecretsManagerBackend', () => { kvBackend._get.onFirstCall().resolves('fakePropertyValue1') kvBackend._get.onSecondCall().resolves('fakePropertyValue2') - const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ + const secretPropertyValues = await kvBackend._fetchDataValues({ data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' @@ -97,7 +97,7 @@ describe('SecretsManagerBackend', () => { kvBackend._get.onFirstCall().resolves('fakePropertyValue1') kvBackend._get.onSecondCall().resolves('fakePropertyValue2') - const secretPropertyValues = await kvBackend._fetchSecretPropertyValues({ + const secretPropertyValues = await kvBackend._fetchDataValues({ data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' @@ -195,12 +195,12 @@ describe('SecretsManagerBackend', () => { describe('getSecretManifestData', () => { beforeEach(() => { - kvBackend._fetchSecretPropertyValues = sinon.stub().resolves([]) + kvBackend._fetchDataValues = sinon.stub().resolves([]) kvBackend._fetchDataFromValues = sinon.stub().resolves([]) }) it('returns secret manifest data', async () => { - kvBackend._fetchSecretPropertyValues + kvBackend._fetchDataValues .resolves([{ fakePropertyName0: 'should-be-overriden', fakePropertyName1: 'fakePropertyValue1' @@ -234,7 +234,7 @@ describe('SecretsManagerBackend', () => { }) it('handles undefined data', async () => { - kvBackend._fetchSecretPropertyValues.resolves([undefined]) + kvBackend._fetchDataValues.resolves([undefined]) kvBackend._fetchDataFromValues.resolves([undefined]) const manifestData = await kvBackend @@ -259,7 +259,7 @@ describe('SecretsManagerBackend', () => { } }) - expect(kvBackend._fetchSecretPropertyValues.calledWith({ + expect(kvBackend._fetchDataValues.calledWith({ data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' @@ -294,7 +294,7 @@ describe('SecretsManagerBackend', () => { } }) - expect(kvBackend._fetchSecretPropertyValues.calledWith({ + expect(kvBackend._fetchDataValues.calledWith({ data: [{ key: 'fakePropertyKey1', name: 'fakePropertyName1' @@ -321,7 +321,7 @@ describe('SecretsManagerBackend', () => { } }) - expect(kvBackend._fetchSecretPropertyValues.calledWith({ + expect(kvBackend._fetchDataValues.calledWith({ data: [], roleArn: undefined })).to.equal(true)