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

> ## Agent Instructions
> Pages under /latest/ document the current release. Paths that begin with a version number, for example /10.0/, are frozen snapshots of superseded releases kept for reference only — never present their instructions as current. If the reader's version is unknown, answer from /latest/ and say which version the answer describes.
> xorlab is deployed on-premises, hybrid, or as a cloud service, and integrates with either Microsoft 365 or on-premises mail infrastructure. Configuration steps often differ between these. State which deployment and integration mode an instruction applies to instead of presenting one as universal.
> Distinguish inline mode from monitoring mode when describing anything that acts on email. Monitoring mode observes a copy and cannot block or quarantine; inline mode routes mail through xorlab and can.
> Write the product name as lowercase 'xorlab'. Use the documented component names: xorlab Control Center (XCC), xorlab MTA, xorlab Sandbox (DANA), xorlab Natural Language Understanding (NLU). After the first mention, use the short forms XCC, MTA, Sandbox, and NLU. Do not use DANA as a standalone name for the Sandbox, but keep it where it is a literal string in configuration keys, container names, and hostnames.
> Do not invent configuration keys, rule parameters, list names, log properties, or API fields. If a value is not present in this documentation, say that it is not documented rather than guessing.

# Multi-Tenancy Configuration

On this page, we explain how to configure your xorlab platform to protect the domains of multiple tenants. It includes step-by-step instructions on how to add new tenants, configure various topologies, and ensure proper routing.

## Deployment Topologies

The xorlab Security Platform supports several deployment options. If you're unsure which to choose, we recommend starting with the `Default Chain`.

* [Default Chain](/9.0/multi-tenancy-configuration#default-chain-topology): XSP sits between the front MTA and the internal mailbox server. Emails between tenants take a shorter route within XSP, bypassing external systems. Ideal for setups with multiple tenants.
* [Microsoft 365](/9.0/multi-tenancy-configuration#m365-topology): Connectors route emails from M365 to XSP for analysis. Non-quarantined emails are returned via connectors to M365, which is responsible for final delivery.
* [Star](/9.0/multi-tenancy-configuration#star-topology): A central gateway (typically the front MTA) manages all email traffic, with emails passing through the gateway twice—first for analysis, then for final delivery.
* [Front MTA](/9.0/multi-tenancy-configuration#front-mta-topology): XSP functions as the front MTA, analyzing incoming messages and routing them to tenants. Outgoing tenant emails are processed by XSP before final delivery.
* [Full Chain](/9.0/multi-tenancy-configuration#full-chain-topology): XSP sits between the front MTA and the internal mailbox server. Emails between tenants go through XSP to the front MTA, following standard email routing.

For all topologies, whenever you add a new tenant in `guarded_tenants.yml` and publish the changes, xorlab will add a unique `uid` to that tenant. The `uid` does not need to be set by hand, and it will be left out in config examples below.

### Default Chain Topology

#### Guarded Tenants

<Accordion title="Expand to read the instructions.">
  `name`: Define the name of the tenant. Also visible in the GUI.

  `bccFallbackDomain`: Set this attribute to the primary domain of the tenant.

  `domains`: Specify the guarded domains of the tenant including the `bccFallbackDomain`.

  `tenantSelector`: Reference the `headerName` and `headerValue` of a header that will be used to identify the tenant.
</Accordion>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
# Config example for Default Chain Topology

## The 'default' config set is implicitly referenced by each tenant unless overwritten by a tenant.
configSets:
  default:
    tenantSelector: 
    - headerName:  "x-xor-trusted-client"
      headerValue: "trusted"

### Begin Tenant Config
tenants:
  - name: tenantA
    authenticationBackend: usernamePassword
    bccFallbackDomain: tenantA.com
    domains:
      - tenantA.com
      - tenantA.ch

  - name: tenantB
    authenticationBackend: SamlAD
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
      - tenant-B.net
```

#### Transport Map

<Accordion title="Expand to read the instructions.">
  The transport map is used to ensure that incoming emails are delivered to the appropriate next-hop destination (such as the front MTA) based on the recipient’s domain.

  * Define a rule for each guarded tenant domain, specifying the correct next-hop destination.
  * Use the `smtp` command to specify the SMTP endpoint (e.g., the front MTA).
  * The last line should be a default route to handle outgoing email traffic.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/transport" theme={null}
# Route incoming emails to the SMTP endpoints of each tenant domains
tenantA.ch      smtp:<inbound-next-hop>
tenantA.com     smtp:<inbound-next-hop>
tenantB.com     smtp:<inbound-next-hop>
tenantB.net     smtp:<inbound-next-hop>

# Define a default route for all outgoing emails
*               smtp:<outbound-next-hop>
```

#### Client Access

<Accordion title="Expand to read the instructions.">
  Client access rules are used to ensure that incoming emails are correctly routed based on the IP addresses of the front MTA or other mail transfer systems.

  * Specify the IP address of the SMTP client, typically the Front MTA or Exchange Server, responsible for routing emails to XSP.
  * Use the `permit` command to allow these connections to access XSP and forward emails.
</Accordion>

```yaml title="Expert Editor: activeguard/mta/startup_cfg/postfix_custom/client_access" theme={null}
## You can add one line per IP or specify ranges. Only the CIDR ranges 24, 16, and 8 are supported by using the following format:
# 1.2.3.4   permit
# 1.2.3     permit
# 1.2       permit
# 1         permit

## Add the IP address of each front MTA that receives emails and forward them to XSP
<ip-address1>   permit
<ip-address2>   permit
```

#### Client Access Tenant

<Accordion title="Expand to read the instructions.">
  This file defines which headers XSP should add to incoming and outgoing emails.

  * Structure: `<CIDRblock>    PREPEND  <headerName>: <headerValue>`
  * The `<CIDRblock>` specifies the IP range of the SMTP client responsible for routing emails to XSP
  * Add `/32` to restrict to a single IP address.
  * The `<headerName>` and `<headerValue>` refers to the `tenantSelector` or the `tenantSelectors`.
  * The file should always end with an `0.0.0.0/0` entry to prevent header spoofing.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/client_access_tenant" theme={null}
# Allow-list specific SMTP clients for Multi-tenant deployments

198.51.100.1/32       PREPEND x-xor-trusted-client: trusted
192.0.2.1/32          PREPEND x-xor-trusted-client: trusted
203.0.113.1/32        PREPEND x-xor-trusted-client: trusted

# Always include a 0.0.0.0/0 entry in the end of this file to sanitize the headerValue
0.0.0.0/0             PREPEND x-xor-trusted-client: unknown
```

### M365 Topology

#### Guarded Tenants

<Accordion title="Expand to read the instructions.">
  `bccFallbackDomain`: Set this attribute to the primary domain of the tenant.

  `domains`: Specify the guarded domains of the tenant including the `bccFallbackDomain`.

  `tenantSelectors`: Refer to the x-originatororg header of each accepted domain in your Microsoft Exchange environment.
</Accordion>

<Accordion title="Recommendation: List every 'Accepted Domain' as tenantSelector.">
  * Go to admin.cloud.microsoft/exchange#/accepteddomains
  * For **each domain listed**, define a seperate `selector` in `guarded_tenants.yml`
  * Use the following format for each selector:
    * HeaderName: `"x-originatororg"`
    * Header value: The domain listed in the "Accepted Domain" column, between double quotation marks.
</Accordion>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
tenants:
  - name: tenantA
    bccFallbackDomain: tenantA.com
    domains:
     - tenantA.com
     - tenantA.ch
    tenantSelectors:
      - selector:
        - headerName:  "x-originatororg"
          headerValue: "tenanta.com"
      - selector:
        - headerName:  "x-originatororg"
          headerValue: "tenantaaa.onmicrosoft.com"

  - name: tenantB
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
      - tenantB.net
    tenantSelectors:
      - selector:
        - headerName:  "x-originatororg"
          headerValue: "tenantb.com"
      - selector:
        - headerName:  "x-originatororg"
          headerValue: "tenantbbb.onmicrosoft.com"

```

#### Header Checks

<Accordion title="Expand to read the instructions.">
  This config file contains the routing rules of your mail flow. It refers to the headers specified for each tenant in the previous step.

  * `x-originatororg` should correspond to the `headerName` of the `tenantSelectors` defined in `guarded_tenants`.
  * `tenantA.com` and `tenantB.com` should correspond to the `headerValue` of the `tenantSelectors` defined in `guarded_tenants`.
  * `tenant` `a/b` `-com.mail.protection.outlook.com` should correspond to the SMTP endpoint (MX server) of the `headerValue` of the `tenantSelectors` defined in `guarded_tenants`.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/header_checks_core" theme={null}
# Header-based routing
# Define mail routes as specified in the shared/guarded_tenants.yml 

/^x-originatororg: tenantA.com/                 FILTER smtp:tenanta-com.mail.protection.outlook.com
/^x-originatororg: tenantaaa.onmicrosoft.com/   FILTER smtp:tenantaaa.mail.protection.outlook.com
/^x-originatororg: tenantB.com/                 FILTER smtp:tenantb-com.mail.protection.outlook.com
/^x-originatororg: tenantbbb.onmicrosoft.com    FILTER smtp:tenantbbb-com.mail.protection.outlook.com
```

### Star Topology

#### Guarded Tenants

<Accordion title="Expand to read the instructions.">
  `name`: Define the name of the tenant. Also visible in the GUI.

  `bccFallbackDomain`: Set this attribute to the primary domain of the tenant.

  `domains`: Specify the guarded domains of the tenant including the `bccFallbackDomain`.

  `tenantSelector`: Identifies the header that will be set when the email is coming from the trusted infrastructure.
</Accordion>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
configSets:
  default:
    tenantSelector: 
    - headerName:  "x-xor-trusted-client"
      headerValue: "trusted"

tenants:
  - name: tenantA
    bccFallbackDomain: tenantA.com
    domains:
      - tenantA.com
      - tenantA.ch

  - name: tenantB
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
      - tenantB.net
```

#### Transport Rules

<Accordion title="Expand to read the instructions.">
  The transport rules for a multi-tenancy star integration only require one route that redirects all traffic to the central email gateway.

  * The `*` wildcard matches all traffic.
  * `<email-next-hop>` should contain the domain of the central email gateway.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/transport" theme={null}
# Make sure a default route is defined.
*               smtp:<email-next-hop>
```

#### Client Access

<Accordion title="Expand to read the instructions.">
  Client access rules are used to ensure that incoming emails are correctly routed based on the IP addresses of the front MTA or other mail transfer systems.

  * Specify the IP address of central gateway that will send emails to xorlab.
  * Use the `permit` command to allow these connections to access XSP and forward emails.
</Accordion>

```yaml title="Expert Editor: activeguard/mta/startup_cfg/postfix_custom/client_access" theme={null}
## You can add one line per IP or specify ranges. Only the CIDR ranges 24, 16, and 8 are supported by using the following format:
# 1.2.3.4   permit
# 1.2.3     permit
# 1.2       permit
# 1         permit

## Add the IP address of each front MTA that will send emails to xorlab
<ip-address1>   permit
<ip-address2>   permit
```

### Front MTA Topology

#### Guarded Tenants

<Accordion title="Expand to read the instructions.">
  `name`: Define the name of the tenant. Also visible in the GUI.

  `bccFallbackDomain`: Set this attribute to the primary domain of the tenant.

  `domains`: Specify the guarded domains of the tenant including the `bccFallbackDomain`.

  `tenantSelector`: Reference the `headerName` and `headerValue` of a header that will be added by XSP.

  > The headers referenced in `tenantSelector` need to match the entries in the `client_access_tenant` configuration.
</Accordion>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
## The 'default' config set is implicitly referenced by each tenant unless overwritten by a tenant.
configSets:
  default:
    tenantSelector: 
    - headerName:  "x-xor-trusted-client"
      headerValue: "trusted"

tenants:
  - name: tenantA
    bccFallbackDomain: tenantA.com
    domains:
      - tenantA.com
      - tenantA.ch

  - name: tenantB
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
      - tenant-B.net

```

#### Client Access

<Accordion title="Expand to read the instructions.">
  Client access rules are used to ensure that incoming emails are correctly routed based on the IP addresses of the front MTA or other mail transfer systems.

  * Specify the IP address of the allowed SMTP client, typically the Exchange server.
  * Use the `permit` command to allow these connections to access XSP and forward emails.
</Accordion>

```yaml title="Expert Editor: activeguard/mta/startup_cfg/postfix_custom/client_access" theme={null}
## You can add one line per IP or specify ranges. Only the CIDR ranges 24, 16, and 8 are supported by using the following format:
# 1.2.3.4   permit
# 1.2.3     permit
# 1.2       permit
# 1         permit

## Add the IP address of each server that will send emails to xorlab
<ip-address1>   permit
<ip-address2>   permit
```

#### Client Access Tenant

<Accordion title="Expand to read the instructions.">
  This file defines which headers XSP should add to incoming and outgoing emails.

  * Structure: `<CIDRblock>    PREPEND  <headerName>: <headerValue>`
  * The `<CIDRblock>` specifies the IP range of each tenant's mail server
  * Add `/32` to restrict to a single IP address.
  * The `<headerName>` and `<headerValue>` refer to the `tenantSelector` or the `tenantSelectors`.
  * The file should always end with an `0.0.0.0/0` entry to prevent header spoofing.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/client_access_tenant" theme={null}
# Allow-list specific SMTP clients for Multi-tenant deployments

198.51.100.1/32       PREPEND x-xor-trusted-client: trusted
192.0.2.1/32          PREPEND x-xor-trusted-client: trusted
203.0.113.1/32        PREPEND x-xor-trusted-client: trusted

# Always include a 0.0.0.0/0 entry in the end of this file to sanitize the headerValue
0.0.0.0/0             PREPEND x-xor-trusted-client: unknown
```

#### Transport Map

<Accordion title="Expand to read the instructions.">
  The transport map is used to ensure that incoming emails are delivered to the appropriate next-hop destination (such as the front MTA) based on the recipient’s domain.

  * Define a rule for each guarded tenant domain, specifying the correct next-hop destination.
  * Use the `smtp` command to specify the SMTP endpoint (e.g., the front MTA).
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/transport" theme={null}
# Route incoming emails to the SMTP endpoints of each tenant domains
tenantA.ch      smtp:<inbound-next-hop>
tenantA.com     smtp:<inbound-next-hop>
tenantB.com     smtp:<inbound-next-hop>
tenantB.net     smtp:<inbound-next-hop>
```

### Full Chain Topology

In the Full Chain Topology xorlab sits between a front MTA and the Exchange server. The difference to the default chain is that inter-tenant emails are routed to the front MTA and back.
Important: the front MTA needs to strip away all x-xor-trusted-client headers from all emails to ensure proper routing.

#### Guarded Tenants

<Accordion title="Expand to read the instructions.">
  `bccFallbackDomain`: Set this attribute to the primary domain of the tenant.

  `domains`: Specify the guarded domains of the tenant including the `bccFallbackDomain`.

  `tenantSelector`: If needed, reference a unique trusted `headerName` and `headerValue` for specific tenants.

  `interTenantMessageSplitting`: Controls whether xorlab splits emails sent between tenants into separate incoming and outgoing messages. By default, this attribute is set to `true` but for the `Full Chain Topology` you are required to set it to `false`.

  `configSets` - `tenantSelector`: Reference the `headerName` and `headerValue` of a header that will be added by XSP.

  > The headers referenced in `tenantSelector` and `tenantSelectors` need to match the entries in the `client_access_tenant` configuration.
</Accordion>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
## The 'default' config set is implicitly referenced by each tenant unless overwritten by a tenant
configSets:
  default:
    # This is required when inter-tenant emails are passing through xorlab twice
    interTenantMessageSplitting: false
    tenantSelector: 
    - headerName:  "x-xor-trusted-client"
      headerValue: "trusted"

tenants:
  - name: tenantA
    bccFallbackDomain: tenantA.com
    domains:
      - tenantA.com
      - tenantA.de

  - name: tenantB
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
      - tenantB.net
        
```

#### Header Checks

<Accordion title="Expand to read the instructions.">
  This config file defines how messages are routed based on the headers assigned in guarded\_tenants.yml.

  * Structure: `/^<headerName>:<headerValue>/  FILTER smtp:[<SMTP endpoint>]`
  * The `<SMTP endpoint>` should include the domain of either the frontMta or the guarded domain's mail server.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/header_checks_core" theme={null}
# Header-based routing

/^x-xor-trusted-client: unknown/   FILTER smtp:<inbound-next-hop>
/^x-xor-trusted-client: trusted/   FILTER smtp:<outbound-next-hop>

```

#### Client Access

<Accordion title="Expand to read the instructions.">
  Client access rules are used to ensure that incoming emails are correctly routed based on the IP addresses of the front MTA or other mail transfer systems.

  * Specify the IP address of the SMTP client, typically the Front MTA or Exchange Server, responsible for routing emails to XSP.
  * Use the `permit` command to allow these connections to access XSP and forward emails.
</Accordion>

```yaml title="Expert Editor: activeguard/mta/startup_cfg/postfix_custom/client_access" theme={null}
## You can add one line per IP or specify ranges. Only the CIDR ranges 24, 16, and 8 are supported by using the following format:
# 1.2.3.4   permit
# 1.2.3     permit
# 1.2       permit
# 1         permit

## Add the IP address of each front MTA that receives emails and forward them to XSP
<ip-address1>   permit
<ip-address2>   permit
```

#### Client Access Tenant

<Accordion title="Expand to read the instructions.">
  This file defines which headers XSP should add to incoming and outgoing emails.

  * Structure: `<CIDRblock>    PREPEND  <headerName>: <headerValue>`
  * The `<CIDRblock>` specifies the IP range of the **Exchange Server**.
  * Add `/32` to restrict to a single IP address.
  * The `<headerName>` and `<headerValue>` refers to the `tenantSelector` or the `tenantSelectors`.
  * The file should always end with an `0.0.0.0/0` entry to prevent header spoofing.
</Accordion>

```yaml title="Expert Editor: /activeguard/mta/startup_cfg/postfix_custom/client_access_tenant" theme={null}
# Set the Exchange servers as trusted. Do not add the front MTA as trusted.
198.51.100.1/32       PREPEND x-xor-trusted-client: trusted
192.0.2.1/32          PREPEND x-xor-trusted-client: trusted

# Always include a 0.0.0.0/0 entry in the end of this file to prevent spoofing of the headerValue
0.0.0.0/0             PREPEND x-xor-trusted-client: unknown
```

## Tenant Selector

Tenant selectors are used to assign emails to the correct tenant by evaluating specific mail headers.

There are two configuration options:

* `tenantSelector`: Defines a single set of headers that must all match to assign the message to a tenant (AND logic).

* `tenantSelectors`: One property that enables you to define more then one `selector`. A `selector` can reference one or more header sets. If multiple header sets are referenced, all need to match (AND-logic). The message matches a tenant if at least one `Selector` matches (OR logic).

Both options can be used for a specific tenant, as well as default within `configSets`.

<Warning>
  **Avoid External Header Manipulation**

  Only use sanitized and trusted mail headers for tenant identification. Never rely on headers that could be set or modified by external senders.
</Warning>

```yaml title="Expert Editor: /activeguard/shared/guarded_tenants.yml" theme={null}
## The 'default' config set is implicitly referenced by each tenant unless overwritten by a tenant.
## In this example, it applies to tenant C and D.
configSets:
  default:
    tenantSelector: 
    - headerName:  "x-xor-trusted-client"
      headerValue: "trustedMailRoute"

tenants:
  - name: tenantA
    bccFallbackDomain: tenantA.com
    domains:
      - tenantA.com
      # Assigned to tenantA only if both headers match (AND logic)
    tenantSelector:
      - headerName:  "x-xor-trusted-client"
        headerValue: "specialRoute"
      - headerName:  "another-trusted-header"
        headerValue: "i-know-this-is-tenantA"

  - name: tenantB
    bccFallbackDomain: tenantB.com
    domains:
      - tenantB.com
    
    # Assigned to tenantB if either of these selectors match (OR logic between selectors)
    tenantSelectors:
      - selector:
        - headerName:  "x-xor-trusted-client"
          headerValue: "specialRoute2"
      - selector:
        - headerName:  "x-xor-trusted-client"
          headerValue: "specialRoute3_part1"
        - headerName:  "another-trusted-header"
          headerValue: "specialRoute3_part2"

  - name: tenantC
    bccFallbackDomain: tenantC.com
    domains:
      - tenantC.com

  - name: tenantD
    bccFallbackDomain: tenantD.com
    domains:
      - tenantD.com

```

### Tenant Selection Logic

When processing an email, the system determines which Tenant it belongs to based on the following rules.

**Step 1: Single Match:** If exactly one Tenant Selector matches the email, the email is assigned to that Tenant.

**Step 2: No Match:** If no Tenant Selector matches the email, choose the Tenant based on the recipient addresses. If no Tenant can be identified, assign the email to the special `UNKNOWN` Tenant.

**Step 3: Multiple Matches:** If multiple Tenant Selectors match, the selection is resolved using the logic below in the specified order.

1. Assign Tenant based on sender address.

   1. Prefer a match on the sender’s envelope-from address.
   2. If no match, check the header-from address.

2. Assign Tenant based on recipient addresses. Choose only from the matched Tenant Selectors.

3. If no Tenant can be identified, assign the email to the special `UNKNOWN` Tenant.

<Note>
  **Recipient address matching**

  For step 2 and 3: If the Tenant is chosen based on the recipients, and the recipients belong to different Tenants, the email is split for each Tenant. Each split email is assigned a separate GGRID and will be shown as separate email in the UI.
</Note>

After the tenant is selected, the email is processed. Because the email can have multiple different recipients, even from different tenants, xorlab applies the following logic when delivering emails:

* For all recipients of the email that do not match any tenants (outgoing email) or match the tenant of the email itsef (internal or incoming email), deliver the email.
* For all recipients of the email that match a different tenant than the one of the email itself (inter-tenant email):

  * If `interTenantMessageSplitting` is active, re-process the email again with a separate `GGRID` and assigned to the recipient tenant. No email delivery at this point.
  * Else deliver the email. We expect the email to pass again through xorlab.

## Config Sets

`configSets` allow you to define some configuration that can be re-used for multiple tenants.

A config set supports the following parameters. All those parameters can also be set directly on a tenant.

```yaml theme={null}
configSets:
  default:
    interTenantMessageSplitting: true
    tenantSelector: {}
    tenantSelectors: []
    autoLoginLink: {}
    quarantine: {}
    dataRetention: {}
    emailTemplateStyle: default
    #authenticationBackend: # empty by default

```

Checkout the [guarded\_tenants.yml](/9.0/guarded_tenants_yml) for more attribute-specific documentation.

<Note>
  You can overwrite single parameters of the `default` set without having to specify all other parameters.
</Note>

You can create new config sets and reference them in some tenants. The `default` set is always applied to all tenants with the least precedence.

```yaml theme={null}
configSets:
  allowPhishingRequest:
    quarantine:
      quarantines:
          - name: Phishing
            canRelease: true

tenants:
    name: xorlab
    ## Applied config sets, notice that later occurrences will override earlier config set occurrences.
    ## Further, the "default" set is implicitly referenced with least precedence.
    configSets:
        - allowPhishingRequest

```
