Tenants & Bandwidth
A tenant is a named owner you attach resources to — networks, addresses, API keys and a bandwidth allowance. If you run workloads for several customers, teams or environments on the same hardware, tenants are how you keep them apart and how you cap what each one can consume.
If everything on your nodes belongs to you, you can ignore tenants entirely. Nothing requires one.
What a tenant actually separates
A tenant is an ownership label plus four things that are genuinely enforced:
| What you get | What it does |
|---|---|
| Ownership of resources | Networks and addresses are recorded against the tenant, so you can see and delete everything one customer owns as a unit. |
| Separation from other tenants | Traffic between the private networks of two different tenants is refused in the packet path — no firewall rule needed. Virtual machines and containers that Stratum runs for a tenant are also separated on the shared segment itself, at their own port. |
| A scoped API key | A key that can act only for that tenant — it cannot read or change another tenant's resources. |
| A bandwidth cap | A real rate limit, applied in the traffic path. See below. |
The separation applies to networks created for a tenant — network create --tenant <id>. It is put back in place when the node restarts, and it cannot be routed around, because private addresses are not reachable from outside either.
Separation on the shared segment
Every tenant network on a node shares the same workload bridge. Refusing routed traffic between tenants is therefore not enough on its own: two workloads on one bridge can also talk to each other directly, frame to frame, without anything being routed. Stratum closes that path for the workloads it runs itself — its virtual machines and the containers you attach with container attach:
- Nothing one tenant's workload sends reaches another tenant's workload directly — not unicast, not broadcast, not multicast, whatever the protocol: IPv4, IPv6 (link-local addresses included), ARP, neighbour discovery, DHCP, or anything else carried in a frame.
- A tenant's workload cannot look up another tenant's addresses. An ARP request for an address in another tenant's network — including that network's gateway on the node — is dropped where it enters.
- The sender is identified by the port its traffic came in on, which a guest cannot fake. A workload that forges another tenant's hardware address is still recognised as itself.
- Same-tenant traffic, the node itself and the uplink are unaffected. Workloads of one tenant reach each other as before, the node reaches every workload (so DHCP, DNS and the gateway keep working), and traffic to and from the outside is handled exactly as before.
- It is in place before the workload first runs. A tenant's virtual machine or container is not started (or attached) on a port that cannot be separated; you get an error saying why. The node checks every 30 seconds that the separation is still in place and restores it, with a security event, if something removed it outside Stratum. It stays in force while the agent restarts, on every supported kernel. After an upgrade it is put back in place as the new version starts, so there is a brief moment during the upgrade without it.
- Only tenant workloads are held apart. A virtual machine or container without a tenant, and anything you plug into the workload bridge yourself, is not a tenant's: it is not separated at its port, and what it sends is not held back from tenant workloads either. Put every customer's workloads under a tenant.
Three things the separation deliberately does not cover:
- Two networks of the same tenant can reach each other. Whether they should is a firewall decision — set the default action to deny and write the allows you want. See Firewall.
- Networks created without a tenant are not separated from anything.
- Public addresses stay reachable, by design. Two tenants that each hold a public address can reach each other on it, exactly as anyone on the internet could — when both are on the same node, that traffic is simply turned around inside the node. See Gateway NAT.
A tenant's virtual machine can also hold one of the public addresses your provider routes to you (see Public Addresses). That address counts as the tenant's: it cannot be used to reach another tenant's private networks, it is covered by the tenant's bandwidth cap and suspension, and it counts towards the tenant's addresses. The cap and the suspension stay with the tenant: once the machine is deleted they no longer apply to the address, and the next machine to take it does not inherit them. Like any public address, it stays reachable from anywhere.
A workload sends only from its own addresses
A tenant's virtual machine or container may only send IPv4 traffic from the addresses Stratum gave it: the address it holds on its network, or its public address. A packet from any other address — another address of its network, another customer's, or one it made up — is dropped at its port, before it reaches another machine, the node or the internet. So is an ARP message announcing an address that is not the workload's own. This matters most for public addresses: providers act against servers that send traffic with forged source addresses.
What keeps working:
- Getting an address by DHCP. A DHCP request is sent before the machine has an address (from 0.0.0.0); it passes.
- Duplicate-address checks (ARP probes, which also carry no address).
- IPv6 link-local traffic, neighbour discovery included. IPv6 is not checked: the node does not give workloads IPv6 addresses yet.
- VLANs a guest builds on top of its own interface. Frames a workload tags with a VLAN number are not checked: the node routes none of them, and the separation above still keeps them away from other tenants' workloads (they reach the tenant's own machines, and anything you plugged into the workload bridge yourself). A frame whose only tag is a priority tag (VLAN 0) counts as untagged and is checked like one.
What no longer works: a second address configured by hand inside a guest, containers inside a virtual machine that are bridged onto its interface with addresses of their own, or an address that floats between two machines. Traffic from such an address is dropped. Give each machine one address and let containers inside it share that address.
As with the separation above, only tenant workloads are held to their addresses; a virtual machine or container without a tenant is not. The check is in place before the workload first runs and is restored within 30 seconds, with a security event, if something removed it outside Stratum.
Suspending a tenant
A suspended tenant's workloads send and receive nothing: not to the internet, not to other tenants, not to the node, and not to each other — whatever the number of machines, networks or addresses it has. Its virtual machines are also stopped and cannot be started until it is resumed; resuming lifts the cut-off and starts again the machines that were running. Suspension is usually driven by your billing system; see Billing Integration.
Creating and deleting tenants
sudo cenvero-str-ctl tenant create --name acme
cenvero-str-ctl tenant list
Deleting a tenant is a cascade — it removes that tenant's API keys, quota, networks and address allocations together:
sudo cenvero-str-ctl tenant delete <tenant-id>
Tenants in a cluster
In a cluster, a tenant belongs to the whole cluster: create, rename, suspend, resume, limit or delete it on any member, and every member applies the change. Deleting it also revokes its API keys on every member, and is refused while any member still holds the tenant's machines, networks or volumes, or cannot be asked. A member that cannot reach the rest of the cluster refuses tenant changes with 503 and changes nothing, because the change has to reach the cluster as a whole: make it on a member that can reach the others, or restore the network between them (see A node cut off from the others). Reading tenants keeps working everywhere. Tenant API keys themselves are made and used on one node: a key works on the node that issued it. Of a tenant's quotas, only the bandwidth cap is shared; its limits on machines, addresses, rules and volumes are set on each node, for that node.
Scoped API keys
A tenant key lets you hand out API access that is confined to one tenant, instead of sharing an operator key that can change everything.
# Mint a key (optionally labelled, optionally time-limited)
sudo cenvero-str-ctl tenant key-generate <tenant-id> --name "acme-portal" --ttl 720h
cenvero-str-ctl tenant key-list <tenant-id>
sudo cenvero-str-ctl tenant key-revoke <key-id>
The key is shown once, when it is minted. Give it a TTL if it is going into a system you do not fully control — a key that expires on its own is one less thing to remember to revoke.
If the node cannot save a change to a key, the command fails and says so; it never reports success. A key that could not be saved when it was minted is not created. A key whose revocation could not be saved stops working at once, but could work again after the agent restarts: run key-revoke again once the cause in the agent's log is fixed. The same holds for apikeys revoke and for deleting a tenant.
What a tenant key can and cannot do. A tenant key is safe to hand to the customer it belongs to:
- It can read its own tenant, its quota (caps and usage) and its billing state, and list, mint and revoke its own tenant's keys. A key it mints belongs to the same tenant and never outlives the key that minted it.
- It can see its own machines, networks and public addresses; start, stop and restart its own machines, open their consoles and reset a password through the guest agent. It signs in to the web console's customer portal, which shows exactly this. While the tenant is suspended it can still look, but not act.
- It cannot change anything you control: creating or deleting machines, networks or volumes, its quota, its bandwidth limit, suspending or resuming it, renaming it, changing its status or deleting it. Those calls are refused (
403) and need your operator token or an operator API key. A suspended customer cannot resume itself, and a capped one cannot lift its cap. - It cannot see or touch another tenant, or anything else on the node.
The tenant quota
A tenant's quota is its bandwidth cap, and that is the only resource capped. 0 means unlimited.
sudo cenvero-str-ctl tenant quota-set <tenant-id> --max-bandwidth-bps 1000000000
cenvero-str-ctl tenant quota <tenant-id>
quota-set changes only what you give it; every other quota field keeps its current value. It refuses a call with nothing to change, a negative value, and a tenant that does not exist. The API behaves the same way (PUT /api/v1/tenant/{id}/quota).
Everything else is deliberately unlimited on every plan — there is no cap on how many addresses, workloads, networks or firewall rules a tenant may have. If you need those bounded for commercial reasons, bound them in your own provisioning layer, where you can refuse the request and tell the customer why.
Your plan's speed ceiling
Above every limit you set yourself sits one you do not: your license carries the maximum speed the node may use, and it is applied to the node's uplink. The ceiling for each plan is listed on the pricing page; your own is whatever your license carries, which you can read with cenvero-str-ctl license status.
Five things worth knowing:
- It is per node, not per account. Each licensed node has its own ceiling, matching how the plans are priced.
- It is the node's total, shared across all its network cards. A licensed node behaves as though its cards have exactly that much capacity between them: a 2 Gbps license on a single 10 Gbps card passes 2 Gbps, and two cards share the same 2 Gbps — you can distribute traffic across them however you like, but the total is still 2 Gbps. Adding a card does not give you more headroom. (Your management interface is deliberately left alone — throttling the control plane would take the node out of its cluster.)
- Speeds are bits per second, the way link speed and the plans are quoted — not bytes.
- It applies on top of anything you configure. A tenant limit below the ceiling gives that tenant its limit; a tenant limit above it does not lift the node past its ceiling.
- Changing plan takes effect without a restart. The node re-reads its license periodically, so an upgrade raises the ceiling within about a minute of the new license landing.
Going over the ceiling does not fail — it throttles. Traffic above the rate is held to it, exactly as described for bandwidth limits below, so a transfer slows rather than breaking.
The ceiling behaves like any other cap here — a credit allowance refilling at the licensed rate, with burst headroom so ordinary traffic is not penalised. See what that means for TCP and UDP below.
Bandwidth limits
Bandwidth is the one resource control that is real, and it is applied on the way out of a node — egress shaping. A limit is a rate in bits per second, and 0 always means unlimited.
There are two ways to apply one, and they answer different questions.
Per tenant — "this customer gets 1 Gbps in total":
sudo cenvero-str-ctl tenant quota-set <tenant-id> --max-bandwidth-bps 1000000000
Per target — "this particular workload gets 100 Mbps", regardless of who owns it:
cenvero-str-ctl bandwidth list
sudo cenvero-str-ctl bandwidth delete <id>
A per-target limit is submitted as a JSON object describing what to limit and at what rate — see the API Reference for the field names, and CLI Reference for the command form.
Pools
A pool is a shared allowance that several targets draw from together, rather than each holding its own independent cap. Use it when a group should be limited collectively — "these five workloads share 500 Mbps between them" — instead of five separate 100 Mbps limits that cannot lend capacity to one another.
Pools are created and filled over the API (POST /api/v1/bandwidth/pools, then POST /api/v1/bandwidth/pools/members per hardware address — see the API Reference); cenvero-str-ctl bandwidth list shows them with your limits. A few rules worth knowing:
- Adding a member that is already in the pool replaces its rate rather than adding a second allocation.
- A member whose rate would take the pool past its total is refused.
- Removing a member stops shaping it — it is no longer held to its pool rate. Removing an address that is not a member is refused, and an unknown pool answers "not found".
What a limit does to traffic
This is the part to understand before you set one, because the behaviour is not what "shaping" usually implies.
A limit is a credit allowance that refills at the rate you set. Every packet spends credit equal to its size. While there is credit, traffic passes untouched. When the credit runs out, traffic over the rate is dropped — not queued and delivered late.
That distinction matters:
- TCP copes well. Loss is exactly the signal TCP uses to slow down, so a TCP transfer finds the rate and settles there. This is the normal case and it works.
- UDP does not. Nothing tells a UDP sender to slow down, so anything over the rate is simply lost. Video, voice, game traffic and metrics streams degrade rather than slow down. Size the limit for the peak these need, not the average.
Unused credit accumulates up to a ceiling, so a burst after a quiet period passes at full speed and only sustained traffic is held to the rate. A short spike is not punished.
Two more consequences worth planning around:
- The cap is enforced per node. Each node shapes the tenant's workloads that live on it to the cap — it is not a single allowance summed across your nodes. On independent nodes, set it on every node where the tenant has workloads; it applies to that node only. In a cluster the cap is set once, on any member, and every member applies it to the workloads it holds — still per node, not summed.
- It applies on the way out. Limiting what a workload can receive means limiting whoever is sending to it, which you only control if the sender is also yours.
Monthly usage quotas
Separately from rate limiting, a node can track how much a workload transfers per calendar month and act when it crosses a threshold. This is a volume cap, not a speed cap — the two are independent, and you can use either or both.
cenvero-str-ctl quota list
cenvero-str-ctl quota get <mac>
Counters reset at the start of each month. Use rate limits to control how fast a tenant can go, and monthly quotas to control how much they can move in total.
See also
- Firewall — the policy that actually separates tenants from each other.
- Networking Overview — networks, endpoints, and how a workload joins one.
- Monitoring & Observability — reading real throughput per workload.
- API Reference — tenant, quota and bandwidth endpoints.