Identity Broker
Docs version v1 (main)Nauthera is pre-1.0, in a design-partner programUpdated
Every organization is its own issuer. An application whose users belong to several organizations would otherwise register a client at each one and work out which issuer a user belongs to. A broker is an organization whose clients sign in the users of other organizations, its members: the application connects once, as a plain OpenID Connect client of the broker, and the user is sent to their own organization from nothing but an email address.
- The member signs its own users in. Its sign-in page, password policy, second factor, lockout, branding and audit log apply unchanged. The broker never sees a password.
- The broker issues the tokens. The application trusts only the broker's issuer. The
ID token names the member in
member_org, its stable ID, andmember_org_slug, so the application can tell organizations apart;subis the broker's own account linked to the member's user. - Both organizations consent. A membership is active only once the broker has invited the member and the member has accepted. Either side can end it.
- One hop. A broker cannot be a member, and a member cannot broker.
The pieces
| Piece | Where | Who declares it |
|---|---|---|
| The broker | any organization with an active membership | nothing to declare |
| The broker's invitation, and which of its clients it admits | a BrokerMembership with spec.member | the broker's identity team |
| The member's acceptance | a BrokerMembership with spec.broker | the member's identity team |
| The email domains routed to a member | the member's Organization spec.emailDomains, proved by a DNS TXT record | the member's platform team, and whoever runs its DNS |
The same can be done through the admin API
(/, /). A
membership side or a domain claim declared from Kubernetes cannot be changed there.
The membership
Each side is declared from a namespace of its own organization, so a team that cannot write in the other organization's namespaces cannot consent for it. The server checks each side against the operator's grant for that side's organization too.
spec.clients on the broker's side lists the broker's clients the membership admits. A
client it does not admit never routes to that member: a broker can admit its members to
Grafana and keep its Argo CD for its own users.
Routing by email domain
The broker sends an address to the member that has verified its domain, and to no
one else. A member claims a domain in spec.emailDomains; the claim reports a TXT record
to publish, and is verified once the record is found.
kubectl get organization acme -o jsonpath='{.status.emailDomains}'[{"domain":"acme.example","state":"Pending",
"record":{"name":"_nauthera-challenge.acme.example","type":"TXT",
"value":"nauthera-domain-verification=…"}}]- A domain is verified for one organization at most. A claim on a domain another
organization verified is reported
Refused. - A domain verified by an organization that is not a member of this broker is answered as an unknown one, so the broker never reveals who owns a domain outside its members.
- The record can live in Git: with external-dns reading
DNSEndpointresources (itscrdsource, andTXTamong its managed record types), aDNSEndpointwith the claim's token publishes it. A DNS resolver may keep a "not found" answer from before the record existed for up to the zone's negative-caching time.
apiVersion: externaldns.k8s.io/v1alpha1
kind: DNSEndpoint
metadata:
name: acme-example-email-domain
namespace: acme
spec:
endpoints:
- dnsName: _nauthera-challenge.acme.example
recordType: TXT
recordTTL: 300
targets: ["nauthera-domain-verification=…"]A sign-in through the broker
The screens are on Broker sign-in.
Mapping members in the application
The application reads member_org_slug from the ID token or userinfo. Grafana, for
example, maps each member to a Grafana organization of its own with one provider:
[auth.generic_oauth]
client_id = grafana
org_attribute_path = member_org_slug && [member_org_slug, email] || ['nauthera', email]
org_mapping = nauthera:1:Viewer acme:2:Viewer globex:3:Viewer admin@acme.example:2:AdminThe broker's own users carry no member_org_slug, and the expression gives them
nauthera instead.
Limits today
- Only members are routed. An address is sent to a member that verified its domain. An address of the broker's own organization, or at a domain no member verified, ends at "No organization found"; there is no fallback to the broker's own sign-in. To sign the broker's own staff in through it, give them an organization of their own that is a member, as for any other.
- Domains decide. Choosing among several organizations for one address, after a one-time code proves control of it, is planned, not built.
Related
- BrokerMembership: the resource reference
- Organization:
spec.namespacesandspec.emailDomains - Broker sign-in: the screens
- Operator: the grant and the team roles
- Organizations: tenants and their issuers