Compare commits

..

39 Commits

Author SHA1 Message Date
Jason O'Donnell 0723fd7348 Update to v2.2.0 (#214) 2021-05-06 13:51:05 -04:00
dependabot[bot] 0405c26bc9 chore(deps): bump jsonata from 1.8.3 to 1.8.4 (#171)
Bumps [jsonata](https://github.com/jsonata-js/jsonata) from 1.8.3 to 1.8.4.
- [Release notes](https://github.com/jsonata-js/jsonata/releases)
- [Changelog](https://github.com/jsonata-js/jsonata/blob/master/CHANGELOG.md)
- [Commits](https://github.com/jsonata-js/jsonata/compare/v1.8.3...v1.8.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:42:25 -04:00
dependabot[bot] 2eea93c25e chore(deps-dev): bump @actions/core from 1.2.6 to 1.2.7 (#206)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.6 to 1.2.7.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:42:11 -04:00
dependabot[bot] 4d9cf786d6 chore(deps-dev): bump @types/jest from 26.0.22 to 26.0.23 (#207)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.22 to 26.0.23.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:41:52 -04:00
dependabot[bot] 575042000a chore(deps): bump handlebars from 4.7.6 to 4.7.7 (#213)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.7.6 to 4.7.7.
- [Release notes](https://github.com/wycats/handlebars.js/releases)
- [Changelog](https://github.com/handlebars-lang/handlebars.js/blob/master/release-notes.md)
- [Commits](https://github.com/wycats/handlebars.js/compare/v4.7.6...v4.7.7)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:41:29 -04:00
dependabot[bot] cc8ad16bec chore(deps): bump lodash from 4.17.20 to 4.17.21 (#212)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.20 to 4.17.21.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.20...4.17.21)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:41:20 -04:00
dependabot[bot] cd1614aee3 chore(deps): bump jsrsasign from 10.1.10 to 10.2.0 (#211)
Bumps [jsrsasign](https://github.com/kjur/jsrsasign) from 10.1.10 to 10.2.0.
- [Release notes](https://github.com/kjur/jsrsasign/releases)
- [Changelog](https://github.com/kjur/jsrsasign/blob/master/ChangeLog.txt)
- [Commits](https://github.com/kjur/jsrsasign/compare/10.1.10...10.2.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:38:52 -04:00
Jason O'Donnell f3a53220d9 changelog++ 2021-05-06 13:24:09 -04:00
Tom Proctor 3526e1be65 Mask each line of multi-line secrets (#208)
* Mask each line of multi-line secrets

* Don't include carriage return characters in masking

* Update CHANGELOG.md
2021-05-05 11:54:07 +01:00
Jason O'Donnell f60544fbda changelog++ 2021-05-04 09:02:26 -04:00
Raman Harnak 9e8f22534f Implement JWT auth (#188) 2021-05-04 08:49:35 -04:00
Maryam Ghanizadeh 8417c61f8a chore(deps): bump marked from 1.2.6 to 2.0.1 security reason (#202) 2021-04-22 16:32:18 -04:00
dependabot[bot] 0cca23248c chore(deps-dev): bump @types/jest from 26.0.19 to 26.0.22 (#201)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.19 to 26.0.22.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-22 15:46:23 -04:00
dependabot[bot] 8dad53ed10 chore(deps): bump got from 11.8.1 to 11.8.2 (#190)
Bumps [got](https://github.com/sindresorhus/got) from 11.8.1 to 11.8.2.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.8.1...v11.8.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-04-22 15:46:05 -04:00
Jason O'Donnell 937d792a86 Add GitHub authentication notice (#200)
* Add GitHub authentication notice

* Typo in perm name
2021-03-26 14:03:15 -04:00
Jason O'Donnell 5e5c06a3c8 Update to v2.1.2 (#180)
* Update to v2.1.2

* Update index.js
2021-01-21 14:45:22 -05:00
Jason O'Donnell ff547e1516 changelog++ 2021-01-11 11:50:03 -05:00
bilucodota 1d4917ec58 - Support complex keys, such as yaml/json files (#173) 2021-01-11 11:47:51 -05:00
Jason O'Donnell 2fb78ab91e Update to v2.1.1 (#168) 2020-12-15 11:55:39 -05:00
dependabot[bot] c261a0ad69 chore(deps): bump ini from 1.3.5 to 1.3.8 (#167)
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.8.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.8)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 11:17:21 -05:00
Jon L 6ac603b23e bump readme to action v2.1.0 (#157) 2020-12-15 11:12:08 -05:00
dependabot[bot] 638924aeb4 chore(deps-dev): bump @types/jest from 26.0.14 to 26.0.19 (#164)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.14 to 26.0.19.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 11:09:42 -05:00
dependabot[bot] 668d59f96b chore(deps): bump got from 11.7.0 to 11.8.1 (#163)
Bumps [got](https://github.com/sindresorhus/got) from 11.7.0 to 11.8.1.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.7.0...v11.8.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 11:09:17 -05:00
dependabot[bot] 208b49ff6c chore(deps-dev): bump semantic-release from 17.1.2 to 17.3.0 (#158)
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.1.2 to 17.3.0.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.1.2...v17.3.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 11:08:50 -05:00
dependabot[bot] 53c0f5bcca chore(deps-dev): bump jest from 26.5.0 to 26.6.3 (#150)
Bumps [jest](https://github.com/facebook/jest) from 26.5.0 to 26.6.3.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v26.5.0...v26.6.3)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 11:04:07 -05:00
Jason O'Donnell b4cef0fa36 Revert "chore(deps-dev): bump jest-when from 2.7.2 to 3.0.1 (#147)" (#166)
This reverts commit 7bc0a10ff8.
2020-12-15 11:00:26 -05:00
dependabot[bot] 7bc0a10ff8 chore(deps-dev): bump jest-when from 2.7.2 to 3.0.1 (#147)
Bumps [jest-when](https://github.com/timkindberg/jest-when) from 2.7.2 to 3.0.1.
- [Release notes](https://github.com/timkindberg/jest-when/releases)
- [Commits](https://github.com/timkindberg/jest-when/compare/v2.7.2...v3.0.1)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-12-15 10:15:59 -05:00
Tom Proctor e5febde8e7 Update jira sync github action (#151) 2020-11-18 10:49:47 +00:00
Jason O'Donnell 2ca76a4465 changelog++ 2020-10-06 13:18:57 -04:00
Jason O'Donnell 5b42d37bab Update to v2.0.2 (#133) 2020-10-06 13:15:24 -04:00
dependabot[bot] 124e6eecdb chore(deps-dev): bump jest from 26.4.2 to 26.5.0 (#132)
Bumps [jest](https://github.com/facebook/jest) from 26.4.2 to 26.5.0.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v26.4.2...v26.5.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-06 11:06:25 -04:00
dependabot[bot] 43c4212f70 chore(deps-dev): bump @types/jest from 26.0.13 to 26.0.14 (#123)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.13 to 26.0.14.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-01 10:33:41 -04:00
dependabot[bot] d4487e4dd0 chore(deps-dev): bump semantic-release from 17.1.1 to 17.1.2 (#124)
Bumps [semantic-release](https://github.com/semantic-release/semantic-release) from 17.1.1 to 17.1.2.
- [Release notes](https://github.com/semantic-release/semantic-release/releases)
- [Commits](https://github.com/semantic-release/semantic-release/compare/v17.1.1...v17.1.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-01 10:32:59 -04:00
dependabot[bot] c7f47bbfcf chore(deps): bump got from 11.6.2 to 11.7.0 (#126)
Bumps [got](https://github.com/sindresorhus/got) from 11.6.2 to 11.7.0.
- [Release notes](https://github.com/sindresorhus/got/releases)
- [Commits](https://github.com/sindresorhus/got/compare/v11.6.2...v11.7.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-01 10:32:32 -04:00
dependabot[bot] 11e2f12f99 chore(deps-dev): bump @actions/core from 1.2.5 to 1.2.6 (#130)
Bumps [@actions/core](https://github.com/actions/toolkit/tree/HEAD/packages/core) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/actions/toolkit/releases)
- [Changelog](https://github.com/actions/toolkit/blob/main/packages/core/RELEASES.md)
- [Commits](https://github.com/actions/toolkit/commits/HEAD/packages/core)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2020-10-01 10:30:25 -04:00
Jason O'Donnell 6c64e41adc changelog++ 2020-10-01 10:23:30 -04:00
ZANCO Bertrand 2f76ad395b Add ability to export Vault Token (#127)
* Add export Vault Token

* Set correct condition for default value

* Add test for exportToken
Fix key with dash

* Restore index.js
2020-10-01 10:22:10 -04:00
Jason O'Donnell 307c9ae581 Add pull_request_target to build action (#129)
* Add pull_request_target to build action

* Remove pull_request from action

* Remove branch specification

* Update as per review
2020-09-23 09:48:24 -04:00
Benjamin Rumble b35ef16370 specify version (#122)
* specify version 

Without specifying `@v2.0.0` GitHub says the string is not the correct format

``` 
The workflow is not valid. .github/workflows/integration_tests.yml (Line: 10, Col: 15): Expected format {org}/{repo}[/path]@ref. Actual 'hashicorp/vault-action',Input string was not in a correct format.```

* v2.0.1

Co-authored-by: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com>

Co-authored-by: Jason O'Donnell <2160810+jasonodonnell@users.noreply.github.com>
2020-09-22 13:44:55 -04:00
15 changed files with 3045 additions and 1765 deletions
+2 -3
View File
@@ -2,9 +2,8 @@ on:
push: push:
branches: branches:
- master - master
pull_request: pull_request_target:
branches: types: [opened, reopened, synchronize]
- master
jobs: jobs:
build: build:
+8 -8
View File
@@ -5,7 +5,6 @@ on:
types: [opened, closed, reopened] types: [opened, closed, reopened]
issue_comment: # Also triggers when commenting on a PR from the conversation view issue_comment: # Also triggers when commenting on a PR from the conversation view
types: [created] types: [created]
workflow_dispatch:
name: Jira Sync name: Jira Sync
@@ -36,26 +35,27 @@ jobs:
JIRA_USER_EMAIL: ${{ secrets.JIRA_SYNC_USER_EMAIL }} JIRA_USER_EMAIL: ${{ secrets.JIRA_SYNC_USER_EMAIL }}
JIRA_API_TOKEN: ${{ secrets.JIRA_SYNC_API_TOKEN }} JIRA_API_TOKEN: ${{ secrets.JIRA_SYNC_API_TOKEN }}
- name: Set ticket type - name: Preprocess
if: github.event.action == 'opened' && !steps.vault-team-role.outputs.role if: github.event.action == 'opened' || github.event.action == 'created'
id: set-ticket-type id: preprocess
run: | run: |
if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then if [[ "${{ github.event_name }}" == "pull_request_target" ]]; then
echo "::set-output name=type::PR" echo "::set-output name=type::PR"
else else
echo "::set-output name=type::ISS" echo "::set-output name=type::ISS"
fi fi
- name: Create ticket - name: Create ticket
if: github.event.action == 'opened' && !steps.vault-team-role.outputs.role if: github.event.action == 'opened' && !steps.vault-team-role.outputs.role
uses: tomhjp/gh-action-jira-create@v0.1.3 uses: tomhjp/gh-action-jira-create@v0.2.0
with: with:
project: VAULT project: VAULT
issuetype: "GH Issue" issuetype: "GH Issue"
summary: "${{ github.event.repository.name }} [${{ steps.set-ticket-type.outputs.type }} #${{ github.event.issue.number || github.event.pull_request.number }}]: ${{ github.event.issue.title || github.event.pull_request.title }}" summary: "${{ github.event.repository.name }} [${{ steps.preprocess.outputs.type }} #${{ github.event.issue.number || github.event.pull_request.number }}]: ${{ github.event.issue.title || github.event.pull_request.title }}"
description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created from GitHub Action for ${{ github.event.issue.html_url || github.event.pull_request.html_url }} from ${{ github.actor }}_" description: "${{ github.event.issue.body || github.event.pull_request.body }}\n\n_Created from GitHub Action for ${{ github.event.issue.html_url || github.event.pull_request.html_url }} from ${{ github.actor }}_"
# customfield_10089 is Issue Link custom field # customfield_10089 is Issue Link custom field
# customfield_10091 is team custom field # customfield_10091 is team custom field
extraFields: '{"fixVersions": [{"name": "TBD"}], "customfield_10091": ["ecosystem"], "customfield_10089": "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"}' extraFields: '{"fixVersions": [{"name": "TBD"}], "customfield_10091": ["ecosystem", "runtime"], "customfield_10089": "${{ github.event.issue.html_url || github.event.pull_request.html_url }}"}'
- name: Search - name: Search
if: github.event.action != 'opened' if: github.event.action != 'opened'
@@ -67,7 +67,7 @@ jobs:
- name: Sync comment - name: Sync comment
if: github.event.action == 'created' && steps.search.outputs.issue if: github.event.action == 'created' && steps.search.outputs.issue
uses: tomhjp/gh-action-jira-comment@v0.1.0 uses: tomhjp/gh-action-jira-comment@v0.2.0
with: with:
issue: ${{ steps.search.outputs.issue }} issue: ${{ steps.search.outputs.issue }}
comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}" comment: "${{ github.actor }} ${{ github.event.review.state || 'commented' }}:\n\n${{ github.event.comment.body || github.event.review.body }}\n\n${{ github.event.comment.html_url || github.event.review.html_url }}"
+31
View File
@@ -1,5 +1,36 @@
## Unreleased ## Unreleased
## 2.2.0 (May 6th, 2021)
Security:
* multi-line secrets are now properly masked in logs [GH-208](https://github.com/hashicorp/vault-action/pull/208)
[CVE-2021-32074](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-32074)
Features:
* JWT auth method is now supported [GH-188](https://github.com/hashicorp/vault-action/pull/188)
## 2.1.2 (January 21st, 2021)
Bugs:
* fixed bug where newlines were being rendered for multi-line secrets [GH-173](https://github.com/hashicorp/vault-action/pull/173)
## 2.1.1 (December 15th, 2020)
Improvements:
* bump jest from 26.5.0 to 26.6.3 [GH-150](https://github.com/hashicorp/vault-action/pull/150)
* bump semantic-release from 17.1.2 to 17.3.0 [GH-158](https://github.com/hashicorp/vault-action/pull/158)
* bump got from 11.7.0 to 11.8.1 [GH-163](https://github.com/hashicorp/vault-action/pull/163)
* bump @types/jest from 26.0.14 to 26.0.19 [GH-164](https://github.com/hashicorp/vault-action/pull/164)
* bump ini from 1.3.5 to 1.3.8 [GH-167](https://github.com/hashicorp/vault-action/pull/167)
## 2.1.0 (October 6th, 2020)
Features:
* Added `exportToken` to share the Vault token as an environment variable [GH-127](https://github.com/hashicorp/vault-action/pull/127)
Security:
* `action/core` updated to 1.2.6 to address minor CVE [GH-130](https://github.com/hashicorp/vault-action/pull/130)
## 2.0.1 (September 15th, 2020) ## 2.0.1 (September 15th, 2020)
Improvements: Improvements:
+25 -2
View File
@@ -36,7 +36,7 @@ jobs:
steps: steps:
# ... # ...
- name: Import Secrets - name: Import Secrets
uses: hashicorp/vault-action uses: hashicorp/vault-action@v2.1.2
with: with:
url: https://vault.mycompany.com:8200 url: https://vault.mycompany.com:8200
token: ${{ secrets.VaultToken }} token: ${{ secrets.VaultToken }}
@@ -71,14 +71,32 @@ with:
caCertificate: ${{ secrets.VAULTCA }} caCertificate: ${{ secrets.VAULTCA }}
``` ```
- **github**: you must provide the github token as `githubToken` - **github**: you must provide the github token as `githubToken`
**Notice: [Vault GitHub authentication](https://www.vaultproject.io/docs/auth/github)
requires `read:org` permissions for authentication. The auto-generated `GITHUB_TOKEN`
created for projects does not have these permissions and GitHub does not allow this
token's permissions to be modified. A new GitHub Token secret must be created with
`read:org` permissions to use this authentication method.**
```yaml ```yaml
... ...
with: with:
url: https://vault.mycompany.com:8200 url: https://vault.mycompany.com:8200
method: github method: github
githubToken: ${{ secrets.GITHUB_TOKEN }} githubToken: ${{ secrets.MY_GITHUB_TOKEN }}
caCertificate: ${{ secrets.VAULTCA }} caCertificate: ${{ secrets.VAULTCA }}
``` ```
- **jwt**: you must provide a `role` & `jwtPrivateKey` parameters, additionally you can pass `jwtKeyPassword` & `jwtTtl` parameters
```yaml
...
with:
url: https://vault.mycompany.com:8200
method: jwt
role: github-action
jwtPrivateKey: ${{ secrets.JWT_PRIVATE_KEY }}
jwtKeyPassword: ${{ secrets.JWT_KEY_PASS }}
jwtTtl: 3600 # 1 hour, default value
```
If any other method is specified and you provide an `authPayload`, the action will attempt to `POST` to `auth/${method}/login` with the provided payload and parse out the client token. If any other method is specified and you provide an `authPayload`, the action will attempt to `POST` to `auth/${method}/login` with the provided payload and parse out the client token.
@@ -247,9 +265,14 @@ Here are all the inputs available through `with`:
| `roleId` | The Role Id for App Role authentication | | | | `roleId` | The Role Id for App Role authentication | | |
| `secretId` | The Secret Id for App Role authentication | | | | `secretId` | The Secret Id for App Role authentication | | |
| `githubToken` | The Github Token to be used to authenticate with Vault | | | | `githubToken` | The Github Token to be used to authenticate with Vault | | |
| `role` | Vault role for specified auth method | | |
| `jwtPrivateKey` | Base64 encoded Private key to sign JWT | | |
| `jwtKeyPassword` | Password for key stored in jwtPrivateKey (if needed) | | |
| `jwtTtl` | Time in seconds, after which token expires | | 3600 |
| `authPayload` | The JSON payload to be sent to Vault when using a custom authentication method. | | | | `authPayload` | The JSON payload to be sent to Vault when using a custom authentication method. | | |
| `extraHeaders` | A string of newline separated extra headers to include on every request. | | | | `extraHeaders` | A string of newline separated extra headers to include on every request. | | |
| `exportEnv` | Whether or not export secrets as environment variables. | `true` | | | `exportEnv` | Whether or not export secrets as environment variables. | `true` | |
| `exportToken` | Whether or not export Vault token as environment variables (i.e VAULT_TOKEN). | `false` | |
| `caCertificate` | Base64 encoded CA certificate the server certificate was signed with. | | | | `caCertificate` | Base64 encoded CA certificate the server certificate was signed with. | | |
| `clientCertificate` | Base64 encoded client certificate the action uses to authenticate with Vault when mTLS is enabled. | | | | `clientCertificate` | Base64 encoded client certificate the action uses to authenticate with Vault when mTLS is enabled. | | |
| `clientKey` | Base64 encoded client key the action uses to authenticate with Vault when mTLS is enabled. | | | | `clientKey` | Base64 encoded client key the action uses to authenticate with Vault when mTLS is enabled. | | |
+17
View File
@@ -36,6 +36,10 @@ inputs:
description: 'Whether or not export secrets as environment variables.' description: 'Whether or not export secrets as environment variables.'
default: 'true' default: 'true'
required: false required: false
exportToken:
description: 'Whether or not export Vault token as environment variables.'
default: 'false'
required: false
caCertificate: caCertificate:
description: 'Base64 encoded CA certificate to verify the Vault server certificate.' description: 'Base64 encoded CA certificate to verify the Vault server certificate.'
required: false required: false
@@ -49,6 +53,19 @@ inputs:
description: 'When set to true, disables verification of the Vault server certificate. Setting this to true in production is not recommended.' description: 'When set to true, disables verification of the Vault server certificate. Setting this to true in production is not recommended.'
required: false required: false
default: "false" default: "false"
role:
description: 'Vault role for specified auth method'
required: false
jwtPrivateKey:
description: 'Base64 encoded Private key to sign JWT'
required: false
jwtKeyPassword:
description: 'Password for key stored in jwtPrivateKey (if needed)'
required: false
jwtTtl:
description: 'Time in seconds, after which token expires'
required: false
default: 3600
runs: runs:
using: 'node12' using: 'node12'
main: 'dist/index.js' main: 'dist/index.js'
+695 -166
View File
File diff suppressed because one or more lines are too long
+8 -8
View File
@@ -37,7 +37,7 @@ describe('integration', () => {
}, },
json: { json: {
data: { data: {
otherSecret: 'OTHERSUPERSECRET', "other-Secret-dash": 'OTHERSUPERSECRET',
}, },
} }
}); });
@@ -100,7 +100,7 @@ describe('integration', () => {
'X-Vault-Token': 'testtoken', 'X-Vault-Token': 'testtoken',
}, },
json: { json: {
otherSecret: 'OTHERCUSTOMSECRET', "other-Secret-dash": 'OTHERCUSTOMSECRET',
}, },
}); });
}); });
@@ -140,18 +140,18 @@ describe('integration', () => {
}); });
it('get nested secret', async () => { it('get nested secret', async () => {
mockInput('secret/data/nested/test otherSecret'); mockInput(`secret/data/nested/test "other-Secret-dash"`);
await exportSecrets(); await exportSecrets();
expect(core.exportVariable).toBeCalledWith('OTHERSECRET', 'OTHERSUPERSECRET'); expect(core.exportVariable).toBeCalledWith('OTHERSECRETDASH', 'OTHERSUPERSECRET');
}); });
it('get multiple secrets', async () => { it('get multiple secrets', async () => {
mockInput(` mockInput(`
secret/data/test secret ; secret/data/test secret ;
secret/data/test secret | NAMED_SECRET ; secret/data/test secret | NAMED_SECRET ;
secret/data/nested/test otherSecret ;`); secret/data/nested/test "other-Secret-dash" ;`);
await exportSecrets(); await exportSecrets();
@@ -159,7 +159,7 @@ describe('integration', () => {
expect(core.exportVariable).toBeCalledWith('SECRET', 'SUPERSECRET'); expect(core.exportVariable).toBeCalledWith('SECRET', 'SUPERSECRET');
expect(core.exportVariable).toBeCalledWith('NAMED_SECRET', 'SUPERSECRET'); expect(core.exportVariable).toBeCalledWith('NAMED_SECRET', 'SUPERSECRET');
expect(core.exportVariable).toBeCalledWith('OTHERSECRET', 'OTHERSUPERSECRET'); expect(core.exportVariable).toBeCalledWith('OTHERSECRETDASH', 'OTHERSUPERSECRET');
}); });
it('leading slash kvv2', async () => { it('leading slash kvv2', async () => {
@@ -179,11 +179,11 @@ describe('integration', () => {
}); });
it('get nested secret from K/V v1', async () => { it('get nested secret from K/V v1', async () => {
mockInput('secret-kv1/nested/test otherSecret'); mockInput('secret-kv1/nested/test "other-Secret-dash"');
await exportSecrets(); await exportSecrets();
expect(core.exportVariable).toBeCalledWith('OTHERSECRET', 'OTHERCUSTOMSECRET'); expect(core.exportVariable).toBeCalledWith('OTHERSECRETDASH', 'OTHERCUSTOMSECRET');
}); });
it('leading slash kvv1', async () => { it('leading slash kvv1', async () => {
+126
View File
@@ -0,0 +1,126 @@
jest.mock('@actions/core');
jest.mock('@actions/core/lib/command');
const core = require('@actions/core');
const {
privateRsaKeyBase64,
publicRsaKey
} = require('./rsa_keys');
const got = require('got');
const { when } = require('jest-when');
const { exportSecrets } = require('../../src/action');
const vaultUrl = `http://${process.env.VAULT_HOST || 'localhost'}:${process.env.VAULT_PORT || '8200'}`;
describe('jwt auth', () => {
beforeAll(async () => {
// Verify Connection
await got(`${vaultUrl}/v1/secret/config`, {
headers: {
'X-Vault-Token': 'testtoken',
},
});
try {
await got(`${vaultUrl}/v1/sys/auth/jwt`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
},
json: {
type: 'jwt'
}
});
} catch (error) {
const {response} = error;
if (response.statusCode === 400 && response.body.includes("path is already in use")) {
// Auth method might already be enabled from previous test runs
} else {
throw error;
}
}
await got(`${vaultUrl}/v1/sys/policy/reader`, {
method: 'PUT',
headers: {
'X-Vault-Token': 'testtoken',
},
json: {
policy: `
path "*" {
capabilities = ["read"]
}
`
}
});
await got(`${vaultUrl}/v1/auth/jwt/config`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
},
json: {
jwt_validation_pubkeys: publicRsaKey
}
});
await got(`${vaultUrl}/v1/auth/jwt/role/default`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
},
json: {
role_type: 'jwt',
bound_audiences: null,
bound_claims: {
iss: 'vault-action'
},
user_claim: 'iss',
policies: ['reader']
}
});
await got(`${vaultUrl}/v1/secret/data/test`, {
method: 'POST',
headers: {
'X-Vault-Token': 'testtoken',
},
json: {
data: {
secret: 'SUPERSECRET',
},
},
});
});
beforeEach(() => {
jest.resetAllMocks();
when(core.getInput)
.calledWith('url')
.mockReturnValueOnce(`${vaultUrl}`);
when(core.getInput)
.calledWith('method')
.mockReturnValueOnce('jwt');
when(core.getInput)
.calledWith('jwtPrivateKey')
.mockReturnValueOnce(privateRsaKeyBase64);
when(core.getInput)
.calledWith('role')
.mockReturnValueOnce('default');
when(core.getInput)
.calledWith('secrets')
.mockReturnValueOnce('secret/data/test secret');
});
it('successfully authenticates', async () => {
await exportSecrets();
expect(core.exportVariable).toBeCalledWith('SECRET', 'SUPERSECRET');
});
});
+77
View File
@@ -0,0 +1,77 @@
const privateRsaKey = `
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
`;
const privateRsaKeyBase64 = Buffer.from(privateRsaKey).toString('base64');
const publicRsaKey = `
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAwavSHLLo7bUSuKX2EKu3
YStrNTGdmhku7sAFaeDyi9His1oot+wzajWp1rqHaGVk4b5o5z6D7Xhm0zYPhpTT
vEd3NyONc9sjVd7sf9rQaBY3QusPYAdF6j0ydTJGnTeG9N2zhHjdMLR+3F39F9Ry
6vddS9w3ibjVERucQtpqGhy5TIWhttk3gN3A7dk972+WCQeKUCC6wU6PvAEUPflT
hQc1hSHldpjVUHQlZkQXl/XHWBzZESwMgiQcAmVL3lkvxmgIYscqWzf8cTHogNrP
ml9Il89N+2XYcEfXgWLOyzGhQggigN9DRHDDE1UWT1foHnmeXAIZPCveKZc/Jp5S
ASIxaZ+r73mWjVt19GSvEsqtejDRmMC3jrYCdISrCVsHkbRQq7/yLCi5sJG9p2gD
91jCgaBy2tw22nWN/KoHm9p/mhzWmlWwVJrFTNiP0qccyoa5h1a6WBPt0oCKQk3I
AMV5HhVw4DhPx8gvh7qwOZk9vXXAFyA8bWhOVIFIJ8i8Gq25y7/bukyzqsEPkQ2m
KgbQnh3VOUCSugJFodPC/Jf7VQK1yRpUZH2v7r9cBjHVnUnePGac3Zns7/iRYBvK
5cIFUg+X48VXIMKIvs4EA8ee8VacVh8tyR6EuP42BU5fGQlvLC+ZKT165maQv/Vl
f52E9W2iFNt3sxB0KFtOkbkCAwEAAQ==
-----END PUBLIC KEY-----
`;
module.exports = {
privateRsaKeyBase64,
publicRsaKey
};
+1916 -1562
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -45,7 +45,8 @@
"homepage": "https://github.com/hashicorp/vault-action#readme", "homepage": "https://github.com/hashicorp/vault-action#readme",
"dependencies": { "dependencies": {
"got": "^11.5.1", "got": "^11.5.1",
"jsonata": "^1.8.2" "jsonata": "^1.8.2",
"jsrsasign": "^10.1.10"
}, },
"peerDependencies": { "peerDependencies": {
"@actions/core": ">=1 <2" "@actions/core": ">=1 <2"
+17 -6
View File
@@ -5,13 +5,14 @@ const got = require('got').default;
const jsonata = require('jsonata'); const jsonata = require('jsonata');
const { auth: { retrieveToken }, secrets: { getSecrets } } = require('./index'); const { auth: { retrieveToken }, secrets: { getSecrets } } = require('./index');
const AUTH_METHODS = ['approle', 'token', 'github']; const AUTH_METHODS = ['approle', 'token', 'github', 'jwt'];
async function exportSecrets() { async function exportSecrets() {
const vaultUrl = core.getInput('url', { required: true }); const vaultUrl = core.getInput('url', { required: true });
const vaultNamespace = core.getInput('namespace', { required: false }); const vaultNamespace = core.getInput('namespace', { required: false });
const extraHeaders = parseHeadersInput('extraHeaders', { required: false }); const extraHeaders = parseHeadersInput('extraHeaders', { required: false });
const exportEnv = core.getInput('exportEnv', { required: false }) != 'false'; const exportEnv = core.getInput('exportEnv', { required: false }) != 'false';
const exportToken = (core.getInput('exportToken', { required: false }) || 'false').toLowerCase() != 'false';
const secretsInput = core.getInput('secrets', { required: true }); const secretsInput = core.getInput('secrets', { required: true });
const secretRequests = parseSecretsInput(secretsInput); const secretRequests = parseSecretsInput(secretsInput);
@@ -60,6 +61,11 @@ async function exportSecrets() {
defaultOptions.headers['X-Vault-Token'] = vaultToken; defaultOptions.headers['X-Vault-Token'] = vaultToken;
const client = got.extend(defaultOptions); const client = got.extend(defaultOptions);
if (exportToken === true) {
command.issue('add-mask', vaultToken);
core.exportVariable('VAULT_TOKEN', `${vaultToken}`);
}
const requests = secretRequests.map(request => { const requests = secretRequests.map(request => {
const { path, selector } = request; const { path, selector } = request;
return request; return request;
@@ -72,7 +78,11 @@ async function exportSecrets() {
if (cachedResponse) { if (cachedResponse) {
core.debug(' using cached response'); core.debug(' using cached response');
} }
command.issue('add-mask', value); for (const line of value.replace(/\r/g, '').split('\n')) {
if (line.length > 0) {
command.issue('add-mask', line);
}
}
if (exportEnv) { if (exportEnv) {
core.exportVariable(request.envVarName, `${value}`); core.exportVariable(request.envVarName, `${value}`);
} }
@@ -124,12 +134,13 @@ function parseSecretsInput(secretsInput) {
throw Error(`You must provide a valid path and key. Input: "${secret}"`); throw Error(`You must provide a valid path and key. Input: "${secret}"`);
} }
const [path, selector] = pathParts; const [path, selectorQuoted] = pathParts;
/** @type {any} */ /** @type {any} */
const selectorAst = jsonata(selector).ast(); const selectorAst = jsonata(selectorQuoted).ast();
const selector = selectorQuoted.replace(new RegExp('"', 'g'), '');
if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && !outputVarName) { if ((selectorAst.type !== "path" || selectorAst.steps[0].stages) && selectorAst.type !== "string" && !outputVarName) {
throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`); throw Error(`You must provide a name for the output key when using json selectors. Input: "${secret}"`);
} }
@@ -156,7 +167,7 @@ function parseSecretsInput(secretsInput) {
*/ */
function normalizeOutputKey(dataKey, isEnvVar = false) { function normalizeOutputKey(dataKey, isEnvVar = false) {
let outputKey = dataKey let outputKey = dataKey
.replace('.', '__').replace(/[^\p{L}\p{N}_-]/gu, ''); .replace('.', '__').replace(new RegExp('-', 'g'), '').replace(/[^\p{L}\p{N}_-]/gu, '');
if (isEnvVar) { if (isEnvVar) {
outputKey = outputKey.toUpperCase(); outputKey = outputKey.toUpperCase();
} }
+74
View File
@@ -2,6 +2,7 @@ jest.mock('got');
jest.mock('@actions/core'); jest.mock('@actions/core');
jest.mock('@actions/core/lib/command'); jest.mock('@actions/core/lib/command');
const command = require('@actions/core/lib/command');
const core = require('@actions/core'); const core = require('@actions/core');
const got = require('got'); const got = require('got');
const { const {
@@ -178,6 +179,12 @@ describe('exportSecrets', () => {
} }
} }
function mockExportToken(doExport) {
when(core.getInput)
.calledWith('exportToken')
.mockReturnValueOnce(doExport);
}
it('simple secret retrieval', async () => { it('simple secret retrieval', async () => {
mockInput('test key'); mockInput('test key');
mockVaultData({ mockVaultData({
@@ -257,4 +264,71 @@ describe('exportSecrets', () => {
expect(core.exportVariable).toBeCalledWith('KEY__VALUE', '1'); expect(core.exportVariable).toBeCalledWith('KEY__VALUE', '1');
expect(core.setOutput).toBeCalledWith('key__value', '1'); expect(core.setOutput).toBeCalledWith('key__value', '1');
}); });
it('export Vault token', async () => {
mockInput('test key');
mockVaultData({
key: 1
});
mockExportToken("true")
await exportSecrets();
expect(core.exportVariable).toBeCalledTimes(2);
expect(core.exportVariable).toBeCalledWith('VAULT_TOKEN', 'EXAMPLE');
expect(core.exportVariable).toBeCalledWith('KEY', '1');
expect(core.setOutput).toBeCalledWith('key', '1');
});
it('not export Vault token', async () => {
mockInput('test key');
mockVaultData({
key: 1
});
mockExportToken("false")
await exportSecrets();
expect(core.exportVariable).toBeCalledTimes(1);
expect(core.exportVariable).toBeCalledWith('KEY', '1');
expect(core.setOutput).toBeCalledWith('key', '1');
});
it('single-line secret gets masked', async () => {
mockInput('test key');
mockVaultData({
key: 'secret'
});
mockExportToken("false")
await exportSecrets();
expect(command.issue).toBeCalledTimes(1);
expect(command.issue).toBeCalledWith('add-mask', 'secret');
expect(core.setOutput).toBeCalledWith('key', 'secret');
})
it('multi-line secret gets masked for each line', async () => {
const multiLineString = `a multi-line string
with blank lines
`
mockInput('test key');
mockVaultData({
key: multiLineString
});
mockExportToken("false")
await exportSecrets();
expect(command.issue).toBeCalledTimes(2); // 1 for each non-empty line.
expect(command.issue).toBeCalledWith('add-mask', 'a multi-line string');
expect(command.issue).toBeCalledWith('add-mask', 'with blank lines');
expect(core.setOutput).toBeCalledWith('key', multiLineString);
})
}); });
+36
View File
@@ -1,5 +1,6 @@
// @ts-check // @ts-check
const core = require('@actions/core'); const core = require('@actions/core');
const rsasign = require('jsrsasign');
/*** /***
* Authenticate with Vault and retrieve a Vault token that can be used for requests. * Authenticate with Vault and retrieve a Vault token that can be used for requests.
@@ -17,6 +18,15 @@ async function retrieveToken(method, client) {
const githubToken = core.getInput('githubToken', { required: true }); const githubToken = core.getInput('githubToken', { required: true });
return await getClientToken(client, method, { token: githubToken }); return await getClientToken(client, method, { token: githubToken });
} }
case 'jwt': {
const role = core.getInput('role', { required: true });
const privateKeyRaw = core.getInput('jwtPrivateKey', { required: true });
const privateKey = Buffer.from(privateKeyRaw, 'base64').toString();
const keyPassword = core.getInput('jwtKeyPassword', { required: false });
const tokenTtl = core.getInput('jwtTtl', { required: false }) || '3600'; // 1 hour
const jwt = generateJwt(privateKey, keyPassword, Number(tokenTtl));
return await getClientToken(client, method, { jwt: jwt, role: role });
}
default: { default: {
if (!method || method === 'token') { if (!method || method === 'token') {
return core.getInput('token', { required: true }); return core.getInput('token', { required: true });
@@ -32,6 +42,32 @@ async function retrieveToken(method, client) {
} }
} }
/***
* Generates signed Json Web Token with specified private key and ttl
* @param {string} privateKey
* @param {string} keyPassword
* @param {number} ttl
*/
function generateJwt(privateKey, keyPassword, ttl) {
const alg = 'RS256';
const header = { alg: alg, typ: 'JWT' };
const now = rsasign.KJUR.jws.IntDate.getNow();
const payload = {
iss: 'vault-action',
iat: now,
nbf: now,
exp: now + ttl,
event: process.env.GITHUB_EVENT_NAME,
workflow: process.env.GITHUB_WORKFLOW,
sha: process.env.GITHUB_SHA,
actor: process.env.GITHUB_ACTOR,
repository: process.env.GITHUB_REPOSITORY,
ref: process.env.GITHUB_REF
};
const decryptedKey = rsasign.KEYUTIL.getKey(privateKey, keyPassword);
return rsasign.KJUR.jws.JWS.sign(alg, JSON.stringify(header), JSON.stringify(payload), decryptedKey);
}
/*** /***
* Call the appropriate login endpoint and parse out the token in the response. * Call the appropriate login endpoint and parse out the token in the response.
* @param {import('got').Got} client * @param {import('got').Got} client
+5 -3
View File
@@ -38,7 +38,9 @@ async function getSecrets(secretRequests, client) {
body = result.body; body = result.body;
responseCache.set(requestPath, body); responseCache.set(requestPath, body);
} }
if (!selector.match(/.*[\.].*/)) {
selector = '"' + selector + '"'
}
selector = "data." + selector selector = "data." + selector
body = JSON.parse(body) body = JSON.parse(body)
if (body.data["data"] != undefined) { if (body.data["data"] != undefined) {
@@ -64,14 +66,14 @@ function selectData(data, selector) {
const ata = jsonata(selector); const ata = jsonata(selector);
let result = JSON.stringify(ata.evaluate(data)); let result = JSON.stringify(ata.evaluate(data));
// Compat for custom engines // Compat for custom engines
if (!result && ata.ast().type === "path" && ata.ast()['steps'].length === 1 && selector !== 'data' && 'data' in data) { if (!result && ((ata.ast().type === "path" && ata.ast()['steps'].length === 1) || ata.ast().type === "string") && selector !== 'data' && 'data' in data) {
result = JSON.stringify(jsonata(`data.${selector}`).evaluate(data)); result = JSON.stringify(jsonata(`data.${selector}`).evaluate(data));
} else if (!result) { } else if (!result) {
throw Error(`Unable to retrieve result for ${selector}. No match data was found. Double check your Key or Selector.`); throw Error(`Unable to retrieve result for ${selector}. No match data was found. Double check your Key or Selector.`);
} }
if (result.startsWith(`"`)) { if (result.startsWith(`"`)) {
result = result.substring(1, result.length - 1); result = JSON.parse(result);
} }
return result; return result;
} }