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 This script performs an Azure Quick Review scan, generates a report, and optionally sends the report via email.
.DESCRIPTION The script performs the following steps:
1. Ensures the report directory exists.
2. Downloads the latest Azure Quick Review tool.
3. Executes the Azure Quick Review scan and generates a report.
4. Optionally sends the generated report via email if email sending is enabled.
.PARAMETER Timer
A parameter that can be used to trigger the script execution based on a timer.
.PARAMETER folderName
The name of the directory where the Azure Quick Review tool and reports will be stored.
.PARAMETER azQuickReviewFilePath
The file path of the generated Azure Quick Review report.
.FUNCTIONS
Test-Directory
Ensures the specified directory exists. If it does not exist, it creates the directory.
Invoke-DownloadAzureQuickReview
Downloads the latest release of the Azure Quick Review tool from GitHub.
Invoke-AzureQuickReviewScan
Executes the Azure Quick Review scan and generates a report in the specified directory.
Send-ReportByEmail
Sends the generated Azure Quick Review report via email if email sending is enabled.
.NOTES - Ensure that the necessary environment variables are set for email sending.
- The script uses managed identity for authentication with Azure.
#>param($Timer)# Define Report Directory$folderName='azqrReports'# Ensure directory existsfunctionTest-Directory{param($folderPath)if(-Not(Test-Path-Path$folderPath-PathTypeContainer)){try{New-Item-ItemTypeDirectory-Path$folderPath-Force|Out-NullWrite-Output"Directory '$folderPath' created successfully."}catch{Write-Error"Failed to create directory '$folderPath': $_"exit1}}}# Download Azure Quick ReviewfunctionInvoke-DownloadAzureQuickReview{param($folderPath)Write-Output"Downloading Azure Quick Review..."try{$azQRLatestReleaseTagUrl='https://api.github.com/repos/Azure/azqr/releases/latest'$azQRLatestReleaseTag=(Invoke-RestMethod-Uri$azQRLatestReleaseTagUrl).tag_name$azQRDownloadUrl="https://github.com/Azure/azqr/releases/download/$azQRLatestReleaseTag/azqr-ubuntu-latest-amd64"Invoke-WebRequest-Uri$azQRDownloadUrl-OutFile"./$folderPath/azqr"chmod+x"./$folderPath/azqr"Write-Output"Azure Quick Review downloaded successfully."}catch{Write-Error"Failed to download Azure Quick Review: $_"exit1}}# Execute Azure Quick Review ScanfunctionInvoke-AzureQuickReviewScan{param($folderPath)Write-Output"Executing Azure Quick Review Scan..."try{$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'$reportName="$($dateTime)_$($env:AZURE_ORG_NAME)_azure_review"Write-Output"Report: [$reportName]"# Execute Azure Quick Review&"./$folderPath/azqr"scan--output-name"./$folderPath/$reportName"$script:azQuickReviewFilePath=(Get-ChildItem-Path./$folderPath/*.xlsx|Sort-ObjectLastWriteTime-Descending|Select-Object-First1).FullNameWrite-Output"Azure Quick Review scan completed successfully. Report saved at $azQuickReviewFilePath."}catch{Write-Error"Azure Quick Review execution failed: $_"exit1}}# Send Email with Report (if enabled)functionSend-ReportByEmail{param($azQuickReviewFilePath)if($env:emailEnabled){Write-Output"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()}}catch{Write-Error"Failed to send email: $_"exit1}}}# Main logicTest-Directory-folderPath$folderNameInvoke-DownloadAzureQuickReview-folderPath$folderNameInvoke-AzureQuickReviewScan-folderPath$folderNameSend-ReportByEmail-azQuickReviewFilePath$azQuickReviewFilePath
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! 🚀