Skip to content

Building apps with a Zero Trust approach to identity. API Management, Functions and Azure SQL. Tutorial

License

Notifications You must be signed in to change notification settings

gbelenky/function-with-aad-apim-sql

Repository files navigation

Create an identity-protected API back-end with Azure Functions, Azure SQL and API Management

This step-by-step tutorial will implement architecture above and contain the follwing steps:

  • Create Azure Functions in VS Code
  • Create SQL Database and add SQL Bindings to the Functions. This repo enhances this sample
  • Deploy Azure Function into Azure
  • Expose the API through the API management
  • Protect Back-End API through AAD so that only this APIM instance can access the back-end API
  • Protect exposed API through the APIM API Keys for the external developers
  • Optional. Protect access to Azure SQL through AAD while using Functions. Based on this and this tutorial

Audience: teams exploring new generation cloud services implementation concepts

Reason for this tutorial: focus more on the complete business solution rather than on separate services

Scenario description

Contoso ToDo Product team has already migrated a couple of their applications into Azure App Service. These applications are using custom implemented Authentication and Authorization. They have heard about Microsoft Zero Trust concept and would like to protect their externally exposed APIs, API back-end and the Azure SQL data.

The team would like to increase developer velocity while using serverless technologies such as Azure Functions

Create Azure Functions in VS Code

Please refer to this existing tutorial and create the following Functions:

  • AddToDo
  • DeleteToDo
  • GetToDo
  • GetToDos
  • UpdateToDo

All these Functions will be using HTTP Trigger and also different HTTP Methods

Replace the generated Functions code with the content in the branch of this repo

Install HTTP REST Client, start the Function and run the tests on your local machine by using the sample requests

The test samples for them are here: sample

Create the SQL Database and tables

Use this quickstart to create your database - do not add sample data to your database as it is descibed in the tutorial

Select the Query Editor in your newly created database and execute this script there:

Add .NET packages for Azure Functions SQL binding as referred here

Open VSCode terminal and execute there

dotnet add package Microsoft.Azure.WebJobs.Extensions.Sql --version 0.1.311-preview

Start adding bindings to the code - start with AddToDo.cs

You also need to update your local.settings.json file configuring the SQLConnectionString

Replace your code by the content here AddToDo.cs, run the Function project and call the function from the test.http and observe the results

Continue with the GetToDo.cs, GetToDos.cs, DeleteToDo.cs and UpdateToDo.cs

Test the rest of the functions with test.http

Deploy Azure Functions

Please refer to this document for the detailed deployment information

Upload local settings:

Verify the deployment in the Azure Portal

Verify your local settings were published. In my case I had to add the SQLConnectionString manually

Test your deployed Function

You can test all your functions from the Azure Portal or add corresponding requests to the test.http file. You can find the Function URL here:

In my case it is https://function-with-aad-apim-sql.azurewebsites.net/api/GetToDos

Expose the API through the API management

Create a new API management instance:

Create Managed Identity for your API Management

Optionally add Application Insights to your API Management

Review and Create your API Management. This will take some minutes to be completed.

Select the APIM resource you jut creted, go to the APIs blade and select "Create from Azure Resource" - "Function App"

Search and select your Function App

Select and import all Functions from your Function App

Click "Create"

After the import you will land in the Design Blade of the APIM

Test access to your backend API from the APIM

As you can see here, your API is already protected by the automatically generated key:

Now, we need to protect the backend API so that only APIM is able to access it.

Step 1. Configure authentication for your Functions App

Go to your Function App and select the Authentication blade:

Select Microsoft

Click Add

Note App (client) Id

Try to access your back-end now:

and this is the result

when testing the Function from APIM you will get the same result:

there is a different picture when testing in the browser:

This means that we limited access to the back-end API only to the indentities inside of the Azure AD tenant where we created identity of the Azure Function (also called Managed Identity describing the Service Principal which was also instantiated in the same AAD Tenant). But still, all identities can access our Function - we need to change it

Step 2. Allow APIM to access the Function

Before we limit access to the backend, we need to allow APIM to access our Function. The following policy will help us to the APIM

<authentication-managed-identity resource="Client_id_of_Backend"/>

If you did not note the Client Id of your Function, you need to revisit the Authentication blade of the Function:

Jump back to APIM and select your API:

Click Inbound Processing -> Policies

Add the following line and replace the resource with your Azure Function Client Id:

Save it and test your API again:

Our request was successful:

Step 3. Allow ONLY APIM to access the Function

If you're unfamiliar with managed identities for Azure resources, check out the overview section.

Be sure to review the difference between a system-assigned and user-assigned managed identity.

Here you can find more information on Service Principals and Applications

To limit access to APIM only you need to

  • Create an App Role for your Function in its AAD registration (this will be correlated with the Service Principal of your AAD App Registration). App Role defines a group of users/applications anabled to access this application and receive receive this App Role as an authorization claim (outside of scope here. More here)
  • Add the APIM Managed Identity Object ID to the App Role
  • Limit access to the Function only to the users/roles in the App Role

A similar approach can be achieved by using Security Groups, but might evolve IT personnel managing AAD Security Groups. Here, we will work through the App Roles.

Go to the application registrations:

select your function:

Create a new App Role:

Currently you cannot assign your APIM Application identity to the app role through the Azure Portal. You will need to go through the Azure CLI or Powershell.

Use the Bash environment in Azure Cloud Shell. For more information, see Azure Cloud Shell Quickstart - Bash.

Launch Cloud Shell in a new window

This is the commandlet you will need to execute:

# Assign the managed identity access to the app role.
New-AzureADServiceAppRoleAssignment -ObjectId $APIMmanagedIdentityObjectId -Id $appRoleId -PrincipalId $APIMmanagedIdentityObjectId -ResourceId $functionServicePrincipalObjectId

functionServicePrincipalObjectId :

Go to the AAD Enterprise Applications

Copy the Object Id

appRoleId :

Go to AAD App registrations, select your registration and the App Role. Copy the App Role Id

APIMmanagedIdentityObjectId:

Go to APIM - search for managed identity and copy the Object Principal id :

Set these values in Powershell and execute the commandlet:

# Enterprise applications 
$functionServicePrincipalObjectId = '15b**********'
# App Role Id
$appRoleId = '78b**********'
# APIM Managed Identity
$APIMmanagedIdentityObjectId = '891******'

# Assign the managed identity access to the app role.
New-AzureADServiceAppRoleAssignment -ObjectId $APIMmanagedIdentityObjectId -Id $appRoleId -PrincipalId $APIMmanagedIdentityObjectId -ResourceId $functionServicePrincipalObjectId

You can see that your back-end Function was successfuly added to the App Role if you go to the Azure AD, Enteprise Applications, locate your application and look at the Users and Groups:

And finally the last step

Verify that you have no access to the function directly

And that you have access through the APIM:

Protect exposed API through APIM API Keys for the external developers

Create a new APIM Product so that external parties can test your API for free (or non-production purposes) from the APIM blade, limit access to just one subscription and add your API to it:

Add Users and Guests to your Product through the Access Control

Add Rate Limit Policy to the Product and limit it to 5 calls per minute and to the overall quota of 100 calls in 7 days.

Publish your product:

Your APIs are usually provided to the API users through the API subscriptions assigned to your products.

You can create your users directly in the portal or invite them through the portal

The [Developer Portal](fully customizable website with the documentation of your APIs. It is where API consumers can discover your APIs, learn how to use them, request access, and try them out.) is a fully customizable website with the documentation of your APIs. It is where API consumers can discover your APIs, learn how to use them, request access, and try them out.

Developers using your APIs can request access to the Developer Portal and receive their API keys using the self-service capabilities of the portal.

Please have a look at the API Management capabilies here.

For the sake of simplicity I created a user with my corporate email address and created a subscription for this user:

The user received the email notification:

The user will see the product here - https://function-with-aad-apim-sql-apim.developer.azure-api.net/product#product=todo-starter

Now the user can try it with the Product Subscription Key

Optional. Protect access to Azure SQL through AAD while using Functions.

If you want to add identity based protection of your Azure SQL and avoid using sensitive connection strings, you can follow this guide

About

Building apps with a Zero Trust approach to identity. API Management, Functions and Azure SQL. Tutorial

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published