EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
MeshCentral Multi-Tenant Isolation Architecture

Overview

Our MeshCentral integration now implements true multi-tenant isolation at every level:

  • Each tenant gets their own user account in MeshCentral
  • Each tenant gets their own device group (mesh) in MeshCentral
  • Agents are assigned to their tenant's group automatically
  • Tenant users can only see and manage their own devices
  • Root tenant (MSP) maintains administrative access to all tenants

This architecture ensures complete separation of tenant data and prevents cross-tenant access at the MeshCentral level, not just our database level.

Architecture Components

1. Database Schema

Tenant Table Extensions:

ALTER TABLE tenants ADD COLUMN
meshcentral_username VARCHAR(100), -- Unique MeshCentral username
meshcentral_password_encrypted TEXT, -- AES-256-GCM encrypted password
meshcentral_group_id VARCHAR(255), -- MeshCentral mesh ID
meshcentral_group_name VARCHAR(255), -- Human-readable mesh name
meshcentral_setup_complete BOOLEAN DEFAULT false; -- Setup status flag

2. Tenant Setup Workflow

When a new tenant is created:

  1. Admin creates user account in MeshCentral for tenant
    • Username: subdomain or tenant_{uuid}
    • Password: Randomly generated 64-char hex
    • Email: {username}@meshcentral.local
    • Permissions: Regular user (no site admin)
  2. Admin creates device group (mesh) for tenant
    • Name: {TenantName} Devices
    • Type: Agent mesh (not Intel AMT)
    • Description: Device group for {TenantName}
  3. Admin links user to mesh with full permissions
    • Permissions: 0xFFFFFFFF (full access)
    • Includes: Remote Desktop, Terminal, Files, Events, etc.
  4. Backend stores credentials in database
    • Password encrypted with AES-256-GCM
    • Encryption key from process.env.ENCRYPTION_KEY
    • Stored in meshcentral_password_encrypted column
  5. Backend marks tenant as setup complete
    • Sets meshcentral_setup_complete = true
    • Future sessions use tenant's own credentials

3. Session Management

When user accesses Remote Desktop:

// 1. Determine which tenant owns the agent
const agent = await getAgentWithTenantId(agentId);
// 2. Get tenant-specific MeshCentral API client
const api = await getTenantMeshAPI(agent.tenant_id);
// - Root tenant (MSP): Uses admin credentials
// - Regular tenant: Uses tenant-specific credentials from database
// 3. Login with tenant credentials
await api.login(); // Uses tenant username/password
// 4. Generate authenticated iframe URL
const iframeUrl = `${MESHCENTRAL_URL}/?login=${api.cookie}&gotonode=${nodeId}`;
// 5. Return pre-authenticated URL to dashboard
// User sees only their tenant's devices in MeshCentral UI

4. Tenant Isolation Layers

Layer 1: MeshCentral User Accounts

  • Each tenant has separate MeshCentral user
  • User can only see meshes they are assigned to
  • No cross-tenant visibility at MeshCentral level

Layer 2: MeshCentral Device Groups

  • Each tenant has separate mesh (device group)
  • Agents register to tenant-specific mesh
  • Devices physically isolated in MeshCentral

Layer 3: Database Tenant Filtering

  • All queries include WHERE tenant_id = $userTenant
  • Root tenant (tenant_id=1) can access all
  • Regular tenants see only their records

Layer 4: JWT Authentication

  • User JWT contains tenant_id claim
  • Backend validates tenant ownership on every request
  • Session tokens linked to specific user + tenant

API Endpoints

Setup Tenant MeshCentral (MSP Only)

POST /api/meshcentral/setup-tenant/:tenantId

Creates user account and device group for tenant.

Request:

curl -X POST https://backend/api/meshcentral/setup-tenant/abc-123 \
-H "Authorization: Bearer {MSP_JWT}"

Response:

{
"success": true,
"message": "Tenant MeshCentral setup complete",
"username": "client_abc",
"meshId": "mesh//abc123...",
"meshName": "Client ABC Devices"
}

Get Agent Installer URL

GET /api/meshcentral/installer/:tenantId?platform=win32

Returns download URL for MeshAgent configured for tenant's mesh.

Request:

curl https://backend/api/meshcentral/installer/abc-123?platform=win32 \
-H "Authorization: Bearer {TENANT_JWT}"

Response:

{
"success": true,
"installerUrl": "https://mesh.example.com/meshagents?id=mesh//abc123...&installflags=0&meshinstall=meshagent.exe",
"meshId": "mesh//abc123...",
"platform": "win32",
"instructions": {
"windows": "Download and run: https://...",
"linux": "wget https://... && chmod +x meshagent && sudo ./meshagent -install",
"macos": "curl -O https://... && chmod +x meshagent && sudo ./meshagent -install"
}
}

Create Authenticated Session

POST /api/meshcentral/session/:agentId

Creates authenticated MeshCentral session using tenant credentials.

Flow:

  1. Get agent from database (with tenant_id)
  2. Get tenant's MeshCentral credentials
  3. Login to MeshCentral with tenant username/password
  4. Return iframe URL with tenant's session cookie
  5. User sees only their tenant's devices

Request:

curl -X POST https://backend/api/meshcentral/session/115 \
-H "Authorization: Bearer {USER_JWT}" \
-H "Content-Type: application/json" \
-d '{"viewMode": 11}'

Response:

{
"success": true,
"sessionToken": "abc123...",
"expiresAt": "2026-02-13T14:30:00Z",
"agent": {
"id": 115,
"uuid": "2c3e2d7a-...",
"hostname": "testing",
"platform": "win32"
},
"iframeUrl": "https://mesh.example.com/?login={TENANT_COOKIE}&gotonode=...",
"viewMode": 11
}

Implementation Details

Password Encryption

// lib/encryption.js
const { encrypt, decrypt } = require('./lib/encryption');
// Encrypt before storing
const encryptedPassword = encrypt(plainPassword);
await db.query(
'UPDATE tenants SET meshcentral_password_encrypted = $1 WHERE tenant_id = $2',
[encryptedPassword, tenantId]
);
// Decrypt when needed
const encryptedPassword = row.meshcentral_password_encrypted;
const plainPassword = decrypt(encryptedPassword);

Encryption Method: AES-256-GCM Key Derivation: scrypt with salt Format: Base64-encoded JSON: { iv, authTag, data }

API Client Caching

// Cache tenant-specific API clients to avoid repeated logins
const tenantAPIClients = new Map();
async function getTenantMeshAPI(tenantId) {
const cacheKey = `tenant_${tenantId}`;
if (tenantAPIClients.has(cacheKey)) {
return tenantAPIClients.get(cacheKey);
}
// Get credentials, create client, login, cache
const api = new MeshCentralAPI(url, username, password);
await api.login();
tenantAPIClients.set(cacheKey, api);
return api;
}

Automatic Setup

Tenants are automatically setup when first accessed:

if (!tenant.meshcentral_setup_complete) {
console.log(`Auto-setting up MeshCentral for tenant ${tenantId}...`);
await setupTenantMeshCentral(tenantId);
}

Agent Installation

For Tenant Users

  1. Get installer URL:
    GET /api/meshcentral/installer/{tenantId}?platform=win32
  2. Download and install agent:
    • Windows: Run meshagent.exe
    • Linux: wget {url} && chmod +x meshagent && sudo ./meshagent -install
    • macOS: curl -O {url} && chmod +x meshagent && sudo ./meshagent -install
  3. Agent registers to tenant's mesh automatically
    • Uses mesh ID embedded in installer URL
    • Appears only in tenant's device group
    • Other tenants cannot see the device
  4. Backend links MeshCentral node to our agent:
    POST /api/meshcentral/auto-link
    {
    "agentUuid": "2c3e2d7a-...",
    "tenantId": "abc-123"
    }

Security Benefits

1. True Isolation

  • Tenants use different MeshCentral accounts
  • Physical separation at MeshCentral level
  • No shared credentials between tenants

2. Credential Security

  • Passwords encrypted at rest (AES-256-GCM)
  • Never transmitted to client browser
  • Admin password only used for tenant setup

3. Audit Trail

  • Every session logged with tenant_id
  • Session tokens track which tenant accessed which agent
  • MeshCentral logs show per-tenant activity

4. Principle of Least Privilege

  • Tenant users have no site admin rights
  • Can only see devices in their mesh
  • Cannot create additional meshes or users

5. MSP Administrative Access

  • Root tenant (MSP) uses admin credentials
  • Can access all tenants' devices for support
  • Maintains oversight without breaking isolation

Testing Procedures

1. Setup New Tenant

# As MSP admin
curl -X POST https://backend/api/meshcentral/setup-tenant/{TENANT_ID} \
-H "Authorization: Bearer {MSP_JWT}"
# Verify in database
SELECT meshcentral_username, meshcentral_group_id, meshcentral_setup_complete
FROM tenants WHERE tenant_id = '{TENANT_ID}';

2. Install Agent on Tenant Device

# Get installer URL
curl https://backend/api/meshcentral/installer/{TENANT_ID}?platform=win32 \
-H "Authorization: Bearer {TENANT_JWT}"
# Download and run installer on target device
# Agent should appear in tenant's mesh in MeshCentral

3. Verify Isolation

# Login as Tenant A user
# Access Remote Desktop tab for Tenant A agent
# Should see device and can connect
# Login as Tenant B user
# Try to access Tenant A agent UUID
# Should get 404: Agent not found
# Login as MSP admin
# Can access both Tenant A and Tenant B agents

4. Verify Session Authentication

# Check that iframe loads without login screen
# Verify tenant can control their device
# Check that only tenant's devices visible in MeshCentral UI

Migration Path

For Existing Tenants

  1. Run setup for all existing tenants:

    SELECT tenant_id FROM tenants WHERE meshcentral_setup_complete = false;
    for tenant in $tenants; do
    curl -X POST https://backend/api/meshcentral/setup-tenant/$tenant \
    -H "Authorization: Bearer {MSP_JWT}"
    done
  2. Get new installer for each tenant:
    • Each tenant needs tenant-specific installer
    • Old agents registered to admin's mesh need reinstalling
    • Or bulk-move agents to tenant meshes via MeshCentral API
  3. Update agent installations:
    • Uninstall old MeshAgent
    • Install new tenant-specific agent
    • Backend auto-links on first connection

For New Tenants

  • Automatic setup on first Remote Desktop access
  • Or manually trigger via /setup-tenant/:id endpoint
  • Provide installer URL to customer
  • Agent auto-registers to correct mesh

Troubleshooting

Tenant Can't See Their Devices

# Check setup status
SELECT meshcentral_setup_complete, meshcentral_group_id
FROM tenants WHERE tenant_id = '{TENANT_ID}';
# If not complete, run setup
POST /api/meshcentral/setup-tenant/{TENANT_ID}
# Verify agent is in correct mesh
# Check agent's meshcentral_nodeid matches tenant's mesh

Session Cookie Not Working

# Verify tenant credentials can login
# Check encryption/decryption working
# Verify MeshCentral URL accessible
# Check session not expired (4 hour TTL)

Agent Not Auto-Linking

# Verify hostname match between agent and MeshCentral node
# Check tenant_id matches between agent and mesh
# Run manual link:
POST /api/meshcentral/auto-link
{
"agentUuid": "...",
"tenantId": "..."
}

Performance Considerations

  • API clients cached per tenant (avoid repeated logins)
  • Sessions expire after 4 hours (reduce MeshCentral load)
  • Password decryption only happens once per session
  • WebSocket connections reused within same client session

Future Enhancements

  1. Session Refresh: Auto-refresh before 4-hour expiry
  2. WebSocket Proxy: Full bidirectional proxy for real-time features
  3. Bulk Agent Migration: Move existing agents to tenant meshes
  4. User Self-Service: Let tenants download their own installer
  5. Monitoring Integration: Track MeshCentral connection status per tenant
  6. Automated Cleanup: Remove unused tenants from MeshCentral
  7. Permission Customization: Fine-tune rights per tenant (e.g., no terminal access)

References