Security Architecture
SecureLink implements defense-in-depth across authentication, authorization, device identity, encrypted communication, and multi-tenant isolation. This page describes how these layers work together.
Authentication and Authorization
SecureLink separates authentication (verifying who you are) from authorization (determining what you can do):
- Keycloak handles authentication — it manages user credentials, login flows, and issues identity tokens
- VSN+ handles authorization — it issues session tokens containing the user's type, tenant, roles, and permissions
Login Flow
When a user signs in via the Web UI, the flow is entirely server-side — the user never sees a Keycloak login page:
Keycloak remains the credential store and enforces password policy and account lockout, but users interact only with the native SecureLink sign-in form. The /auth/exchange endpoint (which accepted a Keycloak JWT directly from the browser) is still present in the codebase for legacy integrations but is no longer the primary user-facing path.
The VSN+ session token contains the full authorization context:
| Field | Description |
|---|---|
| userType | 1 = SuperAdmin, 2 = Tenant Admin, 3 = VPN User |
| tenantId | The tenant this user belongs to (null for SuperAdmin) |
| roles | Role names assigned to the user |
| permissions | Flattened list of permissions derived from roles |
| sessionId | Reference to the server-side session record |
This separation means Keycloak never needs to know about SecureLink's tenant model, roles, or permissions — it only verifies credentials.
Session Lifecycle
| Event | Action |
|---|---|
| Login | Native sign-in form submits to /auth/login; server performs KC password grant and issues VSN+ session token. Default expiry: 8 hours (configurable via VSN_SESSION_DURATION_HOURS). With "Keep me signed in for 30 days": 30 days |
| API call | VSN+ token verified on every request; tenant context extracted for data filtering |
| Refresh | Session token can be refreshed before expiry without re-entering credentials |
| Logout | Session is revoked server-side; token becomes invalid immediately |
| Revocation | Admin revokes a user's sessions — next API call returns 401, redirecting to /login |
Session Revocation Enforcement
When a VSN+ session token is revoked (either by the user via "Revoke All Active" or by an admin):
- The revoked token is definitively invalidated — it returns a 401 Unauthorized error
- The auth middleware does not fall back to Keycloak validation for revoked VSN+ tokens
- This ensures that session revocation is immediate and enforceable, even if the user's Keycloak session is still valid
- The user must re-authenticate through the native login form at
/loginto obtain a new session
Keycloak Instance Separation
The platform uses two separate Keycloak instances with different purposes:
| Instance | Users | Purpose |
|---|---|---|
| Production Keycloak | Tenant admins, VPN users | Authentication for the SecureLink Web UI and API |
| Global VSA Keycloak | Multi-orchestrator administrators | Authentication for the Global VSA management plane |
These instances have separate realms, client configurations, and user directories. They do not share state.
Certificate Provisioning
Every edge device establishes its identity through X.509 certificates provisioned during the bootstrap process. These certificates enable mutual TLS (mTLS) authentication on all subsequent MQTT communication.
Provisioning Flow
The SecureLink Installer CLI provisions devices using a one-time deployment token over HTTPS:
- The installer claims the deployment token via the orchestrator's provision API. The token claim is atomic (
UPDATE ... SET status='claimed' WHERE status='active') to prevent double-use. - The API generates a signed X.509 certificate with the device GUID as the Common Name. The private key is returned unencrypted over the HTTPS connection (secured by TLS + token authentication).
- The installer saves certificates with restricted file permissions (root-owned, 0600). The private key never traverses an unencrypted channel.
- The device establishes an mTLS connection to the MQTT broker using the provisioned certificates.
Deployment Token
Deployment tokens follow the format NLZ-XXXX-XXXX-XXXX-XXXX using an unambiguous character set (excludes I, O, 0, 1 to avoid confusion). Each token is:
- Single-use — once claimed, it cannot be reused
- Time-limited — tokens expire if not used within the configured window
- Atomically claimed — database-level protection against race conditions
Certificate Storage on Edge
After provisioning, certificates are stored on the edge device:
| File | Purpose |
|---|---|
ca.crt | CA certificate — validates the broker's identity |
edge.crt | Device certificate — proves the edge's identity to the broker |
edge.key | Private key — restricted file permissions (0600), never transmitted after provisioning |
Mutual TLS (mTLS)
After bootstrap, all communication between edge devices and the MQTT broker uses mutual TLS:
- The broker presents its certificate, which the edge validates against the CA
- The edge presents its certificate, which the broker validates against the CA
- Both sides must prove their identity before the connection is established
This means:
- Unauthorized devices cannot connect to the MQTT broker
- Messages cannot be intercepted or tampered with in transit
- Each device's identity is cryptographically verified on every connection
MQTT Broker Trust Chain
The edge trust store (ca.crt) may contain two CA certificates:
| CA | Purpose |
|---|---|
| Tenant CA | Signs the edge's device certificate (client identity) |
| EMQX CA | Signs the MQTT broker's server certificate (server identity) |
When the broker uses a separate self-signed CA (common in cloud deployments), the installer appends the broker CA to the edge's trust store automatically. The agent validates the broker's certificate against both CAs using TLS Server Name Indication (SNI) for hostname verification.
SSH Certificate Architecture
SecureLink uses SSH certificates (not plain keys) for both host identity and user authentication:
SSH CA
Each tenant has a dedicated Ed25519 SSH CA keypair stored on the API server. This CA signs both host certificates (for edge sshd identity) and user certificates (for admin access).
Host Certificates
During provisioning, the installer:
- Generates an Ed25519 host keypair on the edge
- Sends the public key to the API for signing
- Receives a signed host certificate with principals (GUID, IP address)
- Configures
sshdwithHostCertificatepointing to the signed cert
User Certificates
When an admin generates an SSH user certificate from the UI:
- The admin provides their SSH public key
- The API signs it with the tenant's SSH CA, valid for 24 hours
- The certificate includes principals
edgeandroot - The edge's
sshdtrusts the certificate viaTrustedUserCAKeys(configured by the installer)
Bastion Architecture
The SSH bastion fetches authorized keys from the API on every connection attempt via AuthorizedKeysCommand. It also trusts all tenant SSH CAs via TrustedUserCAKeys, allowing admin user certificates for ProxyJump access. No static authorized_keys file is needed — the database is the sole source of truth.
Multi-Tenant Isolation
SecureLink enforces tenant isolation at multiple layers:
API Layer
Every API query is filtered by the authenticated user's tenant ID. A Tenant Admin can only see and modify resources belonging to their own tenant. SuperAdmins can access all tenants but must explicitly select a tenant context for most operations.
MQTT Layer
MTGE devices use per-tenant MQTT topics (VSR/{serial}/batch/{tenantId}), ensuring that configuration for one tenant is never delivered to another tenant's processing context on the device.
Data Plane Layer (MTGE)
On multi-tenant gateway edges, VRF (Virtual Routing and Forwarding) technology provides complete data plane isolation:
- Each tenant gets a separate VRF with its own routing table
- WireGuard tunnels, NAT rules, and ACLs are bound to the tenant's VRF
- Traffic cannot cross VRF boundaries unless explicitly configured (e.g., internet breakout)
Database Layer
All tenant-scoped tables include a tenant_id column. Drizzle ORM queries always include a tenant filter when operating on behalf of a Tenant Admin.
WireGuard Key Security
WireGuard tunnels use X25519 key pairs. Keys are:
- Generated using the Node.js native cryptography module
- Encrypted at rest in the database using AES-256-GCM (key derived via PBKDF2 from a per-key salt)
- Never logged — the API enforces that private keys are excluded from all logging output
- Transmitted only inside batch configuration — delivered over the mTLS-encrypted MQTT channel
IKEv2 Certificate Security
IKEv2 App VPN uses a separate certificate chain for StrongSwan:
- CA certificate and server certificate generated per-edge (or per-tenant for MTGEs)
- Client certificates issued per VPN user, bundled as PKCS#12 with a one-time password
- Certificate bundles encrypted in the database using AES-256-GCM with a static environment key (distinct from the PBKDF2 scheme used for WireGuard keys)
- Certificate Revocation List (CRL) maintained and distributed via batch configuration
Further Reading
- Platform Architecture — Component overview and communication paths
- Config Sync Pipeline — How configuration is delivered securely to devices
- MQTT Topic Reference — Topic structure and mTLS requirements