Skip to content
This repository has been archived by the owner on Jul 26, 2022. It is now read-only.

Commit

Permalink
feat: add support for using either Vault k/v 1 or k/v 2 (#426)
Browse files Browse the repository at this point in the history
  • Loading branch information
Flydiverny authored Jul 12, 2020
1 parent 1b18c55 commit 4193050
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ spec:
type: string
vaultMountPoint:
type: string
kvVersion:
description: Vault K/V version either 1 or 2, default = 2
type: integer
minimum: 1
maximum: 2
keyVaultName:
type: string
key:
Expand Down
1 change: 1 addition & 0 deletions examples/hello-service-external-secret-vault.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ spec:
backendType: vault
vaultMountPoint: my-kubernetes-vault-mount-point
vaultRole: my-vault-role
kvVersion: 2 # defaults to 2
data:
- name: password
key: secret/data/hello-service/password
Expand Down
16 changes: 16 additions & 0 deletions examples/vault-kv1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
apiVersion: 'kubernetes-client.io/v1'
kind: ExternalSecret
metadata:
name: database-credentials-from-kv1
spec:
backendType: vault
vaultMountPoint: my-kubernetes-vault-mount-point
vaultRole: my-vault-role
kvVersion: 1
data:
- name: username
key: kv/database
property: db-username
- name: password
key: kv/database
property: db-password
13 changes: 11 additions & 2 deletions lib/backends/vault-backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ class VaultBackend extends KVBackend {
* @param {object} specOptions - Options for this external secret, eg role
* @param {string} specOptions.vaultMountPoint - mount point
* @param {string} specOptions.vaultRole - role
* @param {number} specOptions.kvVersion - K/V Version 1 or 2
* @returns {Promise} Promise object representing secret property values.
*/
async _get ({ key, specOptions: { vaultMountPoint, vaultRole } }) {
async _get ({ key, specOptions: { vaultMountPoint, vaultRole, kvVersion = 2 } }) {
if (!this._client.token) {
const jwt = this._fetchServiceAccountToken()
this._logger.debug('fetching new token from vault')
Expand All @@ -53,7 +54,15 @@ class VaultBackend extends KVBackend {
this._logger.debug(`reading secret key ${key} from vault`)
const secretResponse = await this._client.read(key)

return JSON.stringify(secretResponse.data.data)
if (kvVersion === 1) {
return JSON.stringify(secretResponse.data)
}

if (kvVersion === 2) {
return JSON.stringify(secretResponse.data.data)
}

throw new Error('Unknown "kvVersion" specified')
}
}

Expand Down
75 changes: 67 additions & 8 deletions lib/backends/vault-backend.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,21 @@ describe('VaultBackend', () => {
const role = 'fakeRole'
const secretKey = 'fakeSecretKey'
const secretValue = 'open, sesame'
const quotedSecretValue = '"' + secretValue + '"'
const secretData = { [secretKey]: secretValue }
const quotedSecretValue = JSON.stringify(secretData)
const quotedSecretValueAsBase64 = Buffer.from(quotedSecretValue).toString('base64')
const jwt = 'this-is-a-jwt-token'

const kv1Secret = {
data: secretData
}

const kv2Secret = {
data: {
data: secretData
}
}

beforeEach(() => {
clientMock = sinon.mock()

Expand All @@ -34,11 +45,7 @@ describe('VaultBackend', () => {

describe('_get', () => {
beforeEach(() => {
clientMock.read = sinon.stub().returns({
data: {
data: secretValue
}
})
clientMock.read = sinon.stub().returns(kv2Secret)
clientMock.tokenRenewSelf = sinon.stub().returns(true)
clientMock.kubernetesLogin = sinon.stub().returns({
auth: {
Expand All @@ -51,7 +58,7 @@ describe('VaultBackend', () => {
clientMock.token = undefined
})

it('logs in and returns secret property value', async () => {
it('logs in and returns secret property value - default', async () => {
const secretPropertyValue = await vaultBackend._get({
specOptions: {
vaultMountPoint: mountPoint,
Expand All @@ -74,6 +81,58 @@ describe('VaultBackend', () => {
expect(secretPropertyValue).equals(quotedSecretValue)
})

it('logs in and returns secret property value - kv version 1', async () => {
clientMock.read = sinon.stub().returns(kv1Secret)

const secretPropertyValue = await vaultBackend._get({
specOptions: {
vaultMountPoint: mountPoint,
vaultRole: role,
kvVersion: 1
},
key: secretKey
})

// First, we log into Vault...
sinon.assert.calledWith(clientMock.kubernetesLogin, {
mount_point: mountPoint,
role: role,
jwt: jwt
})

// ... then we fetch the secret ...
sinon.assert.calledWith(clientMock.read, secretKey)

// ... and expect to get its proper value
expect(secretPropertyValue).equals(quotedSecretValue)
})

it('logs in and returns secret property value - kv version 2', async () => {
clientMock.read = sinon.stub().returns(kv2Secret)

const secretPropertyValue = await vaultBackend._get({
specOptions: {
vaultMountPoint: mountPoint,
vaultRole: role,
kvVersion: 2
},
key: secretKey
})

// First, we log into Vault...
sinon.assert.calledWith(clientMock.kubernetesLogin, {
mount_point: mountPoint,
role: role,
jwt: jwt
})

// ... then we fetch the secret ...
sinon.assert.calledWith(clientMock.read, secretKey)

// ... and expect to get its proper value
expect(secretPropertyValue).equals(quotedSecretValue)
})

it('returns secret property value after renewing token if a token exists', async () => {
clientMock.token = 'an-existing-token'

Expand Down Expand Up @@ -101,7 +160,7 @@ describe('VaultBackend', () => {

describe('getSecretManifestData', () => {
beforeEach(() => {
clientMock.read = sinon.stub().returns({ data: { data: secretValue } })
clientMock.read = sinon.stub().returns(kv2Secret)
clientMock.tokenRenewSelf = sinon.stub().returns(true)
clientMock.kubernetesLogin = sinon.stub().returns({ auth: { client_token: '1234' } })

Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,16 @@
"@alicloud/kms20160120": "^1.1.0",
"@azure/identity": "^1.0.2",
"@azure/keyvault-secrets": "^4.0.2",
"aws-sdk": "^2.628.0",
"@google-cloud/secret-manager": "^1.2.1",
"aws-sdk": "^2.628.0",
"express": "^4.17.1",
"js-yaml": "^3.13.1",
"json-stream": "^1.0.0",
"kubernetes-client": "^9.0.0",
"lodash.clonedeep": "^4.5.0",
"lodash.merge": "^4.6.2",
"make-promises-safe": "^5.1.0",
"node-vault": "^0.9.8",
"node-vault": "^0.9.18",
"pino": "^6.0.0",
"prom-client": "^12.0.0"
},
Expand Down

0 comments on commit 4193050

Please sign in to comment.