Skip to content

The v1 docs follow nauthera-server's main branch and its 0.x releases on the way to 1.0, so fields and APIs can still change.

v1

Ownership: Roles and Permissions per Team

Docs version v1 (main)Nauthera is pre-1.0, in a design-partner programUpdated

Nauthera spreads identity work across teams on purpose: the platform team runs the server, application teams declare their own clients next to their code, and administrators manage users without touching either. That only works if each boundary is written down and enforced. This page proposes a split and shows the controls that hold it.

Who owns what

AreaOwnerOthers involved
The deployment: Helm values, PostgreSQL, Redis, certificates, upgradesPlatform teamSecurity reviews the production values
Keys and secrets: the KEK, the MFA seed key, signing keys, the audit checkpoint keyPlatform teamSecurity holds the recovery copy
The main organization and orgs.main settingsPlatform teamSecurity
Deployment-wide policy: second factor, FAPI, registration, captcha, session and token lifetimesSecurityPlatform team applies it
Organizations (Organization resources)Platform teamThe business owner of each tenant
Identity providers (IdentityProvider resources) and their trust settingsPlatform team, with the team that runs the upstream providerSecurity approves trustEmail and trustMfa
An application's OIDCClientThe application teamPlatform team reviews scopes, grants and lifetimes
Rotating an application's client secretThe application team
Users and roles in an organizationThat organization's administratorsSupport handles day-to-day requests
LeaversHR or directory owners trigger it; organization administrators carry it outSee leavers
Audit log retention, forwarding and reviewSecurityPlatform team runs the exporter
On-call for the serverPlatform teamSecurity for threat alerts

Admin roles for people

The admin API and dashboard grant permissions through eight built-in roles. A typical mapping:

WhoRoleWhere
Two or three senior platform engineers, break-glassplatform-ownerMain organization
Security reviewersplatform-auditorMain organization
A tenant's lead administratorsorg-ownerThat organization
Helpdesk staff who create accounts and reset passwordsorg-user-adminTheir organization
Front-line support who look up users and end sessionsorg-supportTheir organization
Compliance reviewersorg-auditorTheir organization
Product owners who want usage numbersorg-viewerTheir organization

Keep platform-owner scarce: it holds every permission in every organization. Grant it through the dashboard or API rather than auth.admin.subjects, which is for the first administrator only. Every grant and revoke needs a recent sign-in and a reason, is emailed to the user and is recorded as role.granted or role.revoked, so a periodic review of those events is the access review.

Administrators can't change their own roles, or accounts more privileged than their own, and the last account that can grant roles in an organization can't lose that role. You don't need extra process to stop someone from locking a tenant out.

Enforcing the boundaries in Kubernetes

The operator turns manifests into server state, so whoever can write a manifest it reads can change the identity provider. Four controls decide what reaches the server.

1. The gRPC allowlist

The server's server.grpc.tls.allowed_clients lists, for each caller's certificate identity, the operations it may call, the organizations it may act in and the namespaces its resources may come from (see the control plane). Give the operator only the operations and organizations it needs, and add a tenant's slug only once that tenant's resources should be reconciled. Other callers, such as a CI job running nauthera-cli, get identities of their own with narrower entries.

2. The operator's namespaces

operator.namespaces (--namespaces) lists the namespaces whose manifests are sent. The default is every namespace. Narrow it to the namespaces of teams that have been onboarded; a manifest elsewhere is refused on the resource as NamespaceNotCovered.

3. Kubernetes RBAC

Give application teams OIDCClient in their own namespace, and nothing else:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: oidcclient-editor
  namespace: billing
rules:
  - apiGroups: ["nauthera.io"]
    resources: ["oidcclients"]
    verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
  - apiGroups: ["nauthera.io"]
    resources: ["oidcclients/status"]
    verbs: ["get"]

Keep IdentityProvider in a namespace only the platform team writes to. Branding themes one client, named by spec.clientId, which can be any client's; give it to application teams only together with an admission rule that ties the client ID to their namespace, or keep it with the platform team. Organization is cluster-scoped, so only a ClusterRole can grant it; grant it to the platform team alone.

4. The namespaces an organization admits

A team allowed to write an OIDCClient configures only an organization that admits its namespace: each Organization lists them in spec.namespaces, and the main organization's are operator.mainOrganizationNamespaces. A resource anywhere else is refused before anything reaches the server, so no admission policy or namespace label is needed for it, and only whoever may edit the cluster-scoped Organization can admit a namespace. See Which organization a resource configures.

apiVersion: nauthera.io/v1alpha1
kind: Organization
metadata:
  name: acme
spec:
  slug: acme
  namespaces: [acme-web, acme-identity]   # nothing else configures acme

Which kinds a team may write there is RBAC's: the chart's team roles split them between the platform, identity and application teams. A ValidatingAdmissionPolicy is still the tool to limit fields within a kind, such as spec.scopes, spec.grantTypes or spec.refreshTokenTtlSeconds, to what your review would allow.

Review

Manifests are reviewed like code. A short checklist for the reviewer of an OIDCClient:

  • Redirect URIs are exact, https, and on hosts the team owns.
  • grantTypes and scopes are the ones the application uses, and offline_access with allowRefresh only where it needs refresh tokens.
  • private_key_jwt where the runtime supports it; otherwise a generated secret.
  • Token lifetimes are no longer than the defaults without a reason.
  • identityProviders lists only the providers the application's users should see.
  • deletionPolicy is a deliberate choice: Retain (the default) survives a deleted namespace, Delete cleans up.

Use CODEOWNERS or your repository's equivalent so that changes to IdentityProvider, Organization and the server's values need the platform team's and security's approval. GitOps & Argo CD shows a repository layout and Argo CD projects that enforce the same split.

Tenants run by someone else

When an organization belongs to a customer or another business unit, hand it over with org-owner to one of its own users: they then grant roles in their organization from its own dashboard, and see only their organization. The platform team keeps the Organization resource, its identity providers and its email relay, and the tenant's administrators keep users and roles. Write down which side handles a tenant's support requests, a tenant's identity provider changing its client secret, and a tenant leaving.