Secure Azure Storage API

Cloud Journey
5 min readJun 11, 2022

--

Overview

This blog is a sequel to https://cloudjourney.medium.com/azure-storage-aad-authentication-f2eb48e481f. We will secure the MyBlobFile API using MS identity platform, move environment variables to app settings and add more API.

This blog’s code is available from https://github.com/Ronnie-personal/identity-for-all/tree/main/SecureApi

AAD App Registration

What Is App Registration

For an identity provider to know that a user has access to a particular app, both the user and the application must be registered with the identity provider. When you register your application with Azure Active Directory (Azure AD), you’re providing an identity configuration for your application that allows it to integrate with the Microsoft identity platform. Registering the app also allows you to:

  • Decide if you want to allow users to sign in only if they belong to your organization.
  • Request scope permissions. For example, “user.read” scope.
  • Define scopes that define access to your web API. These are the scopes that you define.
  • Share a secret with the Microsoft identity platform that proves the app’s identity.

Create App Registration for the API

From https://portal.azure.com azure active directory blade, select “App Registrations”, and click “New registration”, give a name, leave all other default configuration as it is, create the app registration and copy the client id.

In the “Expose an API” blade for the newly created app registration, set Application ID URI as “api://<api service app registration client id>

All APIs have to publish a minimum of two scopes, also called Delegated Permissions, in “Expose an API” blade, click “Add a scope”, for example, I added two scopes, “ToDoList.Read” “ToDoList.Write”. (you may use any other name for the scope)

In app registration “Manifest” blade, update “accessTokenAcceptedVersion”: 2, meaning we use MS identity v2 access token.

Generate Code

dotnet new webapi -au SingleOrg -o SecureApi
cd SecureApi
dotnet add package Azure.Identity
dotnet add package Azure.Storage.Blobs

To learn -au option, run “dotnet new webapp -h”

Options:
-au|--auth
The type of authentication to use
None - No authentication
IndividualB2C - Individual authentication with Azure AD B2C
SingleOrg - Organizational authentication for a single tenant
Windows - Windows authentication
Default: None

Develop Code From Local

The plan is to get parameter values from appsettings, including storage account name and tenant id . You may not want to check in all these settings to code repo.

Here is my approach:

  • Update .vscode/launch.json, “ASPNETCORE_ENVIRONMENT”: “Local”
  • Add appsettings.Local.json file, and update it with actual values for local development only
  • Leave appsettings.json with place holder values
  • Add appsettings.Local.json file to .gitignore
  • git reset appsettings.Local.json
    (so that won’t commit the file and won’t push it to repo)

“dummy” appsettings.json file:

{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "need to update xyz.onmicrosoft.com",
"TenantId": "need to update ",
"ClientId": "need to update ",
"Scopes": "ToDoList.Read ToDoList.Write",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"AzureStorage": {
"AcctName": "need to update tbd",
"ContainerName": "need to update tbd"
}
}

As for updating appsettings.Local.json, Domain and TenantId can be found from https://protal.azure.com Azure active directory blade, ClientId is the app registration client id which is created in first step.

Customize Code

Add MyBlobFile.cs and remove WeatherForecast.cs:

namespace SecureApi;
public class MyBlobFile
{
public string? BlobFile { get; set; }
public DateTimeOffset? LastModified { get; set; }
}

Add MyBlobFileController.cs and remove WeatherForecastController.cs:

This version of the code is almost same as the code from last blog post, we just apply the [Authorize]attribute.

Through dependency injection, we get access to configuration object in the controller class. We also add an API to download blob file.

Validation

Get Access Token

Maker sure to install the latest version of az cli.

Optionally configure “Authorized client applications” to bypass user/admin consent. ‘Microsoft Azure CLI’ client id is ‘04b07795–8ddb-461a-bbee-02f9e1bf7b46’.

If you didn’t configure “Authorized client applications” in api service app registration which is indicated in above screenshot, run az login with scope argument, otherwise go directly to get access token using az cli.

C:\WINDOWS\system32>az login --scope api://<api service app registration client id>/ToDoList.Read api://<api service app registration client id>/ToDoList.Write

A web browser window is popped up, use a test user account to log on, and this account does not necessarily have RBAC permission on the storage account, as long as you sign in from IDE to Azure using admin account which has required RBAC permission.

Now, you may use az cli to get access token.

C:\WINDOWS\system32>az account get-access-token --scope "api://<api service app registration client id>/ToDoList.Read api://<api service app registration client id>/ToDoList.Write"
{
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIs....",
"expiresOn": "2022-06-10 23:53:19.000000",
"subscription": "24c9c37c-bf59-4b84-907c-43819602e881",
"tenant": "9b2ec8d7-37b8-4aac-acd2-9ed0acfb1c5a",
"tokenType": "Bearer"
}

While decode the access token/JWT, we see the audience is the api service app registration client id, issuer is from MS identity platform v2, scope claim is also present.

{
"aud": "api service app registration client id",
"iss": "https://login.microsoftonline.com/<tenant id>/v2.0",
...
"scp": "ToDoList.Read ToDoList.Write",
...
"ver": "2.0"
}

Call API with Authorization Header

Copy the access token and use it as bearer token to call MyBlobFile API, it successfully invoked API, and listed blob files from the storage account container. (if you encounter any issue, sign out and sign in back in IDE with admin account which has storage account RBAC permission and run the API again)

Let’s try other API to download blob file, the file content is returned.

$ curl -k -X 'POST'  'https://localhost:7249/MyBlobFile'   -H 'accept: text/plain'  -H 'Content-Type: application/json' -H 'Authorization: bearer eyJ0eXAiOiJKV1Q....'  -d '{  "blobFile": "dummy.txt"}'
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 45 100 18 100 27 1 1 0:00:27 0:00:14 0:00:13 4
dummy file line #1

Conclusion

It requires almost no coding to secure an API using MS identity platform, in next blog, we will add angular UI code to sing in user and call the secured API.

References

https://www.schaeflein.net/use-a-cli-to-get-an-access-token-for-your-aad-protected-web-api/

https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-how-applications-are-added

--

--

Cloud Journey

All blogs are strictly personal and do not reflect the views of my employer. https://github.com/Ronnie-personal

Recommended from Medium

Lists

See more recommendations