Skip to content

Document service accounts - #1264

Open
peppescg wants to merge 33 commits into
mainfrom
service-accounts-docs
Open

peppescg wants to merge 33 commits into
mainfrom
service-accounts-docs

Conversation

@peppescg

@peppescg peppescg commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Description

Documents service accounts in Stacklok Enterprise, following the acceptance criteria in stacklok/stacklok-enterprise-platform#4934. A service account gives a Kubernetes workload its own directory identity, groups, model set grants, and budget. The workload authenticates to both the AI Gateway and the Connector Gateway with its pod's projected ServiceAccount token, so there's no static key.

New pages:

  • platform/enterprise-directory/service-accounts.mdx (AC4.1, AC4.5, AC4.6): when to use a service account instead of a virtual API key, trusting a cluster's issuer, the creation wizard, pinned and name-only bindings (including reassign), activation, revocation and deletion, and what an account can reach depending on model access, budgets, and connector authentication.
  • ai-gateway/kubernetes-workloads.mdx (AC4.2): the projected token volume, audience and expirationSeconds: 1800, Authorization: Bearer only, what 401, 402, 403, and 503 mean, and where an administrator finds the reason behind a refusal.
  • connector-gateway/kubernetes-workloads.mdx: the same token on /gw/mcp, a curl check, which connectors and tools an account gets (None, Bearer token, and Header injection connectors granted to its groups, no connections to make), and the gateway's 401, 403, and 503.

Updated pages:

  • configure-ai-gateway.mdx: new "Accept service account workloads" section with the cluster administrator's prerequisites (AC4.3).
  • configure-connector-gateway.mdx: new "Accept service account workloads" section (on by default over TLS, what the chart sets up, egress rules, turning it off, accounts shared with the AI Gateway), plus the workloadTrustSaSubjectAllowlist row for a renamed gateway.
  • users-and-groups, manage-budgets, budgets-and-pricing, virtual-api-keys (AC4.4).
  • control-model-access, connector-policies, connectors (service accounts on the Activity tab), both forward-audit-logs pages (service account subjects), the console and directory index pages, and sidebars.ts.

Every claim was checked against stacklok-enterprise-platform main (v0.26.0), including the Connector Gateway work in stacklok/stacklok-enterprise-platform#5799, #5849, #5855, #5930, and #5963.

Keep in draft until

  • The service_accounts console flag is on by default (stacklok/stacklok-enterprise-platform#5519). It still defaults to off in v0.26.0.
  • stacklok/stacklok-enterprise-platform#4933 lands. The pages state the 60-minute token lifetime ceiling it decides; main still has 2 hours.
  • The v0.26.0 upstream release sync lands. The generated Helm reference is still at chart 0.25.0, so it lacks global.stacklok.connectorGateway.workloadIdentity.enabled, connector-gateway.enterpriseConfig.workloadIdentity.pollInterval, and the Connector Gateway entry in the workloadTrustSaSubjectAllowlist default.

Resolved: the Connector Gateway accepts workload tokens (v0.26.0), the console labels the in-cluster issuer This cluster (stacklok/stacklok-enterprise-platform#5543), and #1244 merged.

Where the pages follow the code instead of #4934

  • AC4.5, "bound or not": both gateways refuse any workload the directory doesn't resolve to an active, bound account (stacklok/stacklok-enterprise-platform#5401), even with model access and budgets off.
  • AC4.2, the opaque 401: an invalid token gets 401, while a valid token without an active binding gets 403. The pages cover both, with the audit reason_code values and the Enterprise Manager's workload.resolutions metric and debug log.
  • AC4.3, Envoy trust limits: skipped. The Envoy-based gateway doesn't serve service accounts (stacklok/stacklok-enterprise-platform#4961).
  • AC4.3, in-cluster key permission: both charts bind system:service-account-issuer-discovery, so it's documented as a check, not a manual step.
  • Audience: the console has no default audience, so the pages tell administrators to enter one, with stacklok-enterprise-platform as the example.
  • Key rotation: the pages say to wait 15 minutes before signing with a new key, the longest a gateway keeps cached keys, instead of the default 5-minute valid_for.

Type of change

  • New documentation
  • Documentation update
  • Navigation/structure change

Related issues/PRs

  • stacklok/stacklok-enterprise-platform#4934 (user documentation for service accounts)
  • stacklok/stacklok-enterprise-platform#5024 (console service accounts story)
  • stacklok/stacklok-enterprise-platform#5640 (Connector Gateway service accounts epic)
  • stacklok/stacklok-enterprise-platform#4933 (token lifetime ceiling)
  • stacklok/stacklok-enterprise-platform#5519 (console flag removal)

Screenshots

None. No page in the platform, AI Gateway, or Connector Gateway sections uses screenshots.

Submitter checklist

Content and formatting

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

Navigation

  • New pages include a frontmatter section with title and description at a minimum
  • Sidebar navigation (sidebars.ts) updated for added, deleted, reordered, or renamed files
  • Redirects added to vercel.json for moved, renamed, or deleted pages (no URLs changed, so none needed)

Reviewer checklist

Content

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

🤖 Generated with Claude Code

aponcedeleonch and others added 23 commits October 23, 2026 09:00
Move the budgets API, pricing catalog, spend monitoring, console budget
flow, and audit shipper sections into partials so a second gateway
section can reuse them. The budgets endpoints are served by Enterprise
Manager, so the examples use an Enterprise Manager placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Alejandro Ponce <aponcedeleonch@stacklok.com>
Add a self-contained section for AI Gateway v2 that mirrors the AI
Gateway page set: providers, routing and model access, budgets,
screening, audit logs, telemetry, an endpoints reference, and a
migration guide. Add a platform setup page and wire the section into
the navbar, sidebars, platform overview, and visual tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Alejandro Ponce <aponcedeleonch@stacklok.com>
Make status codes, egress rules, value path conventions, and the
migration mapping agree across the AI Gateway v2 pages and the setup
page, and document where scan decisions land in audit records.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Alejandro Ponce <aponcedeleonch@stacklok.com>
The shared partials carried over errors from the v1 pages. Pricing
writes go through per-entry PUT with If-Match, budget subjects are
directory UUIDs, and the Fluent Bit and Promtail filters dropped
every audit record. Also cover service account budgets and bulk
import precedence, which exist on platform main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add the cluster OIDC issuer and groupsResolutionIssuer to setup,
document disconnect through the API since the console hides it for
v2-only installs, and correct migration mappings, error tables, and
failure classes against source. Also apply repo style conventions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Snapshot capture also persists bodies, ready pods don't prove a
working budgets or provider setup, and removing a provider's Secret
must wait for the rollout so old pods keep their credentials.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Capture stores log-only matches and fail-open requests unredacted, so
turning on scanning alone doesn't protect captured bodies. Name the
settings that do.

Most country-specific Presidio recognizers ship disabled in the bundled
registry, so listing IN_AADHAAR or AU_TFN fails the adapter rollout
rather than enabling detection.

Drop service account caller content (budgets, 403 cause, and the
workloadIssuers migration row) until workload callers are documented.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Trim operational detail the v1 pages don't carry: reason-code, span,
metric, and error tables, troubleshooting entries without a v1
counterpart, and repeated rollout explanations, which now live once in
"How configuration changes apply". Keep sections for v2-only features.

Fill v1 gaps where v2 behaves the same, verified against platform main:
NIST audit fields, the Kubernetes API audit log pointer, Vertex region
and credential notes, the Connector Gateway link, the directory
namespace note, content screening posture, and the private CA note.

Restore the v1 organization default sentence dropped in 5c2a0d7, and
fix the budgets probe check, since a first-try success logs nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document the new implementation as the AI Gateway at the unqualified
/ai-gateway URLs and move the operator-based implementation under
/ai-gateway/legacy, with one navbar entry and one sidebar. Reader-facing
prose no longer says "v2"; literal chart and value names keep it.

Budgets get one shared home (budgets-and-pricing, manage-budgets), and
each gateway gets a budget-enforcement page for its own connection and
verification steps. The legacy setup page moves to
platform/enterprise-platform/legacy/configure-ai-gateway.

Every legacy page carries a pointer to its current counterpart and to a
new "Identify your deployment" section, and current task pages point
back to their legacy counterparts. The retired management API URL
redirects to its legacy location.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A samplingRate of 0 keeps every root span, and a sampled inbound
traceparent is always kept, so the rate is not a fixed fraction of
traffic. The migration guide also lacked a mapping for the legacy
directoryGrpcEndpoint group label lookup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The gateway dials TLS by default and trusts only the system store, but
the directory listener it calls is cleartext on 9091, so the examples
without insecure: true failed every directory call and refused all
traffic. Match the dev and staging setup: port 9091, insecure: true,
and a projected token, which the gateway still sends.

Also scope the virtual API key management API note to the legacy
gateway, which is the only one that deploys it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Title the operator chart references as legacy and the gateway chart as
the AI Gateway, in the hand-written Helm index, the sidebar, and the
upstream-projects config that sets the generated titles at the next
release sync.

The legacy setup page now names clusterOidcIssuer alongside the
allowlist step, since the Enterprise Manager verifies the legacy
gateway's ServiceAccount tokens against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cover every scanning failure setting the chart exposes, including the
hook failure policy and the extraction and mutation failure actions,
with the status codes clients see. Add the global placeholder and
shadow mode, and a minimal KEDA setup that scales Presidio on the
adapter's in-flight metric.

Add migration notes learned from running both gateways in staging:
shared tokens and caches, model access, overlapping Presidio metrics,
per-provider Secrets, and Enterprise Manager allowlist overrides.

Describe how the gateway validates JWTs and virtual API keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The budget enforcement page repeated the bring-up steps and the budgets
page. Move its probe check and CA bundle note into Configure the AI
Gateway, and its catalog mapping and 402 details into Budgets and
pricing. The page itself was removed in the previous commit.

Inline the single-use budget partials, also removed in the previous
commit, back into their pages. Only the audit shippers partial is
shared, so it stays.

Remove conversation capture, which is an unreleased beta feature.

Document how to authenticate to the Enterprise Manager API and point
the budget examples' placeholders at it. Add the scanning hook's
failure policy to the screening posture section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fix the doubled URL scheme, audit field and telemetry gaps, route
timeout claim, and budget duplication. Drop cross-section sidebar
entries. Add a model access guide, pricing and protection checks,
and overview starting points.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Verified against the dev cluster and the platform chart and sprout
source. Covers directory provisioning for token callers, workload
issuers, model access defaults, client API changes from inputSchema,
token metric and claim label mapping, missing CRD fields, and
corrects the screening comparison.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove claims that the directory or budgets behave differently between
the AI Gateway and the legacy gateway, drop the stray user-group
sentence from the migration guide, and move the overview's test request
after budgets and model access.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bedrock Guardrails can't screen /v1/responses on either gateway, since
both run the same adapter. Drop it from the migration guide's behavior
differences and add the caveat to the legacy screening page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add a service accounts guide for administrators and a page on calling
the AI Gateway from Kubernetes workloads, covering stacklok/
stacklok-enterprise-platform#4934. Add the cluster prerequisites to
Configure the AI Gateway, and cover service accounts in the budgets,
model access, audit log, groups, virtual key, and directory pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Describe service accounts reaching connectors through their groups,
limited to None, Bearer token, and Header injection authentication,
and the Access tab warning for connectors that can't serve them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Match the console label the trusted issuers table already uses for
the issuer of the cluster Stacklok Enterprise runs in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs-website Ready Ready Preview Nov 3, 2026 3:01pm UTC

Request Review

Move the model access and budget rules into the wizard step where
the reader decides them, fold activation into account creation, link
to the canonical charge order instead of repeating it, and rephrase
negative statements as positive ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The console starts the in-cluster issuer with an empty Issuer URL, so the
reader enters the issuer the cluster publishes instead of checking a
prefilled value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Base automatically changed from ai-gateway-v2-docs to main October 23, 2026 16:48
peppescg and others added 2 commits November 3, 2026 11:48
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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.

🟡 Changes recommended

Unresolved documentation errors could lead to unsafe ServiceAccount access, incomplete revocation, overly broad IPv6 egress, and incorrect gateway control configuration.

6 open issues
What changed in this PR

Documents service accounts in Stacklok Enterprise, covering workload identity management and Kubernetes access to the AI Gateway and Connector Gateway.

Changes:

  • Adds guides for creating service accounts and authenticating Kubernetes workloads with projected tokens.
  • Documents gateway prerequisites, access controls, budgets, revocation, and troubleshooting.
  • Updates navigation and related administration and audit documentation.
File Description
sidebars.ts Adds service account and workload guides to navigation.
docs/​platform/​enterprise-platform/​configure-connector-gateway.mdx Documents workload trust, permissions, and network requirements.
docs/​platform/​enterprise-platform/​configure-ai-gateway.mdx Adds issuer trust, network access, and key rotation guidance.
docs/​platform/​enterprise-directory/​virtual-api-keys.mdx Directs independent Kubernetes workloads to service accounts.
docs/​platform/​enterprise-directory/​users-and-groups.mdx Explains service account membership and inherited grants.
docs/​platform/​enterprise-directory/​service-accounts.mdx Adds account creation, bindings, access, and revocation guidance.
docs/​platform/​enterprise-directory/​index.mdx Introduces service accounts and trusted issuers.
docs/​platform/​enterprise-console/​index.mdx Links to service account administration.
docs/​connector-gateway/​kubernetes-workloads.mdx Adds token setup, MCP requests, and troubleshooting.
docs/​connector-gateway/​forward-audit-logs.mdx Documents service account audit attribution.
docs/​connector-gateway/​connectors.mdx Explains service account activity display and filtering.
docs/​connector-gateway/​connector-policies.mdx Clarifies compatible connector authentication types.
docs/​ai-gateway/​manage-budgets.mdx Adds console guidance for service account budgets.
docs/​ai-gateway/​kubernetes-workloads.mdx Adds projected-token authentication and error guidance.
docs/​ai-gateway/​forward-audit-logs.mdx Documents workload subjects and authentication events.
docs/​ai-gateway/​control-model-access.mdx Explains explicit service account model grants.
docs/​ai-gateway/​budgets-and-pricing.mdx Adds service account budget APIs and charging rules.

Review effort: Balanced

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mention service accounts in the gateway intros and the AI Gateway
authentication reference, link both handle-errors sections, and align
the Connector Gateway 401 wording with the AI Gateway page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@peppescg

peppescg commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@claude please review this PR as a subject matter expert and technical writer, following .claude/skills/review-docs-pr/SKILL.md and the docs-review criteria in .claude/skills/docs-review/SKILL.md.

Focus on accuracy, clarity, information architecture (placement, duplication, inbound links to the two new Kubernetes workloads pages), and compliance with STYLE-GUIDE.md.

Already known, so don't re-raise:

  • The 60-minute token lifetime, pending stacklok-enterprise-platform#4933.
  • The service_accounts feature flag, pending stacklok-enterprise-platform#5519.

Post one body-level review comment with primary and secondary issues. Don't push commits.

@claude

claude Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @peppescg's task in 2m 23s —— View job


Review: Document service accounts

Verdict: needs a few changes, then it's ready. The three new pages are tightly written, follow Diataxis, and end with Next steps, Related information, and Troubleshooting in the right order. The Kubernetes workloads pages are linked from more than the sidebar. The Copilot fixes in e203b7f hold up: suspend-first revocation, the pod-creation caveat on pinned bindings, /128, and the scoped prerequisites. What's left is mostly about where content lives. One existing page now contradicts the new guidance, and the issuer and key-rotation guidance is split between the directory page and the cluster admin page.

I skipped the 60-minute lifetime and the service_accounts flag, as you asked. I couldn't read stacklok-enterprise-platform from this runner, so I checked claims against this repo's docs and generated references, not the upstream code.


Primary issues

1. roll-out-gateway-clients.mdx now contradicts the new guidance (and is a missing inbound link)
docs/platform/enterprise-platform/roll-out-gateway-clients.mdx:48-54 ("Choose an authentication method") still sends "scripts, scheduled jobs, continuous integration, and other clients without a browser flow" to virtual API keys. The PR's change to virtual-api-keys.mdx:14-17 says Kubernetes agents and jobs should use a service account. This page is where an administrator picks a client auth method, so it's the most natural inbound link for the new pages.
Ask: Add a third bullet, for example: "Use a service account for agents and jobs running in Kubernetes. The workload authenticates with its pod's ServiceAccount token and its requests are attributed to the account." Narrow the virtual-key bullet to scripts and CI outside Kubernetes.

2. Trusted issuer guidance is split across two audiences, and the security reason is on the wrong page

  • service-accounts.mdx:58-61 tells the directory admin to choose This cluster "only when every gateway runs in this cluster."
  • configure-ai-gateway.mdx step 4 ("Plan one issuer per cluster") gives a different condition: "every gateway runs in the same cluster as the workloads it serves." It also gives the reason that matters: clusters often share the default issuer URL, so one This cluster issuer would accept every cluster's tokens.
  • The person who picks This cluster in the console reads the directory page, which leaves out both the workloads condition and the cross-cluster risk. Step 4 is also a console decision, not chart configuration, and the Connector Gateway section doesn't have it.

Ask: Keep the full guidance in one place: the This cluster bullet in service-accounts.mdx "Trust the cluster's issuer". Use the stricter condition (gateways and workloads in the cluster that runs Stacklok Enterprise) and state the shared-issuer-URL risk. On configure-ai-gateway.mdx, replace step 4 with a one-sentence pointer.

3. JWKS key rotation is on the cluster admin page but done in the console
configure-ai-gateway.mdx step 5 ("Rotate signing keys in this order") covers uploaded JWKS and JWKS URLs. Those belong to a trusted issuer the directory admin manages on the Trusted issuers tab. The 15-minute cache applies to both gateways, but only the AI Gateway page mentions it, so someone who only runs the Connector Gateway never sees it.
Ask: Move the rotation steps to service-accounts.mdx as a short subsection under "Trust the cluster's issuer", for example "Rotate an issuer's signing keys". Say they apply to both gateways, and link to them from both configure pages.

4. Revocation: the token-lifetime paragraph can read as if suspending doesn't take effect right away
service-accounts.mdx:155-167: right after "suspend its account... The gateways refuse the workload's next request," the next paragraph says "A token already issued keeps working until it expires... because the gateways verify tokens by their signature." A reader under pressure may take this to mean a suspended account's tokens still work for up to an hour. The point is that deleting the Kubernetes ServiceAccount doesn't revoke anything. That paragraph's last sentence also repeats lines 132-134 (a recreated ServiceAccount matches a name-only binding).
Ask: Lead with the point and drop the repeat, for example: "Deleting the Kubernetes ServiceAccount doesn't revoke access. Tokens already issued stay valid until they expire, up to 60 minutes, because the gateways verify tokens by their signature. Suspend the account or remove its binding instead."


Secondary issues

Issue Recommendation
The pages are ahead of the Helm reference. docs/platform/reference/helm/platform.mdx is generated from chart 0.25.0. Its workloadTrustSaSubjectAllowlist default has no Connector Gateway entry. Neither global.stacklok.connectorGateway.workloadIdentity.enabled nor connector-gateway.enterpriseConfig.workloadIdentity.pollInterval appears in any generated reference yet. Add "the v0.26.0 upstream release sync lands" to the PR's Keep in draft until list, so the keys in configure-connector-gateway.mdx match the reference when this merges.
ai-gateway/kubernetes-workloads.mdx:19 says the administrator "grants it models and a budget" with no condition. service-accounts.mdx:100-104 makes both conditional on the gateway's controls. Change it to "and, when the gateway enforces model access and budgets, grants it models and a budget."
service-accounts.mdx:135-137, "Pin the UID when the account's grants and budget are worth more than what the cluster already grants that ServiceAccount name," is hard to act on. Say it concretely, for example: "Pin the UID for any account whose grants or budget you wouldn't give to whoever can create a ServiceAccount with that name in the namespace."
service-accounts.mdx:200-213: Helm keys in the table headers and the acknowledgeUnmetered/modelAccess.endpoint paragraph are cluster admin config on a page for directory admins. Use plain headers (Model access On/Off, Budgets On/Off) and replace the Helm paragraph with links to the configure page or Control model access and Budgets and pricing, which own those settings.
The rule "None, Bearer token, or Header injection only" is restated in six places: service-accounts.mdx (twice), connector-gateway/kubernetes-workloads.mdx (body and troubleshooting), connector-policies.mdx, and configure-connector-gateway.mdx. Each gives the reason in slightly different words. Keep the explanation in service-accounts.mdx "What an account can reach" and keep the other mentions to one clause plus a link, so a future auth type needs only one edit.
connector-gateway/index.mdx:35 link text "Call the gateway from Kubernetes workloads" doesn't match the page title. Use "Call the Connector Gateway from Kubernetes workloads", per the link-text rule.
ai-gateway/index.mdx:33 still reads "Limit which models each user or group can call," even though the line above now adds service accounts. Add "or service account" for consistency.
manage-budgets.mdx "Service account budgets", where "The account's Budgets tab under Service Accounts" is ambiguous: this section is also about a Service Accounts tab on the Budgets screen. Name the path: "On an account's page under Administration > Service Accounts, the Budgets tab shows..."
ai-gateway/kubernetes-workloads.mdx:158: "Gateways install a new issuer" on a single-gateway page (the Connector page says "The gateway"). Change to "The gateway installs".

What works well

  • The "virtual key vs. service account" choice comes early in service-accounts.mdx and links both ways.
  • The Handle errors tables map each response to its message and to an action, and the audit reason_code and workload.resolutions guidance gives administrators a real diagnostic path.
  • The Connector page reuses the AI page for token rules instead of copying them, so each page stands alone without duplicating.
  • No changelog framing, no em dashes in new prose, and placeholders use <ALL_CAPS> consistently.

Out of scope

  • manage-budgets.mdx uses an en dash in 80–100%. It's probably the literal UI label, so leave it unless the console changes.

I didn't push any commits.

Move issuer choice and JWKS rotation to the service accounts page,
link service accounts from the client rollout page, clarify revocation,
and keep Helm keys and connector auth rules in one place each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@peppescg

peppescg commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@claude thanks for the review. Commit 5f7a7a5 addresses every primary and secondary issue from it. Please review the PR again with the same criteria (.claude/skills/review-docs-pr/SKILL.md and .claude/skills/docs-review/SKILL.md):

  1. Confirm each finding from your previous review is resolved, or say what's still missing.
  2. Report any new issues the changes introduced, especially in the moved content: the This cluster guidance and the new "Rotate an issuer's signing keys" subsection in service-accounts.mdx, and the pointers that replace them in configure-ai-gateway.mdx and configure-connector-gateway.mdx.

Already tracked in the PR's Keep in draft until list, so don't re-raise:

  • The 60-minute token lifetime (stacklok-enterprise-platform#4933).
  • The service_accounts feature flag (stacklok-enterprise-platform#5519).
  • The Helm reference still at chart 0.25.0 until the v0.26.0 release sync.

Post one body-level review comment. Don't push commits.

@claude

claude Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @peppescg's task in 1m 21s —— View job


Re-review: Document service accounts

Verdict: ready once two small fixes land. 5f7a7a5 fixes every primary issue from the last review, and all but one secondary issue. The moved This cluster and key-rotation content reads well on the service accounts page, and both configure pages now point to it. One meaning got lost in the move (item 1 below), and the connector auth-type rule is still restated in more places than needed.

I skipped the 60-minute lifetime, the service_accounts flag, and the chart 0.25.0 Helm reference, as you asked. As before, I couldn't read stacklok-enterprise-platform from this runner, so I checked claims against this repo only.


Previous findings

# Finding Status
P1 roll-out-gateway-clients.mdx contradicts the new guidance ✅ Resolved. The virtual key bullet now covers clients "that act as a person," and a service account bullet links to the new page.
P2 This cluster guidance split across pages ✅ Resolved. The stricter condition and the shared-issuer-URL risk are now in service-accounts.mdx:58-63, and configure-ai-gateway.mdx has a pointer instead. See new issue 1.
P3 JWKS rotation on the cluster admin page ✅ Resolved. Moved to service-accounts.mdx:89-99, says it applies to both gateways, and both configure pages link to it.
P4 Revocation paragraph read as if suspending were delayed ✅ Resolved. It now starts with deleting the Kubernetes ServiceAccount, and the repeated sentence is gone.
S AI Gateway prerequisite made models and budget unconditional ✅ Resolved
S Hard-to-act-on wording for when to pin the UID ✅ Resolved
S Helm keys in the "What an account can reach" table ✅ Resolved. Plain On/Off headers, with links out.
S "None / Bearer token / Header injection" rule repeated in six places ⚠️ Partly resolved. See new issue 2.
S Link text in connector-gateway/index.mdx ✅ Resolved
S ai-gateway/index.mdx didn't mention service accounts ✅ Resolved, but the edit adds a nit (see the secondary issues table).
S Ambiguous Budgets tab path in manage-budgets.mdx ✅ Resolved
S "Gateways install" on a single-gateway page ✅ Resolved

Primary issues

1. The move dropped "its own" issuer URL for clusters registered as Another issuer
The removed step 4 in configure-ai-gateway.mdx said to register each cluster as Another issuer "with its own public issuer URL." service-accounts.mdx:70-72 now says only "When gateways or workloads span clusters, add each cluster this way. Enter its public Issuer URL…"

The bullet just above gives the reason this matters: clusters often share the default issuer URL. A reader whose clusters all use the default https://kubernetes.default.svc issuer still doesn't know they must give each cluster a distinct issuer before adding it. "Add each cluster this way" also doesn't say whether the cluster that runs Stacklok Enterprise is one of them. It should be, because once workloads span clusters, This cluster no longer applies.

Ask: Restore the requirement and make the scope explicit. For example: "When gateways or workloads span clusters, add every cluster this way, including the one that runs Stacklok Enterprise. Each cluster needs its own issuer URL, so a cluster that uses the default issuer needs a unique one set first." Please confirm the uniqueness requirement upstream, since I couldn't.

2. The connector auth-type list still appears in five places
5f7a7a5 shortened the explanation in connector-gateway/kubernetes-workloads.mdx body and linked it to the canonical section. That's good. The full None, Bearer token, or Header injection list still appears in:

  • service-accounts.mdx:199-203, the canonical section (keep)
  • connector-gateway/kubernetes-workloads.mdx:91 (body, now linked) and :161 (troubleshooting)
  • connector-gateway/connector-policies.mdx (new paragraph, links to the top of the page, not the section)
  • configure-connector-gateway.mdx:559

If a new auth type works for service accounts, all five need an edit. The commit message says these rules are kept "in one place each," but they're not yet.

Ask: In connector-policies.mdx, configure-connector-gateway.mdx, and the troubleshooting entry, replace the list with a phrase such as "connectors whose authentication type can serve a service account," linking to service-accounts.mdx#what-an-account-can-reach. This is low risk, so it can wait for a follow-up if you'd rather merge.


Secondary issues (new in 5f7a7a5)

Location Issue Recommendation
service-accounts.mdx:94 "Publish or upload the new public key alongside the current one." With Upload JWKS you upload a whole document, so "alongside" is unclear. "Add the new public key to the JWKS URL's document, or upload a JWKS that contains both the new and current keys."
service-accounts.mdx:95-99 Steps 2 and 3 happen on the cluster, where the API server's signing key changes. The directory admin reading this page usually doesn't do that. Add a lead-in such as "Coordinate with the cluster's administrator, who changes the signing key."
configure-ai-gateway.mdx:372-375, configure-connector-gateway.mdx:580-581 The pointer says "rotate an issuer's signing keys" but links to the parent section. Link the rotation half to #rotate-an-issuers-signing-keys, for example "see Trust the cluster's issuer and Rotate an issuer's signing keys."
configure-ai-gateway.mdx:372-373 The pointer repeats the This cluster condition, a second copy of what you just consolidated. It's one sentence, so it's acceptable, but it can drift. Optional: drop the condition and keep only the link sentence.
ai-gateway/index.mdx:33-34 "show each user only the models they can use" replaced "each caller." control-model-access.mdx:12 still says the endpoints list "only the models the caller can use," and that includes service accounts. Revert to "each caller."
service-accounts.mdx:224-226 "A cluster administrator sets both in the gateway's chart values" links to the whole configure page. The relevant settings are in its Enable it section, around line 58 (budgets.acknowledgeUnmetered). Link to configure-ai-gateway.mdx#enable-it.

What works well

  • The This cluster bullet now gives the condition, the reason, and the alternative in one place. This is the right page for it, because this reader makes the choice.
  • The rotation subsection is short, ordered, and scoped to both gateways. The 15-minute and 60-minute figures match the rest of the PR.
  • The revocation section now flows well: suspend first, then the binding fallback caveat, then why deleting the ServiceAccount doesn't revoke tokens already issued.
  • The new bullet in roll-out-gateway-clients.mdx mirrors the virtual key bullet, and the "act as a person" / "act on their own" contrast matches virtual-api-keys.mdx and the service accounts intro.

I didn't push any commits.

Require a distinct issuer URL per cluster, scope This cluster to the
gateways' placement as the code does, link the rotation subsection
directly, and point remaining connector auth-type lists to one section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@peppescg

peppescg commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

@claude commit c5182ba addresses your re-review. Please check it once more with the same criteria and post one body-level comment. Don't push commits.

What changed, verified against stacklok-enterprise-platform v0.26.0:

  • One issuer per URL. workload_trusts has a UNIQUE constraint on the issuer, and the directory returns "a workload trust for issuer … already exists". The Another issuer guidance now says each cluster needs a distinct issuer URL.
  • This cluster. Each gateway reads in-cluster keys from the API server of its own cluster (workloadtrust/keysource.go, fetchInCluster), so the condition is that every gateway runs in the cluster that runs Stacklok Enterprise. Workloads in other clusters can still use their own Another issuer. I relaxed the "every gateway and every workload" wording to match, and Another issuer now covers every cluster, including that one, when gateways span clusters.
  • Rotation links go straight to #rotate-an-issuers-signing-keys, and the duplicated condition is gone from configure-ai-gateway.mdx.
  • The auth-type list now lives only in "What an account can reach" and in the Connector Gateway workloads page body. connector-policies.mdx, configure-connector-gateway.mdx, and the troubleshooting entry link to that section.
  • The other secondary issues are fixed: the JWKS step 1 wording, the cluster administrator lead-in, "each caller", and the #enable-it link.

Still tracked in Keep in draft until, so don't re-raise them: #4933, #5519, and the v0.26.0 Helm reference sync.

@claude

claude Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Claude finished @peppescg's task in 1m 16s —— View job


Third review: Document service accounts

Verdict: ready to merge once the draft blockers clear. c5182ba resolves both primary issues and all six secondary issues from the re-review. Two small wording problems came in with the reworked Trust the cluster's issuer step. Neither blocks the PR, but both are cheap to fix.

I skipped #4933, #5519, and the v0.26.0 Helm reference sync, as you asked. I still can't read stacklok-enterprise-platform from this runner, so I took the UNIQUE constraint and the fetchInCluster behavior from your description and checked everything else against this repo.


Re-review findings

# Finding Status
P1 "Its own" issuer URL lost, and the scope of Another issuer unclear ✅ Resolved. service-accounts.mdx:75-78 requires a distinct issuer URL per cluster, and :70-72 includes the cluster that runs Stacklok Enterprise when gateways span clusters. Scoping This cluster to where the gateways run (not the workloads) matches the key-source behavior you described, and the mixed case still works: gateways in cluster A, workloads in A and B, with A as This cluster and B as Another issuer.
P2 Auth-type list in five places ✅ Resolved. The full list now appears only in service-accounts.mdx:208-209 (canonical) and connector-gateway/kubernetes-workloads.mdx:91. connector-policies.mdx, configure-connector-gateway.mdx, and the troubleshooting entry link to #what-an-account-can-reach.
S JWKS step 1 "alongside" ✅ Resolved
S Cluster administrator lead-in for rotation ✅ Resolved
S Rotation pointers linked to the parent section ✅ Resolved. Both configure pages link #rotate-an-issuers-signing-keys, and the anchor slug matches the heading.
S Repeated This cluster condition in configure-ai-gateway.mdx ✅ Resolved
S "each user" in ai-gateway/index.mdx ✅ Resolved
S #enable-it link ✅ Resolved. The heading is at configure-ai-gateway.mdx:35.

The 30-second poll in "Both gateways pick up a new or changed issuer" (service-accounts.mdx:85-86) matches both configure pages (configure-ai-gateway.mdx:321, configure-connector-gateway.mdx:552).


New issues (minor)

1. "Another issuer trusts any other cluster" now contradicts the next sentence.
service-accounts.mdx:70-72: the bullet says Another issuer is for "any other cluster," then says to use it for "every cluster..., including the one that runs Stacklok Enterprise." Describe the option by how it works, not by which cluster it's for. For example: "Another issuer trusts a cluster by its public issuer URL and keys. Use it for every cluster other than the one that runs Stacklok Enterprise. When gateways run in more than one cluster, use it for that cluster too."

2. The This cluster reason covers only the shared-URL risk.
service-accounts.mdx:60-62 explains why a gateway in another cluster is unsafe when clusters share the default issuer URL. It doesn't say what happens when the URLs are distinct, which the next paragraph now requires. In that case, a gateway in another cluster can't verify this cluster's tokens, so these workloads are refused there. A reader whose clusters already have distinct URLs could decide the warning doesn't apply and pick This cluster anyway. Suggest stating both outcomes: "Each gateway reads the keys from the Kubernetes API of its own cluster. A gateway in another cluster can't verify this cluster's tokens, and when that cluster shares the issuer URL, it accepts its own cluster's tokens instead."

3. Changing --service-account-issuer affects the whole cluster.
service-accounts.mdx:76-78 tells a self-managed cluster to set a distinct --service-account-issuer without a caveat. That flag governs every projected token in the cluster. If the old value is replaced, the API server rejects tokens that pods already hold until the pods refresh them. Kubernetes accepts the flag more than once: it signs with the first value and accepts all of them. Suggest adding: "Add the new value as the first --service-account-issuer flag and keep the old one after it, so tokens already issued stay valid." Also, "Amazon EKS clusters already have one" is narrower than it needs to be. GKE also issues a per-cluster URL, so "Managed clusters such as Amazon EKS usually already have one" would read better. Please check the AKS behavior before you name it.

4. Nit: configure-connector-gateway.mdx:557-560.
"an account bound for the AI Gateway also reaches the connectors its groups are granted" now reads as unconditional, because the auth-type qualifier moved into the link. "can also reach the connectors its groups are granted" keeps the warning accurate without restating the list.


What works well

  • The issuer section explains which option to pick, why, and what has to be true first (distinct URLs), all in the one place the directory admin reads.
  • With the single-link pointers, the configure pages now just say what to set up in the cluster and link to the console steps.
  • Each page that mentions the auth-type rule now only refers to it and links to "What an account can reach", so a new auth type needs one edit (plus the Connector Gateway workloads page body).

I didn't push any commits.

Describe Another issuer by how it works, state both outcomes of a
gateway outside the cluster, and keep the old issuer when adding one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@peppescg
peppescg marked this pull request as ready for review November 3, 2026 14:59

This branch was successfully deployed

1 active deployment
Preview — d570b754 Deployed Nov 3, 2026 by vercel[bot]
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.

3 participants