Skip to main content
Reference

Role-Based Access Control Enterprise

Define roles and issue scoped API tokens for Rivet Enterprise Edition.

Role-based access control (RBAC) determines which actors, workers, gateways, and KV entries each API bearer token can access.

RBAC requires Rivet Enterprise Edition. It is separate from Kubernetes RBAC, which controls access to your cluster.

Use the ACL API to define permissions and issue tokens for a namespace. Keep your bootstrap admin token private; use scoped tokens for applications and individual users.

Setup

  • API endpoint: Your control-plane endpoint, such as https://rivet.mycompany.com
  • Admin token: Configured as RIVET__AUTH__ADMIN_TOKEN. For BYOC, see Credentials & dashboard. Use it to bootstrap ACL.
  • Auth header: Authorization: Bearer <token> for /acl/* calls. The admin token has acl:create + token:create by default.

Model

Rivet groups permissions into four layers, each composed of the layer below it:

rule  ->  policy  ->  role  ->  token
  • Rule: a single permission grant. Allows the listed operations on a resource in a namespace.
  • Policy: a named bundle of rules.
  • Role: a named bundle of policies.
  • Token: a bearer string bound to one or more roles. Carries the union of all granted permissions.

Rules are additive. There are no deny rules. A token is allowed an operation if any of its rules grant it.

Rule schema

FieldTypeDescription
namespace{ id: "<ns_id>" } or "any"Which namespace the rule applies to.
resourceenumOne of actor, actor_gateway, actor_kv, runner, runner_config, namespace, datacenter, acl, token.
target{ id: "<id>" } or "any"Which specific instance of the resource.
operationsstring[]Subset of create, read, update, delete, list.

Manifest

The example namespace ID must be replaced with your actual namespace ID.

POST /acl/manifest is an atomic upsert of rules, policies, and roles in one call. It is the recommended way to provision ACL.

curl -X POST "$RIVET_ENDPOINT/acl/manifest" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rules":    { "pub-actor":  { "namespace": { "id": "ns_abc123" }, "resource": "actor", "target": "any", "operations": ["read"] } },
    "policies": { "pub-policy": { "rules": ["pub-actor"] } },
    "roles":    { "pub-role":   { "policies": ["pub-policy"] } }
  }'
# Expected: JSON containing the upserted rules, policies, and roles

All ACL endpoints

Manifest covers most provisioning. The per-resource endpoints below exist for fine-grained reads, individual upserts, and deletes.

MethodPathUse
POST/acl/manifestAtomic upsert of rules + policies + roles.
POST/acl/tokensMint a token. Body: { roles, prefix?, duration?, token? }.
GET/acl/tokens/inspectInspect the current Authorization token.
DELETE/acl/tokens/{token_id}Revoke a token.
GET / POST / DELETE/acl/rules/{rule_name}Read, upsert, or delete a rule.
GET / POST / DELETE/acl/policies/{policy_name}Read, upsert, or delete a policy.
GET / POST / DELETE/acl/roles/{role_name}Read, upsert, or delete a role.

Common token types

The patterns below cover the publishable / secret / inspector split most deployments need.

Set your endpoint, admin token, and actual namespace ID before running these examples:

export RIVET_ENDPOINT="http://localhost:6420"
export RIVET_ADMIN_TOKEN="..." # control-plane RIVET__AUTH__ADMIN_TOKEN value
export RIVET_NAMESPACE="ns_abc123" # from GET /namespaces?name=...

Dashboard role

For a person signing into the Enterprise dashboard. This example grants namespace-scoped actor, worker, pool, and gateway management, inspector access through actor_kv:read, and permission to list datacenters. It does not grant ACL or token administration.

cat > dash-manifest.json <<EOF
{
  "rules": {
    "dash-namespace":     { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "namespace",      "target": { "id": "$RIVET_NAMESPACE" }, "operations": ["read"] },
    "dash-actor":         { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor",          "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "dash-actor-kv":      { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_kv",       "target": "any", "operations": ["read"] },
    "dash-actor-gateway": { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_gateway",  "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "dash-runner":        { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "runner",         "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "dash-runner-config": { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "runner_config",  "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "dash-datacenter":    { "namespace": "any",                          "resource": "datacenter",     "target": "any", "operations": ["read", "list"] }
  },
  "policies": { "dash-policy": { "rules": ["dash-namespace", "dash-actor", "dash-actor-kv", "dash-actor-gateway", "dash-runner", "dash-runner-config", "dash-datacenter"] } },
  "roles":    { "dash-role":   { "policies": ["dash-policy"] } }
}
EOF

curl -X POST "$RIVET_ENDPOINT/acl/manifest" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @dash-manifest.json

curl -X POST "$RIVET_ENDPOINT/acl/tokens" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roles": ["dash-role"] }'
# Expected: token metadata and a token value; keep the token private

Issue one token per dashboard user so revoking individual access does not log everyone out. Optionally pass "duration": 900 (seconds) to mint a short-lived token and re-issue on demand from a session layer.

Publishable key

For a frontend client only when every holder should have the listed permissions across the namespace. This example can create, read, update, and connect to actors, but cannot list or delete actors or read their KV.

A publishable token is not a user identity or tenant boundary. Anyone can copy it and exercise its permissions. Restrict rules and enforce application authorization for private actors. The pk prefix is only a label; it does not limit permissions.

cat > pk-manifest.json <<EOF
{
  "rules": {
    "pub-actor":   { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor",         "target": "any", "operations": ["create", "read", "update"] },
    "pub-gateway": { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_gateway", "target": "any", "operations": ["create", "read", "update", "delete", "list"] }
  },
  "policies": { "pub-policy": { "rules": ["pub-actor", "pub-gateway"] } },
  "roles":    { "pub-role":   { "policies": ["pub-policy"] } }
}
EOF

curl -X POST "$RIVET_ENDPOINT/acl/manifest" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @pk-manifest.json

curl -X POST "$RIVET_ENDPOINT/acl/tokens" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roles": ["pub-role"], "prefix": "pk" }'
# { "token": "pk_...", ... }

Secret key

Keep this token on your backend; never ship it to a frontend. This example grants actor and gateway management and worker registration (runner:create), but not actor KV access. The sk prefix does not itself provide additional protection.

cat > sk-manifest.json <<EOF
{
  "rules": {
    "sec-runner":  { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "runner",        "target": "any", "operations": ["create"] },
    "sec-actor":   { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor",         "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "sec-gateway": { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_gateway", "target": "any", "operations": ["create", "read", "update", "delete", "list"] }
  },
  "policies": { "sec-policy": { "rules": ["sec-runner", "sec-actor", "sec-gateway"] } },
  "roles":    { "sec-role":   { "policies": ["sec-policy"] } }
}
EOF

curl -X POST "$RIVET_ENDPOINT/acl/manifest" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @sk-manifest.json

curl -X POST "$RIVET_ENDPOINT/acl/tokens" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roles": ["sec-role"], "prefix": "sk" }'
# { "token": "sk_...", ... }

Inspector-capable role

Same permissions as the publishable key, plus actor_kv:read so the holder can fetch per-actor inspector tokens.

cat > insp-manifest.json <<EOF
{
  "rules": {
    "insp-actor":   { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor",         "target": "any", "operations": ["create", "read", "update"] },
    "insp-gateway": { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_gateway", "target": "any", "operations": ["create", "read", "update", "delete", "list"] },
    "insp-kv":      { "namespace": { "id": "$RIVET_NAMESPACE" }, "resource": "actor_kv",      "target": "any", "operations": ["read"] }
  },
  "policies": { "insp-policy": { "rules": ["insp-actor", "insp-gateway", "insp-kv"] } },
  "roles":    { "insp-role":   { "policies": ["insp-policy"] } }
}
EOF

curl -X POST "$RIVET_ENDPOINT/acl/manifest" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d @insp-manifest.json

curl -X POST "$RIVET_ENDPOINT/acl/tokens" \
  -H "Authorization: Bearer $RIVET_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "roles": ["insp-role"] }'
# Expected: token metadata and a token value; keep the token private

Keep inspector-capable tokens private. See Debugging for how to use them.