Docs

Multi-Tenancy and Team Self-Service

How gateway groups, roles, permission boundaries and labels combine so application teams can ship API configuration without being able to break production.

The question this page answers is the one a platform team asks after the gateway is running: how do I let application teams configure their own APIs without giving them the ability to take down someone else's?

API7 Gateway gives you four independent mechanisms. None of them is a tenancy model on its own; the model is how you combine them. This page is the synthesis — each mechanism's own page has the reference detail.

The four mechanisms

MechanismWhat it isolatesWhat it does not do
Gateway groupsRuntime. A group has its own data planes, its own configuration and its own certificates. Configuration in one group cannot affect another.Does not restrict who may change it. Any user with the right role can configure any group.
Roles and permission policiesWho may perform which action on which resource.Grants are additive. A second role can widen access.
Permission boundariesThe ceiling on a user's permissions, whatever roles they later acquire.Not a grant. A boundary alone gives no access.
LabelsOwnership metadata on resources, and the scope of a declarative sync.Not a security control. A label does not stop anyone editing the resource.

The distinction that matters: gateway groups are the blast-radius boundary; boundaries are the authority boundary; labels are the ownership boundary. Confusing the third for the first two is the common mistake — labels organise, they do not protect.

A model that works

1. One gateway group per environment, not per team

Give each environment its own group — production, staging, and a shared sandbox. Resist a group per team: every group needs its own data planes, its own certificates and its own licensed cores, so per-team groups multiply infrastructure and operational surface without adding isolation that boundaries and labels do not already give you.

Set the environment field to non_production on everything that is not production. Its data-plane cores then count against the non-production quota instead of your production entitlement — see License Management.

Use a group per team only when a team genuinely needs runtime isolation: a different data-plane version, a different network zone, or a compliance boundary that forbids shared infrastructure.

2. Give every team a boundary before you give them a role

A boundary is the only mechanism that survives someone later being granted a broader role. Set it first, as the standing organisational constraint:

curl -k "https://localhost:7443/api/users/${USER_ID}/boundaries" -X PUT \
  -H "X-API-KEY: ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '["<policy-limiting-this-user-to-non-production>"]'

Then grant day-to-day access with roles. The boundary means a mistaken role assignment cannot reach production — the user simply gets nothing extra until the boundary is changed deliberately.

This is what lets you delegate role assignment without delegating the ability to escalate.

3. Label every resource with its owner

Adopt one label key for ownership and apply it universally:

labels:
  team: payments

This buys three things that nothing else does:

  • Scoped declarative sync. adc sync --label-selector team=payments manages only that team's resources and leaves everything else alone, so several teams can run independent pipelines against the same gateway group. See Manage Gateway Configuration with GitOps.
  • Attribution in logs. Consumer labels can be written into access logs, which is what makes per-team traffic and error reporting possible — see Include Consumer Labels in Access Logs.
  • Answering "who owns this route" during an incident, without asking in chat.

Do not use managed-by as your ownership key. ADC claims it, stamping managed-by: adc on everything it writes and overwriting whatever you set.

4. Make promotion the only path to production

Teams get write access to staging and no write access to production. Production changes arrive only by promoting a reviewed, version-controlled configuration:

adc sync -f gateway.yaml --gateway-group staging      # the team's pipeline
adc sync -f gateway.yaml --gateway-group production   # the platform pipeline, after approval

The credential that can write to production belongs to the pipeline, not to a person. Combined with boundaries, this means no individual holds production write access at all — which is usually the control an auditor is actually asking about.

What teams can safely own

Teams ownPlatform ownsWhy
Routes, services and upstreams for their own APIsGateway groups and data-plane lifecycleGroup changes affect every tenant
Their consumers and credentialsGlobal rulesA global rule applies to all traffic in the group
Per-route plugins: auth, rate limits, transformationsCertificates and TLSShared listener surface
Their own declarative file and pipelineRoles, boundaries, licensingDelegating these delegates escalation

Global rules deserve emphasis. They apply to every request in a gateway group, so a team that can write them can affect every other team — and a declarative sync that omits them deletes them, including the prometheus rule that produces your traffic metrics. Keep global rules in the platform team's own pipeline and out of every team-scoped file.

Blast radius

What the worst plausible mistake reaches, if the model above is in place:

MistakeReach
A team breaks its own route configurationTheir own APIs, in the group they can write to
A team's pipeline syncs a file missing half its resourcesTheir own labelled resources only, if the pipeline uses --label-selector
A team's pipeline omits global_rulesThe whole gateway group's global rules, because label scoping does not cover them. This is the reason global rules stay with the platform team
A user is given an over-broad roleNothing, while their boundary holds
A team exhausts a shared rate-limit dictionaryOther tenants in the same group — dictionaries are per data plane, not per tenant

That last row is the limit of the model: gateway groups isolate configuration, not resources. Teams sharing a group share worker processes, connection pools and shared-dictionary space. A team's traffic spike is felt by its neighbours. If a workload needs resource isolation rather than configuration isolation, it needs its own gateway group and its own data planes — see Shared Memory Sizing.