Skip to content
/

Add Azure Active Directory authentication to an App Service from an Azure DevOps Pipeline

Azure App Services make it quite easy for you to add one or more authentication providers to your application. But how do you add Azure AD as a provider using Infrastructure as Code?

In this article I will show you the steps of deploying and securing an Azure App Service with AAD authentication using an Azure pipeline.

I will be referencing some parts of my previous article Manage Azure AD applications from an Azure DevOps Pipeline.

Setting up the web app deployment

Before we can add authentication to a web application, first the infrastructure must be deployed.

For the deployment I will use a simple ARM template that consists of a Linux app service, a site and a couple of configuration settings. In this case I will set it up for use with the latest PHP stack. The ARM template has a single parameter called siteName to use for the name of the site and app service.

As this article is not about deploying a web app using an ARM template, I will not embed the contents here, but you can find the whole deployment file in my GitHub repo.

Web content

I have kept the contents of this web page purposely simple. The index.php file contains some simple scripting to show the web app is working correctly.

<html>
<body>
<h1><?php echo 'Hello World' ?></h1>
<div><?php echo 'Current PHP version: ' . phpversion() ?></div>
</body>
</html>

Configuring the pipeline

I will skip over the steps of connecting an Azure subscription and creating an empty pipeline. These steps are already described in the chapter "Configuring an Azure pipeline" in my previous article.

With the empty pipeline as a base, we need three tasks to deploy this web application. I will add the siteName as a variable to the pipeline, so it can be reused in the tasks that will be added.

variables:
  siteName: hompus-demo

The first step is the Azure Resource Group Deployment task to deploy the ARM template into a resource group.

- task: AzureResourceManagerTemplateDeployment@3
  inputs:
    azureResourceManagerConnection: Azure
    resourceGroupName: $(siteName)-resourcegroup
    location: West Europe
    csmFile: arm-deployment.json
    overrideParameters: -siteName $(siteName)

As it is not possible to deploy a single php file to a web app, zip it with the Archive Files task, then use the Azure App Service Deploy task to deploy the archive to the created web site.

- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: $(Build.SourcesDirectory)/index.php
    includeRootFolder: false
    archiveFile: $(Pipeline.Workspace)/$(Build.BuildId).zip
- task: AzureRmWebAppDeployment@4
  inputs:
    azureSubscription: Azure
    appType: webAppLinux
    WebAppName: $(siteName)
    packageForLinux: $(Pipeline.Workspace)/*.zip

After executing the pipeline, there is now an anonymous web site running in Azure.

Screenshot of a browser showing that the website is working.
The website is working.

Adding Azure AD authentication

To add Azure AD as an authentication provider, an Azure AD app needs to be configured. For all details, I am pointing to my previous article again.

In summary, an Azure CLI task is added. In this pipeline as the second step, after the ARM template is deployed.

- task: AzureCLI@2
  inputs:
    azureSubscription: Azure
    scriptType: pscore
    scriptLocation: inlineScript
    inlineScript: |

It contains the following contents as inline script:

newlines between parameters are only added for readability

# Create application
$appId = (az ad app create --display-name 'Auth $(siteName)'
                           --homepage https://$(siteName).azurewebsites.net
                           --identifier-uris https://$(siteName).azurewebsites.net
                           --reply-urls https://$(siteName).azurewebsites.net/.auth/login/aad/callback
                           --query 'appId'
                           --output tsv)
Write-Host "App ID: $appId"
      
# Add permission to sign in and read user profile
az ad app permission add --id $appId
                         --api 00000002-0000-0000-c000-000000000000
                         --api-permissions 311a71cc-e848-46a1-bdf8-97ff7156d8e6=Scope
      
# Generate new client secret
$password = (head /dev/urandom | tr -dc [:alnum:] | fold -w 30 | head -n 1)
# Set client secret
az ad app credential reset --id $appId
                           --password $password
                           --output none

Now, to add authentication, only the az webapp auth update command has to be added. This makes the app service use the created Azure AD app as a means to authenticate visitors to the web site.

# Update Web App Authentication
az webapp auth update --name $(siteName)
                      --resourcegroup $(siteName)-resourcegroup
                      --enabled true
                      --action LoginWithAzureActiveDirectory
                      --aad-client-id $appId
                      --aad-client-secret $password
                      --token-store true
                      --output none

After executing the pipeline with the updated configuration, nobody is able to view the page anonymously anymore and visitors need to supply a valid Azure AD account to see the page again.

Screenshot showing an authentication prompt for the web site.
The Azure AD authentication prompt for the web site.

Looking in the Azure Portal, it is possible to confirm that the pipeline has configured all settings as requested.

Screenshot of the Azure portal showing the configured App Service Authentication settings.

Source code

I have shared all the related source code in the AzDO.Pipelines.AppService.AADAuth GitHub repository.