A community-driven initiative focused on improving Azure governance, security, and cost management through best practices and automation.
What is Azure Spring Clean
The Azure Spring Clean community initiative is an annual event focused on improving and optimizing Azure environments by promoting best practices, governance, security, and cost management. It encourages cloud professionals, developers, and IT admins to review their Azure resources, clean up unused services, optimize costs, and improve security and compliance.
We should also give a massive shout out to Joe Carlyle and Thomas Thornton for hosting Azure Spring Clean!
Azure Quick Review (AZQR)
Azure Quick Review (AZQR) is an open-source tool developed by Microsoft to quickly assess the security, compliance, and best practices of Azure resources. It provides automated checks and generates reports to help organizations identify misconfigurations, security risks, and optimization opportunities.
For more information you can check the docs page here and the Git repository here
Key Features
Automated Assessments: Scans various Azure services, including compute, networking, security, storage, and databases.
Best Practices Validation: Compares configurations against Microsoft’s best practices.
Security and Compliance: Identifies security vulnerabilities, missing policies, and compliance gaps.
Report Generation: Outputs findings in a structured report (Excel format) for easy review and action.
Use Cases
Cloud Governance: Ensures compliance with security and operational guidelines.
Security Audits: Identifies potential vulnerabilities in Azure deployments.
Cost Optimization: Provides recommendations to improve resource efficiency.
Infrastructure As Code
Deployment Time! I’ve spent some time building out a Function App and some Infrastructure As Code to help streamline this process.
You can check the project over on GitHub bwc-azure-quick-review-functionapp.
Required Modules and Packages
Azure CLI Azure Bicep Az Module (PowerShell) Microsoft Graph Module (PowerShell)*
* Required for Graph Permissions for the Managed Identity
During the deployment, we deploy the following resources:
Deployment Notes
90% of the bicep uses the Azure Verified Modules, However there are some custom modules for RBAC Assignment.
This this to allow the Managed Identity Reader access to the subscription.
Deployment Time
Once you’ve cloned the repository, From the Infra folder execute the following powershell
# Azure Functions profile.ps1## This script runs during a "cold start" of your Function App.# A "cold start" happens when:## * The Function App starts for the first time.# * The Function App starts after being de-allocated due to inactivity.## You can use this file to define helper functions, run commands, or set environment variables.# NOTE: Any non-environment variables will be reset after the first execution.# Authenticate with Azure PowerShell using Managed Identity (MSI) if Managed Identity ID is available.if($env:managedIdentityId){# Disable automatic Az context saving for the current process to avoid conflicts.Disable-AzContextAutosave-ScopeProcess|Out-Null# Authenticate to Azure using Managed Identity.Write-Host"Authenticating with Azure using Managed Identity..."Connect-AzAccount-Identity-AccountId$env:managedIdentityId|Out-Null# Retrieve the Azure access token for Microsoft Graph API.$azAccessToken=(Get-AzAccessToken-AsSecureString-ResourceUrl"https://graph.microsoft.com").Token# Connect to Microsoft Graph using the access token.Write-Host"Authenticating with Microsoft Graph..."Connect-MgGraph-AccessToken$azAccessToken|Out-NullWrite-Host"Authentication successful."}else{Write-Warning"Managed Identity ID is not found. Azure authentication will be skipped."}
requirements.psd1
1
2
3
4
5
6
7
8
9
10
# This file enables modules to be automatically managed by the Functions service.# See https://aka.ms/functionsmanageddependency for additional information.#@{# For latest supported version, go to 'https://www.powershellgallery.com/packages/Az'.# To use the Az module in your function app, please uncomment the line below.'Az.Accounts'='4.*''Microsoft.Graph.Authentication'='2.*''Microsoft.Graph.Identity.DirectoryManagement'='2.*'}
From Overview > Functions > Create Function > Timer Function
<#
.SYNOPSIS Automates the process of downloading, executing, and emailing an Azure Quick Review report.
.DESCRIPTION This script performs the following tasks:
1. Downloads the latest Azure Quick Review tool release from GitHub.
2. Extracts the downloaded release.
3. Executes the Azure Quick Review scan for a specified Azure subscription.
4. Generates a report file with a timestamp and organization name.
5. Sends the generated report via email using SMTP, with configuration provided via environment variables.
6. Cleans up temporary files after sending the email.
.PARAMETER Timer
(Optional) Parameter for scheduling or timing purposes (not used in the script body).
.FUNCTIONS
Send-ReportByEmail
Sends the generated Azure Quick Review report as an email attachment using SMTP.
Requires SMTP and email configuration to be set in environment variables.
Cleans up the report file after sending.
Get-AzureQuickReview
Downloads and extracts the latest Azure Quick Review tool release from GitHub.
Invoke-AzureQuickReviewScan
Executes the Azure Quick Review scan using the downloaded tool.
Sets required environment variables and generates a uniquely named report file.
.ENVIRONMENT VARIABLES
emailEnabled - Enables/disables email sending (any value enables).
emailSMTPServer - SMTP server address.
emailSMTPServerPort - SMTP server port.
emailSMTPAuthUserName - SMTP authentication username.
emailSMTPAuthPassword - SMTP authentication password.
emailSender - Email sender address.
emailRecipient - Email recipient address.
AZURE_ORG_NAME - Azure organization name (set during scan).
AZURE_TENANT_ID - Azure tenant ID (set during scan).
managedIdentityId - Azure managed identity client ID.
.NOTES - Requires PowerShell 5.1+ and necessary Azure/AzureAD modules.
- Assumes the script is run in an environment with required permissions and environment variables set.
- The Azure subscription ID is hardcoded and should be updated as needed.
#>param($Timer)functionSend-ReportByEmail{param($azQuickReviewFilePath)if($env:emailEnabled){Write-Output`r "Sending the report via email..."try{# Fetch environment variables$smtpServer=$env:emailSMTPServer$smtpPort=$env:emailSMTPServerPort$smtpUser=$env:emailSMTPAuthUserName$smtpPassword=$env:emailSMTPAuthPassword# Email details$from=$env:emailSender$to=$env:emailRecipient$date=Get-Date-Format'MMMM yyyy'$subject="[Azure Quick Review] - New Advisory Report - $date"$body=@"
Hello,
This is your Azure Quick Review report.
Tenant Name: $env:AZURE_ORG_NAMETenant ID: $env:AZURE_TENANT_IDPlease find the detailed findings in the attached report.
Best regards,
Azure Quick Review Automation
"@# Create email message$emailMessage=New-ObjectSystem.Net.Mail.MailMessage($from,$to,$subject,$body)$emailMessage.IsBodyHtml=$false$emailMessage.Priority=[System.Net.Mail.MailPriority]::High# Add attachment if availableif($azQuickReviewFilePath){$attachment=New-ObjectSystem.Net.Mail.Attachment-ArgumentList$azQuickReviewFilePath$emailMessage.Attachments.Add($attachment)}# Configure SMTP client$smtpClient=New-ObjectSystem.Net.Mail.SmtpClient($smtpServer,$smtpPort)$smtpClient.Credentials=New-ObjectSystem.Net.NetworkCredential($smtpUser,$smtpPassword)$smtpClient.EnableSsl=$true# Send email$smtpClient.Send($emailMessage)Write-Output"Email sent successfully."# Cleanup$emailMessage.Dispose()if($attachment){$attachment.Dispose()}## File Clean UpRemove-Item-Path$fileName}catch{Write-Error"Failed to send email: $_"exit1}}}functionGet-AzureQuickReview{# Download Azure Quick ReviewWrite-Output`r "Checking for Azure Quick Review Release..."$releaseName='azqr-linux-amd64.zip'$release=Invoke-RestMethod-Uri"https://api.github.com/repos/azure/azqr/releases/latest"$downloadUrl=$($release.assets|Where-Object{$_.name-eq$releaseName}).browser_download_urlWrite-Output"Downloading $downloadUrl"Invoke-WebRequest-Method'Get'-Uri$downloadUrl-OutFile./$releaseNameWrite-Output"Extracting $releaseName"Expand-Archive-Path./$releaseName-DestinationPath.-Force# Clean UpRemove-Item-Path./$releaseName}functionInvoke-AzureQuickReviewScan{## Execute Azure Quick Review$env:AZURE_TOKEN_CREDENTIALS='prod'$env:AZURE_ORG_NAME=(Get-MgOrganization).DisplayName$env:AZURE_TENANT_ID=(Get-AzContext).Tenant.Id$env:AZURE_CLIENT_ID=$env:managedIdentityId# Report Naming$dateTime=Get-Date-Format'yyyy_MM_dd_HH_mm_ss'$Script:reportName="$($dateTime)_$($env:AZURE_ORG_NAME)_Azure_Review"Write-Output`r "Starting Azure Quick Review Report..."&"./bin/linux_amd64/azqr"scan--subscription-idb67e1026-b589-41e2-b41f-73f8803f71a0--xlsx--output-name./$reportName2>&1}## Get Azure Quick ReviewGet-AzureQuickReview## Invoke Azure Quick Review ScanInvoke-AzureQuickReviewScan## Send Email$fileName="$($reportName).xlsx"Send-ReportByEmail-azQuickReviewFilePath./$fileName
How it works
The Function App is configured as a timer-triggered function, automating the Azure Quick Review process. It:
Downloads the latest release of Azure Quick Review.
Conducts an audit of Azure resources.
Generates a report in Excel format.
Sends the report via email using SMTP authentication.
SMTP authentication settings can be configured in the Bicep parameter file.
In the biceep param file, You can configure the SMTP Auth settings.
NOTE
For testing, I used Sendgrid and it worked without issue 👏
// Email - SMTP Configuration@description('Enable Email Notifications')paramemailEnabled=false@description('Configure SMTP Server Address')paramemailSMTPServer=''@description('Configure SMTP Server Port')paramemailSMTPPort=587@description('Configure SMTP Server Username')paramemailSMTPAuthUserName=''@description('Configure SMTP Server Password')paramemailSMTPAuthPassword=''@description('Configure Email Sender')paramemailSender=''@description('Configure Email Recipient')paramemailRecipient=''
Example Email Notification
Azure Quick Review Report Summary
The Excel report generated by Azure Quick Review (AZQR) provides an in-depth overview of your Azure environment, highlighting security risks, compliance gaps, and optimization opportunities. The report is structured into multiple tabs, each offering specific insights into different aspects of your Azure resources.
Report Sections & Breakdown
Recommendations
Provides a summary of key security, compliance, and configuration recommendations.
Highlights areas where best practices are not being followed.
Includes suggested actions to improve security posture, optimize costs, and enhance operational efficiency.
Impacted Resources
Lists the Azure resources affected by the identified issues.
Categorizes findings based on severity (Critical, High, Medium, Low).
Helps prioritize remediation efforts.
Resource Types
Displays the distribution of different resource types found in the environment.
Useful for understanding the Azure services in use.
Inventory
A comprehensive list of all discovered Azure resources.
Provides metadata such as resource name, type, region, subscription, and tags.
Useful for asset management and governance.
Advisor
Extracts relevant recommendations from Azure Advisor.
Covers areas such as reliability, security, performance, cost optimization, and operational excellence.
Helps align with Microsoft’s Well-Architected Framework.
Defender Recommendations
Provides insights from Microsoft Defender for Cloud.
Lists security vulnerabilities and recommendations for remediation.
Helps ensure compliance with security best practices.
Out of Scope
Lists any resources that were excluded from the analysis.
Can be useful to understand if certain resources need to be manually reviewed.
Defender
Detailed breakdown of Defender for Cloud findings, including security alerts and recommendations.
Helps organizations strengthen their security posture.
Costs
Highlights potential cost savings based on Azure Cost Management insights.
Identifies underutilized resources and provides right-sizing recommendations.
Useful for budgeting and cost optimization.
Pivot Table
A dynamic table allowing for custom data analysis.
Enables filtering and sorting of report findings for deeper insights.
Using the Report
Prioritize Security Fixes Focus on the Recommendations, Impacted Resources, and Defender Recommendations tabs first.
Optimize Costs Review the Costs and Advisor sections for efficiency improvements.
Improve Governance Use the Inventory and Resource Types tabs for tracking Azure resource usage.
By leveraging the insights from this report, organizations can enhance security, improve compliance, and optimize costs within their Azure environment.
Wrap Up
Automating Azure Quick Review as part of your governance strategy can save time, enhance security, and improve compliance. By integrating this tool into a scheduled monthly review, you ensure that your Azure environment remains aligned with best practices, security standards, and the Well-Architected Framework (WAF).
Regular reviews help identify misconfigurations, security risks, and cost inefficiencies before they become critical issues. Automating these checks reduces manual effort and provides a consistent, repeatable process for maintaining a secure and optimized cloud environment.
By leveraging Infrastructure as Code (IaC) and automation, you can seamlessly incorporate these reviews into your workflows, enabling proactive governance and continuous improvement.
If you found this valuable, consider sharing your feedback or contributing to the Azure Quick Review GitHub project. Stay secure, stay optimized, and happy auditing! 🚀