Home Azure Billing Role Assignments
Post
Cancel

Azure Billing Role Assignments

Introduction

We want to have a system user that is able to provision subscriptions as part of our vending machine. There’s currently no user interface to do this, only some preview apis from 2019.

The code.

[CmdletBinding()]
param (
    [Parameter(Mandatory)]
    [string]
    $IdentityId,

    # Role Defintion
    [Parameter(Mandatory)]
    [string]
    [ValidateSet('SubscriptionCreator', 'DepartmentReader', 'EA purchaser', 'EnrollmentReader')]
    $BillingRole
)

function Get-AzureBillingAccounts {
    [CmdletBinding()]
    param (
        # Headers
        [Parameter(Mandatory)]
        $Headers
    )
    $data = (Invoke-RestMethod -Method Get -Uri "https://management.azure.com/providers/Microsoft.Billing/billingAccounts?api-version=2019-10-01-preview" -Headers $Headers).value | 
    Select-Object Name, @{'N' = 'accountStatus'; 'E' = { $_.properties.accountStatus } }, @{'N' = 'agreementType'; 'E' = { $_.properties.agreementType } }, @{'N' = 'displayName'; 'E' = { $_.properties.displayName } }, Id
    Write-Output $data
}

function Get-AzureEnrollmentAccounts {
    [CmdletBinding()]
    param (
        # Billing Account Friendly Name
        [Parameter()]
        [string]
        $BillingAccountName,

        # Headers
        [Parameter(Mandatory)]
        $Headers
    )
    
    $data = (Invoke-RestMethod -Method Get -Uri "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts?api-version=2019-10-01-preview" -Headers $Headers).value |
    Select-Object Name, @{'N' = 'AccountName'; 'E' = { $_.properties.accountName } }, @{'N' = 'CostCenter'; 'E' = { $_.properties.costCenter } }, @{'N' = 'DisplayName'; 'E' = { $_.properties.displayName } }, @{'N' = 'Status'; 'E' = { $_.properties.status } }, @{'N' = 'StartDate'; 'E' = { $_.Properties.startDate } }, @{'N' = 'EndDate'; 'E' = { $_.Properties.endDate } }
    Write-Output $data
}

function New-AzureBillingRoleAssignment {
    [CmdletBinding()]
    param (
        # Headers
        [Parameter(Mandatory)]
        $Headers,

        # Role Defintion
        [Parameter(Mandatory)]
        [string]
        [ValidateSet('SubscriptionCreator', 'DepartmentReader', 'EA purchaser', 'EnrollmentReader')]
        $BillingRole,

        # Identity
        [Parameter(Mandatory)]
        [string]
        $IdentityId,

        # Billing Account Name
        [Parameter(Mandatory)]
        [string]
        $BillingAccountName,

        # Enrollment Account Id
        [Parameter(Mandatory)]
        [string]
        $EnrollmentAccountName,

        # Tenant Id
        [Parameter(Mandatory)]
        [string]
        $TenantId
    )
    
    begin {
        # 'SubscriptionCreator' = 'a0bcee42-bf30-4d1b-926a-48d21664ef71'
        # 'DepartmentReader' = 'db609904-a47f-4794-9be8-9bd86fbffd8a'
        # 'EA purchaser' = 'da6647fb-7651-49ee-be91-c43c4877f0c4'
        # 'EnrollmentReader' = '24f8edb6-1668-4659-b5e2-40bb5f3a7d7e'
        # Reference; https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals#permissions-that-can-be-assigned-to-the-service-principal

        $BillingRoles = @{
            'SubscriptionCreator' = 'a0bcee42-bf30-4d1b-926a-48d21664ef71'
            'DepartmentReader'    = 'db609904-a47f-4794-9be8-9bd86fbffd8a'
            'EA purchaser'        = 'da6647fb-7651-49ee-be91-c43c4877f0c4'
            'EnrollmentReader'    = '24f8edb6-1668-4659-b5e2-40bb5f3a7d7e'
        }
        $BillingRoleId = $BillingRoles[$BillingRole]
    }
    
    process {
        # Generate a unique role assignment id.
        # https://learn.microsoft.com/en-us/azure/cost-management-billing/manage/assign-roles-azure-service-principals#assign-enrollment-account-role-permission-to-the-service-principal
        $UniqueRoleAssignmentId = (New-guid).Guid

        # Create a Role Assignment for our Workload Identity.
        $RoleAssignmentUrl = "https://management.azure.com/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts/$EnrollmentAccountName/billingRoleAssignments/$UniqueRoleAssignmentId`?api-version=2019-10-01-preview"
        $Body = @{
            "properties" = @{
                "principalId"       = "$IdentityId"
                "principalTenantId" = "$TenantId"
                "roleDefinitionId"  = "/providers/Microsoft.Billing/billingAccounts/$BillingAccountName/enrollmentAccounts/$EnrollmentAccountName/billingRoleDefinitions/$BillingRoleId"
            }
        } | ConvertTo-Json -depth 100

        try {
            Invoke-RestMethod -Method Put -Uri $RoleAssignmentUrl -Headers $Headers -Body $Body
            Write-verbose "Successfully create the role assignment." -Verbose
        }
        catch {
            throw
        }
    }
}

# The script requires the Az PowerShell Module
if (! (Get-Module 'Az' -ListAvailable)) {
    Throw 'Please install the Az PowerShell Module "https://www.powershellgallery.com/packages/Az"'
}

# Check if the user is already logged in to the Az PowerShell Module.
if (! (Get-AzContext -ListAvailable)) {
    # User is not logged into Az PowerShell Module
    Write-verbose "Please login to the Az PowerShell Module, this is used for confirming the existance of the Application Id and obtain an Azure Access Token" -Verbose
    Login-AzAccount
}

# Use the Access Token provided by Az PowerShell Module and create a header containing it.
$token = $(Get-AzAccessToken).Token
$headers = @{'Authorization' = "Bearer $Token"; 'Content-Type' = 'application/json' }

# Get Tenant Id
$TenantId = (get-azcontext).tenant.id

# Get Billing Account
$BillingAccount = Get-AzureBillingAccounts -Headers $headers | Out-GridView -PassThru
$BillingAccountName = $BillingAccount.Name

# Get Enrollment Account
$EnrollmentAccount = Get-AzureEnrollmentAccounts -BillingAccountName $BillingAccountName -Headers $headers | Out-GridView -PassThru

$Params = @{
    'Headers' = $headers 
    'BillingRole' = $BillingRole
    'IdentityId' = $IdentityId 
    'BillingAccountName' = $BillingAccountName 
    'EnrollmentAccountName' = $EnrollmentAccount.Name
    'TenantId' = $TenantId
}
New-AzureBillingRoleAssignment @Params
This post is licensed under CC BY 4.0 by the author.

Nordic Integration Summit

-