For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /reference/docs/decisions/0035-local-aai-laboratory.md.

0035 โ€” Shared dev-box AAI

Status: Accepted for development use. Date: 6 October 2026. Member-token policy amended on 26 October 2026 after a verified staging authorisation-code/PKCE probe; offline-session limit measured on staging on 28 October 2026.

Developers and dev-box components need an OpenID Connect issuer shaped like GRNET AAI, with their own test users, before registered staging clients exist. Every dev box gets one from dx/common/local_aai, as shared infrastructure next to its storage (decision 0037): make deploy installs it after storage and make reconcile refreshes it. It is development infrastructure; it assigns no production context authority and adds nothing to the context, route, event or subscription registries.

It runs in the separate pharos-aai namespace with its own PostgreSQL on the default ceph-block class. The dev-box k3s role owns K3s; the local_aai role adds only a development CA and an Nginx HTTPS edge. This original edge ownership is superseded by decision 0038: a shared platform role and catalogue own it. Browsers and Pods use one issuer URI; laboratories retain their own namespaces and data.

clients.json declares login clients and public Site trust metadata. pharos-control-plane serves the Pharos web and API, including Icarus, with one-time offline consent. Slurm uses this same client's ordinary access token; there is no exchange request, dedicated exchange client or required resource client. Site entries still export issuer/JWKS/CA configuration without a secret. The committed registry has no exchange configuration or custom mapper.

Both pharos and pharos-baseline reproduce the verified staging member-token shape: RS256 access tokens with site_username, a 3600-second lifetime, no aud, azp identifying the login client, refresh tokens and exchange disabled. The baseline contains only the control-plane login client; pharos also serves tools.

Deployments receive each client's and resource's values as private variables under the names the vault provides on staging, so moving to GRNET changes only the registered values and URLs. The development CA is the one difference deployments must accept. Nothing asks for an administration credential or registers clients by hand.

site_username is released in ordinary access tokens and userinfo, but not ID tokens, using Keycloak's standard user-attribute mapper. Its value remains assigned by an administrator. An owner retains the offline refresh token and refreshes before each native operation. Only the access token reaches Slurm, separately from durable Site commands; the native Site API bearer remains a different identity. Runtime checks the signature, issuer, exact login client (azp), member binding, access-token type, identity scope and a validity window of at most 3600 seconds. A missing audience is accepted; a supplied audience must name only the login client. Slurm independently verifies its trusted signing keys, expiry and native username. Waldur continues to consume the claim from userinfo.

A staging measurement on 28 October 2026 fixed the shape of this mechanism: the offline session has a maximum lifespan counted from consent, and a refresh does not extend it (a refresh about 150 seconds after consent returned refresh_expires_in 86249 against the then-current 86400, the remaining time rather than a fresh 86400). Refresh tokens rotate on every use. The value the issuer reports is already the nearer of the idle timeout and the maximum lifespan, so it is the consent's single deadline; the access token's 3600-second expires_in says nothing about it and the Member Credentials store therefore never uses it as one.

GRNET accepted the requested wider window on 29 October 2026: a 30-day maximum lifespan counted from consent and a 7-day idle timeout. devops/aai/identity_config.py sets those defaults in DEFAULT_OFFLINE_SESSION and keeps both numbers as parameters (OFFLINE_SESSION_MAX_SECONDS, OFFLINE_SESSION_IDLE_SECONDS), so the laboratory realm and a provider change carry no code change. A refresh inside the 7-day idle window keeps the session alive and moves its deadline forward; only the 30-day maximum, counted from consent, can end a session that is in use. Accepted work that runs for up to 14 days therefore fits, provided at least one native action or consent refresh happens inside every 7-day idle window.

Nothing waits for a native action to keep the Session alive. The Member Credentials owner runs one periodic worker beside its revocation sweep (#879): it refreshes every active consent whose idle deadline falls inside the next two intervals, seals the rotated refresh token before the new value is used, and keeps no access token at all. The interval is configurable (MEMBER_CREDENTIALS_REFRESH_SECONDS, three days by default) and must leave one interval of margin inside the agreed idle timeout. It refreshes only a consent of a member who still holds Project execution authority, so a revoked, superseded, lost or expired consent, and the consent of a member who left the Project, is never kept alive. A refresh that the issuer refuses ends the consent in the state that refusal names, with no retry of that token and no token in a log. The 30-day maximum is still the issuer's: a refresh only ever stores the deadline the issuer reports, capped at the agreed maximum, so the worker extends an idle Run towards that maximum and never past it.

Confirmation that the provider applied the wider window is a repeat of the 28 October measurement against a GRNET test client: a session must still answer a refresh after more than 24 hours, and a refresh inside the idle window must return a refresh_expires_in close to the idle timeout rather than a falling remainder of 86400. It is run only against our own test account and recorded as metadata.

The laboratory realm follows those values rather than its earlier 395-day value, and a qualification must not assume a wider window than the issuer reports for the Session it holds.

A second measurement on the same day records what a repeat login does. It opens its own offline session with a full window; the earlier session is neither extended nor asked for a new consent prompt. Every login carrying offline_access therefore replaces the consent a Run already uses: the incoming offline token becomes the Run's token and the previous one is revoked at the issuer before the next native action. The sealed offline token belongs to the Member Credentials context in Metallo, which refreshes and revokes it; no Runtime or browser sees it. A refused refresh ends the consent and defers the Run with a fixed reason. Evidence is the metadata-only record offline-session-second-login-20261028.jsonl from the same staging audit.

Personal credentials are also the only permitted model. Each Slurm job runs as the member who submitted it, with that member's own access token. Impersonating the member through a service account is rejected: DAEDALUS does not permit it, and neither the FirecREST nor the LUMI model offers it. Monitoring, accounting and cancellation for policy reasons use a Slurm coordinator role instead, so they never depend on a member's token; submission always carries the member's own access token.

This deliberately replaces the earlier resource-bound, short-lived exchange policy. The token is a shared login bearer, with up to one hour of residual native validity after revocation: Slurm's local JWT checks do not introspect consent or restrict the token to one API. Runtime access checks and refresh refusal prevent new authorised operations; they cannot revoke a copied JWT already issued. A future requirement for narrower credentials needs a separately agreed policy, not an implicit prerequisite for running with the actual staging contract.

Bootstrap administrator credentials stay in administration jobs. Keycloak receives only its restricted database identity. Test users come from an editable file; generated passwords and credentials stay in private ignored files. This is not an export of GRNET's realm and does not replace GRNET AAI as the production issuer.

Icarus consumer binding

The retained Icarus laboratory reads the generated control-plane and Site OIDC variables, validates their target binding and receives only its client secret and public CA. API, revocation and browser identity traffic uses the public HTTPS issuer. Existing direct-Keycloak policy grants converge to empty rules without replacing their resource identities. Slurm/LDAP/coordinator ownership remains with the laboratory's existing native deployment.

Select a hosted AAI

Amended 20 October 2026. Local Keycloak remains the development default. A workstation may explicitly select an external HTTPS issuer and registered client bindings for Themelio, Waldur and GitLab. .env holds only the mode, issuer and private file path. Credentials travel through SSH input into private runner state and named consumer Secrets; configuration errors and progress contain no secrets.

Argo continues to own the AAI Application and consumer reconciliation. External mode stops local Keycloak and skips its administration hooks while retaining its data and generated passwords. Provider changes and credential rotations change desired-state checksums and restart consumers. Returning to local mode reuses the existing identity. The hosted realm, its registrations, claims and users remain under its own administrator; changing mode does not migrate accounts or revoke existing application sessions. See provider setup.

Page source

Source snapshot ยท Revision f928834c8.