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-portal container and updating the nginx configuration.
  • PaaS: Azure Container Apps provides ACA-managed TLS for the default *.azurecontainerapps.io FQDNs. 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.