A dedicated instance, in your own Azure.
The commercial tier is one Attestree instance per customer, in a resource group in your subscription. We deploy and upgrade it; you own every resource, every identity that can reach it, and the bill. This page is what our onboarding asks of you, said up front: what you provide, what you grant us and what that can reach, what Azure charges, and how you leave.
Where this stands: the dedicated instance is available to design partners on request. We have deployed it once, into a separate customer-zero Azure subscription and Entra tenant onboarded the way this page describes: it reached a bound console with Entra sign-in, then we took it down. That deploy ran from our own machine. The pipeline deploy, an upgrade and the broker have not been proven there yet.
What runs where.
- your traffic
- mutual TLS
- Azure management and identity
- conditional
Scroll the map sideways →
The endpoint and detonation sides are the same as Community Edition, down to the agent and the broker. Their connections, the outbound allowlist and what is deliberately absent are on the architecture page. What differs is the server side, shown here.
Ten wires, three of them Azure’s.
-
1
Endpoint agent → Ingress
HTTPS · :443 on your hostname
Exactly as in Community Edition: enrollment, the wake probe and check-in, span and inventory upload, agent updates and the winget feed. Changes still land in about a minute with no port open on the endpoint.
AUTH One-time enrollment token, then a rotating session token; desired state is signed and checked.
-
2
Operator browser → Ingress
HTTPS · :443 on your hostname
The console. Sign-in redirects to your Entra tenant (flow 7). The ingress serves HTTPS only, with an Azure-managed certificate for your own hostname.
AUTH Entra ID, limited to the operators and auditors named in your parameter file, with roles from the app roles you assign. One local break-glass admin for the day Entra sign-in breaks.
-
3
Detonation broker → TCP :8443
gRPC over mutual TLS · :8443, closed until you list your broker networks
The same broker as Community Edition. The port is closed by default: until your parameter file lists the networks your brokers connect from, no broker can reach the instance and the console will not mint a broker install command. Listed, the ingress passes the port straight to the app, which terminates the mutual TLS itself, and the subnet allows it from those networks only.
AUTH An enrollment token once, then a client certificate from the instance’s own broker CA; the broker pins the instance’s broker CA.
-
4
Container app → Postgres
Postgres wire, TLS · inside the virtual network
All operational state: catalog, fleet, identity, reconciliation and the signed audit log. The server sits on its own delegated subnet with public access disabled.
AUTH The app’s managed identity. There is no database password to store, rotate or leak.
-
5
Container app → Key Vault and storage
HTTPS over private endpoints · inside the virtual network
Signing keys, secrets and the attestation certificate in Key Vault; the attested installer bytes and the data-protection key ring in storage. Both have public network access disabled and resolve through private DNS zones.
AUTH The app’s managed identity, with Key Vault Crypto, Secrets and Certificate User on the vault and Storage Blob Data Contributor on storage, plus AcrPull on the registry.
-
6
Container app → Public internet
HTTPS · :443 outbound
The same downloads as Community Edition: winget manifests at ingest, installers when a broker detonates them, the CVE and KEV feeds, package search on demand. The template does not add an egress firewall; if you route the subnet through one, allow the hosts on the architecture page.
AUTH Pinned host set for the CVE feed, redirect screening and private-range refusal on every fetch, installer SHA-256 checked as it streams.
-
7
Container app → Your Entra tenant
OpenID Connect · login.microsoftonline.com
Signs operators in through your SSO application and reads their app roles. An optional strict mode also checks the account, its sessions and its role in Microsoft Graph, which needs two Graph read permissions you consent to.
AUTH No client secret anywhere: the app proves itself to Entra with its managed identity, as a federated credential on your SSO application.
-
8
Attestree release pipeline → Your resource group
Azure Resource Manager · management plane only
Deploys and upgrades the stack. An operator starts each deploy, GitHub refuses to run it from anything but a release tag and holds it until a named Attestree operator approves it, and the run records the image digest and revision it rolled out.
AUTH A deploy identity you create and own, federated to that pipeline, with three roles on the resource group and nothing above it. Delete it and we are cut off.
-
9
ghcr.io → Your container registry
image import by digest · during a deploy
The signed platform image is imported by digest into a registry in your resource group, and the app pulls it from there.
AUTH Before import, the deployer checks the image’s cosign signature against the exact release workflow at that version’s tag, and refuses anything else.
-
10
Endpoint winget → Vendor download host
HTTPS · :443 outbound, from the endpoint
Only for a version whose installer bytes the instance does not hold, exactly as in Community Edition.
AUTH winget refuses any file whose SHA-256 differs from the pinned one.
Same product, different server side.
| COMMUNITY EDITION | DEDICATED INSTANCE | |
|---|---|---|
| Runs on | Your Docker host | Azure Container Apps, one always-on replica |
| Front door | Host port 18080, TLS from your proxy or the Caddy overlay | Container Apps ingress, HTTPS only on 443, with a managed certificate for your hostname |
| Broker port | Host 18443 | TCP 8443, closed by default; opened only to the broker networks you list |
| Database | Postgres 18 sidecar, password from .env | Postgres Flexible Server 18 on a delegated subnet, no public access, managed-identity sign-in |
| Keys and secrets | Files on the data volume | Key Vault behind a private endpoint, with purge protection |
| Installer bytes | Data volume | Storage account behind a private endpoint, no public access |
| Image | Pulled from ghcr.io by you | Signature-checked, then imported by digest into your own registry |
| Sign-in | Local accounts, roles, TOTP | Entra ID with app roles, plus one local break-glass admin |
| Deploys and upgrades | You | Attestree, through a deploy identity you own |
| Extra egress | None | Your Entra tenant; Microsoft Graph only with strict role checks on |
Seven things, before we promise a date.
Each one is a hard prerequisite. The deployer checks several of them before it touches your subscription, which is cheaper than finding out halfway through.
-
01
An Azure subscription you own
In a tenant you control. The instance runs there and its data never leaves it.
-
02
A region with availability zones, and quota there
For a zone-redundant Container Apps environment, a Postgres Flexible Server and a Key Vault. A quota refusal fails the whole deploy.
-
03
Five resource providers registered
Microsoft.App, Microsoft.DBforPostgreSQL, Microsoft.KeyVault, Microsoft.ContainerRegistry and Microsoft.Storage. An unregistered provider is the most common deploy failure.
-
04
A resource group, created by you
Everything the instance owns lands in it, and nothing else should. The deployer cannot create one, on purpose: a deployer that could would have the whole subscription as its blast radius.
-
05
A DNS zone you can publish in
A CNAME and a TXT record for the console hostname, resolving publicly. A split-horizon zone that answers only inside your network will not get a certificate issued.
-
06
Someone who can create app registrations
Two of them: the deploy identity and the SSO application. Both are yours.
-
07
A named operator and a break-glass group
At least one operator by Entra object id, and a small group whose members are the only ones exempt from the instance’s deny-delete lock.
What you set, and what it defaults to.
One file per instance, with no secret in it and nothing of ours. The deployer checks it before it touches your subscription and names any field it refuses. Defaults as of platform v0.248.0.
| PARAMETER | DEFAULT | WHAT IT SETS |
|---|---|---|
| location | required | The Azure region the instance runs in. |
| hostname | required | The console hostname, in your own domain. |
| operatorObjectIds | at least one | Who operates the console, by Entra object id. An empty list is refused, because nobody could sign in. |
| auditorObjectIds | none | Read-only auditors. They read the fleet, catalog and audit pages and export the audit and evidence bundles; every change refuses them. |
| localAccounts | break-glass-only | The local sign-in beside Entra: disabled, break-glass-only (the one break-glass admin) or enabled. It is set here, never in the console, so nothing in the console can widen who signs in. |
| brokerAllowedCidrs | empty: port closed | The networks your detonation brokers connect from. Port 8443 opens to these alone; a list covering the whole internet is refused unless the deploy run explicitly allows it. |
| allowDefaultHostConsole | false | A DNS-outage break-glass: true lets the console and its sign-in answer on the Azure default name while your hostname does not resolve. |
| backupRetentionDays | 14 | How long Azure keeps the database’s automatic backups, 7 to 35 days. |
| sessionGracePeriodSeconds | 120 | How long open console tabs keep working while an upgrade replaces the running version, 0 to 600. |
One identity you own, three roles, one resource group.
You create an app registration in your tenant and give it these roles, scoped to the resource group and nothing above it. Our release pipeline signs in as it through a federated credential, so there is no client secret to rotate or leak, and you can delete it at any moment to cut us off.
| ROLE | SCOPE | WHY |
|---|---|---|
| Contributor | the resource group | Create and update every resource in the stack. |
| Role Based Access Control Administrator | the resource group | Give the instance’s own managed identities their roles on its vault, storage and registry. Those assignments are visible to you in the portal. |
| Azure Deployment Stack Owner | the resource group | Manage the stack’s deny-delete setting, so offboarding can remove it. |
| Backup platform control (optional, for nightly backups) | the container app | A custom role your administrator creates once, only if you turn on the nightly backup. It can read, stop and start the container app, and nothing else. The stack gives it to the instance’s own backup identity, not to us, so the job can stop the app for its dump and start it again. |
The deploy identity holds no data-plane role. But Contributor lets it update the container app, and the app’s own identity reaches your database and vault. And RBAC Administrator on the resource group could grant it a data role directly. So it could reach your data, by changing what runs or by granting itself access.
- Deploys run only from a release tag. GitHub refuses any other ref; we tested that it does, not just that the rule saves.
- An operator starts each deploy, and GitHub holds every run until a named Attestree operator approves it. Today that can be the person who started it, so it is a deliberate second step, not a second person. Nothing deploys on a schedule or on a push.
- The image signature is checked against that exact release before import.
- Each run records the image digest and revision it rolled out.
- We recommend an activity-log alert on writes to the app and the resource group, sent to your own security mailbox: a record of every deploy that we cannot edit.
Your SSO application
A second app registration, the one your operators sign in through. Separate from the deploy identity. It needs four things before the first deploy, and a fifth after it: a federated credential naming the instance’s own identity, which the deployer prints.
-
Assignment required
so only the users and groups you assign can reach the console at all.
-
A redirect URI
https://<your console hostname>/signin-oidc.
-
Somebody actually assigned
assignment required with nobody assigned is valid, and locks everyone out.
-
The four app roles, and admin consent
Admin, Catalog author, Auditor and Read-only, from a file we supply with the deployer; consent covers its delegated sign-in permission.
Beside Entra sign-in there is one local break-glass admin, for the day Entra sign-in itself breaks. Create it in the first week, give it to two named custodians, store it somewhere that does not sign in through your Entra, and drill it every quarter. You can switch local accounts off entirely, or allow more of them with two-factor required.
Roughly US$250–380 a month, from Microsoft, not us.
We charge for the licence. The Azure spend is billed to you directly and we never see it. The range is October 2026 list prices for a small instance; your agreement and region will move the digits, not the shape. It does not shrink with a small fleet: the always-on replica and the private endpoints bill around the clock.
- Container app
- One replica is always on, so it bills around the clock.
- Postgres Flexible Server
- The largest line: about US$200 a month on the default General Purpose server. Burstable is about US$60 cheaper, but has no on-demand backup, high availability or read replicas.
- Key Vault, storage, registry
- Cents to a few dollars: a handful of keys, a key ring, one image.
- Private endpoints
- Two, each billed by the hour, plus three private DNS zones.
- Log Analytics
- Zero to tens of dollars; ingestion is capped at 1 GB a day.
- Backups, bandwidth
- Small, growing with the backup retention you choose.
Licence, deploy, hand over.
-
01
Issue the licence
A signed file bound to your tenant, your endpoint cap and your term. The instance checks it offline; nothing phones home. From 30 days before it expires, the console names the expiry date and the date new enrollments would stop.
-
02
Prepare the pipeline
A protected release environment for your instance, and the federated-credential values you add to your deploy identity.
-
03
Deploy
A run from a release tag. The first one stops running-but-unbound until your DNS records and SSO credential exist; a rebind run then finishes it.
-
04
Hand over
Your operators sign in and mint their own agent and broker installers. We do not: they carry a one-time token for your instance, which is yours to hold.
You can also run a deploy yourself, with the same script and the same result under your own Azure sign-in: PowerShell 7.4 or later, Azure CLI 2.61 or later with the Container Apps extension and Bicep 0.30 or later, and cosign 3.0.6 or later. The deployer kit is signed and carries a manifest of every file. Run it from the release you deploy: it refuses any image not signed by that exact release tag.
What we commit to, and what we don’t.
- No data-plane role
- We hold no data-plane role on your database, vault or storage. The RBAC Administrator grant could give us one; every assignment shows in your activity log.
- An SLA only where your contract states one
- Response times, escalation contacts and any uptime target are set per agreement. Without one there is no SLA, and the instance runs on Azure’s own availability.
- A lapsed licence switches nothing off
- It is a signed file bound to your tenant that the instance checks offline; it never phones home. When it expires, the instance keeps serving and every enrolled endpoint keeps working. A release built after the expiry runs with new enrollments refused, and from 60 days after the expiry every release refuses them, until you install a renewal. It is not designed to stop a subscription owner from editing their own environment.
Things that break a first deploy
Worth checking before the first run, because each of them looks like our bug when it fires.
Can block the deploy identity or sign-in in a way that looks like our bug. Tell us which apply before the first run.
Breaks the first-run bootstrap: the attestation certificate has to be exportable or the signer cannot sign. Scope the policy to exclude the instance’s vault.
The certificate needs the two records to resolve publicly. Without them the instance still deploys, and agents and brokers can reach it on its Azure address, but the console signs no one in there. A rebind run finishes once the records resolve.
Would cut off every endpoint outside it. The broker port already opens only to the networks you list; the console port has to stay reachable from every endpoint.
Offboarding detaches. It does not delete.
Leaving removes the deployment stack and its deny-delete setting. Every resource, the running app included, stays in your subscription on its last release. You keep the instance and can run it yourself; you simply stop receiving upgrades from us.
If your licence then lapses, the instance keeps serving and keeps managing every endpoint already enrolled. New enrollments stop 60 days after the licence expires, or at once on a release built after the expiry. Installing a renewed licence on the console lifts that straight away, with no restart.
Deleting the resources is your action as the subscription owner. We do it only on your written instruction. One thing to know early: the vault has purge protection, so a deleted instance’s vault name cannot go to a new vault for up to 90 days. Redeploying the same slug recovers the old vault instead.
Your subscription, your keys, your exit.
We're in design-partner mode through GA.