# RBAC & Permissions *Roles, zones, and the configuration file that governs who — human or agent — can do what inside an Aura deployment.* ## Overview Aura's permission model is built around two primitives: **roles** (what kind of actor you are) and **zones** (what region of the codebase a given actor is permitted to act in). Both are enforced at the Mothership and at the pre-commit hook, not at the application layer — which means an actor who has bypassed the CLI cannot bypass the controls. The model is deliberately small. Four roles. Explicit zones. No inheritance trees, no wildcards that silently widen access, no "effective permissions" calculator required to answer the question *can this agent delete this function*. The answer is always readable directly from the config file. This page documents the four roles, the zone primitive, how agent identities differ from human identities, and the exact config file format. ## The four roles | Role | Intended holder | Can read | Can write | Can administer | | --- | --- | --- | --- | --- | | `admin` | Platform team lead | All | All | Yes | | `contributor` | Engineers, trusted agents | Zones they own + public | Zones they own | No | | `reader` | Security reviewers, auditors, managers | All | None | No | | `agent` | Autonomous AI agents | Zones they own + public | Zones they own, with additional guardrails | No | The `agent` role is not a demotion of `contributor` — it has the same zone-scoped write surface — but it is subject to **additional guardrails** that do not apply to humans: - Agent writes that delete a function require an explicit `aura_log_intent` entry naming the function and a reason. The pre-commit hook blocks deletions otherwise. - Agents cannot disable strict mode, even if `strict_mode_locked` is false. - Agents cannot claim a zone currently owned by a human without the human's acknowledgement message flowing through [Sentinel](/sentinel-overview). - Agents have per-minute rate limits on intent log append, configurable per agent identity. These are not moral judgments about agents; they are load-bearing safety properties for teams operating fleets of autonomous coders. ## The zone primitive A **zone** is a named glob pattern over the repository path space, optionally scoped to specific function identities. Every zone has exactly one owner identity and zero or more cooperators. ```toml [[zone]] name = "billing-core" paths = ["services/billing/**"] owner = "user:alice@example.com" cooperators = ["user:bob@example.com", "agent:refactor-bot"] require_review = true min_reviewers = 1 ``` When an actor attempts to modify a file inside `services/billing/`, the Mothership checks: 1. Is the actor the owner? Write allowed. 2. Is the actor a cooperator? Write allowed, review required per `require_review`. 3. Otherwise — write is blocked at the pre-commit hook with a clear message pointing to the zone owner. Zones can be narrower than whole directories. A zone can target a specific function identity: ```toml [[zone]] name = "auth-token-issuance" function_ids = ["fn:a1b2c3d4e5f6..."] owner = "team:security" ``` This is useful when a critical function lives inside an otherwise open directory and must be protected individually. ## Zone ownership vs. file locking Aura zones are **not file locks**. They do not prevent two people from reading or from drafting changes concurrently. What they prevent is the *commit* of a change that lands inside someone else's zone without their consent. This preserves the parallel-development property that made Git famous, while ensuring that accountability remains unambiguous. When an agent or human pulls changes from a teammate, the Mothership automatically checks destination zones before applying. If the incoming change would land inside a zone owned by the current actor, and the push originated from a non-cooperator, the sync subsystem raises an `impact alert` that must be reviewed via `aura_live_impacts` and resolved via `aura_live_resolve`. ## Identities An identity is a stable string of the form `:`. The three supported kinds: - `user:` — a human identity, resolved against your directory. - `agent:` — an autonomous AI agent identity, pinned to a cryptographic public key. - `team:` — a named group that expands to a set of `user:` and `agent:` identities. Directory integration is pluggable. Supported providers: - **OIDC**: any provider speaking OpenID Connect Discovery. Azure AD, Okta, Keycloak, and Google Workspace are tested. - **SAML**: SAML 2.0 for enterprise SSO portfolios. - **Static file**: YAML list of identities and public keys, for air-gapped deployments. - **mTLS**: identity carried in the client certificate subject. ```toml [directory] provider = "oidc" issuer = "https://auth.example.com/" client_id = "aura-mothership" [directory.group_mapping] "aura-admins" = "role:admin" "platform-eng" = "role:contributor" "security-auditors" = "role:reader" ``` Agent identities are registered separately, because agents do not log in through a browser: ```toml [[agent]] identity = "agent:refactor-bot" public_key = "ed25519:…" role = "agent" rate_limit_per_minute = 120 owner = "user:alice@example.com" ``` The `owner` field is important: every agent has a **human owner** who is accountable for the agent's behavior. If an agent produces a problematic commit, the human owner is the audit signal. ## Config file format Permissions live in `/etc/aura/permissions.toml` on the Mothership. The file is hot-reloaded on change; the Mothership logs a `permissions_reload` event into the intent log each time. ```toml [defaults] role = "reader" # anyone not otherwise configured is read-only require_review = false public_zones = ["docs/**", "examples/**"] # --- Roles --- [[role_grant]] identity = "user:alice@example.com" role = "admin" [[role_grant]] identity = "team:platform-eng" role = "contributor" [[role_grant]] identity = "user:auditor@example.com" role = "reader" # --- Teams --- [[team]] name = "platform-eng" members = [ "user:alice@example.com", "user:bob@example.com", "agent:refactor-bot", ] # --- Zones --- [[zone]] name = "billing-core" paths = ["services/billing/**"] owner = "team:platform-eng" require_review = true min_reviewers = 1 reviewer_role = ["contributor"] [[zone]] name = "auth-token-issuance" function_ids = ["fn:a1b2c3d4e5f6..."] owner = "team:security" require_review = true min_reviewers = 2 # --- Agents --- [[agent]] identity = "agent:refactor-bot" public_key = "ed25519:MCowBQYDK2VwAyEA…" role = "agent" rate_limit_per_minute = 120 owner = "user:alice@example.com" ``` ## Strict mode and break-glass `strict_mode` is the global switch that turns every permission check into a **hard block at the pre-commit hook**, including the intent-vs-AST drift check. When `strict_mode_locked = true`, a human with the passcode is required to disable it. ```toml [policy] strict_mode = true strict_mode_locked = true strict_mode_passcode_file = "/etc/aura/secrets/strict-passcode" ``` Break-glass procedure: 1. The on-call engineer runs `aura admin break-glass --reason "incident #4218"`. 2. The CLI prompts for the passcode. 3. Strict mode is disabled for a bounded window (default 30 minutes). 4. An emergency intent record is written, referencing the reason. 5. At the end of the window, strict mode re-enables automatically. The emergency record remains in the intent log forever. This is the only supported way to bypass permission checks. There is no silent override. ## Permission enforcement points Permission checks happen at four points. A request that fails any one is rejected. 1. **CLI pre-flight**: Local check before the CLI attempts any action. Fails fast for offline users. 2. **Pre-commit hook**: The hook verifies zone ownership and intent-vs-AST drift before Git accepts the commit. 3. **Mothership push**: The Mothership re-verifies on `aura_live_sync_push`. Defense in depth — a tampered local hook does not get past this. 4. **Peer receive**: When another peer pulls, the Mothership verifies the originating push was authorized. A compromised peer cannot inject unauthorized changes into teammates. ## Auditing permission changes Every permission change — adding a role, claiming a zone, rotating an agent key — is itself an intent record. The hash chain covers permissions state, not just code changes. That means an auditor running `aura audit verify` can prove that no permission was silently granted or revoked inside the review window. ```bash aura audit export --window 2026-Q1 --include permissions ``` The resulting evidence package includes a `permissions-events.ndjson` file with every change and the actor who performed it. ## Integration with Git platforms Aura's RBAC is **independent of** GitHub, GitLab, or Bitbucket permissions. Aura controls semantic changes; the Git platform controls branch protection and merge gates. The two layers complement each other: - A developer may have write access on GitHub but lack a zone grant in Aura. Their push is accepted by GitHub but blocked by the pre-commit hook. - A developer may have a zone grant in Aura but lack write on GitHub. Their local work succeeds but cannot be pushed to the remote. Run both. They answer different questions. ## Patterns and anti-patterns Patterns we have seen work well at scale: - **One zone per service**, owned by the service's primary team. Cooperators for adjacent teams who occasionally contribute. - **Dedicated zones for agent fleets**, so an agent owner can see exactly what their agents touched. - **Review required on anything in `services/*/security/` paths**, independent of team ownership. Anti-patterns we recommend against: - Giving `admin` to more than three humans. Use `contributor` with well-scoped zones instead. - Using `agent` role for human accounts "to reduce risk" — it removes the ability to break glass. - Overlapping zones that both claim the same paths. The Mothership will refuse to start. ## See Also - [Intent Tracking](/intent-tracking) - [Compliance & Audit](/compliance-and-audit) - [Self-Hosted Deployment](/self-hosted-deployment) - [Sentinel Overview](/sentinel-overview)