Security and multi-tenancy
This page covers CloudGrange's role-based access control model, multi-tenant isolation guarantees, identity provider integration, and how sensitive configuration values are protected at rest.
Role-based access control
CloudGrange enforces RBAC at the API layer. Every request to a protected endpoint is evaluated against the authenticated user's permission set before execution. Permissions are not inherited hierarchically — each endpoint declares exactly which permission it requires.
Built-in roles
| Role | Description |
|---|---|
PlatformAdmin |
Full access to all platform management operations, including identity providers, module install/uninstall, update management, user management, and audit log |
Operator |
Read and write access to cluster operations: register/deregister clusters, submit jobs, manage saved filters, and view notifications |
Viewer |
Read-only access to clusters, inventory, health data, and notifications |
Permission reference
| Permission | Granted to roles | Description |
|---|---|---|
clusters:read |
PlatformAdmin, Operator, Viewer | List and view cluster details |
clusters:write |
PlatformAdmin, Operator | Register new clusters and update cluster metadata |
clusters:admin |
PlatformAdmin | Deregister clusters |
jobs:read |
PlatformAdmin, Operator, Viewer | View job status and results |
jobs:write |
PlatformAdmin, Operator | Submit jobs and batch job sets |
modules:read |
PlatformAdmin, Operator, Viewer | Browse the module catalog |
modules:install |
PlatformAdmin | Install and uninstall modules |
platform:admin |
PlatformAdmin | Identity providers, audit log writes, platform update management, secrets management |
Assigning roles
Roles are assigned to users in the portal under Platform Management → Users & Roles. The local administrator created during the first-run wizard is always assigned PlatformAdmin.
External identity provider users receive the Viewer role by default on first sign-in. Promote them to Operator or PlatformAdmin from the Users & Roles page.
Multi-tenant isolation
CloudGrange uses an org_id column on every tenant-scoped database table to enforce row-level isolation between organisations.
What is isolated
Every resource in CloudGrange — clusters, nodes, jobs, notifications, saved filters, identity providers, modules, and audit log entries — is scoped to an org_id. The API enforces this at the query layer: every data access operation filters by the authenticated user's org_id, regardless of whether the caller supplies an org_id in the request.
Cluster data streams: The Relay WebSocket connection is authenticated using the enrollment token and bound to the org_id that issued it. Inventory data from a Relay connection is written only to that organisation's data partition.
Batch jobs: POST /api/v1/jobs/batch enforces org_id on every job in the batch. A job whose clusterId does not belong to the authenticated user's organisation is rejected with 403, even if the cluster ID is valid.
What is not isolated
The following are platform-level resources, not org-scoped:
- Platform health and version information (
GET /api/v1/platform/updates/check) - Module catalog entries (the catalog is shared; installed state is per-org)
Identity provider integration
CloudGrange ships with no external identity provider configured. After the first-run wizard creates a local administrator account, you can add identity providers under Platform Management → Identity Providers.
Supported providers
| Type | Configuration fields |
|---|---|
| Microsoft Entra ID | Tenant ID, Client ID, Client Secret |
| Active Directory (LDAP) | Domain, Bind DN, Bind password, Base DN |
| Generic OIDC | Authority URL, Client ID, Client Secret |
| Keycloak | Realm URL, Client ID, Client Secret |
Keycloak integration
CloudGrange uses Keycloak as an embedded OIDC broker in PaaS deployments. The Keycloak instance is configured by the platform at first-run and federates to external identity providers configured by the operator.
In the on-premises model, Keycloak runs as the cloudgrange-keycloak container in the Docker Compose stack (not listed in the standard six-container set — it is a separate optional component for sites that want federated SSO). Operators who only need local administrator access do not need Keycloak.
Local administrator (break-glass)
The local administrator account created during the first-run wizard is always active, regardless of how many external identity providers are added or whether they are functioning. It is the break-glass account for platform access.
Do not delete the local administrator account. If you lose the password, recovery requires a database-level reset. See the troubleshooting guide for the reset procedure.
Master encryption key
CloudGrange stores sensitive values in the database — identity provider client secrets, Relay enrollment tokens, and Key Vault credential references — encrypted with AES-256 using a master key.
On-premises
The master key is set in the Docker Compose .env file as CLOUDGRANGE_MASTER_KEY. It must be a 32-character (256-bit) random hex string. Generate it at install time and store it securely outside the VM — it cannot be recovered from the database if lost.
# Generate a suitable master key
[System.Convert]::ToHexString([System.Security.Cryptography.RandomNumberGenerator]::GetBytes(32))
Never commit the master key to version control. Back it up to a secure offline store.
PaaS — Key Vault secret reference
In the Azure PaaS deployment, the master key is stored as a secret in Azure Key Vault (cloudgrange-master-key) and injected into the API container via an ACA secret reference. The secret value is never visible in plaintext in the Azure portal or in ACA environment variable lists.
The Managed Identity attached to the API container app is granted the Key Vault Secrets User role on the Key Vault, which is the minimum permission required to read secret values. It cannot list, delete, or modify secrets.
See Configuration reference — Key Vault secret references for the full rotation procedure.
Transport security
All communication between operators and CloudGrange uses HTTPS:
- On-premises: The installer creates a self-signed TLS certificate for the management host FQDN. Replace it with a CA-signed certificate for production use by mounting the certificate and key into the
cloudgrange-portalcontainer and updating the nginx configuration. - PaaS: Azure Container Apps provides ACA-managed TLS for the default
*.azurecontainerapps.ioFQDNs. Custom domains use ACA-managed Let's Encrypt certificates.
The Relay-to-platform connection is an outbound HTTPS WebSocket from the Relay to the portal URL on port 443. No inbound firewall changes are required on the cluster network.
Audit logging
CloudGrange writes an audit log entry for every state-changing operation:
- User sign-in and sign-out
- Identity provider add/update/remove
- Cluster register and deregister
- Job submit and cancel
- Module install and uninstall
- Platform update apply and rollback
- User role changes
- Manual entries via
POST /api/v1/platform/audit
Audit log entries are scoped to the organisation and include the authenticated user, the operation, the affected resource ID, the timestamp, and the client IP address.
View the audit log in the portal under Platform Management → Audit Log, or query it via the API (see the API reference for the /api/v1/platform/audit endpoint).
In the PaaS deployment, audit log entries are also exported to the Azure Monitor Log Analytics Workspace via the OpenTelemetry Collector.