> ## Documentation Index
> Fetch the complete documentation index at: https://enterprise-docs.crewai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-Organization Namespace Isolation

> Assign each organization a dedicated Kubernetes namespace

## Overview

By default, all organizations share the same Kubernetes namespace (defined by `K8S_NAMESPACE`). Multi-org namespace isolation allows each organization to use a dedicated namespace, providing stronger isolation between organizations.

This feature is optional. Organizations that do not require isolation will continue using the shared namespace as before.

<Warning>
  **Do NOT set `envVars.K8S_NAMESPACE` manually.** The chart automatically derives `K8S_NAMESPACE` from the `crewNamespace` value (default: `crewai-crews`) and injects it into all pods. If you set `K8S_NAMESPACE` manually in `envVars:`, your override takes precedence over the chart value and crew workloads will be routed to the namespace you specified — which is typically the platform namespace, not the per-org crew namespace. Remove any `envVars.K8S_NAMESPACE` from your values file.

  To change the base crews namespace, set `crewNamespace: your-crews-namespace` at the top level of your values file.
</Warning>

<Warning>
  **Fresh-install-only.** Enable `k8s_namespace_isolation` *before* provisioning your first crew. Flipping the flag on after crews already exist in the shared `K8S_NAMESPACE` orphans those workloads — the platform will route subsequent provision/update/delete operations (and the `/health/debug` Studio probe) to `<K8S_NAMESPACE>-org-<id>`, while the original pods sit untouched in the shared namespace. There is no automatic migration path. If you must enable isolation on an existing install, plan to re-provision every crew (Studio internal Assistant + Runner included) into its per-org namespace and clean up the orphaned Deployments by hand.
</Warning>

## Prerequisites

* `K8S_NAMESPACE` is automatically set by the chart from the `crewNamespace` top-level value. Do NOT set `envVars.K8S_NAMESPACE` manually — see the Warning above.
* The `k8s_namespace_isolation` Flipper feature flag is enabled globally
* **Recommended:** Enable `rbac.namespaceIsolation: true` in Helm values to automatically grant cluster-wide permissions for managing per-organization namespaces

### Enable the Feature Flag

```bash theme={null}
kubectl exec -it deploy/crewai-web -- \
  bin/rails runner "Flipper.enable(:k8s_namespace_isolation)"
```

### Enable ClusterRole for Namespace Isolation (Recommended)

The chart can automatically create the required ClusterRole and ClusterRoleBinding to grant the CrewAI Platform ServiceAccount permissions across all organization namespaces. This simplifies setup by eliminating manual RoleBinding creation for each organization.

**Add to your Helm values:**

```yaml theme={null}
rbac:
  create: true
  namespaceIsolation: true  # Creates ClusterRole and ClusterRoleBinding
```

**Then upgrade the release:**

```bash theme={null}
helm upgrade crewai-platform ./helm --values values.yaml
```

<Note>
  When `rbac.namespaceIsolation: true`, the chart creates a ClusterRole with scoped permissions (namespaces, secrets, configmaps, pods, deployments, etc.) and binds it to the CrewAI ServiceAccount. This grants cluster-wide access to manage resources in dynamically created per-organization namespaces (e.g., `crewai-org-1`, `crewai-org-2`).
</Note>

<Warning>
  Enabling `rbac.namespaceIsolation` grants cluster-wide permissions to the CrewAI Platform ServiceAccount. Ensure your organization's security policies allow ClusterRole creation before enabling this feature. If ClusterRole creation is not permitted, use the manual setup approach described below.
</Warning>

## Namespace Naming Convention

When isolation is enabled, each organization gets a dedicated namespace using the format:

```
{K8S_NAMESPACE}-org-{organization_id}
```

For example, if `K8S_NAMESPACE=crewai` and the organization ID is `4`, the namespace will be `crewai-org-4`.

You can find the organization ID and the expected namespace name on the organization's admin page in the warning banner.

## Setting Up a New Organization Namespace

### Automatic Setup (Recommended)

If you enabled `rbac.namespaceIsolation: true` in your Helm values, the platform will automatically create organization namespaces and manage permissions when you deploy crews to a new organization. You only need to ensure the registry secret is copied to new namespaces.

**For each new organization namespace:**

```bash theme={null}
# Copy the registry secret to the new namespace
kubectl get secret docker-registry -n {K8S_NAMESPACE} -o yaml \
  | sed 's/namespace: .*/namespace: {K8S_NAMESPACE}-org-{id}/' \
  | kubectl apply -f -
```

<Note>
  The platform automatically creates the namespace (`{K8S_NAMESPACE}-org-{id}`) when a crew is deployed to the organization. No manual namespace creation or RoleBinding setup is required when using `rbac.namespaceIsolation: true`.
</Note>

### Manual Setup (Alternative)

If you cannot enable `rbac.namespaceIsolation` due to security policies that prohibit ClusterRole creation, manually set up each organization namespace:

#### 1. Create the Namespace

```bash theme={null}
kubectl create namespace {K8S_NAMESPACE}-org-{id}
```

#### 2. Grant the Service Account Access

The platform's service account needs permissions to manage resources in the new namespace:

```bash theme={null}
kubectl create rolebinding crewai-sa-edit \
  --clusterrole=edit \
  --serviceaccount={K8S_NAMESPACE}:crewai-sa \
  --namespace={K8S_NAMESPACE}-org-{id}
```

<Note>
  Replace `{K8S_NAMESPACE}` with your configured namespace (e.g., `crewai`) and `{id}` with the organization ID shown on the organization's admin page.
</Note>

#### 3. Copy the Registry Secret

The new namespace needs access to the container image registry to pull automation images:

```bash theme={null}
kubectl get secret docker-registry -n {K8S_NAMESPACE} -o yaml \
  | sed 's/namespace: .*/namespace: {K8S_NAMESPACE}-org-{id}/' \
  | kubectl apply -f -
```

## Example

### Automatic Setup Example

Setting up namespace isolation for organization 4 with `K8S_NAMESPACE=crewai` and `rbac.namespaceIsolation: true`:

```bash theme={null}
# 1. Enable ClusterRole in Helm values (one-time setup)
# values.yaml:
#   rbac:
#     create: true
#     namespaceIsolation: true

# 2. Upgrade Helm release (one-time setup)
helm upgrade crewai-platform ./helm --values values.yaml

# 3. Enable the feature flag (one-time setup)
kubectl exec -it deploy/crewai-web -- \
  bin/rails runner "Flipper.enable(:k8s_namespace_isolation)"

# 4. Copy registry secret when organization namespace is created
# (The platform creates crewai-org-4 automatically on first crew deployment)
kubectl get secret docker-registry -n crewai -o yaml \
  | sed 's/namespace: .*/namespace: crewai-org-4/' \
  | kubectl apply -f -
```

### Manual Setup Example

Setting up namespace isolation for organization 4 with `K8S_NAMESPACE=crewai` without `rbac.namespaceIsolation`:

```bash theme={null}
# Create the namespace
kubectl create namespace crewai-org-4

# Grant service account access
kubectl create rolebinding crewai-sa-edit \
  --clusterrole=edit \
  --serviceaccount=crewai:crewai-sa \
  --namespace=crewai-org-4

# Copy the registry secret
kubectl get secret docker-registry -n crewai -o yaml \
  | sed 's/namespace: .*/namespace: crewai-org-4/' \
  | kubectl apply -f -
```

## Verification

After setting up the namespace, deploy an automation to the organization. The deployment should target the new namespace. You can verify with:

```bash theme={null}
# Check pods in the org namespace
kubectl get pods -n {K8S_NAMESPACE}-org-{id}

# Check pods by org label
kubectl get pods -l org-id=org-{id} --all-namespaces
```

The warning banner on the organization's admin page will disappear after the first successful deployment.

## Support Bundle Configuration

When using multi-organization namespace isolation, configure support bundles to collect logs from all organization namespaces for comprehensive troubleshooting.

**Add to your Helm values:**

```yaml theme={null}
supportBundle:
  crewLogNamespaces:
    - "crewai-org-1"
    - "crewai-org-2"
    - "crewai-org-3"
```

This ensures support bundles capture crew workload logs (web, worker, redis pods) and events from each organization namespace. See [Support Bundle Configuration](/reference/chart-values/global#supportbundle-crewlognamespaces) for details.

## Troubleshooting

### Deployment Fails with Forbidden Error

The service account does not have permissions in the org namespace.

**If using `rbac.namespaceIsolation: true`:** Verify the ClusterRoleBinding exists:

```bash theme={null}
kubectl get clusterrolebinding crewai-namespace-isolation
```

**If using manual setup:** Verify the namespace-specific RoleBinding exists:

```bash theme={null}
kubectl get rolebinding -n {K8S_NAMESPACE}-org-{id}
```

### Secrets Forbidden Error

If you see an error like:

```
secrets "docker-registry" is forbidden: User "system:serviceaccount:..." cannot get resource "secrets" in the namespace "...-org-{id}"
```

This means the namespace and rolebinding were not set up for this organization. Follow the [setup steps](#setting-up-a-new-organization-namespace) to create the namespace, grant the service account access, and copy the registry secret.

### Image Pull Errors

The registry secret is missing from the org namespace. Re-run the secret copy step:

```bash theme={null}
kubectl get secret docker-registry -n {K8S_NAMESPACE} -o yaml \
  | sed 's/namespace: .*/namespace: {K8S_NAMESPACE}-org-{id}/' \
  | kubectl apply -f -
```

## Required Post-Install Steps

Namespace isolation does not activate automatically after `helm install`. After installing with `rbac.namespaceIsolation: true`, complete these steps:

1. Enable the feature flag:

```bash theme={null}
kubectl exec -it deploy/crewai-web -- bin/rails runner "Flipper.enable(:k8s_namespace_isolation)"
```

2. For each organization namespace when it is first created, copy the registry secret:

```bash theme={null}
kubectl get secret docker-registry -n {K8S_NAMESPACE} -o yaml \
  | sed 's/namespace: .*/namespace: {K8S_NAMESPACE}-org-{id}/' \
  | kubectl apply -f -
```

Without step 1, `rbac.namespaceIsolation: true` creates RBAC objects but namespace isolation routing remains inactive.
