I am going to show how you can run Inspec-Azure tests in an Azure DevOps Pipeline to test and validate your Azure Resources. In a previous blog post, I blogged Using Inspec-Azure to test your Azure Resources . In that blog post I detail how to configure and run Inspec-Azure locally.
In this post I will detail how you can run this in an Azure DevOps Pipeline.
What is Inspec-Azure?
Inspec-Azure is a resource pack provided by Chef that uses the Azure REST API, to allow you to write tests for resources that you have deployed in Microsoft Azure. These tests can be used to validate the Azures resources that were deployed via code using Terraform or Azure RM templates. Inspec is an open source framework that is used for testing and auditing your infrastructure, in this blog post I will show how you can create tests against your Azure resources using Inspec-Azure.
Why run Inspec-Azure in a Pipeline?
Begin the compliance of your Azure resources right at the source – the Azure Pipeline that you are deploying Azure resources from!
Having Inspec-Azure run within your Pipeline integration can flag issues straight away and notify relevant parties that the current pipeline release has a validation testing issue. Great!
The deployment may deploy OK and look fine but the deployment has not been validated as what is expected to be deployed and the actual state the specific resources are in.
Time to Azure DevOps
In this blog post, I am going to detail how to create an Azure DevOps Pipeline to run Inspec-Azure testing, it will be a single stage Pipeline to outline how to run Inspec-Azure only. You can use this to implement into your required pipelines.
As my example will be ran on an Azure DevOps managed agent, you will need to install ruby and then install inspec-bin via gem install, this is done below:-
- task: UseRubyVersion@0 displayName: 'Install Ruby' inputs: versionSpec: '>= 2.5' addToPath: true - script: gem install inspec-bin displayName: 'Install inspec-bin'
The next task, runs a bash script which calls “inspec exec” , notice within the script block you will need to input the required parameters:-
|AZURE_SUBSCRIPTION_ID||Subscription ID of your Azure Subscription|
|AZURE_CLIENT_ID||Client ID of Azure AD Application that has required access to the subscription|
|AZURE_CLIENT_SECRET||Client Secret of above Azure AD Application|
|AZURE_TENANT_ID||The Azure Active Directory tenant(directory) ID.|
- task: Bash@3 displayName: 'Run inspec tests' inputs: targetType: inline script: | export AZURE_SUBSCRIPTION_ID="xxxxxxxx" export AZURE_CLIENT_ID="xxxxxxxx" export AZURE_CLIENT_SECRET="xxxxxxxx" export AZURE_TENANT_ID="xxxxxxxx" inspec exec ./azure-inspec-tests/ -t azure:// --chef-license=accept --reporter cli junit:testresults.xml
Notice the last line of the above, –reporter? This will output the test results in JUnit XML file. This will be used with the PublishTestResults@2 to display these results within Azure DevOps Portal – I will show this later
Finally, to publish test results above to Azure DevOps portal, we will use the PublishTestResults@2 task
- task: PublishTestResults@2 displayName: Publish inspec test results condition: succeededOrFailed() inputs: testResultsFiles: '**/testresults.xml' mergeTestResults: true
Awesome, lets look at how running this pipeline looks within Azure DevOps; I am testing against resources deployed in Azure Portal via Terraform , these resources are found here.
Azure Inspec testing found here – these tests will test for:-
- Resource Group: tamops exists
- Virtual Network: tamops-vnet exists in Resource Group: tamops
- Virtual Network: tamops-vnet has address space: 192.168.0.0/16
- Virtual Network: tamops-vnet has subnet: subnet
Note:- In the latest version of Inspec-Azure there is only a certain amount of resources that are available to be tested against, in previous versions of Inspec-Azure you can use azure_generic_resource but it is deprecated in newer versions. In a later blog I will show how this can be referenced and used within a Docker container.
Full pipeline to run my Inspec Azure testing:-
Pipeline found here on Github
name: $(BuildDefinitionName)_$(date:yyyyMMdd)$(rev:.r) pool: linuxtamops variables: - group: production trigger: none pr: none stages : - stage: test jobs: - job: "Checkout" steps: - task: UseRubyVersion@0 displayName: 'Install Ruby' inputs: versionSpec: '>= 2.5' addToPath: true - script: gem install inspec-bin displayName: 'Install inspec-bin' - task: Bash@3 displayName: 'Run inspec tests' inputs: targetType: inline script: | export AZURE_SUBSCRIPTION_ID="xxxxxxxxxxxx" export AZURE_CLIENT_ID="xxxxxxxxxxxx" export AZURE_CLIENT_SECRET="xxxxxxxxxxxx" export AZURE_TENANT_ID="xxxxxxxxxxxx" inspec exec ./azure-inspec-tests/ -t azure:// --chef-license=accept --reporter cli junit:inspectestresults.xml - task: PublishTestResults@2 displayName: Publish inspec test results condition: succeededOrFailed() inputs: testResultsFiles: '**/inspectestresults.xml' mergeTestResults: true
Output of successful run of the pipeline:-
Review “Run inspec tests” to view the inspec-azure tests within the Pipeline job
Now review the tests section of that Pipeline run, easy to read tests results!
Awesome, a nice-readable test result format! Hopefully this blog will assist you to begin implementing Inspec-Azure into your Azure DevOps Pipelines!