Skip to main content

Create and Manage Tenants

A Tenant represents an organization or major division within your company and serves as the top-level organizational unit in PaletteAI.

A default Tenant is automatically created when you install PaletteAI with global.featureFlags.systemDefaultResources: true in your Helm values. For production workloads with multiple organizations or divisions that require separate GPU quota pools or isolated administrative boundaries, we recommend creating separate Tenants. For guidance on when to create multiple tenants, refer to When to Create Multiple Tenants.

info

PaletteAI automatically creates a tenant-<name> namespace for internal operations when you create a Tenant. You can optionally create your own user namespace to store shared Settings and secrets that Projects inherit. For details on the namespace model, refer to Automatic Resource Creation.

Limitations

  • Tenant creation is not available in the PaletteAI user interface at this time. Tenants must be created using Kubernetes manifests and kubectl commands as described in this guide.

Prerequisites

  • kubectl installed and available in your $PATH.

  • The KUBECONFIG environment variable set to the path of the PaletteAI hub cluster kubeconfig file.

    export KUBECONFIG=<kubeconfig-location>
  • Cluster-admin permissions to manage cluster-scoped Tenant resources.

Create Tenant

Create a Tenant to define organizational boundaries, set GPU quotas, and control access across multiple Projects.

Enablement

  1. Create a directory for the Tenant manifests, and then navigate to it.

    mkdir <tenant-name>
    cd <tenant-name>
  2. (Optional) Create a user namespace for shared Settings and secrets. This namespace is where you store Settings resources that Projects inherit. If you skip this step and do not create a Tenant-level Settings resource, each Project under the Tenant must set its own settingsRef. Refer to Settings for more information.

    1. Create the Tenant namespace. The label palette.ai/tenant: <tenant-name> associates this namespace with your Tenant.

      cat << EOF > namespace.yaml
      apiVersion: v1
      kind: Namespace
      metadata:
      name: <user-namespace>
      labels:
      palette.ai/tenant: <tenant-name>
      EOF
    2. Create a shared Palette secret. This secret must reference a Palette integration.

      cat << EOF > palette-secret.yaml
      apiVersion: v1
      kind: Secret
      metadata:
      name: <palette-secret-name>
      namespace: <user-namespace>
      type: Opaque
      stringData:
      palette: |
      {
      "apiKey": "<your-palette-api-key>",
      "defaultProjectID": "<your-default-project-id>",
      "hostUrl": "<your-palette-host-url>",
      "tenant": "<your-palette-tenant-name>",
      "skipSSLCertificateVerification": false
      }
      EOF
    3. Create a Settings resource in the user namespace that references the Palette secret.

      cat << EOF > settings.yaml
      apiVersion: spectrocloud.com/v1alpha1
      kind: Settings
      metadata:
      name: <settings-name>
      namespace: <user-namespace>
      spec:
      integrations:
      palette:
      name: <palette-secret-name>
      namespace: <user-namespace>
      EOF
  3. Create the Tenant manifest.

    For a complete list of parameters, refer to the Tenant resource spec.

    cat << EOF > tenant.yaml
    apiVersion: spectrocloud.com/v1alpha1
    kind: Tenant
    metadata:
    name: <tenant-name>
    spec:
    displayName: '<tenant-display-name>'
    tenantRoleMapping:
    groups:
    - '<tenant-admin-group-1>'
    - '<tenant-admin-group-2>'
    EOF
  4. Apply the applicable manifests. If you skipped creating a user namespace or Settings resource in step 2, omit those commands.

    # Apply user namespace (if created)
    kubectl apply --filename namespace.yaml

    # Apply Settings resource (if created)
    kubectl apply --filename settings.yaml

    # Apply Tenant (always required)
    kubectl apply --filename tenant.yaml
    Example output (with all resources)
    namespace/primary-dev created
    settings.spectrocloud.com/dev-settings created
    tenant.spectrocloud.com/primary-dev created

Validate

  1. Verify namespaces were created. You should see the user namespace (if you created one) and the controller-created tenant-<name> namespace.

    kubectl get namespaces | grep --extended-regexp '(primary-dev|tenant-primary-dev)'
    Example output
    primary-dev                             Active   5m
    tenant-primary-dev Active 5m

    You can also list user namespaces associated with a Tenant using labels.

    kubectl get namespaces --selector palette.ai/tenant=<tenant-name>
    info

    Only the tenant-<name> namespace is displayed if you did not create a user namespace. The Tenant will work, but Projects must specify their own settingsRef.

  2. Verify the Tenant exists and is ready. If you reference a Settings resource, the SETTINGS column is populated.

    kubectl get tenants
    Example output
    NAME          DISPLAYNAME       READY   SETTINGS       NAMESPACE      PROJECTS   AGE
    default Default Tenant true default default 1 21d
    primary-dev Primary Dev true dev-settings primary-dev 0 5m
  3. Verify the Tenant configuration.

    kubectl describe tenant <tenant-name>

    The following example shows Display Name, Settings Ref, and Tenant Role Mapping under Spec. It also shows the Tenant is ready and has 0 child Projects under Status.

    In Status.Conditions, TenantNamespaceCreated refers to the controller-created tenant-<tenant-name> namespace.

    Example command
    kubectl describe tenant primary-dev
    Example output
    Name:         primary-dev
    Namespace:
    Labels: <none>
    Annotations: <none>
    API Version: spectrocloud.com/v1alpha1
    Kind: Tenant
    Metadata:
    Creation Timestamp: 2026-02-07T15:26:04Z
    Finalizers: spectrocloud.com/tenant-finalizer
    Generation: 1
    Resource Version: 12345678
    UID: abc-123-def-456
    Spec:
    Display Name: Primary Dev
    Settings Ref:
    Name: dev-settings
    Namespace: primary-dev
    Tenant Role Mapping:
    Groups:
    admin
    sre
    Status:
    Child Project Count: 0
    Conditions:
    Last Transition Time: 2026-02-07T15:26:05Z
    Message: Settings configured and ready
    Reason: SettingsConfigured
    Status: True
    Type: SettingsConfigured
    Last Transition Time: 2026-02-07T15:26:05Z
    Message: Tenant namespace created successfully
    Reason: TenantNamespaceCreated
    Status: True
    Type: TenantNamespaceCreated
    Ready: true
    Events: <none>

Modify Tenant

To track changes in version control, update your manifests and apply them with kubectl apply.

Enablement

  1. Open the manifest you want to update and make the necessary changes.

    Use the following table to identify what manifest to update for common changes. For the full parameter list, refer to the applicable Resource page.

    ResourceModificationsAdditional Information
    TenantUpdate displayName. Update tenantRoleMapping.groups. Update gpuResources.Tenants and Projects - GPU Quotas
    SettingsCreate a Settings resource in your user namespace (recommended), and then update the Tenant settingsRef. To remove shared Settings, delete settingsRef from the Tenant spec.Settings

    The following example adds a tenant admin group named operations and sets GPU resource limits.

    vi tenant.yaml
    Updated Tenant
    apiVersion: spectrocloud.com/v1alpha1
    kind: Tenant
    metadata:
    name: primary-dev
    spec:
    displayName: 'Primary Dev'
    settingsRef:
    name: dev-settings
    namespace: primary-dev
    tenantRoleMapping:
    groups:
    - 'admin'
    - 'sre'
    - 'operations'
    gpuResources:
    limits:
    'NVIDIA-A100': 64
    'NVIDIA-H100': 48
    'Default': 24
    requests:
    'NVIDIA-A100': 8
    'NVIDIA-H100': 8
    'Default': 4
  2. Save the file and apply the updated manifest.

    kubectl apply --filename <manifest-location>
    Example command
    kubectl apply --filename tenant.yaml

Validate

Verify the updates were applied to the resource.

kubectl describe tenant <tenant-name>

The following example shows the updated tenant admin group and GPU resource limits.

Example command
kubectl describe tenant primary-dev
Example output
Name: primary-dev
# ... metadata omitted for readability
Spec:
Display Name: Primary Dev
Gpu Resources:
Limits:
Default: 24
NVIDIA-A100: 64
NVIDIA-H100: 48
Requests:
Default: 4
NVIDIA-A100: 8
NVIDIA-H100: 8
Settings Ref:
Name: dev-settings
Namespace: primary-dev
Tenant Role Mapping:
Groups: admin
sre
operations
Status:
Ready: true
Events: <none>

Delete Tenant

Delete a Tenant when you no longer need it. PaletteAI allows you to delete a Tenant only when it has no child Projects.

warning

PaletteAI prevents you from deleting a Tenant that has child Projects. You must delete all Projects under the Tenant before you can delete the Tenant.

Enablement

  1. Verify the Tenant has no child Projects.

    kubectl get tenant <tenant-name> --output jsonpath='{.status.childProjectCount}'

    The output must be 0. If the value is greater than zero, delete the Projects under the Tenant before you continue.

    # List all Projects for this Tenant
    kubectl get projects --all-namespaces --selector palette.ai/tenant-name=<tenant-name>

    # Delete each Project
    kubectl delete project <project-name> --namespace <project-namespace>
  2. Delete the Tenant.

    kubectl delete tenant <tenant-name>
    Example command
    kubectl delete tenant primary-dev
  3. (Optional) Delete the user namespace and Tenant namespace.

    PaletteAI does not delete namespaces automatically when you delete the Tenant. Namespaces may contain Settings and secrets that Projects still reference.

    Before deleting namespaces:

    • Confirm there are no child Projects: kubectl get tenant <tenant-name> --output jsonpath='{.status.childProjectCount}'

    • Confirm no remaining Projects reference the shared Settings namespace (if used).

    • Confirm you no longer need any Secrets/Settings stored in the user namespace.

    # Delete user namespace (if you created one)
    kubectl delete namespace <user-namespace>

    # Delete controller-created Tenant namespace
    kubectl delete namespace tenant-<tenant-name>
    Example
    kubectl delete namespace primary-dev
    kubectl delete namespace tenant-primary-dev

Validate

Verify the Tenant no longer exists.

kubectl get tenants
Example output
NAME      DISPLAYNAME      READY   SETTINGS   NAMESPACE   PROJECTS   AGE
default Default Tenant true default default 1 21d

Next Steps

After you create a Tenant, create Projects under the Tenant. Each Project inherits the Tenant Settings (if configured) and GPU quotas. PaletteAI grants Tenant admin groups admin permissions in all Project namespaces.

If you encounter issues when creating or managing Tenants, refer to Troubleshooting Tenants.