zynactradocs

Administering access

The first admin, baseline roles for everyone, delegation, service accounts, break-glass and the audit trail.

Only the admin service changes access: the admin screens, the access API, zaccess bootstrap-admin and your own code calling admin.Service / AdminService all go through it, and it applies every rule to every caller. Never write to the access tables yourself and never add a back door ("if user is admin").

A new org

The first admin

zaccess bootstrap-admin -org org_acme -user u_founder

Or admin.Bootstrap(ctx, a, store, org, user) (Go) / bootstrapAdmin(access, store, org, user) (TypeScript) in a seed script. It works only while the org has no active access admin.

A baseline role for everyone

Give every member employee (scope self), one of two ways:

  • A group mapping on the IdP's all-staff group. Nothing to run at onboarding; leavers lose it when the IdP removes them from the group.
  • Onboarding code calling createAssignment as a service account, for products without reliable IdP groups.

Delegate

Managers get line_manager with scope team; HR gets hr_officer with the org_unit IDs they look after. From there, people delegate within their own reach: HR for Finance can make someone a manager in Finance, not in Sales.

Service accounts

A service account is an ordinary subject (svc:onboarding) whose grants come from the database like anyone else's. To let it assign roles, an admin assigns it a role holding access.assignment:manage, plus access.delegation:any if it must grant roles it doesn't hold itself (that one is sensitive and needs a reason). Every assignment it makes is in the change log under its ID.

Rules people meet

They try toAnd get
grant a permission at a scope wider than their ownescalation
assign themselves a roleescalation (userId)
grant a sensitive permission globally, or a break-glass role, without a reasoninvalid (reason)
assign break-glass without an end, or for more than 24 hoursinvalid (validUntil)
map a break-glass role to a groupinvalid (roleId)
revoke the last access adminconflict
delete a role that's assigned or mappedconflict

The admin screens preview assignments as the form changes (POST /access/assignments/preview), so these show at the field before anyone submits.

Break-glass

For emergencies, declare a break-glass role in the product manifest:

  break_glass:
    name: Break glass
    breakGlass: true
    permissions:
      "*": global

Assigning it needs a reason and an end at most 24 hours away, and is logged with high severity. Review high-severity entries (GET /access/changes?severity=high) as part of your incident process.

The audit trail

Two records, for two questions:

  • Who changed access? The change log: every role, assignment and group mapping change, with actor, target, reason, severity and before/after. Append-only, enforced by the database. Filter by kind (assignment, role.created), actor, target and severity.
  • Who looked at what? Cerbos decision logs: every check and list plan, with principal, resource, effect and the org rule that denied it. Ship the sidecar's stdout to your log pipeline. See Deploying.

How fast changes apply

Within seconds. The admin service invalidates its own instance's cache, and every other instance's NOTIFY listener drops the affected entries. Without a listener, the cache TTL (60 seconds by default) bounds it.

Edit on GitHub

On this page