Skip to content

Commit 6820409

Browse files
committed
Support Authentik workload job e2e
Signed-off-by: Ryan S <267728323+ironcommit@users.noreply.github.com>
1 parent 926d970 commit 6820409

30 files changed

Lines changed: 2056 additions & 557 deletions

File tree

‎Makefile‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,8 @@ docs-check: ## Validate the Fern docs (fern check + validate-mdx + gated-link ch
123123
cd docs/fern && npm run check
124124

125125
.PHONY: test-auth-idp
126-
AUTHENTIK_E2E_LIFECYCLE ?= fresh
127126
test-auth-idp: ## Run the auth-idp test suite
128-
AUTHENTIK_E2E_LIFECYCLE=$(AUTHENTIK_E2E_LIFECYCLE) uv run --frozen pytest tests/auth_idp -v --run-e2e
127+
bash contrib/auth/authentik/run.sh test $(ARGS)
129128

130129
.PHONY: docs-check-python-snippets
131130
docs-check-python-snippets: ## Syntax-check and type-check Python snippets in one doc (DOCS_PATH=...)

‎contrib/auth/authentik/README.md‎

Lines changed: 82 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The stack seeds these local-only identities:
2323
- Human password: `nemo-user-password-dev`
2424
- Human email: `nemo-user@example.com`
2525
- CLI OIDC client: `nemo-platform-cli`
26-
- Workload identity: `svc-nemo-ci`
26+
- Workload identity: `svc-nemo`
2727
- Workload group: `nemo-editors`
2828

2929
## Start The Stack
@@ -35,35 +35,45 @@ contrib/auth/authentik/run.sh stack
3535
```
3636

3737
This starts NeMo, Authentik, and the local gateway with the existing default
38-
NeMo API image, `my-registry/nmp-api:local`. The script does not build images.
38+
NeMo API image, `my-registry/nmp-api:local`. The `stack` action does not build
39+
images.
3940
Leave this process running. Stop it with `Ctrl-C` when you are done; the script
4041
removes the Compose stack and volumes on exit.
4142

4243
To use a different prebuilt image for the example, pass it explicitly:
4344

4445
```bash
45-
contrib/auth/authentik/run.sh stack --image registry.example.com/nemo/nmp-api:<tag>
46+
export IMAGE_REGISTRY=registry.example.com/nemo
47+
export BAKE_TAG=<tag>
48+
49+
contrib/auth/authentik/run.sh stack --image "$IMAGE_REGISTRY/nmp-api:$BAKE_TAG"
4650
```
4751

48-
The auth-idp test suite has one entrypoint:
52+
Use the same `IMAGE_REGISTRY` and `BAKE_TAG` values in the shell where you
53+
submit the workload job so the job container image matches the running NeMo API
54+
image.
55+
56+
The auth-idp test suite uses the same helper script:
4957

5058
```bash
51-
make test-auth-idp
59+
contrib/auth/authentik/run.sh test
5260
```
5361

54-
To run the tests against the same prebuilt image used by the example, pass the
55-
matching registry and tag to that test target:
62+
For iteration or prebuilt images, pass options to the script directly. See
63+
`contrib/auth/authentik/run.sh --help` for the full option list.
5664

5765
```bash
58-
IMAGE_REGISTRY=registry.example.com/nemo BAKE_TAG=<tag> make test-auth-idp
66+
contrib/auth/authentik/run.sh test --lifecycle reuse
67+
contrib/auth/authentik/run.sh test --image registry.example.com/nemo/nmp-api:<tag>
5968
```
6069

61-
Wait until the gateway is ready:
70+
Wait until the platform is ready through the gateway:
6271

6372
```bash
64-
until curl -sf http://127.0.0.1:18080/apis/auth/discovery >/dev/null; do
73+
until curl -sf http://127.0.0.1:18080/health/ready >/dev/null; do
6574
sleep 2
6675
done
76+
echo "NeMo Platform Ready"
6777
```
6878

6979
The local gateway URL is:
@@ -119,91 +129,80 @@ nemo --context authentik-human workspaces members create \
119129
--workspace "$WORKSPACE" \
120130
--principal nemo-editors \
121131
--roles Viewer \
122-
--roles JobLogWriter \
132+
--roles JobRunner \
123133
--wait-role-propagation
124134
```
125135

126136
Expected result: the human user can manage the workspace, and the workload
127-
group can read the workspace and upload job logs.
137+
group can read the workspace from a job.
128138

129139
## Run A Workload Job
130140

131141
```bash
132142
export JOB_NAME=authentik-workload-demo
133-
export WORKLOAD_TOKEN_SECRET="${JOB_NAME}-token"
134143
```
135144

136-
Fetch a local demo token for the seeded workload identity and store it as a
137-
workspace secret:
145+
Fetch a local demo token for the seeded workload identity:
138146

139147
```bash
140-
export NEMO_WORKLOAD_TOKEN="$(
148+
export WORKLOAD_ACCESS_TOKEN="$(
141149
curl -fsS http://127.0.0.1:18080/application/o/token/ \
142150
-d grant_type=password \
143151
-d client_id=nemo-platform \
144152
-d client_secret=nemo-platform-secret-dev \
145-
-d username=svc-nemo-ci \
146-
-d password=svc-nemo-ci-token-secret-dev \
153+
-d username=svc-nemo \
154+
-d password=svc-nemo-token-secret-dev \
147155
-d scope="openid email groups" \
148156
| python -c 'import json, sys; print(json.load(sys.stdin)["access_token"])'
149157
)"
150-
151-
printf '%s' "$NEMO_WORKLOAD_TOKEN" \
152-
| nemo --context authentik-human secrets create "$WORKLOAD_TOKEN_SECRET" \
153-
--workspace "$WORKSPACE" \
154-
--from-file -
155158
```
156159

157-
Create the job request:
158-
159-
```bash
160-
python - <<'PY' >/tmp/authentik-workload-job.json
161-
import json
162-
import os
163-
import sys
164-
165-
payload = {
166-
"source": "authentik-reference-example",
167-
"spec": {"demo": "authentik-workload-auth"},
168-
"platform_spec": {
169-
"steps": [
170-
{
171-
"name": "workload-workspace-get",
172-
"executor": {
173-
"provider": "cpu",
174-
"profile": "workload",
175-
"container": {
176-
"entrypoint": ["nemo-platform"],
177-
"command": [
178-
"run",
179-
"task",
180-
"--task",
181-
"nmp.hello_world.tasks.workload_workspace_get",
182-
],
183-
},
184-
},
185-
"environment": [
186-
{
187-
"name": "NEMO_WORKLOAD_TOKEN",
188-
"from_secret": {"name": os.environ["WORKLOAD_TOKEN_SECRET"]},
189-
}
190-
],
191-
"config": {"workspace": os.environ["WORKSPACE"]},
192-
}
193-
]
194-
},
195-
}
196-
197-
json.dump(payload, sys.stdout, indent=2)
198-
PY
199-
```
160+
Keep this token in a non-reserved shell variable. Do not export it as
161+
`NEMO_WORKLOAD_TOKEN` in your shell. The NeMo CLI uses that variable as a
162+
runtime credential override, which would make later CLI commands run as the
163+
workload identity instead of `authentik-human`.
200164

201-
Submit the job:
165+
Submit a job that runs the built-in hello-world workload auth task:
202166

203167
```bash
204-
nemo --context authentik-human jobs create "$JOB_NAME" \
168+
export NMP_API_IMAGE="${NMP_API_IMAGE:-${IMAGE_REGISTRY:-my-registry}/nmp-api:${BAKE_TAG:-local}}"
169+
170+
cat <<EOF | nemo --context authentik-human jobs create "$JOB_NAME" \
205171
--workspace "$WORKSPACE" \
206-
--input-file /tmp/authentik-workload-job.json
172+
--input-file -
173+
{
174+
"source": "authentik-reference-example",
175+
"spec": {"demo": "authentik-workload-auth"},
176+
"platform_spec": {
177+
"steps": [
178+
{
179+
"name": "workload-workspace-get",
180+
"executor": {
181+
"provider": "cpu",
182+
"profile": "workload",
183+
"container": {
184+
"image": "${NMP_API_IMAGE}",
185+
"entrypoint": ["nemo-platform"],
186+
"command": [
187+
"run",
188+
"task",
189+
"--task",
190+
"nmp.hello_world.tasks.workload_workspace_get"
191+
]
192+
}
193+
},
194+
"environment": [
195+
{
196+
"name": "NEMO_WORKLOAD_TOKEN",
197+
"value": "${WORKLOAD_ACCESS_TOKEN}"
198+
}
199+
],
200+
"config": {"workspace": "${WORKSPACE}"}
201+
}
202+
]
203+
}
204+
}
205+
EOF
207206
```
208207

209208
Watch it complete:
@@ -212,7 +211,11 @@ Watch it complete:
212211
nemo --context authentik-human jobs get-status "$JOB_NAME" --workspace "$WORKSPACE"
213212
```
214213

215-
After the job reaches `completed`, read the logs:
214+
Expected result: the job reaches `completed`. The workload exits successfully
215+
only after it uses the Authentik workload token to call NeMo through the gateway
216+
and retrieve the workspace.
217+
218+
Read the job logs:
216219

217220
```bash
218221
nemo --context authentik-human jobs get-logs "$JOB_NAME" \
@@ -226,9 +229,6 @@ Expected result: the logs include:
226229
Successfully retrieved workspace: authentik-demo
227230
```
228231

229-
That confirms the job workload used the Authentik workload token to call NeMo
230-
through the gateway.
231-
232232
## Refresh The CLI Session
233233

234234
The example requests `offline_access`, so the CLI stores a refresh token.
@@ -247,7 +247,6 @@ Remove the demo job and workspace if you created them:
247247

248248
```bash
249249
nemo --context authentik-human jobs delete "$JOB_NAME" --workspace "$WORKSPACE"
250-
nemo --context authentik-human secrets delete "$WORKLOAD_TOKEN_SECRET" --workspace "$WORKSPACE"
251250
nemo --context authentik-human workspaces delete "$WORKSPACE"
252251
```
253252

@@ -261,12 +260,19 @@ Then stop the stack with `Ctrl-C` in the terminal running
261260
- `Permission denied`: verify `nemo --context authentik-human auth status`,
262261
then check
263262
`nemo --context authentik-human workspaces members list --workspace "$WORKSPACE"`.
263+
If `auth status` reports a `NEMO_WORKLOAD_TOKEN` or `NEMO_WORKLOAD_TOKEN_FILE`
264+
environment override, run `unset NEMO_WORKLOAD_TOKEN NEMO_WORKLOAD_TOKEN_FILE`
265+
and retry.
264266
If you just created the workspace or member bindings, wait a few seconds and
265267
retry so the authorization cache can refresh.
266268
- Job stays `created` or `pending`: confirm the stack was started with
267269
`contrib/auth/authentik/run.sh stack` and Docker is running.
268-
- Job completes but logs are missing: confirm `nemo-editors` has `JobLogWriter`
269-
on the workspace.
270+
- Job fails while fetching a secret with `status code 401`: confirm the job
271+
request injects `NEMO_WORKLOAD_TOKEN` with `value`, not `from_secret`. The
272+
local gateway accepts Authentik bearer tokens, while the launcher secret-fetch
273+
path uses internal service headers before the workload starts.
274+
- Job fails with `Permission denied`: confirm `nemo-editors` still has `Viewer`
275+
and `JobRunner` on the workspace before creating the job.
270276

271277
## Adapting This Example
272278

‎contrib/auth/authentik/blueprints/nemo.yaml‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,11 @@ entries:
119119
expiring: false
120120

121121
- model: authentik_core.user
122-
id: svc-nemo-ci
122+
id: svc-nemo
123123
identifiers:
124-
username: svc-nemo-ci
124+
username: svc-nemo
125125
attrs:
126-
username: svc-nemo-ci
126+
username: svc-nemo
127127
name: "NeMo demo workload identity"
128128
type: service_account
129129
path: service-accounts
@@ -132,12 +132,12 @@ entries:
132132

133133
- model: authentik_core.token
134134
identifiers:
135-
identifier: svc-nemo-ci-token
135+
identifier: svc-nemo-token
136136
attrs:
137-
identifier: svc-nemo-ci-token
137+
identifier: svc-nemo-token
138138
intent: app_password
139-
user: !KeyOf svc-nemo-ci
140-
key: svc-nemo-ci-token-secret-dev
139+
user: !KeyOf svc-nemo
140+
key: svc-nemo-token-secret-dev
141141
expiring: false
142142

143143
- model: authentik_brands.brand

‎contrib/auth/authentik/config/platform-compose-authentik.yaml‎

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,8 @@ auth:
3131
entities: {}
3232

3333
jobs:
34+
enable_subprocess_executor: false
3435
executors:
35-
- provider: subprocess
36-
profile: default
37-
backend: subprocess
38-
config:
39-
working_directory: /data/subprocess-jobs
40-
cleanup_completed_jobs_immediately: false
41-
ttl_seconds_before_active: 60
42-
ttl_seconds_active: 3600
43-
ttl_seconds_after_finished: 300
4436
- provider: cpu
4537
profile: workload
4638
backend: docker
@@ -54,12 +46,6 @@ jobs:
5446
ttl_seconds_before_active: 60
5547
ttl_seconds_active: 3600
5648
ttl_seconds_after_finished: 300
57-
subprocess:
58-
working_directory: /data/subprocess-jobs
59-
cleanup_completed_jobs_immediately: false
60-
ttl_seconds_before_active: 60
61-
ttl_seconds_active: 3600
62-
ttl_seconds_after_finished: 300
6349

6450
evaluator:
6551
recreate_existing_system_entities: true

‎contrib/auth/authentik/docker-compose.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ x-authentik-env: &authentik-env
1111
services:
1212
nemo:
1313
image: ${IMAGE_REGISTRY:-my-registry}/nmp-api:${BAKE_TAG:-local}
14+
# The local Docker jobs backend controls sibling workload containers through
15+
# the mounted host socket, which Docker Desktop exposes as root-owned.
16+
user: "0:0"
1417
environment:
1518
MODE: development
1619
NMP_CONFIG_FILE_PATH: /etc/nmp/config.yaml

‎contrib/auth/authentik/manifest.yaml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ human_identity:
1414
username: nemo-user
1515
expected_email: nemo-user@example.com
1616
workload_identity:
17-
principal_id: svc-nemo-ci
17+
principal_id: svc-nemo
1818
expected_groups:
1919
- nemo-editors
2020
workload_contract:
@@ -41,8 +41,8 @@ token_acquisition:
4141
grant_type: password
4242
client_id: nemo-platform
4343
client_secret: nemo-platform-secret-dev
44-
username: svc-nemo-ci
45-
password: svc-nemo-ci-token-secret-dev
44+
username: svc-nemo
45+
password: svc-nemo-token-secret-dev
4646
scope: "openid email groups"
4747
healthchecks:
4848
- kind: http

0 commit comments

Comments
 (0)