MSP — cross-tenant triage en delivery
1. Maandagochtend cross-tenant triage
In het dashboard
- Login als MSP-admin → Sidebar → MSP cockpit
- Alle tenants gesorteerd op urgency descending
- Klik tenant met hoogste urgency → opent in tenant context
- 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:
- Top 3 tenants in urgency-lijst → klik door → fix
- Per tenant zie je een mini-Trust-Score (huidige + 24h delta) + de top open alert + de top open kernel-CVE
- 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
- Sidebar → Audit Packs → kies de cliënt’s maand
- Klik ‘Download for handover’ → filter actor LIKE ’%@yourMSP.com’
- Resulterende PDF + .sig zijn ondertekend door de hub
- 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ënt2026-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)
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.pdfVerstuur deze PDF + de .sig rechtstreeks naar de cliënt. Hij
verifieert zelf dat het van monsys-runtime komt, niet van jouw editor:
./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.pub3. White-label branding per tenant
In het dashboard
- Sidebar → Settings → Tenant branding (per cliënt)
- Upload logo + kleur + product name + custom_domain
- Cliënt opent custom_domain → ziet eigen brand, jouw MSP als ‘powered by’
- 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)
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
- Sidebar → Groups → ‘Nieuwe groep’ (in tenant context)
- Rule: all_of [tag=production, tag=eu-west-1]
- Voeg runbook markdown toe in ‘Runbook’ veld
- 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)
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
- Sidebar → Playbooks → kies ‘Isolate network’
- Knop ‘Pre-issue voor agent’ → kies host + valid window
- Conditie (heartbeat lost / critical alert) + TOTP
- 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)
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
- Sidebar → Emergency → ‘Nieuwe Level-3 EAT’
- Vul action + reden + required_approvers = 2
- Andere admins krijgen push op mobile PWA met ‘Approve’/‘Reject’
- 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)
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-01RunPlaybook: db-restoreRequested by alice@yourMSP.com at 14:23Reason: 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
- Sidebar → Billing → tab ‘Cross-tenant overzicht’
- Tabel: actieve agents per tenant + billable (na 5 gratis)
- Totale monthly_eur som per cliënt
- 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
- Tenant switcher top-right → kies cliënt + ‘Impersonate’
- Vul reden + duration 60min + TOTP
- Werk in cliënt context — acties krijgen dubbele actor in audit_log
- 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)
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 tokenDe 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.