# Ownership: Roles and Permissions per Team

> Who owns what when a company runs Nauthera, the roles and Kubernetes permissions each team needs, and how the gRPC allowlist, namespaces and RBAC enforce it.

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

```mermaid
flowchart LR
  PT["Platform team"] --> SRV["Server, keys,<br/>organizations,<br/>identity providers"]
  SEC["Security"] --> POL["Policy, audit,<br/>trust settings"]
  APP["Application teams"] --> CL["OIDCClient,<br/>Branding"]
  ADM["Organization<br/>administrators"] --> USR["Users and roles"]
```

| 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](https://www.nauthera.io/docs/v1/adoption/existing-identity-providers#leavers-and-deprovisioning) |
| 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](https://www.nauthera.io/docs/v1/user-management#authorization). 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.

```mermaid
flowchart TD
  M["OIDCClient manifest"] --> R["1 · Kubernetes RBAC<br/>may this team write here?"]
  R -->|yes| O["2 · operator.namespaces<br/>namespace onboarded?"]
  O -->|yes| P["3 · Organization admits the namespace?<br/>(spec.namespaces)"]
  P -->|yes| G["4 · gRPC allowlist<br/>operation and organization?"]
  G -->|yes| S[("nauthera-server")]
  R -.->|no| X1["Refused by the API server"]
  O -.->|no| X2["NamespaceNotCovered"]
  P -.->|no| X4["NamespaceNotAdmitted"]
  G -.->|no| X3["Refused by 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](https://www.nauthera.io/docs/v1/security#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:

```yaml
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](https://www.nauthera.io/docs/v1/operator#which-organization-a-resource-configures).

```yaml
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](https://www.nauthera.io/docs/v1/operator#who-may-change-what) 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](https://www.nauthera.io/docs/v1/adoption/gitops) 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.
