Calibrant Relay Setup

The Calibrant Relay is a small service you deploy in your own Azure subscription. It handles two things for you:

  • Agent Optimizer — test your Copilot Studio agents as real users (personas), including authenticated test scenarios
  • Tenant Healthcheck — run M365 configuration audits using PowerShell against your tenant via Managed Identity
  • Security Checkup — CIS and CISA SCuBA framework assessments with automated M365 configuration checks

The relay is a Windows VM running Windows Server 2022 Core (no desktop GUI, minimal attack surface). It uses a Managed Identity for all M365 authentication — no passwords, no service account credentials, no domain join required. The VM makes outbound-only HTTPS connections to Calibrant and Microsoft APIs. No inbound ports are open.

Deployment takes about 10–15 minutes (mostly waiting for Azure to provision the VM and install software).

What you need before starting:
  • An Azure subscription where you can create resources (Contributor role or higher)
  • A Calibrant account
  • The Azure CLI installed on your local machine (you'll run a few commands)

Step 1 — Install the Azure CLI

If you already have the Azure CLI installed, skip to Step 2.

# Windows (PowerShell or Command Prompt)
winget install Microsoft.AzureCLI

# Mac
brew install azure-cli

# After installing, sign in:
az login

Verify you're pointed at the right subscription:

az account show --query "{name:name, id:id}" -o table

# Switch subscriptions if needed:
az account set --subscription "Your Subscription Name"

Step 2 — Create a relay in Calibrant

Go to Connections and scroll to the Calibrant Relay section. Click Add Relay, give it a name (e.g. "Production Relay"), and click Create Relay.

You'll see a Relay API Key — copy it now.

Save the API key. It's shown only once. If you lose it, you can regenerate it from the Connections page (which will invalidate the old one).

Step 3 — Create a resource group

az group create --name calibrant-relay-rg --location eastus

Pick the Azure region closest to your users — eastus, westeurope,australiaeast, etc.

Step 4 — Deploy the relay VM

Download the Bicep template and run the deployment command. Replace cal_YourKeyHere with the API key you copied in Step 2, and set a secure password (you'll almost never need it — it's just required by Azure for the VM admin account).

# Download the Bicep template
curl -O https://www.calibrant.ai/relay/main.bicep

# Deploy (takes 10-15 minutes)
az deployment group create \
  --resource-group calibrant-relay-rg \
  --template-file main.bicep \
  --parameters calibrantApiKey='cal_YourKeyHere' adminPassword='YourSecurePassword123!'

When the deployment finishes, you'll see output including a managedIdentityPrincipalId. Copy this value — you'll need it in Step 5 to grant M365 permissions.

What gets deployed:

  • A Windows Server 2022 Core VM (no GUI, Standard_B2s — 2 vCPU, 4 GB RAM)
  • A User-assigned Managed Identity (for M365 authentication)
  • A Virtual Network with a Network Security Group (outbound-only, all inbound denied)
  • A Log Analytics workspace for diagnostics
  • A Custom Script Extension that automatically installs Node.js, PowerShell 7, all M365 modules, and the relay service
View main.bicep template
// Calibrant Relay — Windows VM deployment with Managed Identity
// No domain join required. No inbound ports. Outbound HTTPS only.
// Full source: https://github.com/fusedad/calibrant/blob/main/relay/deploy/main.bicep

@secure()
param calibrantApiKey string
@secure()
@minLength(12)
param adminPassword string
param calibrantApiUrl string = 'https://www.calibrant.ai'
param location string = resourceGroup().location
param pollIntervalMs string = '600000'
param adminUsername string = 'calibrant-admin'
param vmSize string = 'Standard_B2s'
param relayZipUrl string = 'https://www.calibrant.ai/relay/calibrant-relay.zip'

resource identity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
  name: 'calibrant-relay-identity'
  location: location
}
// ... (NSG, VNet, NIC, VM, Extensions)
// Full template at the URL above

Step 5 — Grant M365 permissions to the Managed Identity

The relay's Managed Identity needs permission to read your M365 tenant configuration. This is a one-time setup.

Download and run the permission grant script:

↓ Download grant-healthcheck-permissions.ps1

# In a pwsh 7 terminal on your local machine (not the VM):
./grant-healthcheck-permissions.ps1

The script will open a browser for sign-in (requires a Global Administrator account), grant all necessary permissions, and print a validation report showing every permission as [OK].

For the full list of what the script grants and why, see Permission details below.

Step 6 — Verify the relay is connected

Go to Connections in Calibrant. Within 30 seconds of the bootstrap completing, the relay should show as Online with a green indicator.

If it's still showing offline after a minute, check the relay logs:

az vm run-command invoke \
  --name calibrant-relay-vm \
  --resource-group calibrant-relay-rg \
  --command-id RunPowerShellScript \
  --scripts "Get-Content C:\calibrant-relay\relay.log -Tail 30"

Step 7 — Add test personas (for Agent Optimizer)

Go to Connections → Test Personas. Personas are user accounts the relay impersonates when testing your Copilot Studio agents. Create them once and assign them to any agent.

  1. Click Add Persona and enter the user's UPN (e.g. jane.doe@contoso.com)
  2. Click Authenticate — a device code appears
  3. The user signs in at aka.ms/devicelogin with that code
  4. Name, department, and job title are auto-populated from Microsoft Graph

Viewing logs

# Last 50 lines of relay log (run from your local terminal)
az vm run-command invoke \
  --name calibrant-relay-vm \
  --resource-group calibrant-relay-rg \
  --command-id RunPowerShellScript \
  --scripts "Get-Content C:\calibrant-relay\relay.log -Tail 50"

# Check service status
az vm run-command invoke \
  --name calibrant-relay-vm \
  --resource-group calibrant-relay-rg \
  --command-id RunPowerShellScript \
  --scripts "Get-Service CalirantRelay"

Environment variables

VariableRequiredDescription
CALIBRANT_API_URLYesAlways https://www.calibrant.ai
CALIBRANT_API_KEYYesYour relay API key from the Connections page
AZURE_CLIENT_IDYesManaged Identity client ID — set automatically by the Bicep template
POLL_INTERVAL_MSNoHow often to check for commands (default: 600000ms = 10 minutes)

Pre-installed tools

PowerShell modules

  • ExchangeOnlineManagement — mailbox policies, DKIM, transport rules, connectors
  • Microsoft.Graph — users, groups, Entra ID policies, SharePoint settings
  • MicrosoftTeams — Teams policies, federation, meeting settings
  • PnP.PowerShell — SharePoint site administration
  • Microsoft.Online.SharePoint.PowerShell — SPO service administration

All modules authenticate automatically via Managed Identity before your script runs.

Power Platform

Power Platform checks (environment inventory, DLP policies, flow failures) use the Power Platform BAP API directly via REST. The Managed Identity is registered as a Power Platform management application during the permission grant step (Step 5), which authorizes it to call admin APIs.

Microsoft Fabric / Power BI

Fabric tenant settings checks (CIS Section 9) use the Fabric admin REST API (https://api.fabric.microsoft.com/v1/admin/tenantsettings) via Managed Identity. The grant permissions script assigns the Fabric Administrator Entra ID role. You must also configure settings in the Fabric admin portal.

Security group required. The Fabric admin APIs do not work with "The entire organization" — you must create an Entra ID security group, add the calibrant-relay-identity service principal to it, and specify that group in each setting below.

Step 1: Create a security group in Microsoft Entra ID (e.g. FabricApiAccess) and add the calibrant-relay-identity service principal as a member.

Step 2: In the Fabric admin portal, enable these two settings (they are in different sections of Tenant settings):

  1. Tenant settings > Developer settings > Service principals can call Fabric public APIs — enable, select "Specific security groups", and add your FabricApiAccess group
  2. Tenant settings > Admin API settings > Service principals can access read-only admin APIs — enable, select "Specific security groups", and add the same group
Both settings are required. The first is under "Developer settings" and the second is under "Admin API settings" — a separate section further down the Tenant settings page. Missing either one will result in a 403 Forbidden error. Do not add any Power BI application permissions (e.g., Tenant.Read.All) to the service principal — per Microsoft, these are unnecessary and can cause errors.

Settings take up to 15 minutes to propagate. Fabric checks will show as "Not Evaluated" until the settings take effect.

Permission details (Step 5)

The grant script assigns 22 Microsoft Graph app roles, 1 Exchange Online app role, and 5 Entra ID directory roles:

PermissionUsed for
Organization.Read.AllOrg info, branding, technical contacts, directory sync
Directory.Read.AllUsers, groups, Entra ID roles and members
User.Read.AllGuest users, sign-in activity (stale guest detection)
Application.Read.AllApp registrations with expiring credentials
Policy.Read.AllAuthorization policy, user consent policy, admin consent workflow
RoleManagement.Read.AllPrivileged role assignment counts
Domain.Read.AllDomain list for password expiry policy checks
DelegatedAdminRelationship.Read.AllDelegated admin partner relationships
ServiceHealth.Read.AllActive M365 service health incidents
ServiceMessage.Read.AllService announcements
AuditLog.Read.AllLast sign-in date for stale guest detection
Reports.Read.AllUsage reports
Group.Read.AllM365 group membership, Teams ownership check
Team.ReadBasic.AllTeams list for ownership audit
TeamSettings.Read.AllTeams tenant-level settings
SharePointTenantSettings.Read.AllExternal sharing, anonymous links, sync restrictions
Sites.Read.AllSharePoint site metadata
MailboxSettings.ReadMailbox configuration (not email content)
DeviceManagementManagedDevices.Read.AllEnrolled devices, compliance state, Defender AV status
DeviceManagementConfiguration.Read.AllCompliance policies, device configuration profiles
DeviceManagementServiceConfig.Read.AllIntune tenant-level settings
DeviceManagementRBAC.Read.AllIntune admin role assignments
Exchange.ManageAsAppRequired for Connect-ExchangeOnline -ManagedIdentity
Exchange Administrator roleDKIM, transport rules, connectors, distribution groups, DMARC, spam policies
Teams Administrator roleTeams policies, federation settings, meeting policies, governance
SharePoint Administrator roleSharePoint/OneDrive admin settings
Power Platform Administrator roleDLP policies, environments, flow monitoring via BAP API
Fabric Administrator roleFabric/Power BI tenant settings via admin REST API
Power Platform BAP API registrationAuthorizes the Managed Identity to call Power Platform admin REST APIs

Troubleshooting

  • Relay shows Offline after deployment — the bootstrap script may still be running. It takes 10–15 minutes to install all software. Check progress in the Azure portal: go to your VM → Extensions + applicationsCustomScriptExtension.
  • Bootstrap failed — check the extension logs in the portal or run:
    az vm run-command invoke --name calibrant-relay-vm --resource-group calibrant-relay-rg --command-id RunPowerShellScript --scripts "Get-Content 'C:\WindowsAzure\Logs\Plugins\Microsoft.Compute.CustomScriptExtension\1.10\CustomScriptHandler.log' -Tail 50"
  • PowerShell cmdlets return Access Denied during healthcheck — the Managed Identity permissions may not have propagated yet. Wait 10 minutes after running the grant script and try again.
  • Service starts but shows no agents in logs — check that the API key is correct. Re-run the deployment with the correct key, or update it via Run Command:
    az vm run-command invoke --name calibrant-relay-vm --resource-group calibrant-relay-rg --command-id RunPowerShellScript --scripts "[System.Environment]::SetEnvironmentVariable('CALIBRANT_API_KEY', 'cal_NewKey', 'Machine'); nssm set CalirantRelay AppEnvironmentExtra 'CALIBRANT_API_KEY=cal_NewKey'; Restart-Service CalirantRelay"