Repository navigation
Releases
Releases · ZerosAndOnesLLC/rIDM
rIDM 0.4.1
Changed
- Every Rust dependency is on its latest stable release. Four RustSec advisories against rustls 0.23.45 (RUSTSEC-2026-0346 to 0349) are closed by 0.23.46; x509-parser 0.18, picky-krb 0.13, OpenTelemetry 0.33 (tracing-opentelemetry 0.34), utoipa 6 (utoipa-axum 0.3, utoipa-swagger-ui 10) and uuid 1.28 are the notable moves. testcontainers stays at 0.27 until testcontainers-modules follows. utoipa 6 no longer writes an empty
descriptionon a response, so every success response in the OpenAPI document now saysOK,Created,AcceptedorNo content, and single-elementoneOfwrappers around referenced schemas are gone; the document is otherwise the same. The three zip advisories (RUSTSEC-2026-0367 to 0369) are on the ignore list with a reason: zip is a build-time dependency of utoipa-swagger-ui that unpacks the crate's own vendored archive, never attacker-controlled input, and utoipa-swagger-ui 10 does not yet accept zip 9. - The
ridm-authcrate is published to crates.io from this release on:ridm-auth = "0.4"replaces the git dependency in the quickstart, the crate's README and itsCargo.tomlpoint at the docs and docs.rs, and the packaged crate carries the licence.
Artifacts
- Image:
ghcr.io/zerosandonesllc/ridm:0.4.1(sha256:70276d965ddad151bd89e2a3dd8a6889da5ba5e3a6efe3ae87c5c92b0824ca25), linux/amd64 and linux/arm64 - FIPS 140-3 image:
ghcr.io/zerosandonesllc/ridm:0.4.1-fips(sha256:e39c42b5a691f73c4ab7a726c5d5448f656e8c37169382c254464106b5ee000c), linux/amd64 and linux/arm64 (what it is) - Helm chart:
helm install ridm oci://ghcr.io/zerosandonesllc/charts/ridm --version 0.4.1 - Static binaries for linux amd64 and arm64 below; verify them with
SHA256SUMSand its Sigstore bundle.
Verifying signatures: https://zerosandonesllc.github.io/rIDM/docs/deploy/releases.html#verifying-a-release
rIDM 0.4.0
Added
- The consoles restyled (docs). The admin console has a dark command bar (tenant pill, search with ⌘K, theme switch), a sidebar with live counts and a needs-attention bell, the page as a sheet with breadcrumbs, and user and client details in a floating panel that deep links open. The overview shows four tiles with sparklines and deltas against the previous window, a needs-attention list (locked users, open invitations, keys expiring within 14 days, dead webhook deliveries) and a recent-activity feed. The account console has a dark header with the tenant mark, a security score with the next step to take, every section as a card and parsed user-agent labels on sessions and trusted devices. Every list is on one data table (windowed where long) with one footer for Load more / Newer / Older, skeletons while loading and empty states, and key, client-secret and certificate actions go through a confirmation dialog with a toast on success. Three typefaces are self-hosted (Bricolage Grotesque, Hanken Grotesk, JetBrains Mono); the fonts and the token sheet are documented in
design/README.md. - Tenant appearance (
settings.branding, Settings → Appearance in the console):skin(signal-v2default,signal,vault,registry: four looks as token sets, chosen per tenant),contrast_colornext toprimary_color(six presets or custom; the console shows the readability ratios),mode(system,light,dark) andallow_theme_switch, plusheadlineandtaglinefor the sign-in page. The API validates the colours as CSS colour literals (hex for the contrast colour) and refuses unknown skins and modes. The administered tenant's appearance is worn by the console; the login page preview on the Appearance page renders the real shell. - Sign-in pages: with the Signal v2 skin and a headline the page splits into a brand panel and the form; otherwise a single card. The footer carries the tenant links, Help, a language select and the theme switch (hidden when the tenant forbids switching; the tenant policy wins over the person's choice).
- Server-side sort for users and clients:
?sort=and?dir=onGET /admin/tenants/{slug}/users(created,username,email,status,last_login) and/clients(created,name,type), with a sort-aware keyset cursor, so a sorted table pages without offsets. Four migrations add the supporting indexes withCREATE INDEX CONCURRENTLY. - Bulk actions: enable, disable or delete a selection of users, and delete a selection of IP rules, with one confirmation and one summary toast.
- Filters in the URL on the users, clients and audit pages, so a filtered view can be bookmarked and shared; the audit filters apply as you type.
GET /admin/tenants/{slug}/statsreturnsprevious(the window before, for deltas),counts(users, groups, clients, webhooks, keys, identity providers),attentionwithattention_total, andrecent(the eight newest audit events with actor and subject). The users list returns each row'ssecond_step(passkey,totp,otpor none).npm run screenshotsinui/regenerates the site's screenshots with Playwright.- Valkey with a private CA and client-certificate authentication (#23):
REDIS_TLS_CA_FILEverifies arediss://server against your own roots (outbound HTTPS keeps the system's), andREDIS_TLS_CERT_FILE+REDIS_TLS_KEY_FILEpresent a client certificate, which Valkey'stls-auth-clients-user CNmaps onto an ACL user with no password. Single-server form only; per region asREDIS_TLS_*_<NAME>. The files are re-read whenever they change, so a renewal needs no restart. The Helm chart'sredis.tlsmounts the Secrets. The FIPS build asserts the connection's TLS configuration like every other.
Fixed
- Card headers wrap instead of overflowing; the keys page fits a phone; a held modifier no longer starts a
gshortcut sequence, and Escape cancels one; skip links on the auth and account shells; the console sign-in card no longer prefills the tenant with quotes and prefers the tenant named in the address. - Hints, rails and status colours meet 4.5:1 in every skin, light and dark; the a11y sweep runs every console page in each skin.
Upgrade notes
- The four migrations only add indexes, so a 0.3.0 server keeps running beside 0.4.0 and a rollback needs no database change. The new
settings.brandingfields have defaults; an exported tenant document from 0.3.0 imports unchanged.
Artifacts
- Image:
ghcr.io/zerosandonesllc/ridm:0.4.0(sha256:a84b3281980464c8f7f577f3a4e5bdaecc4d0b8a66420d127e2f91874cf5799e), linux/amd64 and linux/arm64 - FIPS 140-3 image:
ghcr.io/zerosandonesllc/ridm:0.4.0-fips(sha256:0daefd15bcb215474b578cb574b98acb4739b0212def919afeae37ab9fdac05c), linux/amd64 and linux/arm64 (what it is) - Helm chart:
helm install ridm oci://ghcr.io/zerosandonesllc/charts/ridm --version 0.4.0 - Static binaries for linux amd64 and arm64 below; verify them with
SHA256SUMSand its Sigstore bundle.
Verifying signatures: https://zerosandonesllc.github.io/rIDM/docs/deploy/releases.html#verifying-a-release
rIDM 0.3.0
Added
- An optional FIPS 140-3 build (docs, #7). The
fipscargo feature (off by default) and a new image,ghcr.io/zerosandonesllc/ridm:<version>-fips, built on Red Hat UBI 9 fromapi/Dockerfile.fips(no RHEL subscription needed). It runs every TLS connection on rustls' FIPS provider and the AWS-LC FIPS module. It refuses to start unless the module passes its self-test and the host is in FIPS mode;FIPS_ALLOW_NON_FIPS_HOST=trueoverrides the host check for development and CI only. Every feature of the standard build is included. The standard build and image are unchanged. FIPS_TRANSITION(FIPS build only): reads the secrets at rest written before the move to AES-256-GCM, logging and counting each read (ridm_fips_non_approved_total), so an existing deployment can switch to the FIPS build and re-encrypt withrotate-master-key.- PBKDF2-HMAC-SHA512 passwords in the FIPS build (
PBKDF2_ITERATIONS, default 210,000), with a 128-bit salt. Other formats are re-hashed at sign-in. OutsideFIPS_TRANSITION, the FIPS build verifies and bulk-imports only PBKDF2 hashes. The standard build keeps argon2id and reads PBKDF2-SHA512 hashes, so a deployment can move between builds either way. - Kerberos: the RFC 8009 encryption types (
aes128-cts-hmac-sha256-128,aes256-cts-hmac-sha384-192), MIT's and RHEL IdM's default, next to RFC 3962's AES types. GET /admin/tenants/{slug}/users?password_algo=…lists the users whose password hash is in a given format.- Helm chart: FIPS and OpenShift deployments (#21).
image.variant: fipsselects the-fipsimage.database.tlsandmigrations.database.tlsmount a client certificate (akubernetes.io/tlsSecret, one per database role) and a CA, and addsslmode,sslcert,sslkeyandsslrootcertto an inline URL, so the pods and the migration Job authenticate to Postgres by certificate with no password.extraVolumes/extraVolumeMountson the pods andmigrations.extraVolumes/migrations.extraVolumeMountson the Job.route.enabledrenders an OpenShift Route in place of the Ingress.ci/fips-openshift-values.yamlis the worked example (UIDs left to the restricted SCC), and the chart smoke test now installs against a Postgres that accepts onlyhostssl … cert, with the FIPS image in CI. - Secrets at rest in AES-256-GCM, under a key derived per value with HKDF-SHA-256. Every server reads it. The FIPS build writes it now. The standard build keeps writing XChaCha20-Poly1305 for this release, so a rolling update or a rollback to 0.2.0 never meets a value it can't read, and switches in the next release.
rotate-master-key --statuscounts the remaining XChaCha20 rows (legacy_cipher_rows).
Changed
- Hashes, HMAC, random numbers, signing-key generation and TOTP all run on aws-lc-rs, in both builds. The algorithms and stored formats are unchanged: existing keys, TOTP enrolments and tokens keep working.
rsa,p256,ed25519-dalekandtotp-rsare no longer dependencies, and the RUSTSEC-2023-0071 (Marvin) exception is gone withrsa. - Postgres TLS uses aws-lc-rs instead of
ring. - Imported PBKDF2 password hashes are verified with aws-lc-rs.
- Passkeys are verified by rIDM's own WebAuthn relying party on aws-lc-rs, which replaces webauthn-rs. The options, the checks and the stored format are the same, so existing passkeys keep working and a release that still uses webauthn-rs reads the ones registered now. Challenges come from the module's DRBG. Attestation statements are no longer re-verified (rIDM requests and trusts none), so authenticators that send TPM attestation now register. rIDM no longer links OpenSSL, in either build, and the
vendored-opensslfeature is gone. - Kerberos crypto runs on aws-lc-rs, written in-house and checked against the RFC 3961, 3962 and 8009 vectors and a real MIT KDC.
picky-krbis no longer a dependency of the server. - The time spent for an unknown user or a user without a password now matches a real verification under the configured parameters, in either build. It used to verify a fixed, cheaper argon2id hash.
- Temporary passwords are drawn without modulo bias.
Fixed
- The console overview's two-step adoption card described second factors as still to come; it now says what the number counts.
Artifacts
- Image:
ghcr.io/zerosandonesllc/ridm:0.3.0(sha256:14400d2a9575dc48bbd4c5b3355a33cbea3ff08363657e0cd141ffffe83e9b3c), linux/amd64 and linux/arm64 - FIPS 140-3 image:
ghcr.io/zerosandonesllc/ridm:0.3.0-fips(sha256:dc436161b58e102bed4d34215e6d444ef536d888eb010649dc00f701ab1a01d4), linux/amd64 and linux/arm64 (what it is) - Helm chart:
helm install ridm oci://ghcr.io/zerosandonesllc/charts/ridm --version 0.3.0 - Static binaries for linux amd64 and arm64 below; verify them with
SHA256SUMSand its Sigstore bundle.
Verifying signatures: https://zerosandonesllc.github.io/rIDM/docs/deploy/releases.html#verifying-a-release
Images
Multi-arch (linux/amd64, linux/arm64), signed with cosign 3 by this release workflow; see Releases and verification.
| Image | Digest |
|---|---|
ghcr.io/zerosandonesllc/ridm:0.3.0 (also 0.3, latest) |
sha256:14400d2a9575dc48bbd4c5b3355a33cbea3ff08363657e0cd141ffffe83e9b3c |
ghcr.io/zerosandonesllc/ridm:0.3.0-fips (FIPS 140-3 build) |
sha256:dc436161b58e102bed4d34215e6d444ef536d888eb010649dc00f701ab1a01d4 |
oci://ghcr.io/zerosandonesllc/charts/ridm:0.3.0 |
sha256:ed9a82c12bd9b268cc6ec374491448f1ebb675de1199b5ace93dd489d2413bf3 |
rIDM 0.2.0
The first published release. 0.1.0 was cut but never tagged or published, so this
release also contains everything its section of
CHANGELOG.md
lists; the notes below are what came after it.
Added
- SAML 2.0 identity provider. Every tenant publishes IdP metadata at
{issuer}/saml/metadata(entity ID: the issuer) and answersAuthnRequests
over HTTP-Redirect and HTTP-POST at/saml/ssowith a signed, optionally
encrypted (AES-GCM or AES-CBC, RSA-OAEP)Response. A SAML application is
registered as a service provider — a client of the new typesaml, with
saml_service_providersholding its entity ID, consumer URLs, logout URL,
NameID format (pairwise persistent, transient, email or user id), attribute
names, certificates and signing options — from its metadata or by hand, in
the console's new SAML page or at/admin/tenants/{slug}/saml/....
Requests are admitted only from registered SPs, to registered consumer URLs,
once, within ten minutes, with signatures checked against the SP's
certificates (require_signed_requeststo insist). The sign-in itself is
the OIDC one: second factors (REFEDS MFA and Microsoftmultipleauthn
context classes are step-up requests), risk policy, consent and
organizations apply unchanged. IdP-initiated sign-in (/saml/init?sp=) for
SPs that opt in. Front-channel Single Logout: an SP'sLogoutRequestends
the session and walks the browser through the session's other SAML SPs
before answering, and RP-initiated logouts walk them too. The SAML signing
keys are separate from the JWT keys and rotate only by hand (pending,
published first → active → delete). SPs travel in the tenant document under
saml_service_providers. New eventssaml_key.createdand
saml_key.status_changed. The XML signature, canonicalization and
encryption code is rIDM's own (new dependenciesroxmltree,rcgen,
x509-parser,flate2; no C XML library); the parser refuses DTDs,
signatures are accepted only over the element read, and it is checked
against xmlsec1 in both directions (CI installs it) and fuzzed
(saml_message). Both SAML roles are tested against Keycloak 26 on every
build, each side configured from the other's metadata: rIDM as the IdP of a
Keycloak realm and a Keycloak realm as rIDM's upstream (sign-in, encrypted
assertions, tampered and replayed messages, Single Logout from either side,
a key rollover picked up by a metadata refresh). - Organizations within a tenant: membership (a user may belong to several, one
of them primary), role grants scoped to an organization, email domains
verified by DNS TXT record with auto-join, an organization step in the login
flow, and anorg_idclaim in access and ID tokens taken from the session, so
one user can act in different organizations in different sessions. New
ridm:orgs:readandridm:orgs:writepermissions (user managers hold both),
a console page, and a read-only list in the account console. A tenant with no
organizations is unaffected, and no token gains a claim. - Organization administrators: a role granted inside an organization now
reaches the admin API for that organization alone — its record, members,
domains, invitations and internal role grants — and never satisfies a
tenant-wide permission check. A sixth built-in role,ridm:org-admin, is
seeded in every tenant for it. Creating, deleting and listing organizations,
changing a slug or status, and adding an existing user as a member stay
tenant-wide; an organization's own administrator adds people through new
org-scoped invitation routes, andGET …/{org}/grantable-rolessays which
roles they may grant there.GET /admin/megainedorganizationand
organization_permissions, the console opens such an administrator on their
own organization, and the MFA-for-administrators policy counts them. - Risk-based adaptive authentication (
settings.risk, off by default): four
signals — new device, new country, impossible travel and failure velocity —
each with a tenant-set weight, scored against two thresholds.step_up_at
demands a second factor for that sign-in whatever the MFA policy says, and
not even a trusted device waives it;block_atrefuses the sign-in, opening
no session, discarding the flow, denying a waiting device code and returning
access_deniedto the client. Either threshold at0switches that outcome
off. Sign-ins are scored when a first factor passes and when a live session
is reused at/authorizeor a device approval; an allowed one records the
country it came from as history. Newrisk.step_upandrisk.blockedaudit
events (with the score, the signals and the country), a
ridm_risk_decisions_totalcounter, and an Adaptive auth section in the
console. Location comes from trusted-proxy headers
(GEOIP_COUNTRY_HEADERS,GEOIP_LATITUDE_HEADERS,
GEOIP_LONGITUDE_HEADERS) or a MaxMind DB file the deployment supplies
(GEOIP_DB); with neither, the device and velocity signals still work. - Admin impersonation (
settings.impersonation, off by default): an
administrator holding the newridm:users:impersonatepermission (built-in
ridm:owneronly) asksPOST /admin/tenants/{slug}/users/{user}/impersonate
with a reason for a one-time, 60-second link. Opening it gives that browser an
SSO session as the user that lasts at mostmax_minutes. Every access and ID token
minted from the session names the administrator inact({sub, iss}) and
expires with it, and the admin API refuses any token carryingact. The
session owes none of the user's MFA, password-change or risk steps. The
account API refuses everything that needs a recent sign-in, plus consent
withdrawal, with the newurn:ridm:error:impersonation-forbidden, and no consent
can be given. Users holding any admin permission can't be impersonated.
The account console shows a banner with End impersonation, which ends
the session and puts back the browser's own. Newimpersonation.requested,
impersonation.startedandimpersonation.endedevents. Every other event
raised during the session carries the administrator asimpersonator,
stored in a new audit columnimpersonator_id. The column is covered by the hash
chain only when set, so existing rows still verify. The audit API can filter on
it, and the CSV export has it as a new last column. - Audit chain verification you can run yourself:
ridm audit verify --file
checks a JSON export offline with the chain algorithm (now inridm-core),
streaming it.--headpins the hash the export must end on, and--after
the hash it must follow, so consecutive exports prove one chain.ridm audit verifyasks the server andridm audit exportstreams a chain to disk. The
verify endpoint gainedlast_hashandscheduled. - A daily
audit_verifyjob checks every chain that grew, from its last
verified checkpoint. A break is stored, logged, counted
(ridm_audit_chain_breaks_total,ridm_audit_chains_broken) and recorded
once as the newaudit.chain_brokenevent in that tenant's chain. - Feature flags have their own console page (key, description, on/off, and
per-organization values by slug), and applications can read them: the new
standardfeaturesscope adds afeaturesclaim (the flags on for the
sign-in's organization) to access and ID tokens, andGET /t/{slug}/features
answers live for any access token of the tenant.settings.featuresvalues
are now{enabled, description, organizations}; a bare boolean still loads
and is still accepted. - Backchannel sign-in (OpenID CIBA Core 1.0):
POST /t/{slug}/bc-authorize
takes alogin_hint(username or email) or anid_token_hint, an optional
binding_messageandrequested_expiry, and answers anauth_req_id; the
client collects the tokens with the newurn:openid:params:grant-type:ciba
grant, polling or after rIDM pings its notification endpoint
(backchannel_token_delivery_modepollorping, per client; push is not
offered). The user is emailed or texted a link to the account console's new
Requests page, where they approve or deny; an approval is remembered as
consent. At most five requests wait on one user. New
backchannel_requestmessage template,backchannel.requestedand
backchannel.deniedevents,unknown_user_idandinvalid_binding_message
errors, and the CIBA discovery metadata. - The FAPI 2.0 Security Profile per client (
security_profile: fapi2):
registration refuses anything outside the profile,/authorizeaccepts only
pushed requests, PKCE and DPoP-bound tokens are compulsory, client
assertions must be PS256/ES256/EdDSA with the issuer as a stringaud,
request objects and DPoP proofs PS256/ES256/EdDSA, tokens and JARM responses
are signed with ES256 or EdDSA even when the tenant defaults to RSA, and
refresh tokens are not rotated. mTLS is not offered yet, so DPoP is the only
sender constraint. require_pushed_authorization_requestsper client, for PAR without the rest
of the profile.- SAML 2.0 identity providers upstream: an identity provider of the new kind
saml(settings insaml_identity_providers) makes rIDM the service provider
of a SAML IdP. It is set up from the IdP's metadata URL or document
(POST /admin/tenants/{slug}/identity-providers/saml-metadata), and publishes
its own SP metadata at{issuer}/broker/{alias}/saml/metadata(the SP entity
ID), with signing and encryption certificates from the tenant's SAML keys.
AuthnRequests are signed and sent by HTTP-Redirect or HTTP-POST; the
assertion consumer service accepts only responses signed with a registered
certificate (the assertion itself unlesswant_assertions_signedis off),
answering rIDM's request, for this SP and consumer URL, within their window,
once...