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

# Remote Execution isolation and multi-tenancy

> Separate teams and workloads on Remote Execution, from shared workers to agents in separate clusters, regions, or clouds.

<Note>
  **Airflow 3**

  This feature is only available for Airflow 3.x Deployments.
</Note>

One Remote Execution Deployment can serve several teams or workload types. This document explains how much you can separate those workloads from each other, and which Remote Execution Agent Helm chart values control each level of separation.

## Tenants and queues

A *tenant* is one worker queue in a Deployment.

Each entry in the `workers` list of your agent `values.yaml` creates one Kubernetes Deployment of worker Pods, and each entry serves exactly one queue:

```yaml title="values.yaml" theme={null}
workers:
  - name: default-worker
    queues: default
    replicas: 1
    syncSlots: 20
```

The chart fails to install if `workers[].queues` holds more than one queue name. To add a tenant, add another entry to the `workers` list.

You define Remote Execution queues in the agent `values.yaml`. The worker queue settings in the Astro UI apply to the Astro executor and the Celery executor instead. See [Configure worker queues](/docs/astro/configure-worker-queues).

In your Dag code, send a task to a tenant with the `queue` argument:

```python theme={null}
@task(queue="team-a")
def transform_team_a_data():
    ...
```

Every Deployment starts with one tenant, which is the queue that its first worker serves. The queue name identifies the tenant, so two agents that both serve a queue named `team-a` add capacity to one tenant rather than create two tenants.

<Note>
  The number of tenants in a Deployment can affect what the Deployment costs. See [Astro pricing](https://www.astronomer.io/pricing/).
</Note>

## What a tenant isolates

You configure each worker entry on its own, so tenants in the same agent can differ in the following ways.

| Isolation dimension    | Configuration values                                                                             | What it gives each tenant                                                                                                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Code                   | `workers[].image`                                                                                | Its own image, provider packages, and Python version. Teams upgrade dependencies on their own schedule.                                                                                     |
| Hardware               | `workers[].resources`, `nodeSelector`, `affinity`, `tolerations`, `replicas`, `syncSlots`, `hpa` | Its own Pod sizes and node groups, such as a dedicated instance type or GPU nodes.                                                                                                          |
| Identity               | `workers[].serviceAccount`                                                                       | Its own Kubernetes service account. Annotate it for IRSA on AWS, Workload Identity on Google Cloud, or managed identity on Azure, so that each tenant holds only its own cloud permissions. |
| Secrets and XCom scope | `workers[].env`                                                                                  | Its own path within the shared backends, such as a separate secrets prefix or object storage prefix.                                                                                        |

## What tenants in one agent share

One agent is one Helm release. The following values apply to the whole release, and every tenant in it:

* `secretBackend`, `xcomBackend`, and `stateStoreBackend`. Tenants can point at different paths within a backend through `workers[].env`, but they can't use different backend classes.
* `dagBundleConfigList`. One Dag bundle list is parsed by one Dag processor, so every tenant in the agent sees every bundle. Astro routes a task by queue, not by bundle.
* `commonEnv`, which applies to the workers, the Dag processor, and the triggerer.
* The Dag processor, the triggerer, and the Sentinel. The agent runs one of each.
* The Kubernetes namespace, the agent token, and the image pull secret.

A tenant that needs its own backend class, its own Dag sources, or its own namespace needs its own agent. Options 3, 4, and 5 in the following section cover that.

## Isolation options

The five options run from a fully shared execution environment to complete physical separation. All five serve a single Astro Deployment, and each one builds on the option before it.

### Option 1: One tenant on one agent

One Helm release, one worker entry, one queue. All tasks run on the same worker Pods, with the same image, the same service account, and the same environment variables.

Airflow pools, priority weights, and Astro role-based access control are the only separation available. Use this option for a single team, or for pipelines that have the same dependencies, identity, and security requirements. Every Deployment starts here.

### Option 2: Several tenants on one agent

One Helm release with several worker entries, each bound to its own queue. Each tenant gets its own image, hardware profile, service account, and secrets scope:

```yaml title="values.yaml" theme={null}
workers:
  - name: team-a
    queues: team-a
    image: <your-registry>/custom-team-a:latest
    serviceAccount:
      create: true
      annotations:
        eks.amazonaws.com/role-arn: arn:aws:iam::<aws-account-id>:role/team-a-role
    env:
      - name: AIRFLOW__SECRETS__BACKEND_KWARGS
        value: '{"connections_prefix": "airflow/team-a/connections"}'
    nodeSelector:
      workload-tier: team-a

  - name: team-b
    queues: team-b
    image: <your-registry>/custom-team-b:latest
    serviceAccount:
      create: true
      annotations:
        eks.amazonaws.com/role-arn: arn:aws:iam::<aws-account-id>:role/team-b-role
    env:
      - name: AIRFLOW__SECRETS__BACKEND_KWARGS
        value: '{"connections_prefix": "airflow/team-b/connections"}'
    nodeSelector:
      workload-tier: team-b
```

Use this option for teams that need separate code, identity, hardware, and secrets scopes, but can share one Dag processor, one triggerer, and one set of backend classes.

### Option 3: Several agents in one namespace

Two or more Helm releases of the agent in the same Kubernetes namespace. Each release brings its own Dag processor, triggerer, Sentinel, and workers, so tenant groups no longer share a parsing plane and can use different backend classes and different Dag bundles.

This option has one operational requirement: create all secrets outside the chart and reference them by name. The chart creates its secrets with fixed names, so two releases in one namespace collide. Set the following values in each release:

```yaml title="values-agent-a.yaml" theme={null}
resourceNamePrefix: agent-a
createNamespace: false
namespace: <shared-namespace>
imagePullSecretName: agent-a-image-pull
agentTokenSecretName: agent-a-token
sentinelAuthSecretName: agent-a-sentinel-auth
```

Give each release a different `resourceNamePrefix` so that its Deployments, config maps, and service accounts don't collide either.

The namespace stays shared, and so does everything the namespace controls: network policies, resource quotas, RBAC bindings, and Pod security standards apply to all agents together. Use this option when policy limits you to one namespace.

### Option 4: One agent per namespace

Each agent gets its own namespace. Helm creates and manages the secrets again, and the namespace boundary adds:

* Network isolation, because network policies can restrict or deny traffic between namespaces.
* RBAC isolation, because each team can be granted access to its own namespace only. One team can't view or exec into another team's worker Pods.
* Resource governance, because resource quotas and limit ranges cap each namespace separately.
* Separate Pod security standards, so one namespace can run as `restricted` while another runs as `baseline`. See [Install Remote Execution Agents in a restricted Kubernetes namespace](/docs/astro/remote-agents-restricted-kubernetes).
* Secret isolation, because agent tokens, image pull secrets, and Sentinel authentication secrets are namespace-scoped.

Use this option when you need Kubernetes boundaries between business units, environments, or data classifications, but still want one cluster.

### Option 5: Agents in separate clusters, regions, or clouds

Each tenant group runs its own agent in its own cluster. You can register agents to one Deployment from anywhere your infrastructure runs, so a single Deployment can serve clusters in different regions, in different clouds, and in your own data center at the same time.

Nothing is shared except the Astro orchestration plane: separate execution planes, failure domains, network perimeters, and compliance boundaries. Use this option for data residency requirements, for separate development, staging, and production environments, or when an incident in one cluster must not reach another.

## Comparison of the options

|                                                         | Option 1 | Option 2   | Option 3                             | Option 4  | Option 5  |
| ------------------------------------------------------- | -------- | ---------- | ------------------------------------ | --------- | --------- |
| Code (image) isolation                                  | -        | Per tenant | Yes                                  | Yes       | Yes       |
| Hardware isolation                                      | -        | Per tenant | Yes                                  | Yes       | Yes       |
| Identity isolation                                      | -        | Per tenant | Yes                                  | Yes       | Yes       |
| Secrets and XCom scope isolation                        | -        | Per tenant | Yes                                  | Yes       | Yes       |
| Separate secrets, XCom, and state store backend classes | -        | No         | Per agent                            | Per agent | Per agent |
| Separate Dag processor and triggerer                    | -        | No         | Per agent                            | Per agent | Per agent |
| Separate Dag bundles                                    | -        | No         | Per agent                            | Per agent | Per agent |
| Namespace boundary                                      | -        | No         | No                                   | Yes       | Yes       |
| Cluster, region, or cloud separation                    | -        | No         | No                                   | No        | Yes       |
| Helm-managed secrets                                    | -        | Yes        | No, create secrets outside the chart | Yes       | Yes       |

## Related documentation

* [Configure Remote Execution Agents](/docs/astro/remote-execution-configure-agents)
* [Helm chart configuration reference](/docs/astro/remote-agents-helm-reference)
* [Configure Dag sources](/docs/astro/remote-execution-configure-dag-sources)
* [Remote Execution shared responsibility model](/docs/astro/remote-execution-shared-responsibility)
