How to Validate Your IaC Before Deployment Using Azure DevOps and PSRules

Fabian Acosta
Globant
Published in
10 min readSep 28, 2023
Photo by James Harrison on Unsplash

Introduction

Infrastructure as Code (IaC) is a modern approach to managing and administering infrastructure. It enables the definition and configuration of resources through files of code.

This new approach has gained significant popularity in recent years with the use of cloud providers such as Azure, AWS, and GCP. DevOps practices also contribute to this adoption by emphasizing the importance of centralized and versioned code, enabling Continuous Integration (CI) and Continuous Deployment (CD).

While there are numerous benefits to using IaC, we often overlook the importance of validating whether our IaC adheres to best practices or meets minimum requirements before deployment. This validation process is crucial in order to mitigate potential risks to our applications caused by future changes that could have been addressed during the earlier stages of development.

In this article, we will demonstrate how to validate IaC written in Bicep code using Azure Pipelines and the PSRules module. The outcome of this validation will be a comprehensive report containing recommendations for the resources involved.

Key Concepts

It’s important to be familiar with DevOps, CI/CD tools such as Azure DevOps or GitHub Actions, and IaC languages such as Bicep or Terraform. Here are some key concepts about the tools that are used in the exercise:

Exercise Summary

With the above concepts in mind, the goal of this exercise is to use the PSRule module to visualize the status of resources described in Bicep code before deployment through a pipeline

Here is the order of the exercise steps:

  1. Installation of the PSRule extension in Azure DevOps.
  2. Creation of a code-based pipeline hosted in a repository.
  3. Validation of the three pipeline tasks.
  4. Execution of the pipeline.
  5. Visualization of the report.
  6. Customization of the module.

By the end of the exercise, we should have:

  • A code-based pipeline hosted in a repository (as shown in the orange box in the image1 — Left Box).
  • An execution pipeline report with the recommendations (as shown in the purple box in the image1 — Right Box).
Image1 — Exercise overview

The following structure file and code are used during the development of the exercise so that you can clone it from this repository. This is the structure of the project:

── modules
│ ├── sqlserver.bicep = Bicep code with declaration of SQL Server and database resources
│ ├── vm.bicep = Bicep code with declaration of Virtual Machine resources
│ ├── vnet.bicep = Bicep code with declaration of Virtual Network and Subnet
│ └── webapp.bicep = Bicep code with declaration of App Plan Service and App Service Resources
├── main.bicep = Main bicep file with declaration of modules
├── main.bicepparam = Parameters file used by main.bicep
├── azure-pipeline.yaml = Definition of pipeline
└── ps-rule.yaml = File used to custom the PSRule module

Exercise Development

Let’s get started with the exercise. Now we will go step by step from installing and configuring the PSRule extension and getting our recommendations report at the end.

Install the PSRule extension

Go to the organization settings in Azure DevOps, bottom-left corner, then select “Extensions” from the menu:

Azure DevOps Organization Settings menu

Then click the “Browse Marketplace” option in the top-right corner:

Azure DevOps Extensions option

In the Marketplace, search for “PSRule” and click on the PSRule icon that appears in the search results:

Azure DevOps Marketplace search

Now, click on the “Get it free” button:

Azure DevOps PSRule extension

A web page requesting the organization’s information to proceed with the installation will appear. Fill in the requested information and proceed with the installation. Once installed, the extension will be visible in the extensions section, as shown in the image:

Azure DevOps Installed Extensions tab

Note: To install extensions, you must be a member of the Project Collection Administrators group. Check the prerequisites at the following link: Install Extensions.

Create a pipeline as code

Now, we will create the pipeline that runs the validation. Be aware you must have a repository created with the downloaded code. You can use this one as a start.

Go to the project where we will create the pipeline. A project called “bicepcode” has been created as a Git repository in the example. The repository contains the Bicep and YAML code explained in the summary section. Follow these steps:

Go to the Pipelines section of our project, and click “New Pipeline” in the upper-right corner:

Azure DevOps pipelines module

Choose Azure Repos Git as source:

Azure DevOps repository sources

Select the repository:

Azure DevOps repository selection

Select the second option to create the pipeline as code:

Azure DevOps type of pipelines

Finally, select the /azure-pipeline.yaml file and click on “Continue”:

Azure DevOps YAML file selection

You should see a screen similar to the following, showing the pipeline code with the three tasks. Finally, click on the “save” button:

Azure DevOps pipeline as code

Validation of tasks

Let’s check the tasks now. For the pipeline to work correctly, the three tasks must be properly configured. Open the azure-pipeline.yaml to see the details of the tasks. The following image gives an overview of them:

Overview of the three pipeline tasks

Install PSRule: This task installs the module on the agent that will execute the pipeline. In the module option, enter PSRule.Rules.Azure:

- task: ps-rule-install@2
displayName: "Install PSRule"
inputs:
module: PSRule.Rules.Azure
latest: true
prerelease: false

Run PSRule Validation: This task validates the IaC using the PSRule module. The result of this validation is delivered in a file:

- task: ps-rule-assert@2
displayName: "Run PSRule Validation"
continueOnError: true
inputs:
inputPath:
modules: 'PSRule.Rules.Azure'
option: 'ps-rule.yaml'
outputFormat: 'NUnit3'
outputPath: 'ps-rule-results.xml'

This task can be used since it was automatically installed by the extension through the task. The psrule.yamlfile is used to customize the module, which will be explained later in Customization section.

The continueOnErroroption is set to true to enable the pipeline to continue to the next task and see the results as a report. More options to control or stop the pipeline execution are in Stop the Execution section.

Publish PSRule Results: This task publishes and formats the result of the previous task into a detailed report:

- task: PublishTestResults@2
displayName: "Publish PSRule results"
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: 'ps-rule-results.xml'
failTaskOnFailedTests: false
testRunTitle: 'PSRule-File'

This task is an Azure DevOps standard task.

The failTaskOnFailedTest option is set to false to enable the pipeline to continue and see the results as a report. More options to control or stop the pipeline execution are in Break the Execution section.

Pipeline execution

Now that the pipeline is created, let’s follow the following instructions to run it.

Click on the “run” button located in the upper-right corner. A screen will appear to validate the branch and other options. Click on “run”.

Azure DevOps Run pipeline options

Azure DevOps Run pipeline options

A screen with the running job should appear.

Azure DevOps Jobs status

Now, click on the job, and you will see a screen with the running log of each task.

Wait for the job to finish, then go back to the previous screen, where you will see a summary of the job execution. Click on the percentage (%) as illustrated in the following image:

Azure DevOps Job execution summary

Viewing the final report

Now that the pipeline is finished let’s check the report. The report shows us the details of the scanning performed by the module through the pipeline. Additionally, it shows the rule that was validated for each of the components in the bicep code:

Azure DevOps Detailed Report

Let’s check this example; the following recommendation should appear in the report:

Azure DevOps Failed tests

By clicking on it, we will see that the TLS version for the web application is set to 1.0, and the recommendation is a minimum of 1.2:

Azure DevOps Suggested recommendation

This configuration is intentionally set in the AppService module (modules/webapp.bicep) to be reflected in the report. Change minTlsVersion:'1.0'to minTlsVersion:'1.2'. Run the pipeline again and the recommendation will disappear from the report:

resource appService 'Microsoft.Web/sites@2020-06-01' = {
name: webAppName
location: location
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
linuxFxVersion: 'PHP|8.0'
minTlsVersion: '1.0'

We can change the filter of the report to see all scanned rules that passed the test and the Azure Well-Architected Framework best practices:

Azure DevOps Passed tests

Note: PSRule also allows evaluating the current state of already deployed resources. This will be explained in a future article.

Customization

In our environments, some of these rules may not align with our needs, so we may want to customize the scan. That customization is possible through a file. The psrule.yaml file contains sections that enable customization of many features, such as:

  • Rules to exclude
  • Output language
  • Folders or files to ignore during scanning

Note: In the repository, there is a psrule.yaml file with some preconfigured settings.

ps-rule.yaml file example

The previous image shows the Azure.Template.UseDescriptionsrule placed in the rule:excludesection. That means the scanning will not recommend using descriptions for any declared parameter in the code. You can check every rule that PSRule includes for each kind of resource at the following link: By resource — PSRule for Azure. For customization options and configurations, check at this link: Configuring options — PSRule for Azure

Stop the execution

Finally, we are in the last step and we will see some options you can customize to stop the pipeline execution to avoid deploying code with no compliance:

  • failTaskOnFailedTests option on PublishTestResults@2: This task could show a fail status if there are test failures during the execution. The default is false, which will simply publish the results from the results file and the pipeline will stop the execution.
  • continueOnError on any task: if future steps should run even if this step fails. This is a standard option for any task in the pipeline, so you can control if the pipeline stops as soon as any task fails.
  • Outcome option on ps-rule-assert@2: This option filters output to include results with the specified outcome like Fail, Pass, Error, Processed, Problem, All. So this option could be helpful to show only specific outcomes to decide whether the code should be deployed or not.
  • Using Azure DevOps stages and approvals: You can configure a pipeline with two stages, one to validate the IaC and publish the result and a second stage to deploy the code. Azure DevOps gives the option to run the second stage only if some conditions are met and approval is given, so there is a chance to stop or continue the execution according to the needs. See the following image:
Using stages and approvals

Conclusions

One of the main challenges when deploying IaC is ensuring it meets minimum security standards and best practices. Thanks to modules like PSRule, the IaC can be assessed before deployment, allowing for timely action to make any necessary changes to enhance the quality of the resources. It is important to be aware of the status of our IaC before deployment; this will reduce the technical debt and ensure the stability and scalability of the resources.

References

--

--