Skip to content

feat(chart): set allow-listed token clients - #299

Merged
uniqueg merged 6 commits into
devfrom
feat/296-token-clients
Nov 12, 2026
Merged

uniqueg merged 6 commits into
devfrom
feat/296-token-clients

Conversation

@uniqueg

@uniqueg uniqueg commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Summary

The chart can now set tesk-api's option for access tokens of allow-listed clients (elixir-cloud-aai/tesk-api#153), e.g., of a TES gateway that calls TESK with tokens of the client credentials grant.

  • Values auth.tokenClients (off by default): enabled, issuer, jwksUri (optional; default from discovery), audience (required, unless allowAnyAudience: true is set on purpose), claim (default client_id), clients (list of client IDs), requireAtJwt and requireClientSubject (both null: tesk-api's defaults, true). Issuer and JWKS URI must be HTTPS URLs.
  • Rendered by one helper, tesk.tokenClientsEnv (charts/tesk/templates/_helpers.tpl), which holds all variable names (TESK_API_AUTHORISATION_SERVICE_CLIENTS_*). Client IDs are trimmed, blank ones dropped and joined with commas; empty optional keys leave tesk-api's defaults.
  • The chart fails if the option is on without an issuer, without an audience (unless allowAnyAudience: true), without client IDs, or with an auth.mode other than auth. The schema rejects non-URL issuers/JWKS URIs, client IDs with commas or blank, and unknown keys.
  • The notes warn if the option is on with tesk-api 1.2.0 or older (the chart's current appVersion), which ignore it.
  • Docs: docs/deployment.md "Tokens of services" (example, checks, trust implications, audience recommendation), values reference in docs/configuration.md, upgrade notes ("Unreleased").

Closes #296

tesk-api side

The variable names are those of elixir-cloud-aai/tesk-api#154 (for tesk-api#153; tesk.api.authorisation.service-clients.*: enabled, issuer, jwks-uri, audience, client-claim, client-ids, require-access-token-type, require-client-subject), checked against its branch (AuthorisationProperties.ServiceClients and the settings table in its docs/access-control.md); #154 is merged with these names. Should they change, they change in one place here (tesk.tokenClientsEnv, and TOKEN_CLIENTS in the tests). The setting takes effect only with a tesk-api release that contains #154; until then the notes warn. tesk-api's clock-skew-seconds keeps its default (60 s) and isn't exposed. The notes' version check (<1.2.1-0) gets the first tesk-api release with the setting once it is known.

Verification

  • MISE_HELM_VERSION=3.22.1 REQUIRE_HELM=1 uv run pytest -q tests/: 792 passed after merging dev (64 new tests: off/unchanged manifests, minimal and full settings, optional keys, values file, with auth.claim, failures, schema, notes).
  • helm lint charts/tesk --strict (default and with the option on): passed.
  • pre-commit run --all-files: passed.
  • mkdocs build --strict: passed.
  • CI on this PR: all checks passed (CI passed, Chart, Chart install, Test, Lint, Docs, CodeQL, Read the Docs).
  • Reviews: adversarial and quality reviewers, two rounds; round-1 medium findings fixed (sub check exposed and documented, pre-release tags warned, HTTPS-only issuer/JWKS URI, blank claim left out, tests independent of the default appVersion). Sourcery: audience now required unless explicitly opted out (fixed); revocation during the rollout documented (a non-overlapping rollout would mean downtime on every upgrade, so declined); both threads answered and resolved.

Declined review findings

  • claim defaults to client_id in the chart while tesk-api has the same default (redundant): kept, as the issue specifies the chart default client_id; empty still leaves tesk-api's default.
  • Shared helper for the trim/drop/join of auth.claim.values and auth.tokenClients.clients: not extracted; the two are a few lines each and auth.claim lives in the Deployment template, so a refactor of it is outside this issue.
  • Link to tesk-api/access-control.md while the pinned tesk-api docs (v1.2.0) don't cover tokens of services yet: kept, as the page exists and gets the section when docs-sources.yml moves to the tesk-api release with Add missing boilerplate #153.
  • The schema accepts only lowercase https:// issuers and JWKS URIs, stricter than tesk-api (which also allows http:// on localhost): kept, as a localhost issuer makes no sense inside a pod.
  • One place for the requireClientSubject: false caveat instead of three (values comment, reference, guide): kept in all three, as the risk should be visible wherever the value is set.
  • clockSkewSeconds not exposed: tesk-api's default (60 s) fits; can be added on demand.

Open questions

None.

🤖 Generated with Claude Code

https://claude.ai/code/session_011FSoqMpmDCfbACLj3uy6xV

uniqueg and others added 4 commits November 12, 2026 17:47
Add auth.tokenClients (off by default): issuer, jwksUri, audience,
claim (default client_id), clients and requireAtJwt, rendered into the
service-client settings of tesk-api (#153) by one helper,
tesk.tokenClientsEnv, which holds the variable names. The chart fails
if the setting is on without an issuer or client IDs, or with mode
noauth; the notes warn if it is on with tesk-api 1.2.0 or older.

Schema entries, chart tests, the deployment guide (Tokens of services),
the values reference and the upgrade notes.

Closes #296

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FSoqMpmDCfbACLj3uy6xV
From the review: add auth.tokenClients.requireClientSubject and
document tesk-api's sub check; accept only HTTPS issuers and JWKS URIs;
trim the claim and leave a blank one out; warn about pre-releases of
tesk-api 1.2.0 and older too; quote numeric client IDs (docs); test a
mode left unset and the warning with explicit tags only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FSoqMpmDCfbACLj3uy6xV
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FSoqMpmDCfbACLj3uy6xV
@sourcery-ai

sourcery-ai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Reviewer's Guide

API

Define the public chart values for configuring allow-listed token clients and their validation requirements.

  • charts/tesk/values.schema.json L481-571
  • charts/tesk/values.yaml L232-276

Uses of the API

Add the token-client environment entries to the API deployment when the helper emits them.

  • charts/tesk/templates/common/tesk-deployment.yaml L172-177

Implementation

Render token-client settings as tesk-api environment variables, validate required settings, and warn when the configured API version does not support them.

  • charts/tesk/templates/_helpers.tpl L357-368, L562-616

Documentation

Explain the token-client configuration, its security implications, and the version and rollout requirements.

  • docs/configuration.md L129-137
  • docs/deployment.md L347-349, L453-525
  • docs/upgrading.md L38-49

Tests

Test disabled and enabled rendering, defaults, validation, schema constraints, and version warnings for token clients.

  • tests/test_chart.py L1272-1553, L3681-3711

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@uniqueg
uniqueg marked this pull request as ready for review November 12, 2026 18:10
@codecov

codecov Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (a0b0334) to head (c16d457).

Additional details and impacted files
@@            Coverage Diff            @@
##               dev      #299   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            2         2           
  Lines          422       422           
=========================================
  Hits           422       422           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sourcery-ai

sourcery-ai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Linked issues

Checked at commit c16d457

#296 feat(chart): set allow-listed token clients · 5 of 6 met · 1 to check by hand

# Requirement Status Notes
1 Add auth.tokenClients values, off by default, and render them as tesk-api service-client settings. ✅ Met The values and tesk.tokenClientsEnv helper render the settings; the helper is included in the API deployment.
2 Fail clearly when enabled without an issuer or clients, or with auth.mode: noauth. ✅ Met The helper fails for those cases, and also requires an audience unless allowAnyAudience is true.
3 Add chart tests for rendering with the option on and off, and for failure cases. ✅ Met Tests cover disabled and enabled rendering, unchanged manifests while disabled, and invalid or incomplete settings.
4 Document the feature with an example and trust implications, and add the values reference and upgrade notes. ✅ Met The deployment guide includes the example and security guidance; the configuration reference and Unreleased upgrade notes are also updated.
5 With the values set, a deployed tesk-api accepts tokens of the listed clients. 👀 Check by hand (runtime) Deploy with a tesk-api release containing the dependent service-client token support and verify that a listed client's token is accepted.
6 Without the values, the rendered manifests are unchanged. ✅ Met The tests compare disabled rendering with the auth-mode baseline and assert that no token-client environment variables are present.

@sourcery-ai sourcery-ai Bot 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.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="charts/tesk/values.yaml" line_range="255" />
<code_context>
+    # deployment; recommended, so that tokens meant for other services are
+    # refused. Empty leaves `aud` unchecked
+    audience: ""
+    # Claim of the token with the client ID (RFC 9068: client_id; some
+    # providers use azp); empty uses tesk-api's default, client_id
+    claim: client_id
</code_context>
<issue_to_address>
**Cross-audience tokens are accepted**

When an operator enables `auth.tokenClients` but leaves its optional audience unset, and a listed client’s valid token for another service is presented to TESK, a listed client’s token for a different service passes the issuer and client checks without an audience restriction, so its holder can submit tasks to this TESK deployment.

Require a non-empty audience whenever token clients are enabled, or make audience validation mandatory with an explicit opt-out for deployments that accept the risk.

Also at `charts/tesk/templates/_helpers.tpl:597`.
</issue_to_address>

### Comment 2
<location path="charts/tesk/templates/common/tesk-deployment.yaml" line_range="175-176" />
<code_context>
+        {{- /* Tokens of allow-listed clients (e.g., of a gateway with the
+        client credentials grant), which tesk-api checks without the user
+        info: only when on, with mode auth (tesk.tokenClientsEnv) */}}
+        {{- with include "tesk.tokenClientsEnv" . }}
+        {{- . | nindent 8 }}
+        {{- end }}
         {{- /* Null leaves tesk-api's default (off). tesk-api stops at
</code_context>
<issue_to_address>
**Revoked clients remain accepted during rollout**

When a client ID is removed and requests arrive while Kubernetes is starting the replacement pod, the old pod keeps its previous allow-list while the replacement starts, and requests routed to it still accept the removed client’s tokens. The client therefore remains authorized until the old pod is terminated.

Use a non-overlapping rollout strategy for allow-list changes, or document that revocation takes effect only after the rollout has completed.
</issue_to_address>

Sourcery assessment

Needs a human reviewer. 2 findings to address first, and when enabled, tesk-api accepts listed clients’ JWTs without the user-info and group checks, allowing those clients to create tasks and run arbitrary images on the cluster. A mistaken allow-list or token-validation configuration could therefore grant unintended access and trigger work that cannot be undone by reverting the chart; the feature is off by default.

Blocking findings: charts/tesk/values.yaml:255, charts/tesk/templates/common/tesk-deployment.yaml:176


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

Comment thread charts/tesk/values.yaml Resolved
uniqueg and others added 2 commits November 12, 2026 19:33
From the Sourcery review: without an audience, tokens that a listed
client got for other services would be accepted too. The chart now
fails if auth.tokenClients is on without an audience, unless the new
auth.tokenClients.allowAnyAudience is true. The deployment guide also
says that a removed client is refused only once the rollout has
completed, and to disable it at the provider too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011FSoqMpmDCfbACLj3uy6xV
@uniqueg
uniqueg merged commit c123f05 into dev Nov 12, 2026
31 checks passed
@uniqueg
uniqueg deleted the feat/296-token-clients branch November 12, 2026 18:42
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.

feat(chart): set allow-listed token clients

1 participant