DEV Community

Cover image for Eh HELP!? Creating & Sorting Chaos in Azure Subscriptions Automation
Adron Hall
Adron Hall

Posted on

Eh HELP!? Creating & Sorting Chaos in Azure Subscriptions Automation

I'm trying to accomplish a simple task, outlined in the docs for completing this simple task of creating an Azure subscription with the Azure REST API. Currently I'm using Postman and have gone through these steps that Jon Gallant put together - excellent video and blog entry on the topic - and have had success with connecting via service principal, getting an AAD Token and pulling a list of resource groups. Which in my particular video below I put together, I show all of this working and the singular resource group I get returned from Azure.

Again though, I'm trying to create a subscription. I have ownership permissions in active directory and created the service principal I'm using with that user account. Is there another place to put this? Is there some permissions or something particular I'm supposed to assign to the service principal?

Then I Thought

Oh, it seemed I needed to add the permissions, maybe they weren't inherited from the user who creates the service principal or just additional ones were needed. I read a bit more in the doc and noted this:

An existing Owner of the Enrollment Account can grant you access. Similarly, if you want to use a service principal to create an EA subscription, you must grant that service principal the ability to create subscriptions.

The part "you must grant that service principal the ability to create subscriptions" and I thought, aha, got it! So I dig this. Using the az CLI issuing this command as detailed in the docs.

I checked which accounts I have access to with

az billing enrollment-account list

and I got this response.

[
  {
    "id": "/providers/Microsoft.Billing/enrollmentAccounts/7760268a-blah-blah-this-secretdf64c9",
    "name": "7760268a-blah-blah-this-secretdf64c9",
    "principalName": "azure-test@company.com",
    "type": "Microsoft.Billing/enrollmentAccounts"
  }
]

Then I ran the command to add the permissions using the id/name/princpal name available in the previous results.

az role assignment create --role Owner --assignee-object-id <userObjectId> --scope /providers/Microsoft.Billing/enrollmentAccounts/<enrollmentAccountObjectId>

I filled in the parameters, in spite of their confusing nature to not be mapped by name to the things I'm filling them in with. i.e. The keys in the list: id, name, principalName, and type don't map to userObjectId, or enrollmentAccountObjectId. The response I got back with what I entered into the command is confusing, to say the least.

{
  "canDelegate": null,
  "id": "/providers/Microsoft.Billing/enrollmentAccounts/7760268a-blah-blah-this-secretdf64c9/providers/Microsoft.Authorization/roleAssignments/9d682424-blah-blah-this-secretac9f92",
  "name": "9d682424-blah-blah-this-secretac9f92",
  "principalId": "47f9be37-blah-blah-this-secret2c1566",
  "principalName": "adron.hall@company.com",
  "principalType": "User",
  "roleDefinitionId": "/providers/Microsoft.Authorization/roleDefinitions/8e3af657-blah-blah-this-secretbcb635",
  "roleDefinitionName": "Owner",
  "scope": "/providers/Microsoft.Billing/enrollmentAccounts/7760268a-blah-blah-this-secretdf64c9",
  "type": "Microsoft.Authorization/roleAssignments"
}

The first thing I noticed is that this principal name is the email of the other account, not associated (theoretically) with the service principal that executed this request. Oh well I figured this was what it is supposed to be, but with canDelegate set to null, and nothing that really shows a "successfully added permissions" I wasn't sure if this is what I should have expected. I pushed forward anyway.

Next step is to see if I can create a subscription with this newly assigned (theoretically) power for this service principal! Charge! I executed the following using the Azure CLI first.

az account create --offer-type "MS-AZR-0017P" --display-name "Dev Team Subscription" --enrollment-account-object-id "<enrollmentAccountObjectId>" --owner-object-id "<userObjectId>","<servicePrincipalObjectId>"

This is another part of the confusing array of things we have to keep track of, let's discuss. The --offer-type "MS-AZR-0017P" is highly arbitrary, but I get it, you just use one of the options from the docs. So I'm sticking with "MS-AZR-0017P" as shown. The next thing is the display name, cool I'll just make up one.

Now time for the more confusing bits, first up is the enrollmentAccountObjectId. Per the enrollment account item above that I pulled, I'm guessing this is either this value "/providers/Microsoft.Billing/enrollmentAccounts/7760268a-blah-blah-this-secretdf64c9" which has a key of id or maybe it's just the id within the id, the UUID segment 7760268a-blah-blah-this-secretdf64c9? I'm not sure, but I'll start with just 7760268a-blah-blah-this-secretdf64c9 as that seems to be the running case, mostly, sometimes, throughout the CLI use.

Now the userObjectId which I'll guess is the item in the enrollment account keyed name. Not that name and userObjectId actually map but they're both UUIDs so that seems to sync based on the other command above, sort of. Then finally I'll need the servicePrincipalObjectId, which now what is the easiest way to get that? Oh, I remembered that this is usually keyed as an appId not a service principal id, so I ran the following command, and have added some jq magic to make it easier to see just the appId.

az ad sp list --display-name azure-astra | jq '.[0] | {appId}'

Using that for the service principal object ID I executed the now finalized command and got this response!

az account: 'create' is not in the 'az account' command group. See 'az account --help'. If the command is from an extension, please make sure the corresponding extension is installed. To learn more about extensions, please visit https://docs.microsoft.com/en-us/cli/azure/azure-cli-extensions-overview

Ok, that's definitely not what I expected. So now I need an extension to create this thing. Alright, check. I read that doc and pulled up a list of extensions.

az extension list-available --output table

That gave me a big ole' list to choose from. I went through and read them, and decided that the subscription extension was probably what I wanted. I ran az extension add --name subscription and as a response got the following.

The installed extension 'subscription' is in preview.

This seems to make sense, since the subscription API/CLI/REST end points are labeled as in preview. Ok, moving forward. Time to rerun the command again.

az account create --offer-type "MS-AZR-0017P" --display-name "New Magical Subscription" --enrollment-account-object-id "7760268a-blah-blah-this-secretdf64c9" --owner-object-id "7760268a-blah-blah-this-secretdf64c9"

Suspense ensues. I see the CLI message.

 - Running ..

This time the response, after about ~20 seconds comes back as.

{- Finished ..
  "subscriptionLink": "/subscriptions/2afc30a5-8c4a-49cd-ab8e-d05d376e8ef0"
}

Ok, so it worked with the CLI. It seems. Let's get it to work with the REST API now. First things first, we need to confirm that the accounts are accessible via the REST API that we want to add the subscription to.

That includes a GET requests against the URI https://management.azure.com/providers/Microsoft.Billing/enrollmentAccounts?api-version=2018-03-01-preview. Making that request, using the token created as above in Jon Gallant's email, gives me an empty array JSON response.

So I'm still stuck. What is it that needs to be done to fix this service principal so that I can use the REST API to create a subscription? To note, I need to use the API, not the CLI for what I'm working on building. Which it is nice that the CLI completed the action but it clearly is working in a different way than the API requires.

Help me Obi Wan Kenobi!

Top comments (2)

Collapse
 
adron profile image
Adron Hall

...still stuck today. Will post an update when I get this resolved!

Collapse
 
adron profile image
Adron Hall

To note, the solution, after working with the Azure dev team responsible for the API's themselves we were able to narrow it down and determine that an object ID was needed in place of another entity ID, which needless to say is very confusing.

So be sure, if you're working with Azure automation, to try all the ID's in trying to get things sorted out!