Ga naar inhoud

MSP — cross-tenant triage en delivery

1. Maandagochtend cross-tenant triage

In het dashboard

  1. Login als MSP-admin → Sidebar → MSP cockpit
  2. Alle tenants gesorteerd op urgency descending
  3. Klik tenant met hoogste urgency → opent in tenant context
  4. Filter ‘urgency > 50’ om je ochtendwerk te isoleren

/msp/cockpit — één pagina, alle tenants in beheer, gesorteerd op urgency composite:

Of via API (geavanceerd — voor automatisering)

urgency = (open_critical × 10)
+ (open_high × 3)
+ (sla_breach_minutes / 60)
+ (kev_open_cves)
+ (trust_score_delta_24h × -2) -- drop is urgent
+ (overdue_eats × 5)

Workflow:

  1. Top 3 tenants in urgency-lijst → klik door → fix
  2. Per tenant zie je een mini-Trust-Score (huidige + 24h delta) + de top open alert + de top open kernel-CVE
  3. Eén klik “Open in tenant context” gebruikt RBAC-impersonatie (zie §3 hieronder) — geen herinloggen per tenant

Filter: urgency > 50 toont meestal 2-5 tenants. De rest hangt onder 50 en kan deze week — niet vandaag.


2. Tenant-handover rapport — wat we deze maand deden

In het dashboard

  1. Sidebar → Audit Packs → kies de cliënt’s maand
  2. Klik ‘Download for handover’ → filter actor LIKE ’%@yourMSP.com’
  3. Resulterende PDF + .sig zijn ondertekend door de hub
  4. Email naar cliënt — die verifieert offline met monsys-verify-eat CLI

De cliënt vraagt elke maand: “wat heeft je team voor mij gedaan?”

Maandelijkse Audit Pack covert dit al:

  • 2026-04.jsonl.gz — alle EATs uitgevoerd in naam van de cliënt
  • 2026-04.pdf — geaggregeerd: Trust Score evolutie, kernel-updates uitgevoerd, CVEs gefixt, alerts afgehandeld, sessies geopend

MSP-specifiek: filter de PDF op alleen acties door je eigen team (u.email LIKE '%@yourMSP.com'):

Of via API (geavanceerd — voor automatisering)

Terminal window
curl 'https://app.monsys.ai/api/v1/audit-packs/<pack_id>/download?format=pdf&actor_filter=@yourMSP.com' \
-H "Authorization: Bearer $TOKEN" -o handover-acme-2026-04.pdf

Verstuur deze PDF + de .sig rechtstreeks naar de cliënt. Hij verifieert zelf dat het van monsys-runtime komt, niet van jouw editor:

Terminal window
./monsys-verify-eat-linux-x64 verify-pack \
--pack handover-acme-2026-04.pdf \
--sig handover-acme-2026-04.sig \
--pubkey https://transparency.monsys.ai/pubkeys/hub.pub

3. White-label branding per tenant

In het dashboard

  1. Sidebar → Settings → Tenant branding (per cliënt)
  2. Upload logo + kleur + product name + custom_domain
  3. Cliënt opent custom_domain → ziet eigen brand, jouw MSP als ‘powered by’
  4. RBAC scope blijft jouw beheer; cliënt enkel read-only

Sinds schema 31 zit per-tenant branding in de hub. Cliënt-portaal toont hun logo, kleur, domein — niet jouw monsys.ai-brand.

Of via API (geavanceerd — voor automatisering)

Terminal window
curl -X PUT https://app.monsys.ai/api/v1/tenants/<id>/branding \
-H "Authorization: Bearer $MSP_ADMIN_TOKEN" \
-F 'logo=@acme-logo.svg' \
-F 'primary_color=#1e3a8a' \
-F 'product_name=AcmeOps' \
-F 'custom_domain=ops.acme.com'

Cliënt opent ops.acme.com → ziet AcmeOps als brand, jouw MSP staat in de footer als “powered by”. Cliënt kan zelf geen admin-acties doen (dat is jouw RBAC-scope), wel read-only zien wat er gebeurt + zijn eigen audit-evidence downloaden.


4. Auto-groeperen agents per tenant op tag

In het dashboard

  1. Sidebar → Groups → ‘Nieuwe groep’ (in tenant context)
  2. Rule: all_of [tag=production, tag=eu-west-1]
  3. Voeg runbook markdown toe in ‘Runbook’ veld
  4. GroupMembershipWorker (5m tick) updatet lidmaatschap automatisch

Cliënt heeft 40 hosts verdeeld over dev/staging/prod. Statische groepen beheren = onderhoud. Dynamische groepen op tag-regel:

Of via API (geavanceerd — voor automatisering)

Terminal window
curl -X POST https://app.monsys.ai/api/v1/groups \
-H "Authorization: Bearer $TOKEN" \
-d '{
"tenant_id": "<acme_uuid>",
"name": "production-eu",
"rule": {
"all_of": [
{"tag": "production"},
{"tag": "eu-west-1"}
]
},
"runbook_md": "# Production EU runbook\n\n…"
}'

GroupMembershipWorker (elke 5 min) hashet de set en update lidmaatschap. Een nieuwe host die met production,eu-west-1 tags registreert komt automatisch in deze groep + erft de runbook + SLA + on-call rotation van die groep.


5. Pre-issued EATs voor off-hours emergency

In het dashboard

  1. Sidebar → Playbooks → kies ‘Isolate network’
  2. Knop ‘Pre-issue voor agent’ → kies host + valid window
  3. Conditie (heartbeat lost / critical alert) + TOTP
  4. Agent ontvangt EAT via WS, activeert zelf wanneer conditie matcht

Probleem: cliënt heeft een 2:00 incident. Jouw on-call engineer is beschikbaar maar moet eerst hub-toegang doen + TOTP + Ed25519-EAT issuen. Dat is 5 minuten extra wanneer secondes tellen.

Oplossing (mig 091): pre-issued playbook EATs — uitgegeven aan een specifieke agent, met short-TTL én een voorwaarde die alleen on-call-context kan activeren.

Of via API (geavanceerd — voor automatisering)

Terminal window
curl -X POST https://app.monsys.ai/api/v1/agents/<id>/pre-issued-eats \
-H "Authorization: Bearer $TOKEN" \
-H "X-TOTP-Code: 123456" \
-d '{
"playbook_id": "<isolate-network-playbook_id>",
"valid_from": "2026-05-19T18:00:00Z",
"valid_until": "2026-05-20T08:00:00Z",
"conditions": {
"heartbeat_lost_minutes": 5,
"or_severity_critical": true
},
"reason": "After-hours coverage for ACME — Saturday night"
}'

Tijdens het venster, als de agent zelf detecteert dat hij >5min geen heartbeat heeft kunnen sturen óf als een critical alert open staat, mag hij de pre-issued EAT zelf uitvoeren (één keer, single-use nonce gebruikt). Audit-evidence is identiek aan een normaal EAT.

Use cases:

  • Network isolation als ransomware-pattern wordt gedetecteerd
  • Restart van een specifieke applicatie zonder operator-input
  • Quarantine van een verdacht bestand

6. Multi-party signing voor irreversible acties

In het dashboard

  1. Sidebar → Emergency → ‘Nieuwe Level-3 EAT’
  2. Vul action + reden + required_approvers = 2
  3. Andere admins krijgen push op mobile PWA met ‘Approve’/‘Reject’
  4. Bij N approvals (elk eigen TOTP, split-control) → EAT fires

Sommige acties zijn zo destructief dat één TOTP onvoldoende is (production DB restore, kernel-update op CEO laptop, secrets-rotation fleet-wide). Level 3 EATs vereisen quorum.

Of via API (geavanceerd — voor automatisering)

Terminal window
curl -X POST https://app.monsys.ai/api/v1/emergency/quorum \
-H "Authorization: Bearer $TOKEN" \
-H "X-TOTP-Code: 123456" \
-d '{
"agent_id": "<id>",
"actions": [{ "kind": "run_playbook", "id": "db-restore" }],
"reason": "Restore from 2026-04-15 snapshot per ticket TKT-9001",
"required_approvers": 2
}'

Hub stuurt ntfy-notificatie naar elke andere MSP-engineer met admin-rol. Mobile PWA toont “Pending approval — DB restore on ACME”:

ACME / db-prod-01
RunPlaybook: db-restore
Requested by alice@yourMSP.com at 14:23
Reason: Restore from 2026-04-15 snapshot per ticket TKT-9001
[Approve with TOTP] [Reject]

Pas wanneer N goedkeuringen binnen zijn én elk via een verschillende TOTP-flow (split-control: geen één engineer kan twee approvals doen) fires het EAT. Bewijs van quorum staat in audit_log:

SELECT event_type, event_data
FROM audit_log
WHERE event_type = 'emergency_quorum_approved'
AND event_data->>'nonce' = '<nonce>';

Tenant ziet in /audit-packs PDF dat de actie via 2-of-2 quorum is uitgevoerd — sterke evidence voor SOC2 separation-of-duties.


7. MSP-billing — aggregeer alle tenants in één invoice

In het dashboard

  1. Sidebar → Billing → tab ‘Cross-tenant overzicht’
  2. Tabel: actieve agents per tenant + billable (na 5 gratis)
  3. Totale monthly_eur som per cliënt
  4. Knop ‘Export voor invoice’ → CSV per maand

Voor cliënten waar jij de factuur betaalt (jij rebillt later):

Of via API (geavanceerd — voor automatisering)

WITH per_tenant AS (
SELECT t.id, t.name,
COUNT(*) FILTER (WHERE a.is_active=true) AS active_agents,
COUNT(*) FILTER (WHERE a.is_active=true) - 5 AS billable
FROM tenants t
JOIN agents a ON a.tenant_id = t.id
WHERE t.msp_owner = $1::UUID
AND t.created_at < date_trunc('month', NOW())
GROUP BY t.id
)
SELECT name,
active_agents,
GREATEST(billable, 0) AS billable_agents,
GREATEST(billable, 0) * 3.0 AS monthly_eur
FROM per_tenant
ORDER BY monthly_eur DESC;

Eerste 5 agents per tenant zijn gratis (per tenant, niet per MSP). Het msp_owner-veld op tenants is de relatie die je MSP-rol bindt.


8. RBAC-impersonatie voor cross-tenant ondersteuning

In het dashboard

  1. Tenant switcher top-right → kies cliënt + ‘Impersonate’
  2. Vul reden + duration 60min + TOTP
  3. Werk in cliënt context — acties krijgen dubbele actor in audit_log
  4. Cliënt ziet impersonation_started event in eigen Audit Pack

Engineer Alice (MSP-admin) wil een actie uitvoeren in ACME’s context. In plaats van een nieuwe login: impersonate.

Of via API (geavanceerd — voor automatisering)

Terminal window
curl -X POST https://app.monsys.ai/api/v1/auth/impersonate \
-H "Authorization: Bearer $MSP_ADMIN_TOKEN" \
-H "X-TOTP-Code: 123456" \
-d '{
"tenant_id": "<acme_uuid>",
"duration_minutes": 60,
"reason": "Investigating alert #847 on web-03"
}'
# returns scoped token

De resulterende token heeft tenant=ACME en alle queries die ermee gedaan worden, lopen in ACME’s RLS-context. Audit-log toont impersonation_started + alle acties met dubbele actor: jouw user_id (jouw email) én tenant=ACME. Cliënt ziet in zijn eigen audit-pack dat er door je MSP impersonated is — geen surprise audit trails.

Auto-expire na 60 min. Vroeg eindigen via POST /api/v1/auth/impersonate/end.