Terraform Setup
This guide walks you through setting up CXM Azure integration using Terraform.
Prerequisites
Required Software
Azure Authentication
Login to Azure CLI with an account that has:
- Permission to create App Registrations in Azure AD
- Owner or User Access Administrator on target subscriptions
az login
Information to Gather
Before starting, identify:
| Information | Where to Find | Example |
|---|---|---|
| Billing Export Storage Account | Cost Management > Exports | mycompanycostexports |
| Billing Export Resource Group | Same location as storage account | finops-rg |
| Activity Log Storage Account | Monitor > Diagnostic Settings | mycompanyactivitylogs |
| Activity Log Resource Group | Same location as storage account | logging-rg |
Quick Start
1. Create Terraform Configuration
Create a new directory and main.tf file:
terraform {
required_version = ">= 1.9.0"
}
provider "azurerm" {
features {}
}
provider "azuread" {}
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# Enable all features
enable_asset_discovery = true
enable_billing_export_access = true
enable_activity_log_access = true
# Billing export storage (must already exist)
billing_export_storage_account_name = "mycompanycostexports"
billing_export_storage_resource_group = "finops-rg"
# Activity log storage (must already exist)
activity_log_storage_account_name = "mycompanyactivitylogs"
activity_log_storage_resource_group = "logging-rg"
tags = {
environment = "production"
managed-by = "terraform"
}
}
# Output values needed for CXM onboarding
output "cxm_onboarding_values" {
value = module.cxm_integration.cxm_onboarding_values
sensitive = true
}
2. Deploy
terraform init
terraform plan
terraform apply
3. Retrieve Onboarding Values
terraform output -json cxm_onboarding_values
This outputs:
{
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"authentication_method": "client_secret",
"subscription_ids": ["sub-1", "sub-2"]
}
Provide SECURELY these values to CXM to complete onboarding.
To share sensitive data between peers, internally or externally, be cautious to avoid emails, chat, and even storing this data in files.
Copy paste the sensitive data into https://onetimesecret.com/, https://pastebin.com/, or any secure equivalent, with a password and a short expiration date, then encrypt your data, and share the link with your peer (giving him the password on another comm channel is also always better). Your data will be destroy as soon as it is received and viewed.
Configuration Options
Access All Subscriptions
Grant CXM access to all subscriptions in your tenant:
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# Grant access to all subscriptions
all_subscriptions = true
# Optionally exclude specific subscriptions
subscription_exclusions = [
"00000000-0000-0000-0000-000000000001", # Sandbox
"00000000-0000-0000-0000-000000000002", # Dev
]
# ... storage configuration ...
}
Specific Subscriptions Only
Grant access to a specific list of subscriptions:
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# List specific subscriptions
subscription_ids = [
"00000000-0000-0000-0000-000000000001",
"00000000-0000-0000-0000-000000000002",
]
# ... storage configuration ...
}
Management Group Level Access
For large organizations, grant access at the management group level:
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# Grant access at management group level
use_management_group = true
management_group_id = "00000000-0000-0000-0000-000000000000"
# ... storage configuration ...
}
Find your management group ID:
az account management-group list --query "[].{name:name, id:id}" -o table
Disable Optional Features
You can disable features you don't need:
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# Disable specific features
enable_asset_discovery = true # Required for infrastructure analysis
enable_billing_export_access = true # Required for cost analysis
enable_activity_log_access = false # Optional: change tracking
enable_directory_reader = false # Optional: Azure AD user/group reading
# Only need billing storage if billing is enabled
billing_export_storage_account_name = "mycompanycostexports"
billing_export_storage_resource_group = "finops-rg"
}
Custom Naming
Customize resource names:
module "cxm_integration" {
source = "github.com/cxmlabs/terraform-azure-cxm-integration"
# Custom naming
prefix = "cxm" # Prefix for role names
application_name = "cxm-asset-crawler" # Azure AD app display name
# ... rest of configuration ...
}
All Configuration Variables
| Variable | Description | Default |
|---|---|---|
enable_asset_discovery | Enable Reader roles for infrastructure scanning | true |
enable_billing_export_access | Enable access to Cost Management exports | true |
enable_activity_log_access | Enable access to Activity Logs | true |
enable_directory_reader | Enable Azure AD Directory Reader role | true |
all_subscriptions | Grant access to all tenant subscriptions | false |
subscription_ids | List of specific subscription IDs | [] |
subscription_exclusions | Subscriptions to exclude (with all_subscriptions) | [] |
use_management_group | Grant access at management group level | false |
management_group_id | Management group ID | "" |
billing_export_storage_account_name | Storage account for cost exports | "" |
billing_export_storage_resource_group | Resource group for cost storage | "" |
activity_log_storage_account_name | Storage account for activity logs | "" |
activity_log_storage_resource_group | Resource group for activity log storage | "" |
prefix | Prefix for resource names | "cxm" |
application_name | Azure AD Application display name | "cxm-asset-crawler" |
tags | Tags for created resources | {} |
Outputs
| Output | Description |
|---|---|
cxm_onboarding_values | All values needed for CXM onboarding (sensitive) |
tenant_id | Azure AD Tenant ID |
client_id | Application (Client) ID |
client_secret | Client secret for authentication |
subscription_ids | List of enabled subscription IDs |
features_enabled | Summary of enabled features |
Troubleshooting
"Insufficient privileges to complete the operation"
This error occurs when assigning the Directory Reader role without Azure AD admin privileges.
Solution: Either:
- Run Terraform with an Azure AD admin account, or
- Set
enable_directory_reader = falseand assign the role manually later
"Storage account not found"
The specified storage account doesn't exist or isn't accessible.
Solution: Verify the storage account name and resource group:
az storage account show --name mystorageaccount --resource-group my-rg
"Management group not found"
The management group ID is incorrect.
Solution: List available management groups:
az account management-group list
"AuthorizationFailed"
The logged-in user lacks permission to create role assignments.
Solution: Ensure your account has Owner or User Access Administrator role on the target subscriptions.
Next Steps
After deployment:
- Copy the output values from
terraform output -json cxm_onboarding_values - Provide these values to CXM through the onboarding form or API
- CXM will validate the connection and begin data collection