Instructions
Overview
This article outlines the steps to integrate your Azure tenant and its subscriptions with Upwind. Choose the approach that matches your role and requirements:
- Global Admin - Full Tenant: Complete tenant integration with all subscriptions and automatic discovery of new ones
 - Global Admin - Limited Scope: Selective integration of specific subscriptions using scoping parameters
 - Subscription Owner: Integration using pre-created application registrations for users without Global Admin privileges
 
Integration Approaches
Choose the approach that matches your role and access level:
Approach 1: Global Admin - Full Tenant Integration
Who this is for: Global Administrators who want to integrate all subscriptions in the tenant with automatic discovery of new subscriptions. Application Administrators and other privileged users can also use this approach if a Global Administrator grants them Owner role over the root tenant management group.
Prerequisites
Option A: Global Administrator
- Azure Global Administrator role
 - Ability to elevate access to all Azure resources
 
Option B: Application Administrator (or other privileged users)
- Application Administrator role (or equivalent role with app registration permissions)
 - Owner role over root tenant management group (granted by Global Administrator)
 - No need for elevated access - the Owner role provides necessary permissions
 
Required Permissions Setup
Option 1: Self-Elevate Access (Recommended)
Use the "elevate access" feature to temporarily grant yourself User Access Administrator role at the root scope:

Option 2: Request Owner Role Assignment
Have someone with appropriate permissions assign you the Owner role over the root tenant management group.
After gaining elevated access, you should be able to view the root tenant management group in Azure Portal:

Integration Steps
- Elevate Access: Use one of the options above to gain tenant-wide permissions
 - Run Terraform: Execute the Terraform configuration (no scoping variables needed)
 - Grant Admin Consent: A Global Administrator must provide consent for the Microsoft Graph API permissions requested by Terraform
 - Revoke Elevated Access: Remove the elevated permissions after successful deployment
 - Optional: Assign yourself Owner role for ongoing management, then revoke elevated access
 
For automated Terraform operations (Terraform Enterprise, CI/CD pipelines), you can reduce the service principal's permissions after initial deployment:
- After initial apply: Downgrade the Terraform runner's service principal to Reader role over the root tenant management group
 - For routine operations: Reader permissions allow subsequent 
terraform applyoperations as long as no new RBAC changes are needed - For structural changes: Temporarily elevate the service principal back to Owner when making changes that affect tenant-level role assignments or permissions
 
This approach balances security best practices with operational requirements for automated infrastructure management.
Note: If using App Registration authentication for Terraform, see the App Registration Authentication prerequisite.
Terraform Configuration
Use the standard configuration without scoping variables:
locals {
  azure_tenant_id                    = "your-azure-tenant-id"
  azure_orchestrator_subscription_id = "your-azure-orchestrator-subscription-id"
}
provider "azurerm" {
  # For detailed instructions on configuring the Azure provider, please refer to:
  # https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
  subscription_id = local.azure_orchestrator_subscription_id
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
    key_vault {
      recover_soft_deleted_keys    = true
      recover_soft_deleted_secrets = true
    }
  }
}
provider "azuread" {
  tenant_id = local.azure_tenant_id
}
module "upwind_integration_azure_onboarding" {
    source = "upwindsecurity/onboarding/azurerm//modules/tenant"
    # Upwind Credentials
    upwind_client_id     = "your-unique-upwind-client-id"
    upwind_client_secret = "your-unique-upwind-client-secret"
    # Cloud Scanner Credentials
    scanner_client_id     = "your-unique-upwind-scanner-id"
    scanner_client_secret = "your-unique-upwind-scanner-secret"
    # Upwind Details
    upwind_organization_id = "your-upwind-organization-id"
    # Azure Details
    azure_tenant_id = local.azure_tenant_id
    azure_orchestrator_subscription = local.azure_orchestrator_subscription_id
    # Optional customization
    resource_suffix = "upwind"
    azure_cloudscanner_location = "eastus"
}
Approach 2: Global Admin - Limited Scope Integration
Who this is for: Global Administrators who want to integrate only specific subscriptions using scoping parameters.
Prerequisites
- Azure Global Administrator role
 - Application Developer role (minimum) or Application Administrator role for creating app registrations
 - Owner role in the subscriptions you want to include in scope
 
Integration Steps
- No elevated access required - you only need Owner permissions on target subscriptions
 - Configure scoping variables in Terraform to limit integration scope
 - Run Terraform with the scoped configuration
 - Grant Admin Consent: A Global Administrator must provide consent for the Microsoft Graph API permissions requested by Terraform
 
Terraform Configuration
Use scoping variables to limit integration to specific subscriptions:
locals {
  azure_tenant_id                    = "your-azure-tenant-id"
  azure_orchestrator_subscription_id = "your-azure-orchestrator-subscription-id"
}
provider "azurerm" {
  # For detailed instructions on configuring the Azure provider, please refer to:
  # https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
  subscription_id = local.azure_orchestrator_subscription_id
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
    key_vault {
      recover_soft_deleted_keys    = true
      recover_soft_deleted_secrets = true
    }
  }
}
provider "azuread" {
  tenant_id = local.azure_tenant_id
}
module "upwind_integration_azure_onboarding" {
    source = "upwindsecurity/onboarding/azurerm//modules/tenant"
    # Upwind Credentials
    upwind_client_id     = "your-unique-upwind-client-id"
    upwind_client_secret = "your-unique-upwind-client-secret"
    # Cloud Scanner Credentials
    scanner_client_id     = "your-unique-upwind-scanner-id"
    scanner_client_secret = "your-unique-upwind-scanner-secret"
    # Upwind Details
    upwind_organization_id = "your-upwind-organization-id"
    # Azure Details
    azure_tenant_id = local.azure_tenant_id
    azure_orchestrator_subscription = local.azure_orchestrator_subscription_id
    # Subscription Scoping - Include specific subscriptions
    cloudapi_include_subscriptions = [
        "subscription-id-1",
        "subscription-id-2",
        "your-orchestrator-subscription-id"
    ]
    # Cloud Scanner will only scan the subscriptions specified here
    cloudscanner_include_subscriptions = [
        "subscription-id-1"
    ]
    # Optional customization
    resource_suffix = "upwind"
    azure_cloudscanner_location = "eastus"
}
- Do not mix include and exclude: Use either include OR exclude variables, never both together
 - Cloud API superset requirement: Subscriptions scoped for Cloud API must be a superset of subscriptions scoped for Cloud Scanner
 - Orchestrator subscription requirement: The orchestrator subscription must always be included in the Cloud API scope
 
Approach 3: Subscription Owner - Pre-Created App Registration
Who this is for: Users who own specific subscriptions but don't have Global Administrator privileges or permissions to create application registrations.
This approach uses a pre-created App Registration that Upwind will use for authentication to access your Azure resources. This is different from an App Registration used to run Terraform itself. If you're using an App Registration to run Terraform (e.g., in CI/CD), see the note in Approach 1 about required Entra roles for the Terraform runner.
Prerequisites
- Owner role in the subscriptions you want to integrate
 - Pre-created application registration (created by your IT admin)
 - Client secret for the application registration
 - Required Microsoft Graph API permissions granted to the application
 
Required Application Setup (Done by IT Admin)
Your IT administrator needs to create an application registration with:
- Application Registration: Create a new app registration in Entra ID
 - Owner Assignment: Make you an owner of the application registration (so you can configure it)
 - Client Secret: Generate a client secret for the application (or allow you to generate it as owner)
 - API Permissions: Grant the following Microsoft Graph permissions:
User.Read.AllGroup.Read.AllRoleManagement.Read.AllDirectory.Read.AllPolicy.Read.AllUserAuthenticationMethod.Read.All
 - Admin Consent: A Global Administrator must provide consent for these permissions
 
Integration Steps
- Obtain credentials from your IT administrator
 - Configure Terraform with the pre-created application details
 - Run Terraform with subscription scoping
 
Terraform Configuration
Use the pre-created application registration:
locals {
  azure_tenant_id                    = "your-azure-tenant-id"
  azure_orchestrator_subscription_id = "your-azure-orchestrator-subscription-id"
}
provider "azurerm" {
  # For detailed instructions on configuring the Azure provider, please refer to:
  # https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs
  subscription_id = local.azure_orchestrator_subscription_id
  features {
    resource_group {
      prevent_deletion_if_contains_resources = false
    }
    key_vault {
      recover_soft_deleted_keys    = true
      recover_soft_deleted_secrets = true
    }
  }
}
provider "azuread" {
  tenant_id = local.azure_tenant_id
}
module "upwind_integration_azure_onboarding" {
    source = "upwindsecurity/onboarding/azurerm//modules/tenant"
    # Upwind Credentials
    upwind_client_id     = "your-unique-upwind-client-id"
    upwind_client_secret = "your-unique-upwind-client-secret"
    # Cloud Scanner Credentials
    scanner_client_id     = "your-unique-upwind-scanner-id"
    scanner_client_secret = "your-unique-upwind-scanner-secret"
    # Upwind Details
    upwind_organization_id = "your-upwind-organization-id"
    # Azure Details
    azure_tenant_id = local.azure_tenant_id
    azure_orchestrator_subscription = local.azure_orchestrator_subscription_id
    # Pre-created Application Registration
    azure_application_client_id = "your-pre-created-app-client-id"
    azure_application_client_secret = "your-pre-created-app-client-secret"
    # Subscription Scoping - Include only your subscriptions
    cloudapi_include_subscriptions = [
        "your-subscription-id-1",
        "your-subscription-id-2",
        "your-orchestrator-subscription-id"
    ]
    cloudscanner_include_subscriptions = [
        "your-subscription-id-1"
    ]
    # Optional customization
    resource_suffix = "upwind"
    azure_cloudscanner_location = "eastus"
}
Getting Started
- Log in to the Upwind Management Console
 - Select the + (plus) symbol at the top of the screen and select Connect cloud account
 - Choose Azure, and from there Connect Azure Tenant
 - Follow the steps for your chosen approach above
 
Final Configuration
After running Terraform successfully, complete the integration in the Upwind Management Console:
- Define Subscription Scope: Choose which subscriptions should be audited using Cloud APIs or scanned using Upwind Cloud Scanners
 - Enable Auto-Connect (optional): Automatically connect new subscriptions as they're created
 - Test Connectivity: Click Test & Save to verify the connection
 
Cloud Scanner scopes are dependent on the Cloud API scope. If you enable the Cloud Scanner scope, the Cloud API scope must also be enabled.
Unsupported Regions
Some regions are not yet supported for Upwind Cloud Scanner deployments, as Azure Container Jobs are not available in those regions:
- westindia
 - koreasouth
 - israelcentral
 - mexicocentral
 - newzealandnorth
 - qatarcentral
 
Troubleshooting
If you encounter issues during deployment or operation, consult the Troubleshooting guide for solutions and best practices.
Resources Created
Azure Resource Group
A resource group named upwind-cs-rg-{orgId} is created containing:
Azure Key Vault
- Contains secrets for scanner authentication (client ID and client secret)
 
Managed Identities
Three managed identities are created:
- 
VMSS Identity (
upwind-cs-vmss-identity-{orgId})- Assigned to virtual machine scale sets
 - Manages snapshots and disks
 - Has read and snapshot access across subscriptions
 - Has Key Vault Secrets User access
 
 - 
Scaler Function Identity (
upwind-cs-scaler-function-identity-{orgId})- Assigned to container app jobs
 - Manages VMSS scaling
 - Manages disks and snapshots cleanup
 - Has Key Vault Secrets User access
 
 - 
Disk Encryption Identity (
upwind-cs-disk-encryption-identity-{orgId})- Assigned to disk encryption sets
 - Has Key Vault Crypto Service Encryption User access
 
 
RBAC Configuration
Service Principal
Tenant-wide roles:
- Reader
 - Key Vault Reader
 - Security Reader
 - Cosmos DB Account Reader Role
 - Backup Reader
 - Log Analytics Reader
 - Custom role: 
upwindsecurity-{random-hex} 
VMSS Managed Identity
Tenant-wide roles:
- Storage Blob Data Reader
 - Custom role: 
CloudScannerTargetRole-{suffix}-{managementGroup} 
Scaler Managed Identity
Orchestrator subscription role:
- Custom role: 
CloudScannerScalerRole-{suffix} 
Disk Encryption Set Managed Identity
Role:
- Key Vault Crypto Service Encryption User
 
Troubleshooting
If you encounter issues during deployment or operation, consult the Troubleshooting guide for solutions and best practices.