This is an automated email from the ASF dual-hosted git repository.

arm pushed a commit to branch arm
in repository https://gitbox.apache.org/repos/asf/tooling-trusted-releases.git

commit 184c8276fdac8f049622806ec57bfad5f2b88c90
Author: Alastair McFarlane <[email protected]>
AuthorDate: Wed Mar 25 17:54:31 2026 +0000

    apache/tooling-runbooks#21 - add documentation
---
 atr/db/interaction.py               |  2 ++
 atr/docs/authentication-security.md | 46 +++++++++++++++++++++++++++++++++++--
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/atr/db/interaction.py b/atr/db/interaction.py
index 3d9b6ac9..d38e7258 100644
--- a/atr/db/interaction.py
+++ b/atr/db/interaction.py
@@ -40,6 +40,8 @@ import atr.user as user
 import atr.util as util
 import atr.web as web
 
+# Infra-provided service account with permission to run ATR workflows
+# audit_guidance required actor for ATR distribution workflows; must not be 
used for project TP workflows.
 _GITHUB_TRUSTED_ROLE_NID: Final[int] = 254436773
 
 
diff --git a/atr/docs/authentication-security.md 
b/atr/docs/authentication-security.md
index 0a1b6efa..fffe982c 100644
--- a/atr/docs/authentication-security.md
+++ b/atr/docs/authentication-security.md
@@ -13,6 +13,7 @@
 * [Transport security](#transport-security)
 * [Web authentication](#web-authentication)
 * [API authentication](#api-authentication)
+* [GitHub Actions OIDC (Trusted 
Publishing)](#github-actions-oidc-trusted-publishing)
 * [Token lifecycle](#token-lifecycle)
 * [Security properties](#security-properties)
 * [Implementation references](#implementation-references)
@@ -34,7 +35,7 @@ ATR participates in several authentication protocols but does 
not implement an O
 
 **OAuth Client.** ATR delegates user authentication to the ASF OAuth service 
at `oauth.apache.org` via the 
[ASFQuart](https://github.com/apache/infrastructure-asfquart) framework. ATR 
redirects users to the ASF authorization endpoint, receives an authorization 
code in the callback, and immediately exchanges that code for session data. ATR 
does not store authorization codes, issue OAuth tokens, or manage OAuth client 
registrations.
 
-**OIDC Relying Party.** For [trusted publishing](trusted-publishing) 
workflows, ATR validates OIDC ID tokens issued by GitHub Actions 
(`token.actions.githubusercontent.com`). ATR verifies the token signature using 
the provider's JWKS endpoint, and checks the issuer, audience, expiration, and 
expected claims. ATR does not issue OIDC tokens.
+**OIDC Relying Party.** For [trusted publishing](trusted-publishing) 
workflows, ATR validates OIDC ID tokens issued by GitHub Actions 
(`token.actions.githubusercontent.com`). ATR verifies the token signature using 
the provider's JWKS endpoint, checks the issuer, audience, expiration, and 
expected claims, and enforces actor identity requirements that differ between 
project TP and ATR distribution workflows. ATR does not issue OIDC tokens. See 
[GitHub Actions OIDC](#github-actions-oidc-tru [...]
 
 **Resource Server.** ATR issues its own short-lived JWTs (30-minute TTL, 
HS256) for API access. These are a custom API authentication mechanism, not 
OAuth access tokens or refresh tokens. See [API 
authentication](#api-authentication) below.
 
@@ -141,6 +142,46 @@ Authorization: Bearer jwt_token_value
 
 The [`jwtoken`](/ref/atr/jwtoken.py) module handles JWT creation and 
verification. Protected API endpoints use the `@jwtoken.require` decorator, 
which extracts the JWT from the `Authorization` header, verifies its signature 
and expiration, and makes the user's ASF UID available to the handler.
 
+## GitHub Actions OIDC (Trusted Publishing)
+
+GitHub Actions workflows authenticate to ATR using OIDC tokens issued by 
GitHub (`token.actions.githubusercontent.com`). ATR uses this mechanism in two 
distinct contexts with different authorization requirements, described below.
+
+### Token validation
+
+All OIDC-authenticated endpoints share the same cryptographic validation, 
implemented in `jwtoken.verify_github_oidc`. The caller then applies 
context-specific checks on top.
+
+**Header safety.** Before any other processing, ATR inspects the unverified 
JWT header and rejects any token that contains `jku`, `x5u`, or `jwk` fields. 
These fields could redirect key lookup to an attacker-controlled endpoint.
+
+**JWKS retrieval.** ATR fetches the JWKS URI from GitHub's OIDC discovery 
document 
(`token.actions.githubusercontent.com/.well-known/openid-configuration`) over a 
hardened TLS session (`util.create_secure_session`). The resulting URI is then 
validated: its hostname must be `token.actions.githubusercontent.com` and its 
scheme must be `https`. This prevents a compromised or redirected discovery 
response from substituting a different key set.
+
+**Signature and standard claims.** The token is verified using RS256 with the 
key obtained from JWKS. The `iss` must be 
`https://token.actions.githubusercontent.com`, the `aud` must be `atr-test-v1`, 
and both `exp` and `iat` must be present.
+
+**Enterprise and environment claims.** Four additional claims are checked 
against hardcoded expected values: `enterprise` must be `the-asf`, 
`enterprise_id` must match the ASF GitHub enterprise, `repository_owner` must 
be `apache`, and `runner_environment` must be `github-hosted`. Together these 
constrain the token to workflows running inside the ASF GitHub enterprise, on 
official GitHub-hosted runners, under the `apache` organisation.
+
+### Project Trusted Publishing
+
+Project TP allows an `apache/*` project repository to upload release artifacts 
and perform actions on its own ATR project directly from a GitHub Actions 
workflow. The workflow is defined in 
[tooling-actions](https://github.com/apache/tooling-actions) and called from 
the project's own repository.
+
+**Actor requirement.** After cryptographic validation, 
`interaction.trusted_jwt` checks that `actor_id` resolves to a human committer: 
it performs an LDAP lookup to map the numeric GitHub user ID to an ASF UID. If 
`actor_id` belongs to the ASF Infrastructure service account instead, the 
request is rejected. The committer must have their GitHub account registered in 
LDAP.
+
+**Repository and workflow binding.** `interaction._trusted_project` further 
validates the `repository` and `workflow_ref` claims from the token against 
release policies stored in ATR. Only pre-registered workflow paths from 
pre-registered repositories are accepted, so an arbitrary workflow in an 
`apache/*` repo cannot invoke these endpoints.
+
+### ATR distribution workflows
+
+ATR uses a separate set of endpoints to orchestrate distribution to 
third-party platforms such as Maven Central. These workflows live in 
[tooling-actions](https://github.com/apache/tooling-actions) and are triggered 
by ATR itself, not by project committers.
+
+**Trust chain.** An authenticated committer initiates a release distribution 
through ATR. ATR dispatches the workflow via the ASF Infrastructure service 
account, passing the required context (including the SSH public key) into the 
workflow. The workflow runs on GitHub Actions and calls back to ATR with a 
GitHub OIDC token.
+
+**Actor requirement.** `interaction.trusted_jwt_for_dist` checks that 
`actor_id` matches `_GITHUB_TRUSTED_ROLE_NID`, the hardcoded numeric ID of the 
ASF Infrastructure service account. If `actor_id` belongs to a human committer 
instead, the request is rejected. The check uses the numeric ID, which is 
stable across account renames.
+
+The OIDC token proves that the callback came from a workflow ATR itself 
started. The original authorization is inherited from the committer who 
initiated the distribution in ATR — the service account carries no privileges 
of its own beyond triggering the workflow.
+
+The workflow also carries the originating committer's ASF UID as a parameter. 
ATR trusts this value because the service account gate already establishes that 
only ATR could have dispatched the workflow, and ATR embedded the UID when it 
did so.
+
+### SSH key scope
+
+In both cases, the workflow calls ATR's SSH registration endpoint 
(`/publisher/ssh/register` for project TP, `/distribute/ssh/register` for 
distribution workflows), which generates a temporary SSH key bound to the 
specific project. The key cannot be used for any other project. The identity 
attached to the key differs: for project TP it is the committer resolved via 
LDAP from the OIDC `actor_id`; for distribution workflows it is the committer's 
ASF UID passed through the workflow, trusted [...]
+
 ## Token lifecycle
 
 The relationship between authentication methods and tokens:
@@ -192,5 +233,6 @@ Tokens must be protected by the user at all times:
 ## Implementation references
 
 * [`principal.py`](/ref/atr/principal.py) - Session caching and authorization 
data
-* [`jwtoken.py`](/ref/atr/jwtoken.py) - JWT creation, verification, and 
decorators
+* [`jwtoken.py`](/ref/atr/jwtoken.py) - JWT creation, verification, and 
decorators; `verify_github_oidc` implements the OIDC validation chain
+* [`db/interaction.py`](/ref/atr/db/interaction.py) - `validate_trusted_jwt` 
implements the service account authorisation, `trusted_jwt_for_dist` implements 
gating based on the service account
 * [`storage/writers/tokens.py`](/ref/atr/storage/writers/tokens.py) - Token 
creation, deletion, and admin revocation


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to