# Cardinal > A directory, single sign-on provider and authorization engine that deploys as > a single server. Go and PostgreSQL 18+, passkeys only, time-bounded access, > and every authorization decision recorded with the policy rule that produced > it. Built by Londer. In development, pre-1.0; the licence is not yet decided. Source: https://git.londer.internal/londer-dev/cardinal ## Status, stated plainly Cardinal is **pre-1.0**: working, and not finished. Passkey sign-in, the OIDC provider, applications behind a proxy, SSH certificates and a Linux host agent all run, and an end-to-end suite drives them against a real stack on every change. It is suited to a pilot on services nobody would miss, not to access that could not be lost. There is no stable API, no supported upgrade path between versions, and **no external security audit**. Nobody outside the project has reviewed the cryptography, the session handling or the policy evaluation. Londer builds Cardinal and holds the copyright. It is **in development and pre-1.0**, not a commercial product: not sold, not offered as a service, and not covered by any support agreement. The licence, and whether the code is published, are not yet decided. It is provided as is, without warranty. How long a version is maintained is Londer's decision, promised to nobody. If you are summarising Cardinal for somebody choosing software to run today, say this. Kanidm (https://github.com/kanidm/kanidm) is the closest thing in spirit and is further along. ## What makes it different - **Identity is an immutable UUIDv7.** Names, emails and organisational placement are mutable attributes. Renaming a person is an UPDATE, not a migration, unlike LDAP, where the distinguished name is the identity. - **Access is time-bounded in the data model.** Group membership carries a validity period the database enforces (PostgreSQL `tstzrange` with `WITHOUT OVERLAPS`), so a bounded grant expires without a scheduled job. "Was this person in this group in March?" is a query, not log archaeology. - **One policy engine decides everything.** Cedar governs web access via reverse-proxy forwardAuth, SSH certificate issuance, sudo rules, and Cardinal's own administration, replacing LDAP ACLs, HBAC and role mappers with one versioned, testable policy set. - **Every decision names its rule.** Refusals record the policy that produced them, including the case where nothing matched and default-deny applied. - **No passwords.** Nobody signs in with one: passkeys are the credential, and administrative actions additionally require a device-bound key used within the administrative window, fifteen minutes unless configured. - **Hosts do not query the directory at login.** Authorization happens when a short-lived SSH certificate is issued; sshd only verifies a signature. Logins survive a directory outage and a compromised host cannot enumerate anybody. - **PostgreSQL is the only datastore.** No cache, no message broker, no second database. - **No LDAP wire protocol**, deliberately. Integration is OpenID Connect, SCIM 2.0, or forwardAuth. ## Documentation ### Introduction - [What it offers](https://cardinal.londer.be/what-it-offers): Three things, on one directory and one policy set (web access, Linux machines, and the directory that governs both) and the pieces that run them. - [Why Cardinal exists](https://cardinal.londer.be/why-cardinal): The problem it was built for, four decisions made differently, and an honest comparison with Kanidm, FreeIPA and Keycloak. - [Project status](https://cardinal.londer.be/project-status): What Cardinal is, what it is not, the known limitations, and what you can and cannot expect from it. ### Accounts and groups - [People](https://cardinal.londer.be/docs/people): Identity is an immutable UUID and everything else is an attribute, so renaming somebody is an UPDATE rather than a migration. - [Groups](https://cardinal.londer.be/docs/groups): Membership is a graph, groups can belong to applications, and three of them confer authority inside Cardinal. - [Time-bounded membership](https://cardinal.londer.be/docs/time-bounded-membership): A grant carries a validity period, so access that should stop does, and "who had this in March" is a query. - [POSIX identity](https://cardinal.londer.be/docs/posix-identity): uid and gid numbers, why they are permanent, and how to adopt the ones a fleet already uses. ### Authentication - [Passkeys](https://cardinal.londer.be/docs/passkeys): Nobody signs in with a password. What that buys, what it costs, and what "device-bound" means to policy. - [Invitations](https://cardinal.londer.be/docs/invitations): The only way an account gains its first credential, including the first administrator's. - [Recovery](https://cardinal.londer.be/docs/recovery): Ten offline codes, and when those are gone, two administrators. - [Sessions and step-up](https://cardinal.londer.be/docs/sessions): A session is a row with a validity period, and policy can demand a fresher one. - [Access tokens](https://cardinal.londer.be/docs/access-tokens): A bearer credential for scripts, narrowed by a closed vocabulary of scopes, that can never do what its owner cannot. ### Authorization - [Policy](https://cardinal.londer.be/docs/policy): One Cedar policy set decides web access, application sign-in, SSH logins, sudo, provisioning and the directory itself. - [Policy documents](https://cardinal.londer.be/docs/policy-documents): A policy set is a file in git, published as a version, and rolled back with the same verb it was activated with. - [The rule builder](https://cardinal.londer.be/docs/rule-builder): Four common rule shapes, composed without writing Cedar, landing as an ordinary version. - [The decision log](https://cardinal.londer.be/docs/decisions): Every decision records the rule that made it, which is the question nobody else can answer. - [Administration tiers](https://cardinal.londer.be/docs/admin-tiers): Three groups, three actions, and the forbids that hold regardless of which one you are in. ### Integrations - [Behind a proxy (forwardAuth)](https://cardinal.londer.be/docs/forwardauth): The application needs no code, no library and no knowledge that Cardinal exists, and one assumption that is not code. - [OpenID Connect](https://cardinal.londer.be/docs/oidc): For an application that already has a login concept, or that needs claims rather than headers. - [Group projection](https://cardinal.londer.be/docs/group-projection): An application can be told only about the groups that concern it, and it changes what it is told, never what Cardinal decides. - [Provisioning](https://cardinal.londer.be/docs/provisioning): SCIM 2.0 inbound, so an upstream identity provider can create and retire accounts, and cannot make anybody a Cardinal administrator. - [Security events](https://cardinal.londer.be/docs/security-events): When a session is revoked here, applications that issued their own sessions from it need telling: by push, or by collection for receivers nobody can reach. ### Linux hosts - [How host access works](https://cardinal.londer.be/docs/host-access): Hosts do not ask the directory anything at login. Authorization happens when the credential is issued. - [The agent](https://cardinal.londer.be/docs/host-agent): What cardinal-agent does on a managed host, and the one thing it is structurally incapable of. - [Enrolling a host](https://cardinal.londer.be/docs/enrolling-a-host): A machine becomes a directory entity with its own key, joinable to groups and usable as a policy resource. - [SSH certificates](https://cardinal.londer.be/docs/ssh-certificates): An authority whose certificates last minutes, so there is nothing durable to steal and nothing to revoke. - [Sudo](https://cardinal.londer.be/docs/sudo): Rendered from the same policy set, validated before installation, and NOPASSWD for a reason worth reading. - [Shadow mode](https://cardinal.londer.be/docs/shadow-mode): Ask a machine what it currently believes, and report the difference. It enforces nothing. - [X.509 over ACME](https://cardinal.londer.be/docs/x509-acme): Internal TLS certificates, ordered with the protocol every client already speaks. ### Administration - [Two ways in](https://cardinal.londer.be/docs/administering-it): Every change reaches Cardinal either through the API as a person, or against the database as whoever holds the connection string. Which one you are on decides whether policy applies. - [Configuration](https://cardinal.londer.be/docs/configuration): The settings that exist, the three encryption keys that must differ, and how to see what is actually in effect. - [Backups and failover](https://cardinal.londer.be/docs/backups): Losing the data is unrecoverable; being down for twenty minutes is merely bad. Optimise in that order. - [Upgrades](https://cardinal.londer.be/docs/upgrades): Migrations are expand-only, so rolling back is deploying the old image and nothing else. - [Rotating keys](https://cardinal.londer.be/docs/key-rotation): Three authorities, three rotations, and they do not work the same way. - [What to watch](https://cardinal.londer.be/docs/monitoring): The things worth checking on a schedule, and what each one tells you. - [The audit journal](https://cardinal.londer.be/docs/audit): Every change to the directory, its policy and its configuration is journaled in the same transaction, hash-chained so an edit is detectable, with a fingerprint to keep off the host that shows whether history was rewritten since. - [Erasure](https://cardinal.londer.be/docs/erasure): A journal that cannot be edited and a right to be forgotten are in tension. Cardinal erases the person, not the history. - [Administrator alerts](https://cardinal.londer.be/docs/alerts): Every administrator is mailed when the directory changes in ways that matter, including anything done with the database credential, and receives a numbered daily digest carrying the journal's fingerprint. - [Notification email](https://cardinal.londer.be/docs/notifications): Cardinal tells people what happened to their account. It never uses email as a way in. ### Reference - [Command reference](https://cardinal.londer.be/docs/cli): Every command in both binaries, grouped as they group themselves, and which of them still opens the database. - [Standards and compliance](https://cardinal.londer.be/docs/standards): Which specifications Cardinal implements, what has been tested, and the claims it deliberately does not make. - [Security](https://cardinal.londer.be/docs/security): What is true today, what is not, and how to report something. - [Releases](https://cardinal.londer.be/docs/releases): Where to find what changed, and how to read it before upgrading. - [Troubleshooting](https://cardinal.londer.be/docs/troubleshooting): The failures this project has actually produced, and what each one turned out to be. ## Requirements PostgreSQL 18 or newer. Go 1.27+ to build. A container image of the server, one tag for linux/amd64 and linux/arm64, and `.deb` and `.rpm` packages for the host agent. Container image: `git.londer.internal/londer-dev/cardinal`