# How to passwordless authenticate DEV and PROD Systems with an Azure Service

When accessing Azure resources, the **Storage Account,** for example, you can make the access by using the access key or Connection String that is provided on the resource.

# The problem with keys

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673093158403/7743189d-a9c9-416e-b0ec-77b7a2b49e2a.png align="center")

While this is a feasible way of managing access, there are several problems with this approach:

* There are only 2 keys/connection strings. If you have more than 2 people or systems accessing the resource, someone has to **share**. While this is not optimal from a **security** perspective you will have to **rotate** the key at some point, which means everyone with the key has to act. Depending on how the key is stored that can mean a redeployment. That is if everyone was **responsible** enough to disclose how to change the key in the first place.
    
* Secrets can be **leaked**. Totally by **accident**. The safest secret is the one that has no chance of ending up in a GIT Repository or attached in a file in an email. This can be archived by **not having a secret** in the first place.
    

# How to not have a secret in the first place

The answer is a combination of RBAC, Managed Identity and Application Registration.

For this test scenario, we have a Blazor Server App (Client), a Storage Account (Service) and a DEV Machine. The Blazor Server App will be hosted in **Azure**, but the same codebase should work both in Azure and **locally**.

## Architectural overview

To archive this, we

1. Register an Application registration with Azure AD for the DEV machine and use the credentials locally
    
2. Enable Managed Identity on the deployed Web Application
    
3. Add RBAC role assignments on the service
    
4. Use DefaultAzureCredentials() in code
    

## Application registration for the DEV machine

1) Open Azure Active directory at https://portal.azure.com

2) In Application Registrations, add a new one

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673095512976/48bff9cf-d582-4283-935b-868d2e89f2c5.png align="center")

Choose a name you want to identify your machine with. The other options are not important.

3) Go to the overview page of the created application. In the essentials box, note down the Application (client) ID and Directory (tenant) ID

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673095637316/0691f665-9406-4f6f-949d-3e33defbca16.png align="center")

4) In "Certificates and Secrets" add a **secret** or a **certificate**. Both will work, depending on your preference, while certificates are more secure, but also more work. Note down the secret / save the certificate

5) Head to the DEV machine. Review this document: [https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet](https://learn.microsoft.com/en-us/dotnet/api/azure.identity.environmentcredential?view=azure-dotnet)

Add the corresponding variables to your **system environment** variables. Example for using a secret:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673096000033/912c5a97-b392-4c5a-af49-4ffa05c81bef.png align="center")

## Enable managed identity on the deployed solution

1) go to your resource at https://portal.azure.com

2) click on "Identity" and switch "System assigned" Status to "**On**"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673096182835/d0107c66-7f91-4853-a297-a387afba344a.png align="center")

This will automatically create an **enterprise application** (which is NOT an application registration) with the name of the App Service ("DCAResults" in this case)

## Add RBAC Role assignments

After creating an application registration for the DEV machine and an enterprise application for the deployed client app we need to give both access to the service (**storage account**) we want.

1) Open the service resource at https://portal.azure.com and click on "Access Control (IAM)"

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673096433567/5a27b3ba-7964-4e4c-befb-0935e9bfa676.png align="center")

2) Click "Add role assignment" and select the role you need ("Storage Data Table Contributor" in my case, as my app needs to read and write data from a table, but not manage resources and not access blobs or queues).

3) in the "Members" blade, click on "User, group or **service principal**" and "**Select members**". In the popup, search for the Application Registration you created for the DEV machine and add it

4) Now select "**Managed identity**" and select the resource in the popup that you enabled managed identity on

The final summary should look something like this:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1673096925721/bc7310cd-e92b-4caf-b835-aac6e3e4e7fd.png align="center")

## DefaultAzureCredentials

Now all that's left to do is to change the code to utilize both the service principal (app registration) and the managed identity. The class **DefaultAzureCredentials** tries a list of ways to log in as an azure resource. The ones we are going to use are "**EnvironmentCredential**" and "**ManagedIdentityCredential**". Based on what is available the class will automatically select.

```csharp
private static TableClient GetTableClient()
        {
            var credential = new DefaultAzureCredential();
            var serviceClient = new TableServiceClient(new Uri("https://XYZhost2.table.core.windows.net/"), credential);

            TableClient tableClient = serviceClient.GetTableClient( tableName: "dca");
            return tableClient;
        }
```

# Conclusion

And that's it. The code is now going to run both locally and deployed in azure **without** having a key or ConnectionString stored. The Service Principal on the DEV machine can be **reused** to give access from that specific machine automatically.
