/DOCS · MSP-DEPLOYMENT

Deploy CipherRun for
every customer.

A practical runbook for managed security providers: isolate each customer, onboard operators safely, bind SentinelOne tenants, and keep access boundaries explicit.

→ Start the runbook
STEP 1 / MENTAL MODEL

One customer tenant maps to one workspace.

Treat a CipherRun workspace as the security boundary for one customer tenant. Each customer gets one row in workspaces; tenant-owned workflows, incidents, runs, usage, credentials, memberships, and cr_ws_... API keys stay attached to that workspace. Your MSP team can operate several workspaces, but a customer’s records do not become a shared operator pool.

The critical rule is simple: data access uses the caller’s resolved workspace ID, not an arbitrary workspace ID supplied as a request parameter. Keep that rule in your onboarding checklist, API client code, and review process. The workspace selected by authentication and membership checks is the workspace every downstream query must use.

Design test: if a request can change workspaceId without changing the authenticated key or verified membership, it is not ready for production.
STEP 2 / ISOLATION PATH

Resolve first. Filter every query.

The public v1 API accepts a Bearer key beginning with cr_ws_. Its middleware looks up the active key, sets req.workspaceId from the stored workspace_id, and rejects invalid or revoked keys before the handler runs. It does not trust a caller-provided tenant selector.

// routes/api-v1.js
const row = await findActiveKey(plaintext);
req.workspaceId = row.workspace_id;

// The handler uses the resolved ID.
SELECT * FROM workflows WHERE workspace_id = $1;
SELECT ... FROM workflow_runs WHERE workspace_id = $1;

That same pattern covers GET /api/v1/workflows, GET /api/v1/incidents, GET /api/v1/usage, and GET /api/v1/me. A key for Workspace A cannot read Workspace B’s workflows, incidents, runs, usage, or credentials because its stored workspace ownership never changes.

Session routes use the matching RBAC guard. middleware/require-workspace.js reads the route workspace ID, calls getUserRole(customerId, workspaceId), and returns 403 when the caller is not a member. The guard also records the verified ID as req.workspaceId; handlers must continue using that value for membership, runs, settings, integrations, and audit data.

Operational boundary: a successful login or an MSP operator account is not a global cross-workspace bypass. Every workspace must still be selected through a key or a membership-checked route.
STEP 3 / TENANT ONBOARDING

Provision, invite, verify, then issue access.

Run this sequence once for each customer. Keep the workspace ID in your service record, but never use it as a substitute for the authenticated caller’s workspace resolution.

  1. Create the customer workspace. As an authenticated operator, call POST /api/workspaces with { "name": "Customer SOC", "slug": "customer-soc" }. The creator is added as the workspace’s internal admin.
  2. Invite the customer team. An admin calls POST /api/workspaces/:workspaceId/members/invite with the recipient email and the display role Owner, Admin, or Member.
  3. Accept the seven-day invite. The recipient signs in with the same email address and opens GET /api/workspaces/invites/accept?token=.... The server checks the logged-in email against the invite before adding membership.
  4. Mint a workspace API key only as an admin. Use the authenticated admin key-management surface at /admin/apikeys, which calls POST /api/workspaces/:workspaceId/apikeys. Treat the plaintext as a one-time secret: deliver it through your approved secret channel, store only what your runbook requires, and rotate or revoke it when ownership changes.
  5. Verify the tenant identity. Call GET /api/v1/me with the new key and confirm the returned workspace.id and workspace.name match the customer record before enabling automation.
curl -sS \
  -H "Authorization: Bearer cr_ws_REPLACE_WITH_CUSTOMER_KEY..." \
  https://cipherrun.polsia.app/api/v1/me
EXPECTED IDENTITY CHECK
{
  "workspace": { "id": 17, "name": "Customer SOC" },
  "auth_kind": "apikey",
  "scopes": ["workflows:read", "incidents:read", "me:read"]
}
STEP 4 / SENTINELONE HANDOFF

Bind the external tenant before alerts arrive.

SentinelOne is the concrete managed-provider handoff. An admin binds the external tenant ID to the customer workspace with PUT /api/workspaces/:workspaceId/s1-tenant and a body such as { "s1_tenant_id": "customer-tenant-123" }. The binding is normalized and protected by a database uniqueness rule: one SentinelOne tenant can belong to only one workspace.

curl -sS -X PUT \
  -H "Content-Type: application/json" \
  -d '{ "s1_tenant_id": "customer-tenant-123" }' \
  https://cipherrun.polsia.app/api/workspaces/17/s1-tenant

A duplicate binding returns 409 tenant_already_bound; stop and resolve the ownership conflict rather than overwriting another customer. An inbound POST /api/sentinelone/alert whose tenant_id has no binding returns 404 tenant_not_bound_to_workspace. That response is an onboarding signal, not a reason to retry blindly.

Configure the forwarder with the app’s S1_WEBHOOK_SECRET and send it in the X-SentinelOne-Webhook-Secret header. Verify a test alert is authenticated and that the response includes the resolved workspace_id. The created run also carries s1_tenant_id, s1_alert_id, classification, and workspace lineage in its metadata for /admin/s1 and the customer run history.

→ Read the SentinelOne walkthrough
STEP 5 / OPERATOR BOUNDARIES

Make the role translation explicit.

CipherRun displays customer-friendly roles while the enforcement layer uses stable internal names. Keep this mapping in your MSP operating procedure: Owneradmin, Admineditor, and Memberviewer.

Owner / admin

Can manage membership, invitations, role changes, workspace API-key lifecycle, SSO and integration binding, and the opt-in auto-containment setting. Owners can see all workspace-scoped runs and the audit log.

Admin / editor

Can see workspace-scoped runs and the audit log, but does not receive admin-only invitations, role changes, key lifecycle, SSO/integration binding, or auto-containment controls.

Member / viewer

Can see workspace-scoped runs as a member, but cannot access the audit log or administer workspace membership and the protected control-plane settings.

Audit-log access is workspace-scoped and available to internal admin or editor roles through /app/audit-log. Invitations, role changes, API-key issuance/rotation/revocation, SentinelOne binding, and auto-containment are guarded as admin-only actions. Auto-containment is opt-in and defaults off; when enabled, only eligible built-in SentinelOne classifications auto-execute and write an audit row.

There is no global cross-workspace operator bypass. An MSP employee who administers several customers still needs the correct membership or workspace-owned API key for each customer and sees each workspace’s data only within that boundary.
STEP 6 / PRE-PRODUCTION CHECK

Prove the boundary before you automate.

Run this checklist for every customer and retain the results with the tenant handoff record.

Ship the boundary with the handoff.

When the workspace identity, SentinelOne binding, role assignment, and negative access test all agree, the customer is ready for managed automation.