Multi-Tenancy
PaletteAI is multi-tenant. It organizes teams, controls access, and manages GPU resources through a hierarchy of scopes, so platform engineering teams can set organization-wide policy while data science teams keep autonomy over their own workspaces.
For example, artificial intelligence and machine learning (AI/ML) platforms typically serve multiple teams with different needs. Platform teams need to control who can access what, set resource limits, and manage infrastructure, whereas data science teams need isolated workspaces where they can deploy and manage their own workloads. Scopes separate these concerns.
Scopes
Every PaletteAI resource lives in one of the following scopes, identified by the namespace it resides in. A Project is the unit of work, a Tenant groups Projects and shares resources across them, and the System scope shares resources across all Tenants and Projects. The Platform scope is separate: it holds the internal resources that PaletteAI installs and manages, and is not user-facing.
| Scope | Namespace | Owner | Description | Who Can Use It |
|---|---|---|---|---|
| Project | <project-name> | Project admins | An isolated workspace where a team deploys and manages AI/ML applications and models. Most day-to-day work happens here. | Only within the Project itself. |
| Tenant | tenant-<tenant-name> | Tenant admins | An organization or major division that groups Projects, sets GPU quotas, and shares resources across its Projects. App Deployments, Model Deployments, and Compute Pools can also be created directly at Tenant scope. | Every Project in the Tenant, unless a resource narrows access with sharedWith. |
| System | pai-system | Platform operators | Top-level scope for resources you define and deploy once for the whole organization — the same kinds available at Tenant and Project scope (Compute Pools, AIWorkloads, Profile Bundles, and more). User-managed, not installer-managed. | Every Tenant and Project, unless a resource narrows access with sharedWith. |
| Platform | mural-system (default, configurable) | PaletteAI | Internal platform-wide resources reserved for core operations (controllers, ConfigMaps, Flux sources) and the built-in resources installed by the PaletteAI definitions installer (Definitions, Scaling Policies, Profile Bundles, etc.). Cannot be edited in place but can be cloned into any scope and customized. | Any scope, by reference or by cloning. Not directly editable. |
Each scope shares resources only with the level directly below it, opt-in and controlled per resource. For the sharing model, refer to Sharing Resources.
Scope Labels
PaletteAI applies scope-aware labels to every resource so that the UI can identify its scope. These labels are metadata only and are not used to enforce access.
palette.ai/scoperecords the scope itself, set toproject,tenant,system, orbuilt-in. Thebuilt-invalue is used for the Platform scope.palette.ai/projectholds the project name, andpalette.ai/tenantholds the tenant name. Which labels appear depends on the scope:- Project-scoped resources — Contain both
palette.ai/projectandpalette.ai/tenant - Tenant-scoped resources — Contain only
palette.ai/tenant - System-scoped resources — Contain neither
- Platform-scoped resources — Contain neither
- Project-scoped resources — Contain both
For example, the following labels are attached to the Profile Bundle ollama-model in the Project docs-project, which is a part of the default Tenant.
kubectl describe profilebundles ollama-model --namespace docs-project
Name: ollama-model
Namespace: docs-project
Labels: app=ollama
palette.ai/project=docs-project
palette.ai/scope=project
palette.ai/tenant=default
Resource Creation
The scope you are in determines the types of resources you can create or modify in the UI. Most of these resources can be created directly from the left main menu, while other are found under Project Settings, Tenant Settings, and System Settings.
| Resource | Kind | Spec | Project UI | Tenant UI | System UI |
|---|---|---|---|---|---|
| App Deployment | AIWorkload | - | ✅ | ✅ | ✅ |
| Autoscaling Policy | ScalingPolicy | - | ✅ | ✅ | ✅ |
| Compute | Compute | - | ✅ | ✅ | ✅ |
| Compute Config | ComputeConfig | - | ✅ | ✅ | ✅ |
| Compute Pools | ComputePool | - | ✅ | ✅ | ✅ |
| Definitions | DefinitionRevision | - | ✅ | ❌ | ❌ |
| Model as a Service Mappings | Project, Tenant, or System | modelSettings.profileBundleMappings | ✅ | ✅ | ✅ |
| Model Deployment | AIWorkload | - | ✅ | ✅ | ✅ |
| Models List | Project, Tenant, or System | modelSettings | ✅ | ✅ | ✅ |
| Profile Bundles | ProfileBundle | - | ✅ | Import only | Import only |
| Projects | Project | - | ❌ | ✅ | ✅ |
| RBAC | Project or Tenant | tenantRoleMapping or roleMapping | ✅ | ✅ | ❌ |
| Repositories | HelmRepository or OCIRepository | - | ✅ | ❌ | ❌ |
| Resource Limits | Project, Tenant, or System | gpuResources | ✅ | ✅ | ✅ |
| Settings | Settings | integrations | ✅ | ✅ | ✅ |
| System | System | - | ❌ | ❌ | ✅ |
| Target Namespaces | Project, Tenant, or System | admissionConfiguration | ✅ | ✅ | ✅ |
| Tenants | Tenant | - | ❌ | ✅ | ❌ |
| Variables | VariableSet | - | ✅ | ✅ | ✅ |
| Workload Profile | WorkloadProfile | - | ✅ | ❌ | ❌ |
Namespace Isolation
Many PaletteAI resources point to other resources by namespace. For example, a Compute Pool references the Profile Bundle it is built from. To keep Projects isolated, an admission webhook checks every one of these references when a resource is created or updated, and rejects any that points somewhere it should not. A resource can never reference another Project's namespace.
In the tables below, the allowed namespaces mean:
- Project — The resource's own namespace (the Project it lives in)
- Tenant — The parent Tenant namespace (
tenant-<tenant-name>), where a Tenant admin shares resources across Projects - System — The system namespace (
pai-system), whose resources may be shared with Tenants and their Projects by a system administrator - Built-in — The built-in platform namespace (
mural-system), where default resources such as built-in ScalingPolicies live
Project-scoped Resources
| Resource | Field | Allowed Namespaces |
|---|---|---|
AIWorkload | spec.computePoolRef.namespace | - Project - Tenant (if shared with the Project) - System (if shared with the Project) |
AIWorkload | spec.profileBundles[].namespace | - Project - Tenant (if shared with the Project) - System (if shared with the Project) |
AIWorkload | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - Project - Tenant - System |
ComputePool | spec.clusterVariant.imported.environmentRef.namespace | - Project |
ComputePool | spec.profileBundleRef.namespace | - Project - Tenant (if shared with the Project) - System (if shared with the Project) |
ComputePool | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - Project - Tenant - System |
ComputePool | spec.clusterVariant.*.scalingPolicyRef.namespace | - Project - Tenant (if shared with the Project) - System (if shared with the Project) - Built-in |
ProfileBundle | spec.*.workloadProfileRefs[].namespace | - Project |
Project | spec.computeConfigRef.namespace | - Project - Tenant |
Settings | spec.integrations.palette.namespace | - Project |
Tenant-scoped Resources
| Resource | Field | Allowed Namespaces |
|---|---|---|
AIWorkload | spec.computePoolRef.namespace | - Tenant - System (if shared with the Tenant) |
AIWorkload | spec.profileBundles[].namespace | - Tenant - System (if shared with the Tenant) |
AIWorkload | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - Tenant - System |
ComputePool | spec.clusterVariant.imported.environmentRef.namespace | - Tenant |
ComputePool | spec.profileBundleRef.namespace | - Tenant - System (if shared with the Tenant) |
ComputePool | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - Tenant - System |
ComputePool | spec.clusterVariant.*.scalingPolicyRef.namespace | - Tenant - System (if shared with the Tenant) - Built-in |
ProfileBundle | spec.*.workloadProfileRefs[].namespace | - Tenant |
Project | spec.computeConfigRef.namespace | - Tenant |
Settings | spec.integrations.palette.namespace | - Tenant |
System-scoped Resources
| Resource | Field | Allowed Namespaces |
|---|---|---|
AIWorkload | spec.computePoolRef.namespace | - System |
AIWorkload | spec.profileBundles[].namespace | - System |
AIWorkload | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - System |
ComputePool | spec.clusterVariant.imported.environmentRef.namespace | - System |
ComputePool | spec.profileBundleRef.namespace | - System |
ComputePool | spec.workloadDeploymentConfigs[].workloadProfileRef.namespace | - System |
ComputePool | spec.clusterVariant.*.scalingPolicyRef.namespace | - System - Built-in |
ProfileBundle | spec.*.workloadProfileRefs[].namespace | - System |
Project | spec.computeConfigRef.namespace | - System |
Settings | spec.integrations.palette.namespace | - System |
A Settings resource does not have a dedicated namespace of its own. It lives in a Project, Tenant, or System namespace, and its spec.integrations.palette.namespace must point to that same namespace, so the Palette credential secret always sits alongside the Settings resource that uses it.
For information on how resources are shared across scopes, refer to Sharing Resources.
Access and Permissions
PaletteAI manages access with standard Kubernetes Role-Based Access Control (RBAC), bound to OpenID Connect (OIDC) groups rather than individual users. For an overview of the Tenant and Project roles, refer to Roles and Permissions. External integrations and credentials are configured through Settings.
Default Resources
PaletteAI creates a default Tenant and Project during installation. These provide a starting point for exploration but should be customized for production use.
To disable default resource creation, set global.featureFlags.systemDefaultResources to false in your Helm chart values.
global:
featureFlags:
systemDefaultResources: false