2

I am fetching a subscription's Secure Score using the Microsoft Azure Security Center (ASC) Management Client Library. All operations in the library state that

You should not instantiate directly this class, but create a Client instance that will create it for you and attach it as attribute.

Therefore, I am creating a SecurityCenter client with the following specification:

SecurityCenter(credentials, subscription_id, asc_location, base_url=None)

However, it seems to me like the only way to get the asc_location information properly is to use the SecurityCenter client to fetch it... The spec says the same as the quote above, You should not instantiate.... So I am stuck not being able to create the client because I need the ASC location to do so, and I need to create the client to get the ASC locations.

The documentation mentions

The location where ASC stores the data of the subscription. can be retrieved from Get locations

Googling and searching through the Python SDK docs for this "Get locations" gives me nothing (else than the REST API). Have I missed something? Are we supposed to hard-code the location like in this SO post or this GitHub issue from the SDK repository?

maritio_o
  • 117
  • 10

3 Answers3

1

As offical API reference list locations indicates:

The location of the responsible ASC of the specific subscription (home region). For each subscription there is only one responsible location.

It will not change, so you can hardcode this value if you already know the value of asc_location of your subscription.

But each subscription may have different asc_location values(my 2 Azure subscriptions have different asc_location value). So if you have a lot of Azure subscriptions, you can just query asc_location by API (as far as I know, this is the only way I can find to do this)and then use SDK to get the Secure Score, try the code below:

from azure.mgmt.security import SecurityCenter
from azure.identity import ClientSecretCredential
import requests
from requests.api import head, request 

TENANT_ID = ''
CLIENT = ''
KEY = ''
subscription_id= ''
getLocationsURL = "https://management.azure.com/subscriptions/"+subscription_id+"/providers/Microsoft.Security/locations?api-version=2015-06-01-preview"


credentials = ClientSecretCredential(
    client_id = CLIENT,
    client_secret = KEY,
    tenant_id = TENANT_ID
)

#request for asc_location for a subscription
azure_access_token = credentials.get_token('https://management.azure.com/.default')
r = requests.get(getLocationsURL,headers={"Authorization":"Bearer " +  azure_access_token.token}).json()
location = r['value'][0]['name']
print("location:" + location)

client = SecurityCenter(credentials, subscription_id, asc_location=location)
for score in client.secure_scores.list():
    print(score)

Result: enter image description here enter image description here

Stanley Gong
  • 11,522
  • 1
  • 8
  • 16
  • I hoped to avoid querying the API to get the subscription's ASC location. I was thinking of this as the solution if there is no other way. Do you think the Python SDK doc explanation `can be retrieved from Get locations` refers to using the REST API? – maritio_o Jan 08 '21 at 08:25
  • @maritio_o, if you know each of your subscription's ASC location, there is no need to query API to get it anymore, you can just hardcode or config it directly. The way that query API for ASC location just in case you have a lot of Azure subscriptions. – Stanley Gong Jan 08 '21 at 08:31
  • Hi @maritio_o, if my post is helpful, could you please accept it as an answer? – Stanley Gong Jan 10 '21 at 08:22
  • Apologies @stanley-gong. It didn't answer my question, so I waited over the weekend to see if it would be answered. Your answer is a workaround for my question as the question asks for a way to solve it using the SDK, not the API. If you are sure that using the API is the only way, feel free to update your answer and I will accept it :) – maritio_o Jan 11 '21 at 09:17
  • @maritio_o I have updated my answer, if you want to get the value of asc_location, using API is the only way as if you not know its value, you can't instantiate a security center client to call functions. – Stanley Gong Jan 12 '21 at 01:39
  • Thanks, Stanley. I appreciate your help^_^ – maritio_o Jan 12 '21 at 06:37
0

I recently came across this problem.

Based on my observation, I can use whatever location under my subscription to initiate SecurityCenter client. Then later client.locations.list() gives me exactly one ASC location.

# Any of SubscriptionClient.subscriptions.list_locations will do
location = 'eastasia'

client = SecurityCenter(
            credential, my_subscription_id,
            asc_location=location
        )

data = client.locations.list().next().as_dict()
pprint(f"Asc location: {data}")

In my case, the it's always westcentralus regardless my input was eastasia.

Note that you'll get exception if you use get instead of list

data = client.locations.get().as_dict()
pprint(f"Asc location: {data}")
# azure.core.exceptions.ResourceNotFoundError: (ResourceNotFound) Could not find location 'eastasia'

So what i did was a bit awkward,

  1. create a SecurityCenter client using a location under my subscription
  2. client.locations.list() to get ASC location
  3. Use the retrieved ASC location to create SecurityCenter client again.
cfchou
  • 1,239
  • 1
  • 11
  • 25
0

I ran into this recently too, and initially did something based on @stanley-gong's answer. But it felt a bit awkward, and I checked to see how the Azure CLI does it. I noticed that they hardcode a value for asc_location:

def _cf_security(cli_ctx, **_):
    from azure.cli.core.commands.client_factory import get_mgmt_service_client
    from azure.mgmt.security import SecurityCenter


    return get_mgmt_service_client(cli_ctx, SecurityCenter, asc_location="centralus")

And the PR implementing that provides some more context:

we have a task to remove the asc_location from the initialization of the clients. currently we hide the asc_location usage from the user. centralus is a just arbitrary value and is our most common region.

So... maybe the dance of double-initializing a client or pulling a subscription's home region isn't buying us anything?

ajk
  • 4,473
  • 2
  • 19
  • 24