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:
parent
2ca76a4465
commit
8a7c9e8dd1
5 changed files with 113 additions and 1 deletions
12
README.md
12
README.md
|
|
@ -80,6 +80,16 @@ with:
|
||||||
caCertificate: ${{ secrets.VAULTCA }}
|
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.
|
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
|
## Key Syntax
|
||||||
|
|
@ -247,6 +257,8 @@ 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 | | |
|
||||||
|
| `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. | | |
|
| `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` | |
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ inputs:
|
||||||
githubToken:
|
githubToken:
|
||||||
description: 'The Github Token to be used to authenticate with Vault'
|
description: 'The Github Token to be used to authenticate with Vault'
|
||||||
required: false
|
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:
|
authPayload:
|
||||||
description: 'The JSON payload to be sent to Vault when using a custom authentication method.'
|
description: 'The JSON payload to be sent to Vault when using a custom authentication method.'
|
||||||
required: false
|
required: false
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ 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','kubernetes'];
|
||||||
|
|
||||||
async function exportSecrets() {
|
async function exportSecrets() {
|
||||||
const vaultUrl = core.getInput('url', { required: true });
|
const vaultUrl = core.getInput('url', { required: true });
|
||||||
|
|
|
||||||
12
src/auth.js
12
src/auth.js
|
|
@ -1,5 +1,6 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
const core = require('@actions/core');
|
const core = require('@actions/core');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* 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,17 @@ 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 '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: {
|
default: {
|
||||||
if (!method || method === 'token') {
|
if (!method || method === 'token') {
|
||||||
return core.getInput('token', { required: true });
|
return core.getInput('token', { required: true });
|
||||||
|
|
|
||||||
82
src/auth.test.js
Normal file
82
src/auth.test.js
Normal 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')
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
Loading…
Reference in a new issue