Create an Enterprise Data Plane on Azure
This guide covers Azure provisioning for the Dedicated and BYOC deployment models. Customer-managed encryption keys for the Dedicated model are not currently supported on Azure.
Before you begin
- Confirm the deployment model and target Azure region with the PromptQL team.
- Record the Data Plane name, domain, availability zones, VNet CIDR, and private-connectivity requirements.
- BYOC requires a dedicated Azure subscription or approved resource groups, permission to register Enterprise applications, and permission to assign roles.
- Confirm the selected region and subscription have sufficient quotas for the required services.
Network and availability plan
- Select one Azure region and the required availability zones.
- Reserve a non-overlapping VNet CIDR, normally /16 to /20.
- Confirm the network path to each data source: VNet peering, VPN, Azure Private Link/Private Endpoint, or another approved private path.
- For BYOC, use a dedicated subscription or approved resource groups and confirm policies and quotas permit AKS, database, storage, load-balancing, identity, and networking resources.
Dedicated
- In the PromptQL Enterprise console, open Data Planes and select Create Data Plane.
- Choose Dedicated, enter the Data Plane name and domain, and select the cloud, region, and availability zones.
- Enter the approved network ranges and private-connectivity settings.
- Review the configuration and create the Data Plane.
- Monitor provisioning until the status is Active. Initial provisioning typically takes about 60 minutes.
- Validate project creation, user authentication, connector deployment, and private connectivity to each required data source.
BYOC
What you need to do
- Prepare a dedicated Azure subscription or approved resource groups and confirm the target region, quotas, policies, and VNet range.
- Register the PromptQL infrastructure-management service principal in your Microsoft Entra ID tenant.
- Deploy the role-assignment template below to the approved resource groups.
- Register the required AKS API server VNet integration feature.
- Provide the subscription ID, tenant ID, resource group names, region, and network plan to PromptQL.
- Keep the service-principal registration and role assignments in place while PromptQL operates the Data Plane.
PromptQL then uses the scoped service principal to provision, upgrade, and operate the approved resources in your Azure subscription.
Detailed Azure setup
Prerequisites
- Azure Account with administrative access
- Dedicated Azure Subscription where PromptQL will provision BYOC infrastructure
- Permissions to register Enterprise applications in your Azure AD tenant
- Permissions to assign roles at the subscription level
Provisioning Access
You need to register the PromptQL provisioning service principal in your Azure AD tenant:
For Infrastructure Provisioning (PrivateDdnInfra):
- Log in with an account that has permissions to register Enterprise applications
- Open a browser tab and navigate to the following URL, replacing
<TENANT_ID>with your Azure Tenant ID:https://login.microsoftonline.com/<TENANT_ID>/oauth2/authorize?client_id=4f7f1f59-f0b0-4adb-8603-2afacc50552b&response_type=code&redirect_uri=https://hasura.io/docs/3.0/private-ddn/creating-a-data-plane/byoc - Verify the service principal details match exactly:
- Client ID:
4f7f1f59-f0b0-4adb-8603-2afacc50552b - Name:
Hasura Cloud Infrastructure Manager
- Client ID:
- Select "Consent on behalf of your organization" and click "Accept"
- You will be redirected back to this documentation page, confirming the registration was completed
After completing the registration process, you can verify that the service principal was created successfully:
- Go to the Azure Portal
- Navigate to Azure Active Directory → Enterprise applications
- Search for "Hasura Cloud Infrastructure Manager" to confirm it appears in your tenant
Use the provided Azure Bicep template to automatically set up the required roles and permissions:
- Copy the following ARM template and save it as
role.json:
role.json
{
"$schema": "https://schema.management.azure.com/schemas/2018-05-01/subscriptionDeploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.37.4.10188",
"templateHash": "17100090430408911702"
}
},
"parameters": {
"resourceGroupNames": {
"type": "array",
"metadata": {
"description": "An array of resource group names to assign the role in."
}
},
"principalId": {
"type": "string",
"metadata": {
"description": "The principal (service principal) ID to assign the role to."
}
},
"principalType": {
"type": "string",
"defaultValue": "ServicePrincipal",
"allowedValues": [
"User",
"Group",
"ServicePrincipal"
],
"metadata": {
"description": "The type of principal (User, Group, or ServicePrincipal)."
}
}
},
"resources": [
{
"type": "Microsoft.Authorization/roleDefinitions",
"apiVersion": "2022-04-01",
"name": "[guid(subscription().id, 'HasuraCloudBYOCRole')]",
"properties": {
"roleName": "HasuraCloudBYOC",
"description": "Role for PromptQL BYOC",
"type": "CustomRole",
"assignableScopes": [
"[subscription().id]"
],
"permissions": [
{
"actions": [
"Microsoft.DBforPostgreSQL/flexibleServers/*"
]
}
]
}
},
{
"copy": {
"name": "roleAssignments",
"count": "[length(parameters('resourceGroupNames'))]"
},
"type": "Microsoft.Resources/deployments",
"apiVersion": "2022-09-01",
"name": "[format('roleAssignment-{0}', parameters('resourceGroupNames')[copyIndex()])]",
"resourceGroup": "[parameters('resourceGroupNames')[copyIndex()]]",
"properties": {
"expressionEvaluationOptions": {
"scope": "inner"
},
"mode": "Incremental",
"parameters": {
"customRoleDefinitionId": {
"value": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', guid(subscription().id, 'HasuraCloudBYOCRole'))]"
},
"principalId": {
"value": "[parameters('principalId')]"
},
"principalType": {
"value": "[parameters('principalType')]"
}
},
"template": {
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.37.4.10188",
"templateHash": "4955557183172246065"
}
},
"parameters": {
"customRoleDefinitionId": {
"type": "string",
"metadata": {
"description": "The custom role definition ID to assign."
}
},
"principalId": {
"type": "string",
"metadata": {
"description": "The principal (user, group, service principal) object ID to assign the role to."
}
},
"principalType": {
"type": "string",
"defaultValue": "ServicePrincipal",
"allowedValues": [
"User",
"Group",
"ServicePrincipal"
],
"metadata": {
"description": "The type of principal (User, Group, or ServicePrincipal)."
}
}
},
"variables": {
"networkContributorRoleId": "4d97b98b-1d4f-4787-a291-c67834d212e7",
"managedIdentityContributorRoleId": "e40ec5ca-96e0-45a2-b4ff-59039f2c2b59",
"managedIdentityOperatorRoleId": "f1a07417-d97a-45cb-824c-7a7467783830",
"aksContributorRoleId": "ed7f3fbd-7b88-4dd4-9017-9adb7ce333f8",
"storageAccountContributorRoleId": "17d1049b-9a84-46fb-8f53-869881c3d3ab",
"rbacAdministratorRoleId": "f58310d9-a9f6-439a-9e8d-f62e7b41a168",
"rbacCondition": "!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'} OR ActionMatches{'Microsoft.Authorization/roleAssignments/delete'}) OR (@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {4d97b98b-1d4f-4787-a291-c67834d212e7, acdd72a7-3385-48ef-bd42-f606fba81ae7, b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b, ba92f5b4-2d11-453d-a403-e96b0029c9fe, 2a2b9908-6ea1-4ae2-8e65-a410df84e7d1} AND @Request[Microsoft.Authorization/roleAssignments:PrincipalType] ForAnyOfAnyValues:StringEqualsIgnoreCase {'ServicePrincipal', 'MSI'})"
},
"resources": [
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, parameters('customRoleDefinitionId'), parameters('principalId'), 'custom')]",
"properties": {
"roleDefinitionId": "[parameters('customRoleDefinitionId')]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('networkContributorRoleId'), parameters('principalId'), 'network')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('networkContributorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('managedIdentityContributorRoleId'), parameters('principalId'), 'identity')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('managedIdentityContributorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('managedIdentityOperatorRoleId'), parameters('principalId'), 'operator')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('managedIdentityOperatorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('aksContributorRoleId'), parameters('principalId'), 'aks')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('aksContributorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('storageAccountContributorRoleId'), parameters('principalId'), 'storage')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('storageAccountContributorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]"
}
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id, variables('rbacAdministratorRoleId'), parameters('principalId'), 'rbac')]",
"properties": {
"roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', variables('rbacAdministratorRoleId'))]",
"principalId": "[parameters('principalId')]",
"principalType": "[parameters('principalType')]",
"condition": "[variables('rbacCondition')]",
"conditionVersion": "2.0"
}
}
]
}
},
"dependsOn": [
"[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', guid(subscription().id, 'HasuraCloudBYOCRole'))]"
]
}
]
}
-
Deploy the template using Azure CLI:
# Set your subscription az account set --subscription "your-subscription-id" # Get the Object ID of the PromptQL provisioning service principal PRINCIPAL_ID=$(az ad sp list --filter "appId eq '4f7f1f59-f0b0-4adb-8603-2afacc50552b'" --query "[0].id" --output tsv) # Deploy the template az deployment sub create \ --name "hasura-cloud-byoc" \ --location "East US" \ --template-file role.json \ --parameters \ resourceGroupNames='["your-resource-group-name"]' \ principalId="$PRINCIPAL_ID" \ principalType="ServicePrincipal"Replace the following values:
your-subscription-id: Your Azure subscription IDyour-resource-group-name: The resource group where PromptQL will operate (you can specify multiple resource groups:'["rg1","rg2","rg3"]')"East US": Your preferred Azure region
-
Monitor the deployment:
az deployment sub show --name hasura-cloud-byoc --query 'properties.provisioningState'
Additional Requirements
Register the required Azure feature flag for API server VNet integration:
az feature register --namespace "Microsoft.ContainerService" --name "EnableAPIServerVnetIntegrationPreview"
You can check the registration status with:
az feature show --namespace "Microsoft.ContainerService" --name "EnableAPIServerVnetIntegrationPreview"
What to provide to PromptQL
Gather the following information from your Azure Portal and provide it to the PromptQL team:
Required:
- Subscription ID: The target subscription where BYOC infrastructure will be deployed
- Tenant ID: Your Azure AD tenant identifier
- Resource Group Name(s): The resource group(s) where PromptQL will operate
- Azure Region: The target region for deployment (e.g., "East US", "West Europe")
Optional:
- Preferred Availability Zones: Specific logical zone IDs within your chosen region
- If not specified, PromptQL will select zones automatically
- Use logical zone IDs (e.g., "1", "2", "3") which map to physical zones
- You can get the zone mappings by running:
Replaceaz rest --method get \ --uri '/subscriptions/{subscriptionId}/locations?api-version=2022-12-01' \ --query 'value[?name==`eastus` && availabilityZoneMappings != `null`].{displayName: displayName, name: name, availabilityZoneMappings: availabilityZoneMappings}'eastuswith your desired region name and{subscriptionId}with your subscription ID - Example: ["1", "2", "3"] for logical zones 1, 2, and 3
- VNet CIDR: Custom CIDR block for the virtual network (/16-/19 range)
- Default: 10.0.0.0/16 if not specified
- Important: Ensure this doesn't conflict with existing networks if using VNet peering