Skip to main content

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:

InformationWhere to FindExample
Billing Export Storage AccountCost Management > Exportsmycompanycostexports
Billing Export Resource GroupSame location as storage accountfinops-rg
Activity Log Storage AccountMonitor > Diagnostic Settingsmycompanyactivitylogs
Activity Log Resource GroupSame location as storage accountlogging-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.

Share securely sensitive data with your peers

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

VariableDescriptionDefault
enable_asset_discoveryEnable Reader roles for infrastructure scanningtrue
enable_billing_export_accessEnable access to Cost Management exportstrue
enable_activity_log_accessEnable access to Activity Logstrue
enable_directory_readerEnable Azure AD Directory Reader roletrue
all_subscriptionsGrant access to all tenant subscriptionsfalse
subscription_idsList of specific subscription IDs[]
subscription_exclusionsSubscriptions to exclude (with all_subscriptions)[]
use_management_groupGrant access at management group levelfalse
management_group_idManagement group ID""
billing_export_storage_account_nameStorage account for cost exports""
billing_export_storage_resource_groupResource group for cost storage""
activity_log_storage_account_nameStorage account for activity logs""
activity_log_storage_resource_groupResource group for activity log storage""
prefixPrefix for resource names"cxm"
application_nameAzure AD Application display name"cxm-asset-crawler"
tagsTags for created resources{}

Outputs

OutputDescription
cxm_onboarding_valuesAll values needed for CXM onboarding (sensitive)
tenant_idAzure AD Tenant ID
client_idApplication (Client) ID
client_secretClient secret for authentication
subscription_idsList of enabled subscription IDs
features_enabledSummary 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 = false and 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:

  1. Copy the output values from terraform output -json cxm_onboarding_values
  2. Provide these values to CXM through the onboarding form or API
  3. CXM will validate the connection and begin data collection