Multi-Tenancy
OpenFlows supports multiple independent teams on a single Coder deployment. Each tenant is a logical boundary composed of a Coder user, a repository binding, a dedicated NEXUS workspace, and a namespaced Redis keyspace. Multi-tenancy is not achieved by running separate Coder servers; it is achieved by isolating identity, state, and workspaces within one shared Coder runtime. This guide explains the tenant model, how to use Coder RBAC, and how Redis keyspace prefixes enforce isolation.
Coder is the only runtime. OpenFlows is a thin orchestration brain that provisions ephemeral Coder workspaces and stores state in Redis. In a multi-tenant deployment, every tenant gets its own brain (NEXUS workspace) and its own memory slice (Redis keyspace), but they all share the same underlying Coder control plane. The security boundary is therefore Coder's RBAC plus Redis keyspace prefixes, not physical separation.
Manage tenants with the CLI
Tenant Model
A tenant is a five-tuple. All five pieces must be in place for a tenant to operate:
| Component | Description |
|---|---|
| Coder user | A normal Coder user account that belongs to the team. The tenant acts as that user for workspace and GitHub operations. |
| Repository binding | A GitHub repository (e.g. owner/repo) the tenant is authorized to work on. Multiple repos per tenant are allowed. |
| NEXUS workspace | A dedicated Coder workspace named openflows-nexus-{"{tenant}"} that hosts the orchestrator controller for that tenant. |
| Redis keyspace prefix | All SharedStore keys are prefixed with ns:{"{tenant}"}: to isolate state, queues, and worker slots from other tenants. |
| Coder RBAC | Role-based access controls inside Coder determine which tenant users can create workspaces, view the tenant, or manage external auth. |
One Coder server, many teams
Coder RBAC
Coder provides the identity layer. Each tenant maps to a Coder user (or a service account for NEXUS) and a Coder group for the team. Coder's built-in RBAC controls who can:
- Provision workspaces under the tenant's namespace.
- Access the tenant's NEXUS workspace and view its logs.
- Configure GitHub external auth on behalf of the tenant.
- See cost and audit logs for the tenant's workspaces.
OpenFlows does not implement its own user management. It relies on Coder groups, roles, and template permissions. Assign tenant membership by adding Coder users to the tenant's group, and assign admin rights by granting the Owner role on that group.
| Role | Permissions |
|---|---|
| Owner | Tenant admin. Can add/remove repos, manage Coder external auth, and operate the NEXUS workspace. |
| Member | Team member. Can view tenant status, create worker workspaces, and open tickets. |
| Viewer | Read-only. Can view the TUI dashboard and logs but cannot trigger or modify work. |
| NEXUS service account | A non-human Coder user that owns the openflows-nexus-{"{tenant}"} workspace and has limited, scoped permissions. |
# Create a Coder group for the tenant coder groups create my-team --name "My Team" # Add users to the group coder groups add-members my-team alice bob charlie # Grant the group access to the OpenFlows workspace template coder template update --acl-group my-team:use openflows-nexus
NEXUS is a service account, not a human user
CODER_NEXUS_TOKEN.
Redis Keyspace Prefixes
SharedStore is the central state machine. In production, it runs on Redis. Without
namespacing, all tenants would share the same keys and collide on ticket IDs, worker IDs,
and event rings. OpenFlows enforces a mandatory prefix of ns:{tenant}: on
every Redis key. The tenant slug is the canonical namespace identifier.
The prefix is applied automatically by the SharedStore implementation. Application code
and operators do not need to remember to include it. However, when you inspect Redis
directly with redis-cli, you must include the prefix to see the tenant's data.
| Key Pattern | Purpose |
|---|---|
ns:{"{tenant}"}:tickets | Map of ticket IDs to ticket status for the tenant. |
ns:{"{tenant}"}:worker_slots | Map of worker IDs to worker status for the tenant. |
ns:{"{tenant}"}:pending_prs | List of PRs waiting for VESSEL to merge. |
ns:{"{tenant}"}:flow_recovery | Recovery state and inconsistencies detected by NEXUS. |
ns:{"{tenant}"}:event_ring | Ring buffer of the last 1000 events for the tenant TUI. |
# Inspect all keys for a tenant redis-cli --scan --pattern 'ns:my-team:*' # Look at a specific ticket redis-cli HGET ns:my-team:tickets ISSUE-123 # Count the tenant's worker slots redis-cli HLEN ns:my-team:worker_slots
Keyspace isolation is not authorization
Per-Tenant NEXUS Workspace
Each tenant runs its own NEXUS controller inside a dedicated Coder workspace. See the NEXUS workspace guide for details on startup, fault isolation, and cost attribution.