After configuring Single Sign-On (SSO) for Stratusphere, you can add a Microsoft Azure data source to your Stratusphere organization. The Azure data source uses Entra ID to authenticate to your tenant via an App Registration & Service Principal. Authentication is handled using a public/private certificate key pair. We assign the built-in Reader role to your Tenant Root Group, which enables identification of cost optimization and security findings.
Open Entra ID in the Azure Portal
Go to Manage ➡️ Properties
Enable the "can manage access to all Azure subscriptions and management groups in this tenant" option
API token for the Stratusphere data API
Public key certificate, used for Entra ID authentication
The identity used by Stratusphere to analyze your cloud environment is called an App Registration in Entra ID. This identity can be created using the Microsoft Azure CLI tool. You can access the Azure CLI from the built-in CloudShell environment in the Azure Portal, if you don't have it installed locally.
To open the Azure CloudShell, simply open the Azure Portal and click on the Shell icon, next to the bell icon, in the top-right navigation bar. Then click PowerShell, select an Azure Subscription to use for Stratusphere deployment, and click the Apply button.
Next, replace the IMPORTANT
line below with the public key provided by StratusGrid, and run the following script.
$Account = az account show | ConvertFrom-Json
$NewApp = az ad app create --display-name stratusgrid-stratusphere
$App = $NewApp | ConvertFrom-Json
# Delete the Service Principal (if it exists) and re-create it with a new GUID
$ServicePrincipal = az ad sp create --id $App.appId | ConvertFrom-Json
az role assignment create --assignee $App.appId `
--role Reader `
--scope "/providers/Microsoft.Management/managementGroups/$($Account.tenantID)"
@'
IMPORTANT: REPLACE THIS LINE WITH THE PUBLIC KEY GENERATED BY STRATUSGRID
'@ | Out-File -Path publickey.pem
az ad app credential reset --id $App.appId --cert '@publickey.pem'
$Text = @'
Please copy/paste this information to StratusGrid:
TenantID: {0}
SubscriptionID: {1}
App Registration ID: {2}
Service Principal ID: {3}
'@ -f $Account.tenantId, $Account.id, $App.appId, $ServicePrincipal.id
Write-Host -Object $Text -ForegroundColor Green
Stratusphere needs an Azure Storage Account, to ingest billing data from, and an Event Grid subscription to notify when new data is available. These resources are deployed through an Azure Resource Manager (ARM) JSON template.
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"stratusphereTopicName": {
"type": "string",
"defaultValue": "stratusgrid-stratusphere"
},
"storageAccountNamePrefix": {
"type": "string",
"defaultValue": "sgstratusphere"
},
"containerName": {
"type": "string",
"defaultValue": "cme"
},
"location": {
"type": "string",
"defaultValue": "eastus"
},
"webhookURL": {
"type": "string",
"defaultValue": "https://data.stratusphere.app/azure/cme"
},
"stratusphereAPIToken": {
"type": "securestring"
},
"servicePrincipalId": {
"type": "string",
"metadata": {
"description": "This is the Service Principal ID associated with the Entra ID App Registration previously created. Please ensure you use the Service Principal ID property, not the App ID."
}
}
},
"variables": {
"dataSourceId": "[take(replace(subscription().subscriptionId,'-',''), 10)]",
"storageAccountName": "[concat(parameters('storageAccountNamePrefix'), variables('dataSourceId'))]"
},
"resources": [
{
"type": "Microsoft.Storage/storageAccounts",
"apiVersion": "2023-01-01",
"name": "[variables('storageAccountName')]",
"location": "[parameters('location')]",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {
"accessTier": "Hot"
}
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices",
"apiVersion": "2023-01-01",
"name": "[format('{0}/{1}', variables('storageAccountName'), 'default')]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]"
]
},
{
"type": "Microsoft.Storage/storageAccounts/blobServices/containers",
"apiVersion": "2023-01-01",
"name": "[format('{0}/{1}/{2}', variables('storageAccountName'), 'default', parameters('containerName'))]",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices', variables('storageAccountName'), 'default')]"
]
},
{
"type": "Microsoft.Authorization/roleAssignments",
"apiVersion": "2022-04-01",
"name": "[guid(resourceGroup().id)]",
"properties": {
"roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '2a2b9908-6ea1-4ae2-8e65-a410df84e7d1')]",
"principalId": "[parameters('servicePrincipalId')]"
}
},
{
"type": "Microsoft.EventGrid/systemTopics",
"apiVersion": "2022-06-15",
"name": "[parameters('stratusphereTopicName')]",
"location": "eastus",
"dependsOn": [
"[resourceId('Microsoft.Storage/storageAccounts/blobServices/containers', variables('storageAccountName'), 'default', parameters('containerName'))]"
],
"properties": {
"source": "[resourceId('Microsoft.Storage/storageAccounts', variables('storageAccountName'))]",
"topicType": "Microsoft.Storage.StorageAccounts"
}
},
{
"type": "Microsoft.EventGrid/systemTopics/eventSubscriptions",
"apiVersion": "2022-06-15",
"name": "[concat(parameters('stratusphereTopicName'), '/', parameters('stratusphereTopicName'), '-webhook')]",
"dependsOn": [
"[resourceId('Microsoft.EventGrid/systemTopics', parameters('stratusphereTopicName'))]"
],
"properties": {
"destination": {
"properties": {
"maxEventsPerBatch": 10,
"preferredBatchSizeInKilobytes": 64,
"endpointUrl": "[parameters('webhookURL')]",
"deliveryAttributeMappings": [
{
"properties": {
"value": "[concat('Basic ', parameters('stratusphereAPIToken'))]",
"isSecret": true
},
"name": "Authorization",
"type": "Static"
}
]
},
"endpointType": "WebHook"
},
"filter": {
"subjectEndsWith": "manifest.json",
"includedEventTypes": [
"Microsoft.Storage.BlobCreated"
],
"enableAdvancedFilteringOnArrays": true
},
"labels": [],
"eventDeliverySchema": "CloudEventSchemaV1_0",
"retryPolicy": {
"maxDeliveryAttempts": 30,
"eventTimeToLiveInMinutes": 1440
}
}
}
]
}
To create the Cost Management Export with the Microsoft Azure Portal, follow these steps.
cme
actual
If an invalid Stratusphere API token is provided as input to the ARM template deployment, you may receive the following error message.
ERROR: Webhook validation handshake failed for https://data.stratusphere.app/azure/cme. Http OPTIONS request failed with response code Unauthorized. For troubleshooting, visit https://aka.ms/esvalidationcloudevent. Activity id:ec08ccbd-6395-4499-b04f-2e3045e9e484, timestamp: 12/16/2024 10:13:21 PM (UTC).