DD-0055 — Member SSH access to Icarus-hpc
Related ADR: ADR-0055.
Status: Draft for review. The dev-ikons laboratory and e2e lane are qualified; Icarus-hpc qualification remains outstanding.
Date: 2026-10-21.
Terminology (Pharos platform, Icarus-cloud, Icarus-hpc, Site agent, access agent, Site Runtime) is defined in ADR-0055.
1. Components and accounts
All connections open from Icarus-hpc. Icarus-hpc exposes no inbound port to Pharos.
2. Flows
2.1 Account provisioning (upstream Waldur and Site agent)
Verified against Mastermind 8.1.3
marketplace/handlers.py
and the Site agent ldap plugin.
- A Project gets a Resource of the HPC Icarus offering through an Order
(Create). When the Order reaches
PENDING_PROVIDERorEXECUTING, Waldur creates an offering user for every Project member. A member who later receives a Project role in that Project also gets an offering user. Both require the offering'sservice_provider_can_create_offering_userplugin option. - With the
service_providerusername policy, Metallo writes the username the member holds at the Site (the Party'ssitebinding) onto the offering user, and POSIX IDs come from the provider's pool. Waldur does not derive the name from a claim, and the Site agent never generates one. - The Site agent's
order_processmode creates the Resource's Slurm account underpharos. Itsmembership_syncorevent_processmode lets the account-name plugin's LDAP backend create the entry (withldapPublicKeyinuser_object_classes) under that name and pin the UID it got on the offering user (set_posix_attributes), and theslurmplugin add the user's association. - Losing a Project role removes that association. Offering-user auto-deletion is
not enabled, so the offering user is not released and the LDAP entry stays
enabled (ADR-0055 decision 7). The upstream
on_departuresetting has onlydisableanddelete; confirm in the lab that no release occurs without auto-deletion.
OK in Waldur therefore does not prove that the LDAP entry exists. The access
agent tolerates that interval (§5.3).
2.2 Submitting and revoking a key
Suspension is reversible. Site-binding retirement is terminal, as defined by Party Governance. Suspending a Party preserves its Site bindings. Reinstating the Party does not reverse a binding's retirement or reinstate old SSH authorisations.
Each submitted key records the member authority version and Site-binding ID that authorised it. A later authority version invalidates the earlier grant even if Metallo first observes the reinstated state after an interruption. Beto owner events wake this check; a periodic sweep recovers missed wake-ups and restarts. Confirmed withdrawal can revoke keys independently of AUP availability. An unavailable owner query defers the decision.
Removal follows the existing Site acknowledgement and propagation-window rules. It prevents subsequent authentication with the managed key; it does not terminate SSH sessions that are already open. Member-initiated revocation remains ungated by HPC eligibility, AUP or account readiness; the API still requires an authenticated Party. Automatic withdrawal handles suspended users who cannot sign in.
3. ssh_access context (Metallo)
3.1 Aggregate and states
MemberSshAccess is one aggregate per (member_id, site). Its children are the
member's keys. One root per member makes per-member fingerprint uniqueness and
"one submission per member at a time" atomic with the root version check. Children
have no separate write repository.
Every transition replaces or clears comment. Each submission, resubmission or
revocation increments the key's generation; Site results for an older generation
change nothing. A missing acknowledgement never proves that an add did not reach
LDAP: revocation waits for a removed result and the propagation window before it
reports revoked, so delete and resubmit are unavailable until then. Repeated
revoke or resubmit returns the key as is, per #678.
3.2 Commands and queries
Key checks are one shared implementation used by validate, submit and resubmit:
public key only (private material rejected without echoing it), no control
characters except tab, ssh-ed25519 or ssh-rsa of at least 3072 bits, server-side
fingerprint/algorithm/bits, per-member limit (10 proposed).
3.3 Ports
Projections built from Beto events are owned by ssh_access, stored in its database
with receipts, and fenced by source revision. Eight durable subscriptions and
checkpoint queries supply initial loading and repair. The canonical Party is the
API actor and browser principal. Fixtures remain an explicit development option.
Numeric UID and AUP acceptance use owner queries during this transition. Resource Provisioning already reconciles Waldur offering users against Beto Site bindings; its fresh account reports supply the numeric UID. Retained Themelio is the current platform AUP authority. Waldur Terms of Service remain separate. Missing or stale authority defers new access. A periodic worker rechecks held keys and durably revokes those whose member has not accepted the current AUP. Confirmed absence of a Party or current policy binding is distinct from an owner outage: the required policy version remains readable independently of that binding, so absence cannot leave revocation retrying indefinitely. Revocation commands identify the observed key generations, allowing a later resubmission to be revoked again while protecting newer generations from delayed work.
Future events require an authoritative owner, ordered revisions, explicit absence semantics and snapshot repair before replacing these adaptors. Implementation details and qualification boundaries are in the SSH Access context.
3.4 Persistence
Private PostgreSQL database pharos_ssh_access, restricted runtime role, migrations
applied by administration (scripts/migrate.py), following
Site Coordination's aggregate and
receipt pattern:
- root and children (
pharos.aggregateskindmember_ssh_access, child table for keys); - command receipts and recorded outcomes;
- a pending Site work index:
(site, member_id, root revision)for roots with unacknowledged generations, updated in the root transaction; - Site result receipts keyed by
(key_id, generation); - Beto event receipts and projections. Browser projection bytes and one principal-targeted publication intent per actor commit with every root revision.
4. Site protocol
Served by the existing Metallo Site API listener
(site_api.py) on dedicated routes, declared in a
new HTTP contract next to
site-coordination.v1.yaml.
- The Site is derived from the credential, never from the body.
memberRefis an opaque per-Site reference, not the canonical member ID. - Pull is idempotent and stateless for the agent: pending work stays pending until acknowledged. The agent needs no cursor or local journal.
- Authentication uses a native bearer: at least 256 random bits, digest and grant stored on the Site API side, grant bound to principal, Site, route scope, expiry and revocation, verified on every request. The verifier is shared with the native Site Runtime. A Runtime credential is refused on SSH routes and an access-agent credential on command routes.
- Error mapping follows Secure Site communication:
401,403,409,422,503, with redacted bodies. - Icarus-cloud exposes the listener on a separate Site API host, for example
https://site.staging.pharosfactory.ai. The client appends/v1/site/ssh-access/*; the edge routes that hostname and prefix to the Site API. Browser API and Site API remain separate hosts and backends with separate identities and credentials. Native agents use scoped bearers and require no OIDC redirect or callback registration.
5. Access agent
5.1 Packaging and configuration
A Site-side composition under services/metallo/services/ with its adaptor in the
ssh_access context, packaged for systemd. Unit pharos-ssh-access-agent, user
pharos-ssh-access, NoNewPrivileges=yes, ProtectSystem=strict,
PrivateTmp=yes, credentials through LoadCredential=.
Configuration: Site API URL and CA file; bearer credential file (read on each
request); LDAP URI (ldapi:// with SASL EXTERNAL on the directory host, or
ldaps:// with CA, bind DN and password file); people base
ou=people,ou=pharos,…; pull interval; snapshot interval; backoff bounds.
For ldapi, the directory maps the service user's exact Unix peer credentials to
the restricted access-agent DN; no LDAP password is loaded. See the
agent packaging guide.
5.2 LDAP operations
Only these operations exist; there is no generic command execution.
- Search
uid=<username>under the people base, attributesuid,uidNumber,entryUUID,entryCSN,objectClass,sshPublicKey. MODIFY_ADD sshPublicKey: <exact line>includesMODIFY_ADD objectClass: ldapPublicKeywhen the class is absent. Both changes are one atomic modify.MODIFY_DELETE sshPublicKey: <exact line>includes deletion of that class when a fresh read shows this is the last value. Both changes are one atomic modify.- Every modify has a critical RFC 4528 assertion for
uidNumber,entryUUIDand the freshly readentryCSN. Concurrent changes retry from a fresh read; duplicate attribute/class results do not prove that the atomic key change was applied. BothMUST sshPublicKeyandMAY sshPublicKeyschemas are supported. - Read back the same entry.
Values are matched by fingerprint. The agent removes only values whose fingerprint Pharos holds for that member; it never removes or rewrites other values.
5.3 Algorithm
Treat "already present" and "already absent" as success. The snapshot pass repeats the same steps for every member, which recovers a crash between an LDAP change and its acknowledgement and any drift in managed values.
5.4 Propagation window
LDAP read-back proves the directory state, not the login path. ssh_access keeps
an applied key in pending_deployment (or a removed key in pending_revocation)
until observedAt + propagation_window. The window is configuration, set from the
lab measurement and the Icarus-hpc SSSD settings; the SSSD default
entry_cache_timeout is 5400 s. The Icarus-hpc administrators accepted a 120 s
window on 23 October 2026. A revocation that remains pending beyond its alert
budget raises an operational alert.
6–10. Browser surface, laboratory and delivery
The browser API and its live projection (§6), the metallo-ikons-1 laboratory
(§7), verification (§8), delivery (§9) and the open questions (§10) are in
DD-0055 — browser surface, laboratory and delivery.
Section numbers continue there unchanged.
Page source
Source snapshot · Revision f928834c8.