From 2de03da519f1b9abd6906ae6a4e10ebb7155d188 Mon Sep 17 00:00:00 2001 From: josh Date: Mon, 5 Jun 2023 21:00:29 -0400 Subject: [PATCH] Add example of a token with a policy to read allocs Signed-off-by: josh --- plugins/nomad-backend/README.md | 2 +- plugins/nomad-backend/src/service/router.ts | 46 +++++++++++++------- plugins/nomad/README.md | 48 ++++++++++++++++++++- 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/plugins/nomad-backend/README.md b/plugins/nomad-backend/README.md index 3a25df2a72..bb0b48fe4a 100644 --- a/plugins/nomad-backend/README.md +++ b/plugins/nomad-backend/README.md @@ -47,4 +47,4 @@ export default async function createPlugin( + apiRouter.use('/nomad', await nomad(nomadEnv)); ``` -Note: for this backend to work, the `nomad` configuration described in the README of `@backstage/plugin-nomad` must be configured. +Note: for this backend to work, the `nomad` configuration described in the README of `@backstage/plugin-nomad` must be implemented. diff --git a/plugins/nomad-backend/src/service/router.ts b/plugins/nomad-backend/src/service/router.ts index aa863e3493..7c462d811e 100644 --- a/plugins/nomad-backend/src/service/router.ts +++ b/plugins/nomad-backend/src/service/router.ts @@ -41,7 +41,7 @@ export async function createRouter( resp.json({ status: 'ok' }); }); - router.get('/v1/allocations', async (req, resp) => { + router.get('/v1/allocations', async (req, res) => { // Check namespace argument const namespace = (req.query.namespace as string) ?? ''; if (!namespace || namespace === '') { @@ -53,23 +53,29 @@ export async function createRouter( logger.debug(`request headers: namespace=${namespace} filter=${filter}`); // Issue the request - const allocationsResp = await fetch( - `${addr}/v1/allocations?namespace=${encodeURIComponent( - namespace, - )}&filter=${encodeURIComponent(filter)}`, - { - method: 'GET', - headers: { - Accept: 'application/json', - 'X-Nomad-Token': token || '', - }, + const endpoint = `${addr}/v1/allocations?namespace=${encodeURIComponent( + namespace, + )}&filter=${encodeURIComponent(filter)}`; + const allocationsResp = await fetch(endpoint, { + method: 'GET', + headers: { + Accept: 'application/json', + 'X-Nomad-Token': token || '', }, - ); + }); + + // Check response + if (allocationsResp.status !== 200) { + const body = await allocationsResp.text(); + logger.error(`failed to call /v1/allocations endpoint: ${body}`); + res.status(allocationsResp.status).send(body); + return; + } // Deserialize and return const allocationsBody = await allocationsResp.json(); logger.debug(`/v1/allocations response: ${allocationsBody}`); - resp.json(allocationsBody); + res.json(allocationsBody); }); router.get('/v1/job/:job_id/versions', async (req, resp) => { @@ -82,8 +88,10 @@ export async function createRouter( // Get job ID const jobID = (req.params.job_id as string) ?? ''; + logger.info(`token: ${token}`); + // Issue the request - const versionsResp = await fetch( + const apiResp = await fetch( `${addr}/v1/job/${jobID}/versions?namespace=${encodeURIComponent( namespace, )}`, @@ -96,8 +104,16 @@ export async function createRouter( }, ); + // Check response + if (apiResp.status !== 200) { + const body = await apiResp.text(); + logger.error(`failed to call /v1/job/:job_id/versions endpoint: ${body}`); + resp.status(apiResp.status).send(body); + return; + } + // Deserialize and return - const versionsBody = await versionsResp.json(); + const versionsBody = await apiResp.json(); logger.debug(`/v1/job/:job_id/versions response: ${versionsBody}`); resp.json(versionsBody); }); diff --git a/plugins/nomad/README.md b/plugins/nomad/README.md index ef83b34fe1..593888f64c 100644 --- a/plugins/nomad/README.md +++ b/plugins/nomad/README.md @@ -12,7 +12,7 @@ This plugin has a corresponding backend plugin required to call the Nomad cluste ### Features -At the time of writing, this plugin provides two components: +This plugin provides two components: - a table to view recent [job versions](https://developer.hashicorp.com/nomad/docs/commands/job/history) - a table to view [allocations for a job and/or group](https://developer.hashicorp.com/nomad/tutorials/manage-jobs/jobs-inspect) @@ -25,7 +25,7 @@ You will need to have the backend Nomad plugin, `@backstage/plugin-nomad-backend You will need a running Nomad cluster with an API address that is reachable from the `@backstage/plugin-nomad/backend` plugin [running in the back end](https://backstage.io/docs/overview/architecture-overview/#third-party-backed-plugins). You can follow [this tutorial](https://developer.hashicorp.com/nomad/tutorials/enterprise/production-deployment-guide-vm-with-consul) to learn how to deploy one. -If your Nomad cluster has ACLs enabled, you will need a `token` with at least [`list-jobs` and `read-jobs` capabilities](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-policies#namespace-rules). You can check [this tutorial](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-create-policy) for more info. +If your Nomad cluster has ACLs enabled, you will need a `token` with at least the [`list-jobs`capability](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-policies#namespace-rules). You can check [this tutorial](https://developer.hashicorp.com/nomad/tutorials/access-control/access-control-create-policy) for more info or the minimal [example below](#example-policy). ### Installation @@ -121,3 +121,47 @@ const serviceEntityPage = ( #### Requirements - `nomad.io/job-id` and/or `nomad.io/group` annotations must be set + +## ACL Policy Example + +Because this plugin uses API endpoints that require the `list-jobs` capability, the token you provide to the plugin's [`nomad` configuration](#configuration) needs at least that. + +To create such a token you can create a policy like below. This policy applies to all namespaces: + +```hcl +# backstage.policy.hcl +namespace "*" { + policy = "read" +} + +node { + policy = "read" +} +``` + +And create a policy for it: + +```bash +nomad acl policy apply backstage backstage.policy.hcl +``` + +Then create a client token for it: + +```bash +nomad acl token create -name=backstage -policy=backstage +Accessor ID = 5e9fe97b-76c5-8803-21b8-083308dc6c11 +Secret ID = 93e034ad-e504-42f9-129d-5d81be9f13d3 +Name = backstage +Type = client +Global = false +Create Time = 2023-06-05 00:45:20.51905 +0000 UTC +Expiry Time = +Create Index = 54 +Modify Index = 54 +Policies = [backstage] + +Roles + +``` + +In the example above, the `Secret ID` is the `token` to use in the [configuration](#configuration).