Compare commits

...

12 Commits

Author SHA1 Message Date
Antoine Méausoone 3747195c5f feat(namespace): handle request on vault namespace (#5)
* feat(namespace): handle request on vault namespace
2019-11-24 15:21:11 -06:00
Richard Simpson 0104a02854 doc: fix old docs 2019-10-16 10:23:36 -05:00
Richard Simpson c81d6f1774 doc: add small clarification comment 2019-10-16 10:17:12 -05:00
Richard Simpson da9a93f3f5 fix: package action (#3)
Package action output per github docs.
2019-10-15 14:00:01 -05:00
Richard Simpson 6784ab3896 chore: try using different env name? 2019-09-20 18:33:56 -05:00
Richard Simpson 609488b35d chore: fix formatter fail 2019-09-20 18:29:04 -05:00
Richard Simpson 42871c7c42 chore: switch to semantic release 2019-09-20 18:28:48 -05:00
Richard Simpson 9c822dc25c chore: fix env var name 2019-09-20 18:23:30 -05:00
Richard Simpson bb5aae504b chore: add github token 2019-09-20 18:20:54 -05:00
Richard Simpson 6adb719ae2 chore: fix type 2019-09-20 18:18:14 -05:00
Richard Simpson 54b24ddb30 chore: add auto 2019-09-20 18:16:55 -05:00
Richard Simpson fbe0bd395b feat: bump name and add branding 2019-09-20 18:00:21 -05:00
11 changed files with 10634 additions and 66 deletions
@@ -1,26 +1,7 @@
name: Test
on: [push] on: [push]
jobs: jobs:
unit: test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install and test
run: |
npm ci
npm test
env:
CI: true
integration:
runs-on: ubuntu-latest runs-on: ubuntu-latest
services: services:
@@ -40,11 +21,51 @@ jobs:
node-version: 10.x node-version: 10.x
- name: npm install - name: npm install
run: npm ci run: npm ci
- name: npm build
run: npm run build
- name: npm run test
run: npm run test
env:
CI: true
- name: npm run test:integration - name: npm run test:integration
run: npm run test:integration run: npm run test:integration
env: env:
VAULT_HOST: localhost VAULT_HOST: localhost
VAULT_PORT: ${{ job.services.vault.ports[8200] }} VAULT_PORT: ${{ job.services.vault.ports[8200] }}
CI: true
test-ent:
runs-on: ubuntu-latest
services:
vault:
image: hashicorp/vault-enterprise:1.3.0_ent
ports:
- 8200/tcp
env:
VAULT_DEV_ROOT_TOKEN_ID: testtoken
options: --cap-add=IPC_LOCK
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: npm ci
- name: npm build
run: npm run build
- name: npm run test
run: npm run test
env:
CI: true
- name: npm run test:integration-ent
run: npm run test:integration-ent
env:
VAULT_HOST: localhost
VAULT_PORT: ${{ job.services.vault.ports[8200] }}
CI: true
e2e: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -66,6 +87,8 @@ jobs:
node-version: 10.x node-version: 10.x
- name: npm install - name: npm install
run: npm ci run: npm ci
- name: npm build
run: npm run build
- name: setup vault - name: setup vault
run: node ./e2e/setup.js run: node ./e2e/setup.js
env: env:
@@ -83,5 +106,20 @@ jobs:
- name: verify - name: verify
run: npm run test:e2e run: npm run test:e2e
publish:
runs-on: ubuntu-latest
needs: [test, e2e]
steps:
- uses: actions/checkout@v1
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: npm install
run: npm ci
- name: release
if: success() && endsWith(github.ref, 'master')
run: npx semantic-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+21 -2
View File
@@ -1,6 +1,6 @@
# vault-action # vault-action
A helper action for easily pulling secrets from the v2 K/V backend of vault. A helper action for easily pulling secrets from the default v2 K/V backend of vault.
## Example Usage ## Example Usage
@@ -68,11 +68,30 @@ This action can take multi-line input, so say you had your AWS keys stored in a
```yaml ```yaml
with: with:
keys: | secrets: |
ci/aws accessKey | AWS_ACCESS_KEY_ID ; ci/aws accessKey | AWS_ACCESS_KEY_ID ;
ci/aws secretKey | AWS_SECRET_ACCESS_KEY ci/aws secretKey | AWS_SECRET_ACCESS_KEY
``` ```
### Namespace
This action could be use with namespace Vault Enterprise feature. You can specify namespace in request :
```yaml
steps:
# ...
- name: Import Secrets
uses: RichiCoder1/vault-action
with:
url: https://vault-enterprise.mycompany.com:8200
token: ${{ secrets.VaultToken }}
namespace: ns1
secrets: |
ci/aws accessKey | AWS_ACCESS_KEY_ID ;
ci/aws secretKey | AWS_SECRET_ACCESS_KEY ;
ci npm_token
```
## Masking ## Masking
This action uses Github Action's built in masking, so all variables will automatically be masked if printed to the console or to logs. This action uses Github Action's built in masking, so all variables will automatically be masked if printed to the console or to logs.
+9 -3
View File
@@ -5,17 +5,23 @@ const got = require('got');
async function exportSecrets() { async function exportSecrets() {
const vaultUrl = core.getInput('url', { required: true }); const vaultUrl = core.getInput('url', { required: true });
const vaultToken = core.getInput('token', { required: true }); const vaultToken = core.getInput('token', { required: true });
const vaultNamespace = core.getInput('namespace', { required: false });
const secretsInput = core.getInput('secrets', { required: true }); const secretsInput = core.getInput('secrets', { required: true });
const secrets = parseSecretsInput(secretsInput); const secrets = parseSecretsInput(secretsInput);
for (const secret of secrets) { for (const secret of secrets) {
const { secretPath, outputName, secretKey } = secret; const { secretPath, outputName, secretKey } = secret;
const result = await got(`${vaultUrl}/v1/secret/data/${secretPath}`, { const requestOptions = {
headers: { headers: {
'X-Vault-Token': vaultToken 'X-Vault-Token': vaultToken
} }};
});
if (vaultNamespace != null){
requestOptions.headers["X-Vault-Namespace"] = vaultNamespace
}
const result = await got(`${vaultUrl}/v1/secret/data/${secretPath}`, requestOptions);
const parsedResponse = JSON.parse(result.body); const parsedResponse = JSON.parse(result.body);
const vaultKeyData = parsedResponse.data; const vaultKeyData = parsedResponse.data;
+8 -2
View File
@@ -1,4 +1,4 @@
name: 'Vault' name: 'Vault Secrets'
description: 'A Github Action that allows you to consume the v2 K/V backend of HashiCorp Vault as secure environment variables' description: 'A Github Action that allows you to consume the v2 K/V backend of HashiCorp Vault as secure environment variables'
inputs: inputs:
url: url:
@@ -10,6 +10,12 @@ inputs:
secrets: secrets:
description: 'A semicolon-separated list of secrets to retrieve. These will automatically be converted to environmental variable keys. See README for more details' description: 'A semicolon-separated list of secrets to retrieve. These will automatically be converted to environmental variable keys. See README for more details'
required: true required: true
namespace:
description: 'The Vault namespace from which to query secrets. Vault Enterprise only, unset by default'
required: false
runs: runs:
using: 'node12' using: 'node12'
main: 'index.js' main: 'dist/index.js'
branding:
icon: 'unlock'
color: 'gray-dark'
+4744
View File
File diff suppressed because it is too large Load Diff
+12
View File
@@ -0,0 +1,12 @@
# Start vault server locally
# You can run integration tests against server by running
# `VAULT_HOST=localhost VAULT_PORT=8200 CI=true npm run test:integration-ent`
version: "3.0"
services:
vault:
image: hashicorp/vault-enterprise:1.3.0_ent
environment:
VAULT_DEV_ROOT_TOKEN_ID: testtoken
ports:
- 8200:8200
privileged: true
+131
View File
@@ -0,0 +1,131 @@
jest.mock('@actions/core');
jest.mock('@actions/core/lib/command');
const core = require('@actions/core');
const got = require('got');
const { when } = require('jest-when');
const { exportSecrets } = require('../action');
describe('integration', () => {
beforeAll(async () => {
// Verify Connection
await got(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}/v1/secret/config`, {
headers: {
'X-Vault-Token': 'testtoken',
},
});
// Create namespace
await got(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}/v1/sys/namespaces/ns1`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
},
json: true,
});
// Enable secret engine
await got(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}/v1/sys/mounts/secret`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
'X-Vault-Namespace': 'ns1',
},
body: {"path":"secret","type":"kv","config":{},"options":{"version":2},"generate_signing_key":true},
json: true,
});
await got(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}/v1/secret/data/test`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
'X-Vault-Namespace': 'ns1',
},
body: {
data: {
secret: "SUPERSECRET_IN_NAMESPACE",
},
},
json: true,
});
await got(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}/v1/secret/data/nested/test`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
'X-Vault-Namespace': 'ns1',
},
body: {
data: {
otherSecret: "OTHERSUPERSECRET_IN_NAMESPACE",
},
},
json: true,
});
})
beforeEach(() => {
jest.resetAllMocks();
when(core.getInput)
.calledWith('url')
.mockReturnValue(`http://${process.env.VAULT_HOST}:${process.env.VAULT_PORT}`);
when(core.getInput)
.calledWith('token')
.mockReturnValue('testtoken');
when(core.getInput)
.calledWith('namespace')
.mockReturnValue('ns1');
});
function mockInput(secrets) {
when(core.getInput)
.calledWith('secrets')
.mockReturnValue(secrets);
}
it('get simple secret', async () => {
mockInput('test secret')
await exportSecrets();
expect(core.exportVariable).toBeCalledWith('SECRET', 'SUPERSECRET_IN_NAMESPACE');
});
it('re-map secret', async () => {
mockInput('test secret | TEST_KEY')
await exportSecrets();
expect(core.exportVariable).toBeCalledWith('TEST_KEY', 'SUPERSECRET_IN_NAMESPACE');
});
it('get nested secret', async () => {
mockInput('nested/test otherSecret')
await exportSecrets();
expect(core.exportVariable).toBeCalledWith('OTHERSECRET', 'OTHERSUPERSECRET_IN_NAMESPACE');
});
it('get multiple secrets', async () => {
mockInput(`
test secret ;
test secret | NAMED_SECRET ;
nested/test otherSecret ;`);
await exportSecrets();
expect(core.exportVariable).toBeCalledTimes(3);
expect(core.exportVariable).toBeCalledWith('SECRET', 'SUPERSECRET_IN_NAMESPACE');
expect(core.exportVariable).toBeCalledWith('NAMED_SECRET', 'SUPERSECRET_IN_NAMESPACE');
expect(core.exportVariable).toBeCalledWith('OTHERSECRET', 'OTHERSUPERSECRET_IN_NAMESPACE');
});
});
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
verbose: true
};
+1 -1
View File
@@ -1,3 +1,3 @@
module.exports = { module.exports = {
testPathIgnorePatterns: ['/node_modules/', '<rootDir>/integration/', '<rootDir>/e2e/'], testPathIgnorePatterns: ['/node_modules/', '<rootDir>/integration/', '<rootDir>/e2e/','<rootDir>/integration-ent'],
}; };
+5596
View File
File diff suppressed because it is too large Load Diff
+49 -36
View File
@@ -1,38 +1,51 @@
{ {
"name": "vault-action", "name": "vault-action",
"version": "0.1.0", "version": "0.1.0",
"description": "A Github Action that allows you to consume vault secrets as secure environment variables.", "description": "A Github Action that allows you to consume vault secrets as secure environment variables.",
"main": "index.js", "main": "dist/index.js",
"scripts": { "scripts": {
"test": "jest", "build": "ncc build index.js -o dist",
"test:integration": "jest -c integration/jest.config.js", "test": "jest",
"test:e2e": "jest -c e2e/jest.config.js" "test:integration": "jest -c integration/jest.config.js",
}, "test:integration-ent": "jest -c integration-ent/jest.config.js",
"repository": { "test:e2e": "jest -c e2e/jest.config.js"
"type": "git", },
"url": "git+https://github.com/RichiCoder1/vault-action.git" "release": {
}, "branch": "master",
"keywords": [ "plugins": [
"hashicorp", "@semantic-release/commit-analyzer",
"vault", "@semantic-release/release-notes-generator",
"github", "@semantic-release/github"
"actions", ],
"github-actions", "ci": false
"javascript" },
], "repository": {
"author": "Richard Simpson <richardsimpson@outlook.com>", "type": "git",
"license": "MIT", "url": "git+https://github.com/RichiCoder1/vault-action.git"
"bugs": { },
"url": "https://github.com/RichiCoder1/vault-action/issues" "keywords": [
}, "hashicorp",
"homepage": "https://github.com/RichiCoder1/vault-action#readme", "vault",
"dependencies": { "github",
"@actions/core": "^1.1.1", "actions",
"got": "^9.6.0" "github-actions",
}, "javascript"
"devDependencies": { ],
"@types/jest": "^24.0.18", "author": "Richard Simpson <richardsimpson@outlook.com>",
"jest": "^24.9.0", "license": "MIT",
"jest-when": "^2.7.0" "bugs": {
} "url": "https://github.com/RichiCoder1/vault-action/issues"
},
"homepage": "https://github.com/RichiCoder1/vault-action#readme",
"dependencies": {
"@actions/core": "^1.1.1",
"got": "^9.6.0"
},
"devDependencies": {
"@types/jest": "^24.0.18",
"@zeit/ncc": "^0.20.5",
"jest": "^24.9.0",
"jest-when": "^2.7.0",
"semantic-release": "^15.13.24"
}
} }