5
0
Fork 0
mirror of https://github.com/hashicorp/vault-action.git synced 2025-11-14 18:13:45 +00:00

implemented kubernetes auth

This commit is contained in:
johannes.guenther 2020-11-17 21:50:03 +01:00
parent 2ca76a4465
commit 8a7c9e8dd1
5 changed files with 113 additions and 1 deletions

View file

@ -80,6 +80,16 @@ with:
caCertificate: ${{ secrets.VAULTCA }}
```
- **kubernetes**: you must provide the path to the token in the `tokenPath`variable as well as the roleName for kuberentes bases auth this is interesting if [kubernetes auth](https://www.vaultproject.io/docs/auth/kubernetes) in combination with self hosted runners is deployed:
```yaml
...
with:
url: https://vault.mycompany.com:8200
method: kubernetes
roleName: ${{ secrets.KUBE_ROLENAME }}
tokenPath: /var/run/secrets/kubernetes.io/serviceaccount/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.
## Key Syntax
@ -247,6 +257,8 @@ Here are all the inputs available through `with`:
| `roleId` | The Role Id for App Role authentication | | |
| `secretId` | The Secret Id for App Role authentication | | |
| `githubToken` | The Github Token to be used to authenticate with Vault | | |
| `roleName` | The rolename of the serviceaccount for the kubernetes authentification | | |
| `tokenPath` | The path to the serviceacconut secret with the jwt-token for kubernetes based authentification | | |
| `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. | | |
| `exportEnv` | Whether or not export secrets as environment variables. | `true` | |

View file

@ -26,6 +26,12 @@ inputs:
githubToken:
description: 'The Github Token to be used to authenticate with Vault'
required: false
roleName:
description: "The role name for the kubernetes authentification"
required: false
tokenPath:
description: "The path to the kubernetes service account secret, the action reads the content of this file on the runner"
required: false
authPayload:
description: 'The JSON payload to be sent to Vault when using a custom authentication method.'
required: false

View file

@ -5,7 +5,7 @@ const got = require('got').default;
const jsonata = require('jsonata');
const { auth: { retrieveToken }, secrets: { getSecrets } } = require('./index');
const AUTH_METHODS = ['approle', 'token', 'github'];
const AUTH_METHODS = ['approle', 'token', 'github','kubernetes'];
async function exportSecrets() {
const vaultUrl = core.getInput('url', { required: true });

View file

@ -1,5 +1,6 @@
// @ts-check
const core = require('@actions/core');
const fs = require('fs');
/***
* Authenticate with Vault and retrieve a Vault token that can be used for requests.
@ -17,6 +18,17 @@ async function retrieveToken(method, client) {
const githubToken = core.getInput('githubToken', { required: true });
return await getClientToken(client, method, { token: githubToken });
}
case 'kubernetes': {
const tokenPath = core.getInput('tokenPath', { required: true })
const data = fs.readFileSync(tokenPath, 'utf8')
const roleName = core.getInput('roleName', { required: true })
if (!(roleName && data) && data != "") {
throw new Error("Role Name must be set and a kubernetes token must set")
}
const payload = { jwt: data, role: roleName }
return await getClientToken(client, method, payload)
}
default: {
if (!method || method === 'token') {
return core.getInput('token', { required: true });

82
src/auth.test.js Normal file
View file

@ -0,0 +1,82 @@
jest.mock('got');
jest.mock('@actions/core');
jest.mock('@actions/core/lib/command');
jest.mock("fs")
const core = require('@actions/core');
const got = require('got');
const fs = require("fs")
const { when } = require('jest-when');
const {
retrieveToken
} = require('./auth');
function mockInput(name, key) {
when(core.getInput)
.calledWith(name)
.mockReturnValueOnce(key);
}
function mockApiResponse() {
const response = { body: { auth: { client_token: testToken, renewable: true, policies: [], accessor: "accessor" } } }
got.post = jest.fn()
got.post.mockReturnValue(response)
}
const testToken = "testoken";
describe("test retrival for token", () => {
beforeEach(() => {
jest.resetAllMocks();
});
it("test retrival with approle", async () => {
const method = 'approle'
mockApiResponse()
const testRoleId = "testRoleId"
const testSecretId = "testSecretId"
mockInput("roleId", testRoleId)
mockInput("secretId", testSecretId)
const token = await retrieveToken(method, got)
expect(token).toEqual(testToken)
const payload = got.post.mock.calls[0][1].json
expect(payload).toEqual({ role_id: testRoleId, secret_id: testSecretId })
const url = got.post.mock.calls[0][0]
expect(url).toContain('approle')
})
it("test retrival with github token", async () => {
const method = 'github'
mockApiResponse()
const githubToken = "githubtoken"
mockInput("githubToken", githubToken)
const token = await retrieveToken(method, got)
expect(token).toEqual(testToken)
const payload = got.post.mock.calls[0][1].json
expect(payload).toEqual({ token: githubToken })
const url = got.post.mock.calls[0][0]
expect(url).toContain('github')
})
it("test retrival with kubernetes", async () => {
const method = 'kubernetes'
const jwtToken = "someJwtToken"
const testRoleName = "testRoleName"
const testTokenPath = "testTokenPath"
mockApiResponse()
mockInput("tokenPath", testTokenPath)
mockInput("roleName", testRoleName)
fs.readFileSync = jest.fn()
fs.readFileSync.mockReturnValueOnce(jwtToken)
const token = await retrieveToken(method, got)
expect(token).toEqual(testToken)
const payload = got.post.mock.calls[0][1].json
expect(payload).toEqual({ jwt: jwtToken, role: testRoleName })
const url = got.post.mock.calls[0][0]
expect(url).toContain('kubernetes')
})
})