Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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` | |
Expand Down
6 changes: 6 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ inputs:
githubToken:
description: 'The Github Token to be used to authenticate with Vault'
required: false
roleName:
Comment thread
jogueber marked this conversation as resolved.
description: "The role name for the kubernetes authentification"
Comment thread
jogueber marked this conversation as resolved.
required: false
tokenPath:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably have a default /var/run/secrets/kubernetes.io/serviceaccount/token, which for 99% of the use cases the JWT will be found.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gonna do that :)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jojo19893 Are you still planning on making this change? I can, to get this moving again

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poke 😄

description: "The path where the Kubernetes service account JWT is located"
required: false
authPayload:
description: 'The JSON payload to be sent to Vault when using a custom authentication method.'
required: false
Expand Down
2 changes: 1 addition & 1 deletion src/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
12 changes: 12 additions & 0 deletions src/auth.js
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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 });
Expand Down
82 changes: 82 additions & 0 deletions src/auth.test.js
Original file line number Diff line number Diff line change
@@ -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')
})

})