We are Codebeez. We specialise in everything Python and help our clients build custom scalable, robust and maintainable solutions.
In today's dynamic cloud computing landscape, deploying applications efficiently and securely is paramount. Azure Logic Apps stand out in this regard, requiring a unique approach that balances flexibility with robustness. This blog post explores a specialized method that seamlessly integrates Azure DevOps and Azure Managed Identities, specifically designed for the deployment of Azure Logic Apps.
The focus here is on customizing and optimizing the deployment of Azure Logic Apps. We will walk through how Azure DevOps streamlines the development cycle, while Azure Managed Identities enhance security, eliminating the need for managing credentials manually. This combination provides a powerful toolkit for developers looking to deploy Azure Logic Apps efficiently and securely.
In this blog, we will explore how to utilize DevOps and Managed Identity effectively for deploying Logic Apps. We'll cover:
- Managed Identity Benefits
- Infrastructure as Code for Logic Apps
- API Connection and App Roles:
Managed Identity Benefits
In the world of Azure cloud services, Service Principals have traditionally been a cornerstone for managing application permissions and access control. However, this approach is not without its security vulnerabilities, particularly concerning the management of secrets and the integration with Azure KeyVault.
They present several security challenges:
- managing secrets or credentials for authentication is required, which can be a complex and secure task.
- even with tools like Azure KeyVault, there's a possibility of accidental exposure, particularly in automated scripts or when secrets are stored in environment variables.
- regular updates of secrets are essential for security but often overlooked or complicated, leading to potential risks.
- the manual process of managing these credentials can lead to errors and subsequent security breaches.
Managed Identities
To address the challenges associated with traditional based Service Principals, Azure has introduced Managed Identities, a feature designed to enhance security and streamline the authentication process. Here's how Managed Identities tackle these challenges:
- managed Identities eliminate the need for manual secret management, thus simplifying the authentication process..
- azure takes over the entire lifecycle of Managed Identities, including their creation, management, and rotation..
- managed Identities enable developers to concentrate on development, with Azure handling the intricacies of secure authentication.
- this approach aligns with the principles of Infrastructure as Code (IaC) and seamlessly integrates into DevOps workflows, thereby enhancing the security and efficiency of cloud-based application management.
Infrastructure as Code for Logic Apps
By creating an Azure Logic App for using Managed Identities, we take a modular approach with Bicep files, each serving a specific purpose in the deployment process. By breaking down the deployment into separate Bicep modules, we create a clean and maintainable codebase. Here's how each module fits into the bigger picture:
ManagedIdentity.bicep
This module is responsible for creating the Managed Identity itself. The Managed Identity serves as a secure principal for our Logic App, allowing it to authenticate with Azure services without storing credentials in code. Here’s what the ManagedIdentity.bicep module does:
The main module of the provided Azure Bicep file defines and sets up a Microsoft Azure Logic App workflow. This Logic App is configured to trigger automatically on a weekly basis. Key components include:
Logic App Workflow Definition: A resource of type Microsoft.Logic/workflows is declared, indicating the creation of a Logic App.
User-Assigned Managed Identity: The Logic App is assigned a user-defined managed identity, allowing it to securely interact with other Azure resources. Which we referenced in our Managed Identity.Bicep
Our third module, 'api connection.bicep,' is designed to create an API connection resource for Office 365. This step is crucial because in this scenario, we are using a logic app to monitor Microsoft 365 licenses.
API Connection and App Roles
App Roles are like the keys to the kingdom, defining who can do what within your application. You specify the permissions required for different actions and assign them to different roles. For example, you can have roles like "ReadUserData" or "WriteCalendarEvents."
Now, let's see how this all fits together when your application wants to access Microsoft Graph API:
Your application needs to make an authenticated request to Microsoft Graph API. Instead of dealing with secrets or credentials, it uses the Managed Identity's identity endpoint to obtain an access token. This access token serves as the golden ticket, allowing your application to authenticate requests (in this case) to Microsoft Graph API.
But how do you ensure that the App Roles are correctly assigned to your Managed Identity? This is where a bit of scripting comes into play. Here's how it works:
You retrieve the Microsoft Graph Application ID (Graph ID). This ID is unique to Microsoft Graph and identifies the application.
Using the Graph ID, you query the Microsoft Graph API to get the list of available App Roles for your application.
$graphId = "00000003-0000-0000-c000-000000000000"
$graphversion = "v1.0"
$url = "https://graph.microsoft.com"
$endpoint = "servicePrincipals?`$filter="
$filter = "appId eq '$graphId'"
$uri = "$url/$graphversion/$endpoint$filter"
$graphResource = (az rest --method get --uri $uri | ConvertFrom-Json).value
You then fetch the specific App Role IDs that your application needs. For example, you might need the "Organization.Read.All" role.
$orgReadAll = az ad sp show --id $graphId --query "appRoles[?value=='Organization.Read.All'].id | [0]" -o tsv
Finally, you ensure that the Managed Identity has these roles assigned to it. If not, you add the role assignments.
foreach ($appRoleId in $appRoleIds) {
$roleMatch = $currentRoles -match $appRoleId
if ($roleMatch.Length -eq 0) {
$body = "{'principalId':'$principalId','resourceId':'$graphResourceId','appRoleId':'$appRoleId'}"
az rest --method post --uri https://graph.microsoft.com/v1.0/servicePrincipals/$principalId/appRoleAssignments --body $body --headers Content-Type=application/json
}
}
Pipeline
We now shift our focus to the orchestration of the deployment process. Having crafted three pivotal Bicep modules, each with a specific role—establishing Managed Identity, defining the Logic App's workflow, and setting up API connections—we now reach the crucial step of deployment automation. To facilitate this, we harness the power of YAML pipelines in Azure DevOps. YAML, a human-readable data serialization standard, is used here to define our Continuous Integration/Continuous Deployment (CI/CD) pipeline. This YAML pipeline serves as the blueprint that Azure DevOps will follow to deploy our resources. It will call upon our Bicep modules in a sequential manner, ensuring that each resource is deployed correctly and dependencies are respected.
trigger:
- main
stages:
- stage: Deploy
jobs:
- job: DeployBicepModules
pool:
vmImage: 'ubuntu-latest'
steps:
- checkout: self
- task: AzureCLI@2
inputs:
azureSubscription: 'YourAzureServiceConnection' # Replace with your Azure service connection name
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az deployment group create --resource-group $(ResourceGroupName) \
--template-file ./Bicep/ManagedIdentity.bicep \
--parameters managedIdentityName=$(ManagedIdentityName) resourceLocation=$(ResourceLocation)
az deployment group create --resource-group $(ResourceGroupName) \
--template-file ./Bicep/LogicAppWorkflow.bicep \
--parameters workflowName=$(LogicAppName) resourceLocation=$(ResourceLocation)
az deployment group create --resource-group $(ResourceGroupName) \
--template-file ./Bicep/APIConnection.bicep \
--parameters apiConnectionName=$(APIConnectionName) resourceLocation=$(ResourceLocation)
This YAML pipeline triggers on changes to the main branch, utilizing an Ubuntu latest image pool to run Azure CLI tasks. Each task deploys a corresponding Bicep module by invoking the Azure CLI's az deployment group create command, which deploys resources to a resource group in Azure.
With the YAML pipeline configured, we have now established an automated pathway that brings our Bicep modules from code to cloud, completing the cycle of a fully automated Infrastructure as Code, using Managed Identities.
Once deployed it should look like this :
Conclusion
In conclusion, we've successfully deployed a Logic App with a user-managed identity, ushering in a new era of secure and efficient application deployment. We've bid farewell to the old Service Principal method and eliminated the need for Azure KeyVault, streamlining our automation processes dramatically. This not only enhances security but also paves the way for future applications to seamlessly leverage managed identities, accelerating our journey towards more agile and secure cloud solutions.