05 · Architecture
Multi-Tenant Security and Role-Based Access Control
Supporting multiple clients is useful. Accidentally crossing their boundaries is unacceptable.
In this article
- I designed around MSPs from the start
- A data leak is not an internal convenience
- Why I minimise stored infrastructure data
- Thinking through the awkward routes
- Why tenant boundaries matter
- Choose a defensible data model
- Role-based access with least privilege
- Defend against insecure direct object references
- Minimise data and secure integrations
- A practical test matrix
- Engineering review checklist
The design boundaries that keep vulnerability workflows separated across organisations.
These are notes from problems I have actually wrestled with in vulnerability operations, not a claim that every feature is solved or that every customer has the same environment. I built VulnOps because the everyday work between finding a vulnerability and closing it deserved better tools.
I designed around MSPs from the start
VulnOps was not intended to be a vulnerability dashboard for one small team. My target was the reality of MSPs and MSSPs, where one operation may support several clients with different applications, service agreements and appetite for change. A setting that is acceptable for one customer can be unacceptable for another. Some clients keep business-critical software long after the vendor stops supporting it. The application has to help engineers record those exceptions without treating every exception as negligence.
A data leak is not an internal convenience
It is tempting to assume that because an MSP legitimately serves several customers, cross-client visibility is harmless. I do not agree. A report sent to the wrong client can be a contractual breach and a serious hit to trust, even if both clients are handled by the same provider. Access needs to be intentional and limited by role, tenant and task. Administrative users may require broad operational oversight, but that does not mean every engineer should be able to browse every client finding or export every report. A manager's convenience is not an access-control model.
Why I minimise stored infrastructure data
I did not want VulnOps to become another rich inventory of hostnames, device identifiers and network maps. The data-minimisation approach is to keep vulnerability definitions and the remediation workflow in the platform while leaving detailed asset information in the scanner and deployment systems. Less copied data means fewer opportunities for a mistake to expose it. This is a design philosophy rather than a proof that nothing sensitive can ever enter logs, uploads or integrations. A proper security review still has to test all those paths.
Thinking through the awkward routes
Designing tenant boundaries forced me to imagine what could go wrong through exports, background tasks, search results, saved filters and integrations, not just the obvious page URLs. I would mentally run through alternate paths to the same information, almost like Doctor Strange checking possibilities. That habit comes from my operational experience and earlier experience building a company. Tenant isolation is only credible when permission checks happen server-side, queries enforce tenant scope and tests try to cross the boundary deliberately. A role label on a frontend button is not an authorization control.
Why tenant boundaries matter
A multi-tenant vulnerability platform is not simply a dashboard with a customer dropdown. Security findings, risk exceptions, script contents and deployment connections may reveal sensitive details about an organisation. One tenant must never be able to read another tenant's records by guessing an identifier or changing a request parameter. VulnOps is designed to support a service provider managing several organisational environments while maintaining separate operational scopes. The essential security question is not whether the interface hides other customers; it is whether every backend operation enforces the same boundary. An elegant React filter cannot compensate for a missing server-side tenant check. Tenant isolation has to be built into the data model, queries, authorization decisions, background jobs and audit events.
Choose a defensible data model
In a shared-database design, records generally need an explicit tenant or organisation identifier and clear ownership relationships. A vulnerability definition can be shared at a conceptual level while assignments, notes, exception decisions and integration credentials must remain scoped. All endpoints that fetch, update, export or delete operational records should derive the allowed tenant context from the authenticated identity and server-side memberships. Do not accept a tenant ID from a browser as proof of entitlement. Where the product supports sub-environments inside an organisation, define whether an organisation-level administrator can see all sub-environments and whether an environment-level engineer can operate only inside assigned scopes. Those rules should be written down before permissions become scattered across API routes.
Role-based access with least privilege
Three-tier role models can be useful when they correspond to distinct responsibilities: platform administrator, tenant administrator and operational engineer or viewer. The names matter less than the capabilities each role can exercise. Reading vulnerability reports is different from changing a risk acceptance, approving a script or initiating an Intune deployment. Sensitive actions should require explicit permissions and, where appropriate, separate approval. A platform administrator should not automatically need access to customers' underlying endpoint data. VulnOps describes three-tier RBAC and tenant isolation as product controls; any actual deployment needs tests proving those controls operate across API endpoints, file exports and scheduled tasks. Permissions should be denied by default so a new route does not become public inside an authenticated session.
Defend against insecure direct object references
A common failure looks ordinary: an authenticated user requests /api/findings/1234 and the server returns that object without validating ownership. The fact that the user is logged in does not authorise access to every object. Test object-level authorization by creating two tenants with similar records and attempting cross-tenant reads, updates and deletions using real but unauthorised identifiers. Repeat the tests for nested resources such as comments, script revisions, approval records and export jobs. A status-code check alone is insufficient if a background job later processes an unauthorised object. Use query filters, shared authorization helpers and defensive database constraints where appropriate. Audit denied attempts without leaking the requested confidential content into logs.
Minimise data and secure integrations
VulnOps describes a data-minimisation philosophy: store vulnerability definitions and remediation workflow information rather than importing hostnames, device IDs and detailed network maps. That reduces the consequences of a compromise, but it does not remove the need to protect integration secrets or user activity. API credentials should be encrypted at rest or kept in a dedicated secret store, masked in logs and rotated when ownership changes. Incoming signed feeds can use HMAC-SHA256, but a signature alone is not replay protection. Validate timestamp windows, reject duplicate nonce or message identifiers and bind the signature to the exact bytes received. Apply rate limits and explicit source allowlists where justified. These controls should complement, not replace, server-side authorization.
A practical test matrix
For each role and tenant, test create, read, update, delete, bulk export, script generation and deployment operations. Include missing memberships, expired sessions, suspended accounts and stale background jobs. Test whether an engineer who loses access can still retrieve a previously generated download link. The strongest audit evidence comes from automated negative tests that reliably fail when a tenant filter is removed. Keep an immutable-enough record of sensitive actions and monitor unusual cross-scope requests. The lesson is that multi-tenancy is a property of the entire application, not a feature that can be demonstrated with a role selector. A platform is not ready for sensitive customer work until isolation survives intentionally hostile API requests.
Engineering review checklist
Before using this approach in production, document the affected versions, prerequisite access, approval owner, intended change, test evidence, rollback limitations and independent validation criteria. Revisit the outcome after the next scan cycle. These checks help distinguish a successful script execution from a defensible security decision and prevent an incomplete change from being reported as closed.
