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
| Area | Owner | Others involved |
|---|---|---|
| The deployment: Helm values, PostgreSQL, Redis, certificates, upgrades | Platform team | Security reviews the production values |
| Keys and secrets: the KEK, the MFA seed key, signing keys, the audit checkpoint key | Platform team | Security holds the recovery copy |
The main organization and orgs.main settings | Platform team | Security |
| Deployment-wide policy: second factor, FAPI, registration, captcha, session and token lifetimes | Security | Platform team applies it |
Organizations (Organization resources) | Platform team | The business owner of each tenant |
Identity providers (IdentityProvider resources) and their trust settings | Platform team, with the team that runs the upstream provider | Security approves trustEmail and trustMfa |
An application's OIDCClient | The application team | Platform team reviews scopes, grants and lifetimes |
| Rotating an application's client secret | The application team | |
| Users and roles in an organization | That organization's administrators | Support handles day-to-day requests |
| Leavers | HR or directory owners trigger it; organization administrators carry it out | See leavers |
| Audit log retention, forwarding and review | Security | Platform team runs the exporter |
| On-call for the server | Platform team | Security for threat alerts |
Admin roles for people
The admin API and dashboard grant permissions through eight built-in roles. A typical mapping:
| Who | Role | Where |
|---|---|---|
| Two or three senior platform engineers, break-glass | platform-owner | Main organization |
| Security reviewers | platform-auditor | Main organization |
| A tenant's lead administrators | org-owner | That organization |
| Helpdesk staff who create accounts and reset passwords | org-user-admin | Their organization |
| Front-line support who look up users and end sessions | org-support | Their organization |
| Compliance reviewers | org-auditor | Their organization |
| Product owners who want usage numbers | org-viewer | Their 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. 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.. 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 acmeWhich 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., 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. grantTypesandscopesare the ones the application uses, andoffline_accesswithallowRefreshonly where it needs refresh tokens.private_key_jwtwhere the runtime supports it; otherwise a generated secret.- Token lifetimes are no longer than the defaults without a reason.
identityProviderslists only the providers the application's users should see.deletionPolicyis a deliberate choice:Retain(the default) survives a deleted namespace,Deletecleans 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.