Skip to content

Corporate Tenant Registry

ENTERPRISE Feature

The Corporate Tenant Registry requires an ENTERPRISE licence. It is not available on STARTER or PRO tiers.

Manage multiple Microsoft Entra ID tenants that belong to the same organisation. CertifyClouds discovers, monitors, and rotates credentials across all of them from a single deployment.


Overview

A typical enterprise spans more than one Entra ID tenant: a primary ("home") tenant for day-to-day operations and additional tenants for subsidiaries, acquired companies, geographic regions, or environment boundaries (dev / staging / production). The Corporate Tenant Registry lets you onboard those additional tenants so CertifyClouds can:

  • Discover and monitor Key Vault secrets, certificates, and keys across every onboarded tenant
  • Rotate App Registration credentials in any onboarded tenant
  • Surface all assets in the unified inventory with a per-tenant badge
  • Alert on expiring credentials regardless of which tenant they live in

Corporate tenants vs external tenants

Aspect Corporate Tenant Registry External tenants (Azure AD B2C)
Tenant type Full Entra ID tenants with Azure subscriptions and Key Vaults Azure AD B2C tenants (identity-only, no Key Vaults)
What is discovered Key Vault secrets, certificates, keys, and App Registration credentials App Registration secrets and certificates
Rotation Key Vault secrets / certificates / keys + App Reg credentials App Reg credentials only
Licence ENTERPRISE PRO or ENTERPRISE

One organisation, multiple tenants

The Corporate Tenant Registry is for a single organisation that spans multiple Entra ID tenants. It is not a multi-customer isolation model. CertifyClouds runs as one deployment; the registry extends its reach across your organisation's tenant boundary.


Concepts

Home tenant

The tenant in which CertifyClouds itself is deployed. Its Managed Identity (or Service Principal) is the deployment credential. The home tenant is added to the registry automatically at first start; you cannot delete it. Scan, rotation, and sync for home-tenant assets use the deployment credential as before.

Onboarded tenant

Any additional Entra ID tenant you register in the Corporate Tenant Registry. Each onboarded tenant gets its own dedicated Service Principal (provisioned by the onboarding script) whose client secret is stored encrypted at rest. Credential operations on onboarded-tenant assets always use that tenant's own credential - they never reuse the home deployment credential.

Credential routing

Every Azure write operation resolves its credential at the point of execution:

  • Home assets use the deployment credential.
  • Onboarded-tenant assets use the per-tenant ClientSecretCredential, wrapped in a bounded wrapper that enforces a wall-clock timeout per token acquisition. Credentials are cached with tenant-scoped keys so SP rotation invalidates the cache automatically.

Before any write is executed, the platform verifies that the credential's actual token tid matches the intended tenant. A mismatch is a hard refusal - the write is never sent.


Prerequisites

  • ENTERPRISE licence (the multi_tenant feature entitlement)
  • Azure CLI (az) installed on the machine running the onboarding script
  • jq installed (brew install jq on macOS, apt install jq on Debian/Ubuntu)
  • Admin access in the target (onboarded) Entra tenant to create an App Registration and grant admin consent for Microsoft Graph permissions

Step 1: Provision the Service Principal (onboarding script)

Run onboard-corporate-tenant.sh (included in your CertifyClouds delivery package; contact [email protected] if your package predates it) in the target tenant to create the App Registration, Service Principal, client secret, and role assignments CertifyClouds needs.

Sign in to the target tenant

The Azure CLI creates App Registrations in the tenant of the current session. You must sign in to the target tenant before running the script:

az login --tenant <TARGET_TENANT_GUID> --allow-no-subscriptions

The script validates that your current session matches --tenant and refuses to run if they differ, preventing accidental provisioning in the wrong directory.

Preview first (no changes)

By default the script is a dry run - it prints every az command it would execute without making any changes:

On Windows, read Running from Windows before running the script.

./onboard-corporate-tenant.sh --tenant <TARGET_TENANT_GUID>

Review the output, then add --apply to actually provision:

./onboard-corporate-tenant.sh --tenant <TARGET_TENANT_GUID> --apply

Flags

Flag Purpose
--tenant <guid> (Required) Target Entra tenant GUID
--apply Execute the changes. Without this the script only previews
--with-rotation Also grant write permissions for credential rotation (see below)
--with-resource-updates Also grant Contributor on consuming resources for full-stack rotation (opt-in, broad)
--subscription <guid> Scope role grants to one subscription. Repeatable. Omit to grant across all subscriptions in the target tenant
--display-name <name> App Registration display name. Default: CertifyClouds Corporate Tenant Workload (Production)

Grants by mode

Grant Scope Purpose
Reader Subscription Enumerate subscriptions, vaults, resources
Key Vault Reader Subscription Read vault and secret/certificate/key metadata
Microsoft Graph Application.Read.All Tenant-wide Read App Registrations and Service Principals

All discovery grants, plus:

Grant Scope Purpose
Key Vault Secrets Officer Subscription Create/update secret versions
Key Vault Certificates Officer Subscription Create/update certificate versions
Key Vault Crypto Officer Subscription Rotate keys, KV-to-KV replication
Microsoft Graph Application.ReadWrite.All Tenant-wide Rotate App Registration credentials

All rotation grants, plus:

Grant Scope Purpose
Website Contributor Subscription Update App Service configuration after rotation
SQL Server Contributor Subscription Update SQL Server connection strings after rotation
Container Apps Contributor Subscription Update Container Apps secrets after rotation
Logic App Contributor Subscription Update Logic App connections after rotation

Subscription-scoped write access

The write roles above are granted at subscription scope, meaning they cover every resource of that type in the subscription. If your security policy requires least-privilege, re-create the role assignments at resource-group or vault scope after provisioning and remove the subscription-scoped ones.

Application.Read.All (and Application.ReadWrite.All when --with-rotation is used) are application permissions that require tenant-wide admin consent from a Global Administrator. The script attempts to grant consent automatically. If your account lacks that role, it prints the portal steps to hand to an admin:

  1. Azure Portal > Microsoft Entra ID > App registrations
  2. Open the app (e.g. CertifyClouds Corporate Tenant Workload (Production))
  3. Go to API permissions
  4. Click Grant admin consent for [Tenant Name] and confirm

The Key Vault scan and subscription enumeration work without consent. App Registration discovery in the onboarded tenant requires consent before it returns results.

Script output

On a successful --apply run, the script prints the values to paste into the CertifyClouds UI:

  Tenant ID (GUID):     xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
  Tenant domain:        yourcompany.onmicrosoft.com
  App (client) ID:      yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
  Client secret:        <secret value>
  Secret expires:       <date>

Copy the client secret now

The client secret value is shown once and cannot be retrieved again. Copy it immediately into the CertifyClouds form, or store it in a vault.

Key Vault firewalls on onboarded tenants

CertifyClouds can enumerate a Key Vault resource with Azure RBAC while still receiving data-plane 403 (ForbiddenByFirewall) responses when it tries to list secrets, certificates, or keys. If the vault firewall is off (properties.networkAcls.defaultAction is Allow, or the vault has no network ACLs), there is nothing to configure. If it is Deny, grant the CertifyClouds deployment a network path using one of the three options below. All three keep the vault firewalled to everyone else.

Which option to choose:

Your situation Use
Deployment subnet has the Microsoft.KeyVault service endpoint (the usual case - it does whenever your home-tenant vaults use subnet rules) Option 1 - virtual-network rule (recommended, simplest)
Deployment subnet has no service endpoint, and you can route outbound through a stable public IP Option 2 - NAT gateway + IP allowlist
You need a fully-private path (no public Key Vault endpoint at all), or neither of the above fits Option 3 - Private Endpoint

Option 1 (recommended): cross-tenant virtual-network rule

A Deny vault admits CertifyClouds when its networkAcls.virtualNetworkRules lists the subnet the CertifyClouds deployment runs on. The subnet lives in your home (deployment) tenant; the vault lives in the onboarded tenant. Because the Corporate Tenant Registry is one organisation spanning several Entra tenants (not separate companies), an administrator with rights in both tenants adds the rule directly - Key Vault virtual-network rules do work across the Entra tenants of one organisation.

The Azure portal can't add this rule: its "Add a virtual network" picker only lists subnets in the vault's own subscription, so a cross-tenant deployment subnet cannot be selected there. Add it with the CLI below (or the onboarding script), using the subnet's full resource ID.

Prerequisite: the deployment subnet has the Microsoft.KeyVault service endpoint enabled (already true whenever your home-tenant vaults use subnet rules).

az keyvault network-rule add \
  --name <onboarded-vault> \
  --subscription <onboarded-subscription> \
  --subnet "/subscriptions/<home-sub>/resourceGroups/<rg>/providers/Microsoft.Network/virtualNetworks/<vnet>/subnets/<deployment-subnet>"

The onboarding script automates this: ./onboard-corporate-tenant.sh --tenant <GUID> --subnet <deployment-subnet-id> --apply.

Keep defaultAction=Deny - the rule grants access only to the CertifyClouds subnet, so the vault stays firewalled to everyone else while CertifyClouds reads its secrets, certificates, and keys using the onboarded tenant's Service Principal.

Option 2: NAT gateway + public IP allowlist

Key Vault IP rules only match a public source IP. That works only when the deployment subnet does not have the Microsoft.KeyVault service endpoint - otherwise traffic reaches the vault over the Azure backbone with no public source IP (the audit log shows CallerIPAddress 0.0.0.0) and an IP rule can never match.

To use IP allowlisting deliberately: attach a NAT gateway with a static public IP to the deployment subnet (and do not enable the Key Vault service endpoint on that subnet), so all outbound traffic egresses via that one stable IP. Then allowlist it:

# find the deployment's stable egress IP (NAT gateway public IP; Container Apps: outboundIpAddresses)
az containerapp show --name <app> --resource-group <rg> --query properties.outboundIpAddresses
az keyvault network-rule add --name <onboarded-vault> --subscription <onboarded-subscription> --ip-address <egress-ip>/32

The onboarding script automates the IP-rule add: ./onboard-corporate-tenant.sh --tenant <GUID> --ip-address <egress-ip>/32 --apply. Note: Azure Container Apps NAT-gateway/custom egress requires a workload-profile environment; a consumption-only environment has a large rotating egress pool that cannot be allowlisted, so use Option 1 or 3 there.

Option 3: cross-tenant Private Endpoint (fully private)

Gives the onboarded vault a private IP inside your deployment VNet, so the vault can disable public network access entirely and CertifyClouds still discovers and reads its contents over the private endpoint.

  1. Create a Private Endpoint in the CertifyClouds deployment VNet (a dedicated subnet with private-endpoint network policies disabled), targeting the onboarded-tenant vault, in manual-request mode.
  2. A Key Vault admin in the onboarded tenant approves the pending private-endpoint connection.
  3. Add a privatelink.vaultcore.azure.net private DNS zone linked to the deployment VNet, with an A record for the vault name pointing at the Private Endpoint's private IP, so the deployment resolves the vault privately.
  4. Optionally set the vault's publicNetworkAccess to Disabled once the Private Endpoint is confirmed working.

This is a multi-party manual flow (two tenants, DNS), so it is not automated by the onboarding script - follow the steps above per vault.

Symptom of a missing network path

Vaults appear in the scan, but the items inside them show zero results, or scan logs show Key Vault data-plane 403 (ForbiddenByFirewall) responses.


Step 2: Register the tenant in CertifyClouds

  1. Go to Tenants in the left-hand navigation and open the Corporate tab
  2. Click Add Tenant
  3. Enter the values from the script output:

    Field Value
    Tenant ID Target tenant GUID
    Tenant Domain e.g. yourcompany.onmicrosoft.com
    Display Name A friendly name for the tenant
    Client ID App Registration (client) ID
    Client Secret Secret from the onboarding script
  4. Click Test Connection to verify. A successful test confirms CertifyClouds can authenticate to the tenant.

  5. Click Register Tenant to save.

Step 3: Run a scan

After registering a tenant, trigger an initial Key Vault scan:

  • All tenants at once: go to Assets > Scan and click Run Scan. The scan runs across the home tenant and all active onboarded tenants sequentially.
  • Via the API: POST /api/assets/discovery/scan with { "corporateTenantId": <id> } to scan a single onboarded tenant.

Discovered assets are tagged with their owning tenant. The unified inventory shows all assets together; filter by tenant using the tenant switcher in the header or the corporateTenantId filter on the Assets page.


Per-tenant scanning

The platform scans each onboarded tenant using that tenant's own Service Principal credential. The home subscription allow-list does not apply to onboarded-tenant scans - each onboarded tenant is scanned across all subscriptions visible to its Service Principal.

Assets inherit their tenant from their subscription: after a scan, each asset's corporate_tenant_id is set to match the subscription it lives in. This tag propagation is idempotent and only updates rows whose tag is stale.


Per-tenant rotation

Rotation for onboarded-tenant assets follows the same flow as home-tenant rotation (confirm dialog, real-time progress stream, grace window, history entry with a tenant badge), with the routing layer ensuring the correct credential is used:

  1. The rotation engine resolves which tenant owns the operation's legs (vault, subscription, App Registration). If any leg belongs to an onboarded tenant, the routing resolves to that tenant's credential.
  2. Before each Azure write, the token tid is verified to match the intended tenant. A mismatch is a hard refusal.
  3. The rotation record is stamped with the resolved corporate_tenant_id so the history table reflects which tenant was written.

Cross-tenant operations (where rotation legs span more than one tenant) are refused. Each rotation job is single-tenant.


Tenant isolation model

Layer Isolation mechanism
Credential storage Per-tenant SP client secret stored encrypted at rest. The home tenant has no stored secret; it uses the deployment credential.
Credential routing Every Azure write resolves its credential from the tenant tag on the target resource. The home credential is never used for onboarded-tenant writes.
Token verification Before each write, the platform decodes the acquired token's tid claim and refuses if it does not match the intended tenant.
Scan isolation Each onboarded tenant is scanned with its own credential. The vanished-asset reconcile is scoped to (subscription, vault), so a scan for one tenant never disables assets belonging to another.
Scope Within-organisation isolation: prevents wrong-tenant writes. Not a network isolation or data-residency boundary.

Service Principal expiry

The onboarded tenant's Service Principal secret has a 2-year validity by default. The tenant card on Tenants → Corporate shows the expiry date alongside a status badge so you can see at a glance when renewal is due.

The Auto-rotate before expiry toggle uses the managed-secret monitor schedule to mint a new secret, verify it, save it, and retire the old one before expiry. If the toggle is off, set a calendar reminder before the expiry date; if the secret expires, scanning, discovery, and rotation for that tenant will fail until it is renewed by re-running the onboarding script with --rotate-secret --apply and updating the client secret in the tenant registration form in the UI.


Troubleshooting

Symptom Likely cause Resolution
"Connection failed" on test Wrong Client ID or secret Re-run the onboarding script with --apply to mint a fresh secret
No App Registrations discovered Admin consent not granted Grant consent in the Azure portal (API permissions page)
Assets not appearing for onboarded tenant Scan not run after registration Run a scan from Assets > Scan
Rotation refused for onboarded-tenant asset --with-rotation grants not provisioned Re-run the onboarding script with --with-rotation --apply
"Multi-tenant rotation is disabled" Operational kill-switch off Enable the ENABLE_MULTI_TENANT_ROTATION flag under Settings > Advanced > App Behaviour

Security best practices

  1. Least privilege: use --with-rotation only if you need CertifyClouds to rotate credentials in that tenant. Discovery-only onboarding does not require write grants.
  2. Rotation write grants are subscription-scoped: after onboarding, narrow them to a resource group or vault if your security policy requires least-privilege.
  3. Monitor SP expiry: the onboarded tenant's SP secret expires in 2 years. The expiry date is shown on the tenant card. Set a calendar reminder and renew by re-running the onboarding script with --rotate-secret --apply, then updating the client secret in the tenant registration form.
  4. az login --tenant <guid> is interactive when the target tenant enforces MFA or Conditional Access, so be ready to complete the sign-in in a browser or device prompt.
  5. Re-running the onboarding script without --rotate-secret keeps the existing secret; a new secret is only minted on the first run or when you pass --rotate-secret.
  6. Review access: periodically review the CertifyClouds App Registration in each onboarded tenant's Azure portal to confirm permissions remain as expected.