Introduction
As a developer who is using Azure most of the times, one of the first tasks I am doing when setting up my developer laptop is to make sure the Azure environment considers it as a trusted machine. Doing so enables me to use RBAC permission in Azure without being worried to keep connection string all over my development machine and stop being worried about whether I have accidentally exposed some secrets into an appsettings.json
like files and maybe even worse, push them into a repository! 🤷🏻♂️
Authenticate your machine
The first step is to download Azure CLI on you machine, depending on your developer environment you could use different approaches! Here you could find how to install it whether you are on Linux, Windows, or MacOS.
To make sure the installation was successful you could run az version
, once running it, you should see some output similar to mine, indicating which version of the tool is installed!
The next step is to run az login
, if it automatically opened the browser, then follow the steps, if not, copy the URL and you should be able to follow the steps provided but the authentication process. It could differ, based on whether you have been already logged into Azure or not. It will ask you about the user name and password, and if the 2-FA (Two-Factor Authentication) is activated on your account, it will ask for some extra steps to enter or confirm the login attempt.
After a successful login, the output in the console will show you the active subscriptions this user has access to, of which you could then select to be the default one, either by entering the subscription name or the number:
Now your could issue commands from the terminal against the selected azure subscription, for instance the next code snippet shows the output of running
az group list
which lists all the resource groups in the default subscription I chose before:
❯ az group list
[
{
"id": "/subscriptions/<subscription-id>/resourceGroups/rg-learning",
"location": "westeurope",
"managedBy": null,
"name": "rg-learning",
"properties": {
"provisioningState": "Succeeded"
},
"tags": null,
"type": "Microsoft.Resources/resourceGroups"
}
]
depending on the permissions this user has, one could definitely issue different commands. But, wait, I am not going to always communicate with my Azure environment via a terminal 🤔 how is this going to help me avoid connection strings on the development machine? Well, let's take a look into that!
Authenticate you Application
Let's say I have an application that wants to connect to Azure Blob Storage, one way is to grab the connection strings from the Azure Portal, select your storage account and navigate to the Access keys
section, there you could find the primary and secondary connection strings:
Now, in the code, when I want to use the BlobServiceClient
to connect to the Azure Blob Storage, there are several overrides to connect to the service, one of which is providing the complete connection string, which is exactly the one we are trying to avoid (red-arrow), the other one (highlighted in green-yellow) is accepting a TokenCredential
and is the one we are interested in:
There are several credential providers that could be used to create a token credential. And to use them one need to add the
Azure.Identity
NuGet package to the project, at the time of writing this post it is on version 1.13.2
.
❯ dotnet add package Azure.Identity --version 1.13.2
After adding the package we could create a secure connection to the service, by just providing the public URI of the service, depending on the service it could have different formats, however, in this example it would be like https://<storage-account-name>.blob.core.windows.net
; by using the AzureCliCredential
class we could authenticate the application against Azure environment, it uses the exact same user as is connected to Azure through the az login
command provided earlier in this post.
var blobServiceClient = new BlobServiceClient(
new Uri("https://<storage-account-name>.blob.core.windows.net"),
new AzureCliCredential());
The same approach could be done for any other service that exists on Azure. There is one tiny problem though; 😜 the application can now only authenticate itself, if and only if, there is an azure cli command available on the environment it is running on; this is not the case for every environment! What if we deploy the application to Azure itself, there is no Azure Cli 🤷🏻♂️
To overcome this issue, there is another credential provider named DefaultAzureCredential
it has a chain of other concrete providers and will check which one of them is available in the running environment, the first one that is available will be used. The list is as the following:
- EnvironmentCredential
- WorkloadIdentityCredential
- ManagedIdentityCredential
- SharedTokenCacheCredential
- VisualStudioCredential
- VisualStudioCodeCredential
- AzureCliCredential
- AzurePowerShellCredential
- AzureDeveloperCliCredential
- InteractiveBrowserCredential
For instance it is best practice to use ManagedIdentity
when running applications inside the Azure environment. By using the DefaultAzureCredential
not only we could eliminate the connection string on our local machine, we could eliminate them altogether and rely on more trusted approaches like ManagedIdentity
.
Conclusion
Using connection strings to connect to any service might at first sight be the easiest way to go with, however, it comes with challenges of maintaining them and being sure that thy are not accidentally revealed! A better and more secure approach would be to authenticate our (local) environments or machines against Azure, and using the credential classes for managing a TokenCredential
for accessing Azure resources.
At the end, thanks for reading, enjoy coding and Dametoon Garm [**]