How to authenticate Python interactively to Microsoft Azure

This time I would like to explain how we can authenticate interactively to Azure resources from interactive Python code execution like Jupyter notebooks.

Running a static Python app that utilizes Azure resources, the most convenient way to authenticate to Azure would probably be using a Service Principal. Or if the App is hosted on Azure environment that would be an Azure Managed Identity. These apps act on behalf of the user principal that it contains and is programmed to use it.
Any user that executes the code simply has permissions on the resources the Service Principal has access to….

Bad practise

But while running python code on Jupyter notebooks you are running an interactive session (from your own machine or docker instance). This would mean that code is executed on your users behalf. You could utilize a Service Principal like many code examples will do. But you might not want to haull credentials (service principals) arround. This is a serious security concern. Like I said before any user that will have access to the Service Principal secret will have access to the permissions assigned to it. Also, using them in Jupyter would mean having secrets in plain text, which is bad practise number one!

But for you it doesn’t have to be this way, there are other ways and those aren’t described in a lot of the code-examples.

While most code-examples for consuming Azure resources, utilize Service principals and their object ids and secrets or managed identities. These are examples for scripts or apps and running autonomiously. It might need a database for storing the user database. In that case any user that would like to use it would have to authenticate itself agains this user database. That is their use case…

An example can be found here: https://docs.microsoft.com/en-us/azure/python/python-sdk-azure-authenticate

Interactively

But within Jupyter we are interactively running code that would need access to resources on behalf of the user.

Like KQLMagic?

As I descibed in my previous blog how you could authenticate KQLmagic to a Log analytics workspace using devicecode. This devicecode method is more preferable than keeping secrets in the code and also the fact that in some point in time you need to replace them, copy, paste credentials???  awfull practise!

So the first Azure resource that I would like to explain, on how to utilize securely,  will be Azure Keyvault!

With this skill under our belts things are starting to get more secure.

Two Solutions!?

In fact there are multiple solutions! I will descibe 2 of them and their use cases. First we will setup an Azure keyvault then we will build 2 code examples that will utilise the keyvault.

Setup

To help you reproduce every step I will include instructions to deploy a keyvault and create a secret. So let’s start with that.

Create keyvault

You will need at least contributor access to an Azure subscription to complete this step.
We could complete this step even within Python but let’s save that for another time. I provide the commands for Azure CLI. You can open an Azure CLI console easily https://shell.azure.com

A menu could popup to help you create a storage account. Just proceed with that, it will cost none to little on your subscription. Make sure Bash is selected…

First we create a resource group

az group create –name "ContosoResourceGroup" –location eastus

view raw
cre_rg.sh
hosted with ❤ by GitHub

Screenshot 2019-11-01 at 14.06.45

Next we create a randomized name, keyvault and a secret, and we format some output that we will need later.

#we create a randomized name, the name of the keyvault has to be unique within the current cloud
#it will be publicly available using this name.
keyvaultName="keyvault-$(cat /proc/sys/kernel/random/uuid | cut -c-7)"
keyvaultURI=$(az keyvault create –name $keyvaultName –resource-group "ContosoResourceGroup" –location eastus –query "properties.vaultUri" –output tsv)
az keyvault secret set –vault-name $keyvaultName –name "ExamplePassword" –value "sampleSecretValueIn_plaintext"
tenantID=$(az account show –output tsv –query tenantId)
echo "The URI for the keyvault is: $keyvaultURI"
echo "The ID for the tenant is: $tenantID"

view raw
cre_name_kv_secr.sh
hosted with ❤ by GitHub

Screenshot 2019-11-01 at 14.10.26The output will contain two lines stating the URI of the keyvault and the tenant ID where your keyvault will reside. Copy the values so we can use them in the following steps.

Having a resource and sample data in place now it is time to run code from Jupyter using Visual Studio Code.

I use the Python extension for Visual Studio Code which I highly recommend, but if you don’t have access to Visual Studio Code you could follow along using Jupyter as this code is purely python of course but I warn you it isn’t not half as fun!

Code

For this solution we have two options which I will describe both.

Option 1: Devicecode using msrestazure and Microsoft Azure Active Directory Authentication Library (ADAL) for Python, the advantage being that we hold a cached access-token that typically is valid for one hour. So we authenticate once and in the coming hour we will access.
The disadvantage: we need extra code to handle the situation of expiration of the access-token or do this manually by executing the request again.
If expiration is not a problem in your use case I would go for this option.

Option 2: Devicecode using azure-identity from the azure sdk for python. This approach supports the client libraries that are contained in the sdk. It provides a very clean and simple way of authentication by just a couple of lines code. And this method will prevent the access-token to expire as it isn’t cached. You could see this as a security measure…
The disadvantage: because the access-token isn’t cached every request to a resource has to be authenticated.

It really depends on your scenario which is convenient for you. If you need access to several resources or have multiple calls to the same resource choose option 1.
If caching access-tokens is a potential security risk to you and need to run just a couple of calls to resources during the day choose option 2.
And maybe you should shift to other authentication methods than devicecode in code after you have gained access to keyvault by using the devicecode.

Option 1 (ADAL)

Step 1: First we install and or upgrade needed libraries

!pip install msrestazure nocachedir upgrade
!pip install azurekeyvault nocachedir upgrade

view raw
48option1step1.py
hosted with ❤ by GitHub

Step 2: If they are successfully are installed and updated we import the needed methods

import adal, uuid, time
from msrestazure.azure_active_directory import AADTokenCredentials
from azure.keyvault import KeyVaultClient
from msrestazure.azure_cloud import AZURE_PUBLIC_CLOUD

view raw
48option1step2.py
hosted with ❤ by GitHub

Step 3: Now we set the variables we need

secret_name = 'ExamplePassword'
vault_uri = '<replace this text and brackets>'
tenant_id='<replace this text and brackets>'
cloud=AZURE_PUBLIC_CLOUD
authority_host_uri = cloud.endpoints.active_directory + \
'/' + tenant_id
keyvault_resource_uri = 'https://vault.azure.net&#39;
client_id = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'

view raw
48option1step3.py
hosted with ❤ by GitHub

secret_name: this is the name of the secret value that is stored in the keyvault, we created this in the cloudshell before with the name ‘ExamplePassword’ which is an example of a secret we stored.
vault_uri: This URI is a unique address on the internet for your keyvault, the value is provided in the cloudshell when we created the keyvault. Please replace everything between the single quotes.
tenant_id: This is a unique ID for our Azure Active directory and also provided in the cloudshell when we created the keyvault. If you want to find your tenant ID by using the portal you can find it using this link.
cloud: This constant is used to assign which Azure cloud you are using. There are several National clouds that have their own addresses for authentication. Using these constants we can quickly resolve the different URI’s. This is handy feature of the ADAL. If you use Azure cloud, which is most common, you can leave the value to AZURE_PUBLIC_CLOUD.
authority_host_uri: we formulate the authority host here.
keyvault_resource_uri: If you use public cloud this is the URI to which your credential will be authenticated. For the sake of simplicity I didn’t put much effort in resolving this by the cloud constant. Azure keyvault has it’s own authentication boundary which is also a reason why the access policies exist next to IAM and in the other way around. So the access-token we will receive will only work to keyvault. For other resources you will need another access token. And a different uri to authenicate to. Keep this in mind if you need more Azure Resources.
client_id: This is the application ID that will be used to identify by which application the request is requested. This value is the default ID of “Microsoft Azure Cross-platform Command Line Interface“. See screenshot in step 4.

Step 4: Next we are creating an authentication request and save the received access token to a tokencredential that can be utilised by the azure.keyvault library.

context = adal.AuthenticationContext(authority_host_uri, api_version=None)
code = context.acquire_user_code(keyvault_resource_uri, client_id)
print(code['message'])
kv_token = context.acquire_token_with_device_code(keyvault_resource_uri, code, client_id)
kv_credential = AADTokenCredentials(kv_token, client_id)

view raw
48option1step4.py
hosted with ❤ by GitHub

Screenshot 2019-11-01 at 14.29.49
This will display instructions how to complete the authentication request. Copy the code, click the url or browse to https://aka.ms/devicelogin
past the code, sign in to your account and close the browsing session.
If you have passed this successfully you are ready to use keyvault.

Screenshot 2019-11-01 at 14.30.13

Step 5: utilize the credential, create the keyvault client object, print the value.

keyvault_client = KeyVaultClient(kv_credential)
supersecret = keyvault_client.get_secret(vault_uri, secret_name, '')
print("The secret value is: "+ supersecret.value)

view raw
48option1step5.py
hosted with ❤ by GitHub

Screenshot 2019-11-01 at 14.36.17

And we are done!
Now you are ready to save any secrets to Azure Keyvault and use them in python by only signing in to your account by using the browser, “I love it when a plan comes together….”

For instance you could use this to retrieve a secret of a Service Principal and work further using that, but if that is your plan go for Option 2 because it is cleaner code and doesn’t cache your access-token…

Option 2 (Azure SDK for Python)

Step 1: First we install and or upgrade needed libraries

!pip install azureidentity nocachedir upgrade
!pip install azurekeyvaultsecrets nocachedir upgrade

view raw
48option2step1.py
hosted with ❤ by GitHub

Step 2: If they are successfully are installed and updated we import the needed methods

from azure.identity import DeviceCodeCredential
from azure.keyvault.secrets import SecretClient

view raw
48option2step2.py
hosted with ❤ by GitHub

Step 3: Now we set the variables we need

secret_name = 'ExamplePassword'
vault_uri = '<replace this text and brackets>'
tenant_id='<replace this text and brackets>'
authority_host_uri = 'login.microsoftonline.com'
keyvault_resource_uri = 'https://vault.azure.net&#39;
client_id = '04b07795-8ddb-461a-bbee-02f9e1bf7b46'

view raw
48option2step3.py
hosted with ❤ by GitHub

secret_name: this is the name of the secret value that is stored in the keyvault, we created this in the cloudshell before with the name ‘ExamplePassword’ which is an example of a secret we stored.
vault_uri: This URI is a unique address on the internet for your keyvault, the value is provided in the cloudshell when we created the keyvault. Please replace everything between the single quotes.
tenant_id: This is a unique ID for our Azure Active directory and also provided in the cloudshell when we created the keyvault. If you want to find your tenant ID by using the portal you can find it using this link.
authority_host_uri: we formulate the authority host here, notice the difference to option one…
keyvault_resource_uri: If you use public cloud this is the URI to which your credential will be authenticated to. For the sake of simplicity I didn’t put much effort in resolving this by the cloud constant. Azure keyvault has it’s own authentication boundary which is also a reason why the access policies exist next to IAM and in the other way around. So the access-token we will receive will only work to keyvault. For other resources you will need another access token. And a different uri to authenicate to. Keep this in mind if you need more Azure Resources.
client_id: This is the application ID that will be used to identify by which application the request is requested. This value is the default ID of “Microsoft Azure Cross-platform Command Line Interface”. See screenshot option 1 step 4.

Step 4: Create a credential object to the authority host.

credential = DeviceCodeCredential(client_id, authority=authority_host_uri, tenant=tenant_id)

view raw
48option2step4.py
hosted with ❤ by GitHub

Notice how much more simple the previous step was compared to option 1 step 4, basically we achieved the same goal. But now we aren’t authenticated yet.

Step 5: utilize the credential, create the keyvault client object, print the value.

secret_client = SecretClient(vault_uri, credential)
supersecret = secret_client.get_secret(secret_name)
print("The secret value is: "+ supersecret.value)

view raw
48option2step5.py
hosted with ❤ by GitHub

After the keyvault client object is created we still didn’t have to authenticate.
The moment get_secret is called, devicelogin will be executed and instructions will appear.
Everytime you will execute a method on the keyvault client devicelogin will appear.

Screenshot 2019-11-01 at 14.48.41

And we are done!

Conclusion

To sum up, if we need utilise any Azure resource we have multiple options to sign in to Azure Active Directory to get access to those resources. For interactive sessions the safest method will be utilising device code login. Microsoft Azure Active Directory Authentication Library (ADAL) for Python and azure sdk for python both offer options to achieve this.
Which is most convenient to use? This depends on your use case. Familiarise yourself with the different behaviours and you will understand their advantages and shortcomings.

Like I said at the end of the Option 1, now you have gained access to keyvault securely your could shift to other authentication mechanisms without having to hard code credential information.

Information about these libraries:
https://github.com/Azure/azure-sdk-for-python
https://azure.github.io/azure-sdk-for-python/

https://github.com/AzureAD/azure-activedirectory-library-for-python
https://adal-python.readthedocs.io/

Usefull other resources about MS and Python:
https://devblogs.microsoft.com/python/
https://docs.microsoft.com/windows/python/resources

One thought on “How to authenticate Python interactively to Microsoft Azure

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.