Skip to content

Commit 2bb785c

Browse files
committed
docs: address ADR-0009 review comments on route/router refactor and AWS caller identity (CM-1333)
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
1 parent 70f1c0b commit 2bb785c

1 file changed

Lines changed: 28 additions & 24 deletions

File tree

docs/adr/0009-akrites-cdp-public-api-authentication.md

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,9 @@ READ_MAINTAINERS: 'read:maintainers',
234234
Reads `req.auth.payload.azp`. Throws `UnauthorizedError` if the value is
235235
missing or not in the allowlist passed at wire-up. Fails closed.
236236

237-
**`backend/src/api/public/v1/index.ts`**insert a **new** route
238-
registration after the existing `/akrites` mount (line 44) and before the
239-
404 catch-all at line 46:
237+
**`backend/src/api/public/v1/index.ts`**update the existing
238+
`/akrites-external` mount at line 46 to add the `azp` allowlist and the
239+
mount-level scope check on top of the existing `oauth2Middleware`:
240240
```ts
241241
router.use(
242242
'/akrites-external',
@@ -250,10 +250,16 @@ router.use(
250250
)
251251
```
252252

253-
`akritesExternalRouter()` is a **new module** at
254-
`backend/src/api/public/v1/akrites-external/index.ts` — separate from the
255-
existing `akritesRouter` and free of its inner scope guards, so the
256-
mount-level `requireScopes` above is authoritative for this route.
253+
`akritesExternalRouter()` at
254+
`backend/src/api/public/v1/akrites-external/index.ts` already exists (a
255+
recent main merge brought it in) and currently carries per-subrouter
256+
`requireScopes` guards inherited from the pre-decision scaffold —
257+
`[READ_PACKAGES, READ_STEWARDSHIPS]` on packages, `[READ_PACKAGES]` on
258+
advisories/blast-radius, `[READ_MAINTAINER_ROLES]` on contacts. Refactor
259+
the module to strip all inner read-scope guards, so the mount-level
260+
`requireScopes` above is the authoritative check for this route. Leave
261+
any write-scope guards on write routes (there are none today, but the
262+
convention holds).
257263

258264
`/akrites` (Self Serve) is untouched.
259265

@@ -268,27 +274,25 @@ Implement the token exchange described in the Auth Flow diagram:
268274
allow `secretsmanager:GetSecretValue` on the full LF secret ARN. If
269275
LF confirms the secret is encrypted with a customer-managed KMS key
270276
(see the Context KMS note), also allow `kms:Decrypt` on that KMS key
271-
ARN. Choose one of the delivery patterns Eric outlined; each has a
272-
different rotation behavior:
273-
- **ECS `ValueFrom`** on the task definition, referencing the LF
274-
secret ARN. The secret is injected as an environment variable at
275-
task start only — ECS does not refresh `ValueFrom` values while the
276-
task is running. Rotation therefore requires task replacement; the
277-
step-5 retry-once flow means restarting the task, not an in-process
278-
re-read.
279-
- **EKS External Secrets Operator + IRSA**, with the operator
280-
configured to re-sync the secret on a short refresh interval so
281-
pods pick up the rotated value shortly after LF rotates. In-process
282-
retry is still possible if the operator has already refreshed.
283-
- **Direct SDK read** using the workload role — process reads the
284-
secret via `GetSecretValue` at boot and again on demand for the
285-
step-5 retry. Simplest match for the retry-once flow without
286-
touching the task/pod lifecycle.
277+
ARN. Common delivery patterns — Akrites picks one, and the specific
278+
role ARN(s) LF grants in the item policy follow that choice
279+
(task execution role for ECS `ValueFrom`, operator SA role for EKS
280+
External Secrets Operator, workload role for a direct SDK read):
281+
- **ECS `ValueFrom`** — secret injected at task start only, so
282+
rotation means task replacement, not an in-process re-read.
283+
- **EKS External Secrets Operator + IRSA** — pods pick up rotated
284+
values on the operator's refresh interval.
285+
- **Direct SDK read** — process reads the secret at boot and again
286+
on demand for the step-5 retry; simplest match for the
287+
retry-once flow.
287288

288289
Dev: 1Password via the LF-provided vault item.
289290
2. Build and sign a `client_assertion` JWT with `alg: RS256` and header
290291
`kid` set to the current key's ID. Claims: `iss` = `sub` =
291-
Akrites client ID, `aud` = LFX Auth0 tenant token endpoint URL, short
292+
Akrites client ID, `aud` = **LFX Auth0 tenant base URL, with the
293+
trailing slash** (e.g. `https://linuxfoundation.auth0.com/`, or the
294+
custom-domain equivalent) — Auth0's `private_key_jwt` verifier
295+
expects the issuer URL, not the `/oauth/token` endpoint. Short
292296
`exp` (≤ 5 min), unique `jti`.
293297
3. POST to Auth0 `/oauth/token` as `application/x-www-form-urlencoded`
294298
with:

0 commit comments

Comments
 (0)