At TechFabric, our enterprise customers often ask to hold the encryption keys for their own data as this is needed to meet their compliance requirements. They want to have control over their data and it's an absolute deal breaker if the database vendor doesn't provide them the ability to choose their own encryption keys. This wasn't possible in Azure PostgreSQL before but that changes with the latest update to Azure Database for PostgreSQL.
If your product runs on Azure Database for PostgreSQL Flexible Server, the answer can now be yes: the customer keeps the key in their own Azure account, and your server encrypts their data with it. Saying yes costs engineering time, a dedicated server for that customer, and a kind of production outage your on-call engineers can't fix. This post covers what the setup takes, what it changes in production, and how to decide when it earns a place on your roadmap.
Cross-tenant customer-managed keys have been generally available since 29 September 2026. If the customer revokes the key, their database usually goes offline within the hour, and nobody on your team can bring it back.
Who needs a customer-held key
The case is narrow. Your product stores a customer's data in a Postgres server in your subscription, and that customer wants cryptographic control they can exercise alone. Microsoft's own docs frame the scenario as a server in the tenant of an independent software vendor, the service provider, with the key in a vault in a different tenant that the customer manages (Data encryption at rest). The customer holds the key, you hold the data, and neither of you can quietly change that.
The first thing we'd check is how the product is laid out today, because the key belongs to the server. A Flexible Server has one dataEncryption setting with one primary key URI. If your customers share a server, separated by schema or by a tenant_id column, there's no way to give one of them a key of their own. Saying yes means a dedicated server for that customer, with its own compute, backups, upgrades and monitoring, and a migration to get their rows onto it. For a product that's pooled every tenant into one database since day one, that's the real cost of the deal, and it's usually bigger than the key work.
A product that already gives its largest customers a server each is in a much better position. There, cross-tenant CMK is a configuration change on servers you already run separately.
How the setup works across two tenants
The mechanism is workload identity federation in Microsoft Entra. You, the provider, create a multitenant app registration and a user-assigned managed identity, then add that identity to the app as a federated identity credential so it can act as the app. The customer installs the app in their tenant, which creates a service principal there, and grants that service principal access to a key. Your Postgres server then uses the managed identity, through the app, to reach the key. No secret crosses between tenants, so there's nothing to store or rotate on that link.
On your side, the federated credential uses your tenant as issuer, the managed identity's principal ID as subject, and api://AzureADTokenExchange as the audience, as the Azure Storage cross-tenant guide shows (the Postgres docs point to it for this step):
az ad app federated-credential create --id $multiTenantAppObjectId --parameters credential.json
The customer runs their half in their own tenant. We'd send them these commands with the app ID filled in, because a security team that has to work out the steps from the docs is a slower security team:
az ad sp create --id $multiTenantAppId
az keyvault key create --vault-name $kvName --name $keyName --kty RSA --size 4096
az role assignment create --role "Key Vault Crypto Service Encryption User" \
--scope $kvResourceId --assignee-object-id $servicePrincipalId
Postgres accepts RSA or RSA-HSM keys of 2,048, 3,072 or 4,096 bits, and Microsoft recommends 4,096. The vault needs soft delete and purge protection on, and it can be a Managed HSM instead of a standard vault. The customer sends back the key identifier, and you create the server with it:
az postgres flexible-server create \
--resource-group myResourceGroup \
--name myServer \
--location eastus2 \
--key $keyIdentifier \
--identity myIdentity \
--federated-client-id $federatedClientId
--federated-client-id is the multitenant app's client ID, and it's what makes this cross-tenant. Without it Azure treats the request as an ordinary single-tenant configuration, and the server can't reach a key in the customer's tenant.
Limits of cross-tenant CMK on Flexible Server
Most of these can't be fixed once the server exists, so we'd go through them with the customer before anyone signs. The encryption mode is fixed at creation, so a server can't move from service-managed to customer-managed keys or back, and moving an existing customer means a point-in-time restore onto a new server configured with their key. Their Key Vault or Managed HSM also has to be in the same Azure region as the server, which is a request you're making of their infrastructure rather than yours.
Geo-redundant backup doubles the work. The backup key has to live in a vault in the backup region, reached by a separate user-assigned identity created in that region, and you pass it with --backup-key, --backup-identity and --backup-federated-client-id. That's a second vault the customer runs for you. Long-term retention backups aren't supported on cross-tenant CMK servers at all, so a contract that promises multi-year backup retention needs another answer.
The automation has gaps too. Azure PowerShell doesn't support the feature yet. In ARM or Bicep you need API version 2026-04-01-preview or later, and every update has to resend all the data encryption properties, because a PATCH that leaves out primaryFederatedIdentityClientId is treated as a non-cross-tenant configuration. We'd put a test on that in the pipeline that deploys the server.
One multitenant app can be installed in any number of customer tenants, but it holds at most 20 federated identity credentials. Past twenty managed identities you'll be sharing them across customers, so it's worth deciding early how identities map to customers and who in your team owns the app, because it's now a piece of production infrastructure installed in every customer's tenant.
Key rotation and revocation in production
Rotation is the part that breaks quietly. A key URI that includes a version pins the server to that version, so every rotation in the customer's vault needs an update on your side, and you won't always hear about it first. We'd always use a versionless key URI (leave the version GUID off), which Microsoft calls automatic key version updates. The server picks up the new version and re-wraps its data encryption key. Microsoft also asks that the old version stay enabled for at least two hours after a rotation while that happens, which belongs in the customer's rotation procedure, not yours.
Revocation is the feature working as designed. If the key is disabled, deleted, expires, or the customer removes your app's role or tightens their vault firewall, the server goes Inaccessible and refuses every connection, generally within 60 minutes. When access comes back it can take up to another 60 minutes to return to Ready. Nothing your engineers do in your tenant shortens either window.
Before the first customer goes live we'd alert on the server's Resource Health and on Key Vault access failures in the Activity Log, through an action group, so you hear it from Azure and not from a support ticket. We'd start the runbook with how support reaches the customer's key administrator, by name and out of hours, and we'd write into the contract who owns the downtime when the customer's key becomes unavailable, whether they meant it or not. And we'd rehearse a disable and re-enable on a sandbox server with the customer's security team, timing how long recovery actually takes.
Restores and replicas need a rule of their own. A point-in-time restore or a read replica of a CMK server is encrypted too, and Microsoft says the original key must not be revoked after a restore, so the customer's "we'll rotate to a fresh key and kill the old one" habit needs checking against your restore history.
Copies of the data outside Postgres
This encrypts one Postgres server at rest, including its write-ahead log, server logs and backups. It does nothing for the copies of that customer's data elsewhere in your platform, and a SaaS product usually has several. Think of a search index, a Redis cache, CSV exports in Blob Storage, an analytics copy in a warehouse or a Databricks lakehouse. A customer who revokes the key expecting their data to go dark everywhere will find it still readable in each of those.
Some of those stores have their own customer-managed key options, Azure Storage's cross-tenant CMK among them, and some don't. We'd map every store that holds the customer's data before promising anything, and say in the security questionnaire exactly which stores the customer's key protects. It also doesn't change who can read data inside the database once it's running, because your application's roles and row-level security still decide that.
Our recommendation
Build it when a specific customer's security team asks for it, and price the dedicated server and the second vault into that deal. Get their key administrator's name, their Azure regions, and whether they need geo-redundant or long-term backups before you start, because those three answers decide whether the setup fits at all. Then pilot it on a sandbox server and rehearse a revoke and restore before production.
Don't build it because it sounds like good security hygiene. For a company running its own data in its own tenant, ordinary customer-managed keys, or Microsoft's default service-managed keys, carry the same encryption without a second tenant or an outage you can't fix yourself. If your product is moving towards dedicated infrastructure for enterprise customers anyway, this is a reasonable thing to build into the platform as one more option on that tier.
Frequently asked questions
Can I switch an existing PostgreSQL Flexible Server to cross-tenant customer-managed keys?
No. The encryption mode is set when the server is created and can't be changed later. To move an existing server onto a customer's key you restore a point-in-time backup onto a new server configured with that key, as Microsoft's data encryption documentation describes, and then cut your application over to it.
What happens if the customer revokes the key?
The server moves to an Inaccessible state and denies all connections, generally within 60 minutes. Once the customer restores access, it can take up to 60 minutes for the server to revalidate the key and return to Ready.
Does cross-tenant CMK work with geo-redundant backup?
Yes, with a second key in a vault in the backup region and a separate user-assigned managed identity in that region, set with --backup-key, --backup-identity and --backup-federated-client-id. Long-term retention backups aren't supported on cross-tenant CMK servers.
Can I ask my own software vendors for a customer-held key?
Yes, if they run Azure Database for PostgreSQL Flexible Server, it's now a fair request. The useful follow-up questions are the limits above: whether they'll give you a dedicated server, whether your vault has to sit in their region, how they handle geo-redundant and long-term backups, and which of their other stores holding your data your key won't cover.