Access control
Namespaces, ownership, the seeded RBAC roles, and Grants: who can see, change, SSH into, and read your resources.
Ringleader’s access model has three layers: namespaces (the tenancy boundary), ownership (you control what you create), and Grants (explicit, per-object sharing). RBAC roles decide what verbs you hold in a namespace; ownership narrows the write verbs to your own objects; Grants selectively widen access to specific peers.
Above the namespace sits the organization, the company a namespace belongs to. It is what makes “admin of every namespace in Acme” expressible as a single grant.
Namespaces & onboarding
A namespace is the unit of tenancy: a team or business unit. Every resource lives in one, and cross-references stay within it. Every namespace rolls up to exactly one organization.
The control plane does not create a namespace eagerly. On your first login it decides where you land, once, by this precedence:
- A pre-assignment by an operator: a shared namespace, into which you are
bound as
namespace-memberornamespace-reader, per that organization’s choice. - A verified, auto-join company domain: if your email domain is verified for an organization that allows auto-join, you land in that organization’s shared namespace, on the same rung it chose, with no operator involvement. See Organizations.
- Otherwise, a personal namespace derived from your email with a short random
suffix (e.g.
alice-acme-com-k3f9x2), into which you are bound asnamespace-admin: full control of everything in it. You are also made theorg-adminof the personal organization it rolls up to, so a solo signup can administer their own tenancy, registering a trust anchor or authoring a service account, with no operator acting first. This applies to the personal branch only: someone auto-joined into a company’s org under case 2 is an ordinary participant in it.
Which rung the two shared landings use is set on the organization:
Org.spec.defaultMemberRole selects namespace-member, the default, or
namespace-reader, the read-only rung for people who should see a namespace
without being able to provision. Like every Org field it is written by a Ringleader
operator; an org-admin reads it but cannot change it.
It is read from the namespace you land in, so it applies to a pre-assignment and an
auto-join alike, but only if that namespace names the organization in its spec.org.
A namespace created for a pre-assignment carries no org, and until it names one
everyone lands on the default rung whatever the organization selected. An org-admin
can create a namespace that already names their org; stamping one that already exists
without an org is Ringleader’s to do.
Your rung is decided at your first login and never revised afterwards. Changing
either setting later moves nobody who has already onboarded; moving someone between
rungs means editing their RoleBinding, which a namespace-admin or org-admin
can do.
Either way you can read your teammates’ resources but cannot modify or delete them.
As a namespace-member you fully control your own; as a namespace-reader you
create nothing in the namespace except your own device-local SSH keys and port-forward
bindings, never a workstation, secret or config.
When you omit -n, the CLI targets the namespace you pinned with
rl namespace use, else your origin’s
spec.defaultNamespace, else the reserved local.
Ownership: personal resources
Workstation, Secret, WorkstationConfig,
ConfigMap, Grant,
ServiceAccount, and Integration
are owner-scoped personal kinds. Like a Unix file, you own what you create.
On every write, the control plane stamps the owner from your verified identity,
and a client cannot forge it. The
consequence for a namespace-member:
- You may
create,update, anddeleteyour own objects of those kinds. - Peers may
get/listthem (reads are open within the namespace) but cannotupdateordeletethem. ASecretis the exception, in the stricter direction: every read returns its redacted projection, yours included, and seeing the values takes--reveal, which needs ownership, theaccessverb, or a Grant. - Owning something does not stop a peer referencing what they can already read.
A workstation that names a
WorkstationConfiginspec.configs, or ascripts/filesentry that names aConfigMap, gets those bytes whoever authored them. - Where a config applies by selector rather than by name, ownership does decide
reach: one an admin authored applies to every matching workstation in the
namespace, while one a member authored applies only to workstations that member
owns, and stops applying to a workstation they lose. An admin who loses their
admin rights does not stop: their config narrows to the workstations they own, like
any member’s. A member’s
ConfigMaplikewise supplies content to a selector-applied config only where that member authored the config. - A
ServiceAccountis an identity rather than something a workstation consumes, and it has a rule of its own: it keeps working only while its owner could still create one in this namespace. Demote that person tonamespace-reader, or remove them from the namespace, and the account is suspended, whether they were an admin or an ordinary member. Restore their access, or recreate the account under someone who is staying.
A namespace-admin (personal namespaces, and admins of shared ones) is not
owner-restricted: they manage every object in the namespace, whoever created it.
The built-in roles
The built-in roles define what a subject may do. They are predefined by Ringleader (not something you author), so their meaning is consistent everywhere.
The first four form a ladder: each rung contains every rung listed above it,
so each row states only what it adds. node-owner and public-info are not part
of that ladder, since every authenticated user holds both, and global-admin sits
outside it entirely.
| Role | Who gets it | What it adds |
|---|---|---|
namespace-reader | Shared-namespace members, where Org.spec.defaultMemberRole selects it | get/list/watch on everything in the namespace, and create/update/delete on your device-local localbindings and sshkeys. It creates nothing else, in particular no workstation, which on a cloud-backed organization is real spend. |
namespace-member | You, in a shared namespace (the default rung) | Owner-scoped create/update/delete on workstations, secrets, workstationconfigs, configmaps, grants, serviceaccounts and integrations, your own only. |
namespace-admin | You, in your personal namespace, and the admins of a shared one | The same verbs for any owner, not just your own. They cover these kinds of the namespace: workstations, workstationconfigs, configmaps, secrets, grants, serviceaccounts, integrations, cloudidentities, edges, policies, sshkeys, localbindings, and the namespace’s own roles and rolebindings. It is a curated set, not a blanket wildcard. |
org-admin | An organization’s administrators | Everything a namespace-admin has, in every namespace of their organization, plus that organization’s own structure: its namespaces, orgroles, orgrolebindings, CloudAccounts, identityproviders and orgpolicies, plus read-only access to its user roster. Confined to their own organization. (Reading the organization and its domains is not one of these: every authenticated user can read their own, through public-info.) |
node-owner | Every authenticated user | Owner-scoped management of your own device records (nodeinfos). |
public-info | Every authenticated user | get/list/watch on namespaces, organizations and their domains, and role definitions and org role bindings, so you can see who administers your org. The user roster is not included. |
global-admin | Ringleader operators (break-glass) | Full access to everything, everywhere. The only role that holds the wildcard. |
Two limits hold for every rung below global-admin:
- No role grants
accesson a secret it does not own. An administrator owns a Secret’s object lifecycle and can delete it, but reading a plaintext they do not own still requires ownership or an explicit Grant. - No role can escalate itself. You cannot bind a subject (including yourself) to permissions you do not already hold.
How a role reaches you
A role is just a rule set. What decides where it applies is the binding that carries it:
| Binding | Reaches |
|---|---|
RoleBinding (namespaced) | One namespace. |
OrgRoleBinding (cluster-scoped, carries spec.org) | Every namespace of one organization, including ones created later, plus that org’s own structure (its namespaces, org roles, org role bindings, org policies, cloud accounts, identity providers, and user roster). |
GlobalRoleBinding (cluster-scoped) | Everywhere. Operators only. |
A binding may reference a built-in GlobalRole, a namespaced Role, or an
org-scoped OrgRole. An OrgRoleBinding’s reach over cluster-scoped objects is
confined to the org’s own, so it can never grant a verb on another org’s objects, or
on global roles.
Inspect what you actually hold at each origin with:
rl auth status --show-accessThe access verb & secrets
Reading a Secret’s values (not just its redacted projection) is gated by a
distinct access verb: the same verb that admits objects which consume the
secret (a ${secret:NAME} reference, a git source’s credentialRef, a Tailscale
authKeyRef). You hold access on your own secrets automatically; a Grant with
rights: [access] extends it to a peer.
rl secret get db --reveal # requires the access rightGrants: explicit per-object sharing
A Grant is a namespaced kind that opens a single owned object to specific subjects. It is the only way a peer gains:
- SSH access to a workstation you own (
rights: [ssh]), or - value access to a secret you own (
rights: [access]).
There is no namespace-wide SSH fan-out: SSH to a workstation is ownership (automatic) + Grants (explicit), nothing else.
Create and revoke Grants with the share/unshare commands rather than
hand-writing them:
rl workstation share my-box --with user:alice@acme.com
rl workstation unshare my-box --with user:alice@acme.comGrant spec
apiVersion: core.ringleader.dev/v1
kind: Grant
metadata:
name: my-box-to-alice
namespace: dev
spec:
target:
kind: Workstation # Workstation | Secret
matchName: my-box # exact name, or "*" for every object of the kind
subjects:
- user:alice@acme.com # beneficiaries
rights:
- ssh # ssh (Workstation) | access (Secret)| Field | Type | Description |
|---|---|---|
target.kind | string | Required. Workstation or Secret. |
target.matchName | string | Exact object name, or * for every object of the kind. (Exactly one of matchName/matchLabels.) |
target.matchLabels | map | Select potentially many targets by label. |
subjects | []string | Beneficiaries (user:…, sa:…, workload:…, node:…; system:authenticated is admin-only). |
rights | []string | ssh for a Workstation, access for a Secret. |
Owner scope vs. admin scope
Every Grant carries a scope, set by the control plane from the rights you actually held when you created it, never trusted from the client:
owner: created byshare/unshare. It lights up a target only while you still own it, so a Grant can never hand out more than you could yourself.admin: created with--admin, and requires namespace-admin rights. It widens SSH only: an admin-scope Grant reaches any workstation in the namespace. It does not widen secret access; an admin-scope Grant on a secret still works only for secrets you own, because an admin has no authority over a teammate’s plaintext.
That second half is worth knowing before you rely on it. Naming a teammate’s
existing secret is refused outright when you create the Grant, and says why.
Every other shape is accepted and then quietly covers only your own secrets: a
--all share, and a Grant you write by hand that selects by labels or names a secret
nobody has created yet. rl secret access <name> shows the owner and every Grant
currently in force.
This “a Grant never grants more than its creator could grant directly” rule is re-checked continuously, so a Grant stops applying if you lose ownership of its target, except an admin-scope SSH Grant, which was never bounded by ownership in the first place, and which keeps applying even if you later lose your admin rights.
See also
- Sharing & access CLI:
share,unshare,access. - Secret handling via the
accessverb and${secret:NAME}references. - ServiceAccount: the non-human identities you bind these same roles to.
- Policy: what a namespace or an organization permits a workstation manifest to name.