Skip to content

docs: add ADR-0009 for Akrites CDP public API authentication (CM-1333)#4345

Open
joanagmaia wants to merge 6 commits into
mainfrom
docs/CM-1333-akrites-cdp-auth-adr
Open

docs: add ADR-0009 for Akrites CDP public API authentication (CM-1333)#4345
joanagmaia wants to merge 6 commits into
mainfrom
docs/CM-1333-akrites-cdp-auth-adr

Conversation

@joanagmaia

@joanagmaia joanagmaia commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds ADR-0009 documenting the authentication strategy for the Akrites → CDP public API integration.
  • Adds a high-level companion doc docs/akrites-cdp-auth-highlevel.md (mirror of the internal DSP page).
  • Covers all four affected repositories: auth0-terraform, lfx-secrets-management, crowd.dev, and Akrites (external).
  • Includes a Mermaid sequence diagram of the full auth flow: cross-account key read → Auth0 token exchange → CDP request → azp + scope validation.

Context

Akrites is a new external consumer needing read-only access to CDP's public API through a new /akrites-external route on the existing public API listener. The ADR formalizes the M2M auth strategy:

  • Existing cdp_public_api resource server (not a new one) — a new RS would mean minting a second audience for the same logical API with no separate service backing it.
  • azp allowlist middleware on the /akrites-external route as the sole gate for consumer identity. Scopes alone do not identify the consumer.
  • Domain scopes read:packages, read:advisories, read:maintainers on the granted token. read:packages already exists on the RS and is reused (also granted to lfxone_cdp); read:advisories + read:maintainers are new.
  • RSA private_key_jwt authentication, with the private key in an LF-owned AWS Secrets Manager entry. A resource (item) policy on that secret grants Akrites' workload IAM role GetSecretValue (+ kms:Decrypt if CMK). Akrites reads cross-account — same pattern as cross-account S3.
  • LF-side rotation via lfx-secrets-management on the standard cadence. Akrites reacts to invalid_client by re-reading the latest key version and retrying once.

Open decision

Where Akrites runs (AWS account + workload IAM role) is not yet confirmed — deferred to the week of 2026-07-27. If Akrites has no AWS account (or no workload role for LF to grant access to via the item policy), we fall back to a shared client_secret variant: same client, same scopes, same CDP middleware chain — only the lfx-secrets-management sync source flips from auth0_jwt back to auth0, and rotation becomes out-of-band. Fallback is documented in both docs; CDP-side code is unaffected either way.

Companion PRs

  • auth0-terraform — new Akrites External client, new scopes on cdp_public_api, new grant: PR #350 (draft) — branch feat/CM-1333-akrites-external-cdp-auth.
  • lfx-secrets-management (to be implemented) — sync entry rotating the client to private_key_jwt, destinations 1Password + LF-owned AWS Secrets Manager: branch feat/CM-1333-akrites-external-secret-sync (PR pending).

Jira: CM-1333

🤖 Generated with Claude Code

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 15, 2026 10:29
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Documentation-only ADR and index update; no runtime auth or API behavior changes in this PR.

Overview
Adds ADR-0009 (status proposed) and indexes it in docs/adr/README.md. The ADR records how external consumer Akrites will authenticate to CDP’s existing public API on /akrites-external, without introducing a new Auth0 resource server or audience.

The chosen default is M2M private_key_jwt: Akrites reads an LF-owned RSA key from cross-account AWS Secrets Manager, exchanges a signed client_assertion at LFX Auth0 for a Bearer token on cdp_public_api, then calls CDP. Consumer identity is isolated via a planned azp allowlist on the route (not scopes alone); access is limited to read:packages, read:advisories, and read:maintainers. The doc spells out follow-on work across auth0-terraform, lfx-secrets-management, crowd.dev (new azpAllowlistMiddleware, env config, mount-level scopes, refactor of inner scope guards on the existing akrites-external router), and the external Akrites repo, plus a Mermaid auth-flow diagram.

It also documents an open assumption (Akrites AWS workload role, KMS/CMK for cross-account decrypt) and a client_secret fallback if Akrites cannot do cross-account secret reads, with deltas for secrets sync only.

Reviewed by Cursor Bugbot for commit 2bb785c. Bugbot is set up for automated code reviews on this repo. Configure here.

@joanagmaia
joanagmaia requested a review from ulemons July 15, 2026 10:32

Copilot AI left a comment

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.

Pull request overview

Adds a proposed ADR for Akrites machine-to-machine authentication to the CDP public API.

Changes:

  • Defines the Auth0 token exchange and authorization flow.
  • Outlines implementation across four affected repositories.
  • Adds ADR-0009 to the ADR index.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
docs/adr/0009-akrites-cdp-public-api-authentication.md Documents the proposed authentication architecture and implementation plan.
docs/adr/README.md Adds ADR-0009 to the index.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/README.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Copilot AI review requested due to automatic review settings July 15, 2026 10:34

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/README.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Align proposed approach with LF-owned Secrets Manager cross-account read
model, prune Alternatives to shared client_secret fallback only, switch
scopes to read:packages + read:advisories + read:maintainers, and fix
Mermaid diagram parse errors.

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 21, 2026 13:43

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 10 comments.

Comments suppressed due to low confidence (3)

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

  • The PR description says this integration will use a dedicated resource server and a read:akrites scope, but the ADR decides to reuse cdp_public_api with three different scopes. These are materially different authentication designs; update either the PR description or this decision so reviewers know which architecture is actually proposed.
Authenticate Akrites against the **existing `cdp_public_api` resource
server**, gated by an **`azp` allowlist middleware** in CDP (sole consumer
identity gate) and domain scopes **`read:packages`**, **`read:advisories`**,
**`read:maintainers`** on the granted token. Distribute the RSA private

docs/adr/README.md:18

  • The index date does not match the ADR's 2026-07-21 date, leaving conflicting metadata for the same decision.
| [ADR-0009](./0009-akrites-cdp-public-api-authentication.md) | Akrites → CDP public API authentication | proposed | 2026-07-14 |

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

  • The ADR ends without the mandatory ## Consequences section and its ### Positive, ### Negative, and ### Risks subsections required by .claude/rules/adr-format.md:16-31. Capture the accepted trade-offs and mitigations before this ADR is merged.
  LF rather than auto-retry; do not tight-loop.

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
Copilot AI review requested due to automatic review settings July 21, 2026 13:49

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (8)

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

  • The referenced companion document is not included in this PR or present in the repository, despite the PR description saying it is added. Add docs/akrites-cdp-auth-highlevel.md, or remove this reference and update the PR description.
High-level overview: `docs/akrites-cdp-auth-highlevel.md`
(mirror of the internal DSP page).

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

  • This route-level scope check does not replace the existing nested checks. akrites-external/index.ts:43 still also requires read:stewardships, and line 66 requires read:maintainer-roles; neither is granted here, so the documented Akrites token will receive 403s for package and contact endpoints. Update those subrouter guards and the OpenAPI contract to use the new domain scopes; otherwise grant the existing scopes.
  requireScopes(
    [SCOPES.READ_PACKAGES, SCOPES.READ_ADVISORIES, SCOPES.READ_MAINTAINERS],
    'all',
  ),

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

  • ECS ValueFrom injects the secret only when a task starts; a running task does not receive rotated values. That option cannot support the documented invalid_client re-read without redeployment. Require an SDK/runtime fetch through the task or pod role, or explicitly document forced task deployment on rotation.
   full LF secret ARN. Prod options: ECS `ValueFrom` on the task definition
   with the LF ARN, or EKS External Secrets Operator + IRSA. Dev:
   1Password via the LF-provided vault item.

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

  • A cross-account Secrets Manager secret cannot use the AWS-managed aws/secretsmanager key, so a customer-managed KMS key and kms:Decrypt permissions are mandatory, not conditional. Also, kms:Decrypt belongs in the KMS key policy and caller identity policy—not the secret resource policy. Apply the same correction to the optional-CMK wording earlier in the ADR.
**Resource policy on the LF secret** — grants Akrites' workload IAM role
`secretsmanager:GetSecretValue` + `secretsmanager:DescribeSecret`. Deny
wildcards. If the secret is CMK-encrypted, the KMS key policy must also
allow `kms:Decrypt` for that role. Akrites' AWS account ID + workload role
ARN required from the Akrites team before the resource policy can be

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

  • The Auth0 request description omits required form fields (client_id, audience, and client_assertion), and the assertion step omits Auth0's required claims. Following these steps literally cannot complete the token exchange; document the complete request and the required iss, sub, aud, exp, and unique jti claims.
2. Build and sign `client_assertion` JWT (RS256).
3. POST to Auth0 `/oauth/token` with `grant_type=client_credentials` +
   `client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer`.

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

  • This ADR ends after Alternatives and omits the mandatory ## Consequences section with ### Positive, ### Negative, and ### Risks. Add it as required by .claude/rules/adr-format.md:16-31; rotation ordering, cross-account availability, and the consumer-allowlist operational burden should be captured there.
## Alternatives Considered

docs/adr/README.md:18

  • The index date does not match the ADR's 2026-07-21 date, making the ADR index inaccurate.
| [ADR-0009](./0009-akrites-cdp-public-api-authentication.md) | Akrites → CDP public API authentication | proposed | 2026-07-14 |

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

  • The Context section substantially exceeds the required 2–5 sentences in .claude/rules/adr-format.md:25. Keep only the situation and decision forces here, and move implementation details into clearly named sections after the Decision.
## Context

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 14:14
Fix audience contradiction (shared AUTH0_CONFIG across public routes),
correct public URL path to /api/v1/akrites-external, reword the new route
mount as an insertion before the 404 handler, soften KMS wording with a
DevOps validation note, expand Akrites-side delivery patterns to reflect
ValueFrom rotation constraints, spell out the /oauth/token request body,
drop the stale highlevel doc reference, and bump the ADR index date.

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
@joanagmaia
joanagmaia force-pushed the docs/CM-1333-akrites-cdp-auth-adr branch from eb630a6 to 70f1c0b Compare July 21, 2026 14:15

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (4)

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

  • The ADR is missing the mandatory ## Consequences section with ### Positive, ### Negative, and ### Risks. .claude/rules/adr-format.md:27-30 requires all of these before an ADR can be added, so please document the accepted trade-offs and mitigations.
  LF rather than auto-retry; do not tight-loop.

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

  • This Context contains substantially more than the required 2–5 sentences and mixes background with detailed implementation guidance. .claude/rules/adr-format.md:25 requires a concise Context; move the KMS, route, and scope details into dedicated sections so the decision record remains scannable.
## Context

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

  • The PR description says it adds docs/akrites-cdp-auth-highlevel.md, but that companion document is absent from the changed files and repository. Either include the promised mirror or update the PR description so the documented scope matches the change.
# ADR-0009: Akrites → CDP public API authentication

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

  • This mount-level all check, combined with removing inner scope guards, does not implement the domain-level handler isolation claimed at lines 62–64: every admitted token must carry all three scopes and can reach every handler. Either enforce each scope on its corresponding subrouter, or explicitly document that these scopes are an all-or-nothing route bundle rather than independent domain authorization.
  requireScopes(
    [SCOPES.READ_PACKAGES, SCOPES.READ_ADVISORIES, SCOPES.READ_MAINTAINERS],
    'all',

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Copilot AI review requested due to automatic review settings July 21, 2026 14:18

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (5)

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

  • The PR description says this change adds docs/akrites-cdp-auth-highlevel.md, but that companion document is absent from the changed files and the checkout. Either add the promised document or update the PR description so the delivered scope is accurate.
# ADR-0009: Akrites → CDP public API authentication

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

  • This Context is far beyond the required 2–5 sentences and mixes implementation instructions, open questions, and decision details into the problem statement. Please keep the Context concise and move the detailed material into focused sections; .claude/rules/adr-format.md:25 makes the 2–5 sentence structure mandatory for ADRs.
## Context

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

  • Cross-account Secrets Manager access cannot use the AWS-managed aws/secretsmanager key; AWS requires a customer-managed KMS key plus aligned key and identity policies. Leaving the CMK as conditional allows an implementation that cannot retrieve the secret, so make this a requirement rather than a DevOps validation item throughout the ADR.
If the secret is encrypted with a customer-managed KMS key (likely
required for cross-account decrypt — LF DevOps to confirm), the KMS key
policy must also grant `kms:Decrypt` to that role. Akrites reads

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

  • This is not the repository's current state: akritesExternalRouter() and its mount already exist, and the router has four endpoint-specific requireScopes guards (index.ts:43,54,66,76). The proposed mount-wide all-scopes guard also conflicts with the existing OpenAPI security declarations. Document this as a migration, decide whether per-domain authorization is intentionally being removed, and include the required OpenAPI update.
`akritesExternalRouter()` is a **new module** at
`backend/src/api/public/v1/akrites-external/index.ts` — separate from the
existing `akritesRouter` and free of its inner scope guards, so the
mount-level `requireScopes` above is authoritative for this route.

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

  • The ADR ends after Alternatives and omits the mandatory ## Consequences section with ### Positive, ### Negative, and ### Risks. Add those sections before merging; they are required by .claude/rules/adr-format.md:28 and are especially important for the stated cross-account and rotation trade-offs.
## Alternatives Considered

Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md Outdated
Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
…WS caller identity (CM-1333)

Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
Copilot AI review requested due to automatic review settings July 21, 2026 14:57

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (7)

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

  • The ADR ends without the mandatory ## Consequences section and its ### Positive, ### Negative, and ### Risks subsections. .claude/rules/adr-format.md:27-31 requires all four headings, so this ADR does not satisfy the repository template yet.
  LF rather than auto-retry; do not tight-loop.

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

  • This section is substantially longer than the required 2–5 sentence Context in .claude/rules/adr-format.md:25. Please move implementation detail into later supporting sections and keep Context focused on the forces that prompted the decision.
## Context

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

  • The Decision is five sentences, while .claude/rules/adr-format.md:26 limits it to 1–3 sentences. Condense the selected authentication, authorization, and secret-delivery choice here; retain the conditional and implementation details in supporting sections.
## Decision

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

  • Requiring all three scopes at the mount and then removing the subrouter checks makes authorization all-or-nothing: every accepted token can call every domain handler. That contradicts lines 62–64, which say domain scopes constrain which handlers are reachable, and prevents least-privilege package-, advisory-, or maintainer-only access. Keep the azp gate global and enforce each domain scope on its relevant subrouter, or explicitly revise the decision if all-or-nothing access is intended.
  requireScopes(
    [SCOPES.READ_PACKAGES, SCOPES.READ_ADVISORIES, SCOPES.READ_MAINTAINERS],
    'all',
  ),

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

  • config.get('akritesExternal.clientId') throws during module import when the environment variable is absent. Because the plan only adds the custom-environment mapping, any local, test, or deployed environment not populated before this code rolls out will fail backend startup. Include the required environment propagation and rollout order, or make configuration optional while keeping the route fail-closed.
Add:
```ts
export const AKRITES_EXTERNAL_CLIENT_ID: string = config.get<string>('akritesExternal.clientId')
**docs/adr/0009-akrites-cdp-public-api-authentication.md:313**
* This retry procedure cannot work for the documented ECS `ValueFrom` option: as lines 281–282 note, a running task cannot re-read the rotated value and must be replaced, so an in-process retry uses the same stale key. Specify separate recovery behavior for each delivery mode and update the sequence diagram accordingly; ECS needs task replacement rather than re-fetch-and-retry.
  1. On invalid_client: discard the cached key → re-fetch from the secret
    store (SDK read, or task/pod refresh depending on the pattern chosen
    in step 1) → retry the token exchange once. LF rotates the keypair
    without notice.
**docs/adr/0009-akrites-cdp-public-api-authentication.md:1**
* The PR description says this change also adds `docs/akrites-cdp-auth-highlevel.md`, but that companion document is absent from the changed files. Add the promised document or update the PR description so reviewers and consumers have an accurate deliverable list.

ADR-0009: Akrites → CDP public API authentication

</details>


Comment thread docs/adr/0009-akrites-cdp-public-api-authentication.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants