5
0
Fork 0
mirror of https://github.com/hashicorp/vault-action.git synced 2025-11-09 16:16:55 +00:00
This commit is contained in:
Max Wagner 2023-04-03 21:20:47 +00:00 committed by GitHub
commit a2519fbb6f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 125 additions and 29 deletions

View file

@ -421,7 +421,7 @@ steps:
Here are all the inputs available through `with`:
| Input | Description | Default | Required |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | -------- |
| `url` | The URL for the vault endpoint | | ✔ |
| `secrets` | A semicolon-separated list of secrets to retrieve. These will automatically be converted to environmental variable keys. See README for more details | | |
| `namespace` | The Vault namespace from which to query secrets. Vault Enterprise only, unset by default | | |
@ -445,6 +445,8 @@ Here are all the inputs available through `with`:
| `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. | | |
| `tlsSkipVerify` | When set to true, disables verification of server certificates when testing the action. | `false` | |
| `retryVaultTokenRetrieval` | When set to true, attempts to authenticate with Vault will be retried when an HTTP error occurs | `false` | |
## Masking - Hiding Secrets from Logs

View file

@ -85,6 +85,9 @@ inputs:
secretEncodingType:
description: 'The encoding type of the secret to decode. If not specified, the secret will not be decoded. Supported values: base64, hex, utf8'
required: false
retryVaultTokenRetrieval:
description: 'Enable retrying retrieval of Vault server tokens. If not specified the token request to the Vault server will only be tried once.'
required: false
runs:
using: 'node16'
main: 'dist/index.js'

View file

@ -31,6 +31,7 @@ async function exportSecrets() {
headers: {},
https: {},
retry: {
methods: [...got.defaults.options.retry.methods],
statusCodes: [
...got.defaults.options.retry.statusCodes,
// Vault returns 412 when the token in use hasn't yet been replicated
@ -68,6 +69,11 @@ async function exportSecrets() {
defaultOptions.headers["X-Vault-Namespace"] = vaultNamespace;
}
const retryVaultTokenRetrieval = (core.getInput('retryVaultTokenRetrieval', { required: false }) || 'false').toLowerCase() != 'false';
if (retryVaultTokenRetrieval === true) {
defaultOptions.retry.methods.push('POST');
}
const vaultToken = await retrieveToken(vaultMethod, got.extend(defaultOptions));
defaultOptions.headers['X-Vault-Token'] = vaultToken;
const client = got.extend(defaultOptions);

View file

@ -67,3 +67,88 @@ describe('exportSecrets retries', () => {
});
});
});
describe('exportSecrets retrieve token retries', () => {
var server = new ServerMock({ host: "127.0.0.1", port: 0 });
var calls = 0;
beforeEach((done) => {
calls = 0;
jest.resetAllMocks();
when(core.getInput)
.calledWith('token', expect.anything())
.mockReturnValueOnce('EXAMPLE');
when(core.getInput)
.calledWith('secrets', expect.anything())
.mockReturnValueOnce("kv/mysecret key");
when(core.getInput)
.calledWith('method', expect.anything())
.mockReturnValueOnce('approle')
when(core.getInput)
.calledWith('roleId', expect.anything())
.mockReturnValueOnce('roleId')
when(core.getInput)
.calledWith('secretId', expect.anything())
.mockReturnValueOnce('secretId')
when(core.getInput)
.calledWith('retryVaultTokenRetrieval', expect.anything())
.mockReturnValueOnce('true')
server.start(() => {
expect(server.getHttpPort()).not.toBeNull();
when(core.getInput)
.calledWith('url', expect.anything())
.mockReturnValueOnce('http://127.0.0.1:' + server.getHttpPort());
done();
});
});
afterEach((done) => {
server.stop(done);
});
function mockKvRetrieval() {
server.on({
path: '/v1/kv/mysecret',
reply: {
status: 200,
headers: { "content-type": "application/json" },
body: function() {
return JSON.stringify({ data: {"key": "value"} })
}
}
});
}
function mockStatusCodes(statusCodes) {
server.on({
method: 'POST',
path: '/v1/auth/approle/login',
reply: {
status: function() {
let status = statusCodes[calls];
calls += 1;
return status;
},
body: function() {
return JSON.stringify({ auth: {"client_token": "token"} });
}
}
});
}
it('retries on 500 status code', (done) => {
mockKvRetrieval()
mockStatusCodes([500, 201])
exportSecrets().then(() => {
expect(calls).toEqual(2);
done();
});
});
});