How to setup an App Service & Database, using private V-Net and authorize access via Azure Active Directory using Terraform

Corrado Cavalli
Corrado Cavalli
Published in
6 min readJul 22, 2021

A complete infrastructure provisioning example

Introduction

Hosting a Web API project inside an Azure App Service and have it interacting with a database is a quite common infrastructure scenario, in this post I’m going to describe how to provision such infrastructure using Terraform.

This is not a Terraform tutorial so I will assume you have an intermediate knowledge of it, in case you’re looking for a Terraform introduction, you can follow this link.

Scenario

The GitHub repository accompanying this post shows how to create an Azure App Service hosting a Web API project hosted inside a docker container that connects via a private V-Net to a database (PostgreSQL in our case but it could be replaced by any other database) and manages API authorization via Azure Active Directory.
We are using a private endpoint to limit attack surfaces so that nothing other than the App Service can reach the database and its data.

Architecture diagram

As you can see from the architectural diagram there are also three other important actors involved:

  • Azure KeyVault: We are going to use it to store sensitive data, like the database username and password.
  • Container registry: While not strictly necessary, in the provided sample the Web API code will run in a Docker container whose image will be downloaded from provisioned Azure Container Registry.
  • Active Directory: Manages authorization access to Web API endpoints.

The code repository and machine setup

All the code described in this post is available here, in order to make the code usable as-is without complicated machine setup it uses a Visual Studio Code devcontainer (more on it here) so be sure to have the mandatory prerequisites (Docker, Remote Development extension pack…) installed if you want to try deploying the infrastructure to your own Azure environment.

I highly encourage you to clone the repo and follow this post while browsing the source code.

Once cloned the repository, to open it inside associated devcontainer, just click the green arrows in the lower-left corner of Visual Studio Code

and then select the Reopen in Container option.

The first time it will take a while because all the image parts must be downloaded, just be patient.

How the sample is organized

Once you open the repository inside VS Code and opened it in the devcontainer you will see a project structure like the one below

Project structure

All the infrastructure definition files are contained inside /terraform folder. All the major building blocks are inside the /terraform/modules folder, while the main.tf file is the one that defines how those modules relate to each other.

Let’s now dig into /terraform/modules/api folder since this module contains the dependencies, definitions and outputs related to Web API, V-Net, database and Active Directory authorization.

Content of /terraform/modules/api

variables.tf : contains all the variables the module expects in order to function properly, as you can see many of them are values coming from previously created resources (e.g., keyvault_id).

main.tf : contains the resource definitions to create the whole API-related infrastructure.

The main resources provisioning steps are

  • V-Net infrastructure creation.
  • PostgreSQL database provisioning with private endpoint.
  • App Service Plan provisioning.
  • Key Vault sercrets with sensitive info .

Also note that App Service authorization is enabled and set to the application registration created by the AD module.

Authorization part inside App Service

The App Service is configured to pass required info to hosted app via environment variables.

App Service configuration section

This configuration is also visible inside Azure portal via Configuration property of deployed App Service where you can also notice that some variables are linked to the Key Vault resource.

App Service Configuration section in Azure portal

output.tf : exposes information like the url of our brand-new Web Api deployment that we’ll need during the testing phase.

Active Directory application registration

The module inside /terraform/ad folder is the one taking care of creating the Active Directory application registration that will be later associated with our App Service.
Please note, inside main.tf of the usage of some ‘magic’ guids representing some specific services and scopes, you can read more about them here.

Active Directory application definiton

How to deploy the infrastructure

  • Run az login from VS Code terminal and login into your subscription.
  • Navigate to /terraform folder.
  • Execute the following commands
    - terraform init
    - terraform apply -auto-approve

After a while you should see something like this in your terminal, please note that the sXXXXX prefix and app registration id will be different since randomly generated.

Example of deployment result

If you browse the resource group via Azure portal, you will see a similar list with created resources.

Example of deployed infrastructure

And under Active Directory -> App Registration page you will find the related app-registration

Example of AD app registration entry

At this point there is just one component missing, the app that exposes the Web Api and connects to the database, that in our case is fully contained into a docker container, so in order to deploy it you need to upload the image to the newly created Azure Container Registry.

To do this navigate to /src folder and run this command.

az acr build –registry [registry-name] –image webapi-demo -f api/dockerfile .

example

az acr build –registry se2c0a6acr –image webapi-demo -f api/dockerfile .

After a while the image will be deployed to Azure container and automatically downloaded by the App Service, you can check the progress from Azure portal navigating to the Container settings property of the App Service.

Image downloaded from Azure Container Registry

Testing the API

Is now time to test our deployment, for this we’ll use a well-known tool named Postman.

If we try to access the Customers endpoint, you will see that you are not authorized (Status:401)

Access to customers enpoint is Unauthorized

In order to have the proper authorization we need to provide a Bearer token in the Authorization header of the request, so let’s get it by passing the required parameters to following endpoint

https://login.microsoftonline.com/[tenant-id]/oauth2/token

Note: You can get your tenant id in the overview section of your Azure AD app registration.

Tenant Id

Let’s set the Content-Type of this request to application/x-www-form-urlencoded

Content-Type

Then let’s pass request parameters in request’s body.

Parameters for access token request

You can get the value of generated client_id/resource and client_secret parameters inside provisioned Key Vault

KeyVault secrets

Now copy the return access_token value and let’s use it as Authorization header for the request to the customers endpoint.

And now, as you can see, your request is successful (Status: 200) 😊

Closing

The scenario of a server exposing some Web Apis that communicates with a database is quite widespread nowadays, despite this, however, the documentation on how to implement it with Terraform is not so easy to find.

I hope this post and the code inside the associated repository can help make your scenario-like easier to accomplish.

--

--

Corrado Cavalli
Corrado Cavalli

Senior Sofware Engineer at Microsoft, former Xamarin/Microsoft MVP mad about technology. MTB & Ski mountaineering addicted.