Insight Tech APAC Blog Logo

Testing and Validation of Bicep Templates using PSRule

stephentulp
December 13, 2023

7 minutes to read

Bicep Advent Calendar

Introduction

In this blog post, we will look at how we can use PSRule to introduce validation and testing of Bicep modules and templates against things like the Azure Well-Architected Framework.

What is PSRule?

PSRule is a PowerShell module that allows you to validate infrastructure as code (IaC) and objects using PowerShell rules. It is an open-source, cross-platform, and general-purpose rules engine that integrates with popular continuous integration (CI) systems. You can use PSRule to define reusable business rules, provide recommendations, and share rules across teams or an organizations. PSRule support various scenarios such as validating Azure resources and GitHub repositories.

Why Should I use it?

PSRule assists in identifying changes to improve the quality of deployments into Azure using the principles of the Azure Well-Architected Framework (WAF) to:

  • Provide alignment to the WAF: Helps to improve the quality of IaC.
  • Link to documentation: Provides guidance on how to implement the change.
  • Examples: Examples are provided in Azure Bicep and ARM templates syntax that you can leverage in your own code.
  • Extensible: Use over 400 built-in tests or write your own tests in PowerShell, YAML, or JSON.

Testing Bicep Templates with PSRule

Now lets install PSRule locally and test one of the Bicep templates.

  • Install locally by running the following commands in a PowerShell.
Install-Module -Name 'PsRule' -Repository PSGallery -Scope CurrentUser -Force
Install-Module -Name 'PSRule.Rules.Azure' -Repository PSGallery -Scope CurrentUser -Force

Note: For the full installation instructions (local, Azure Devops & GitHub) use this link, we will use the GitHub option for tomorrows post.

  • We will need a ps-rule.yaml file in the root of our Bicep template folder, this file contains settings for PSRule, (EXAMPLE)
# Use rules from the following modules. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#includemodule
include:
  module:
    - PSRule.Rules.Azure
    - PSRule.Rules.CAF

# Require a minimum version of modules that include referenced baseline. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#requires
requires:
  PSRule: "@pre >=2.3.2"
  PSRule.Rules.Azure: "@pre >=1.18.1"

# Reference the repository in output (Change this to your GitHub Repo) - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#repositoryurl
repository:
  url: https://github.com/Insight-Services-APAC/insight-bicep-advent-calendar

execution:
  # Ignore warnings for resources and objects that don't have any rules. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#executionunprocessedobject
  unprocessedObject: Ignore

# Define baseline configuration - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#configuration
configuration:
  # Enable expansion for Bicep source files.
  AZURE_BICEP_FILE_EXPANSION: true

  # Expand Bicep module from Azure parameter files.
  AZURE_PARAMETER_FILE_EXPANSION: true

  # Set timeout for expanding Bicep source files.
  AZURE_BICEP_FILE_EXPANSION_TIMEOUT: 45

  # Set allowed locations for resources.
  AZURE_RESOURCE_ALLOWED_LOCATIONS:
    - australiaeast

  # Set allowed locations for resource groups.
  AZURE_RESOURCE_GROUP:
    location: australiaeast

input:
  # Ignore common files that don't need analysis. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#inputpathignore
  pathIgnore:
    - "**/bicepconfig.json"
    - "*.yaml"
    - "*.yml"
    - "*.md"
    - "*.ps1"
    - "*.png"
    - ".github/"
    - "src/modules/CARML/"

binding:
  # When binding has been configured these values override automatic binding by default - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#bindingprefertargetinfo
  preferTargetInfo: true
  # When an object is passed from the pipeline, PSRule assigns the object a TargetType. TargetType is used to filter rules based on object type and appears in output results. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#bindingtargettype
  targetType:
    - resourceType
    - type

rule:
  # Exclude specific rules from being validated. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#ruleexclude
  exclude:
    - Azure.Resource.UseTags
    - Azure.NSG.LateralTraversal

output:
  # Using the output/culture property. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#outputculture
  culture: ["en-AU", "en-US"]

Lets run PSRule across an example Bicep template and see the results.

Invoke-PSRule -InputPath '.\blog\storageAccount-v1.bicep' -Module 'PSRule.Rules.Azure'

PSRule

As we can see from the output above, we have a number of pass and fails outcomes and also a recommendation for each rulename. From the image we can see the following failures:

  • Azure.Storage.UseReplication
  • Azure.Storage.SoftDelete
  • Azure.Storage.ContainerSoftDelete
  • Azure.Storage.Firewall
  • Azure.Storage.MinTLS
  • Azure.Storage.BlobPublicAccess

If we want to get a better understanding of these failures, we can run the following command to get more information.

Assert-PSRule  -InputPath '.\blog\storageAccount-v1.bicep' -Format Detect

PSRule PSRule

Now we have a better understanding of the failures and also a link to the documentation on how to fix the issue. Now lets run the validation on another template that has addressed the failures from the previous template.

Assert-PSRule  -InputPath '.\blog\storageAccount-v2.bicep' -Format Detect

We can now see that there is only one failure and that is for the Azure.Storage.UseReplication rule, lets have a look at the output.

PSRule

We have a couple of options to address this failure:

  • We can exclude the rule from validation by adding the following to the ps-rule.yaml file. This will suppress the rule from being validated for all storage accounts and would be useful if you are only using a single Azure region.
rule:
  # Exclude specific rules from being validated. - https://microsoft.github.io/PSRule/v2/concepts/PSRule/en-US/about_PSRule_Options/#ruleexclude
  exclude:
    - Azure.Resource.UseTags # Tags deployed via templates.
    - Azure.NSG.LateralTraversal
    - Azure.Storage.UseReplication # Storage replication is not required for all storage accounts as only a single region is used.
  • We can get really specific and create a suppression group for the rule and only suppress it for the storage account that we are deploying. This is useful if you are deploying to multiple regions and only want to suppress the rule for a specific storage account.

For details on authoring suppression groups see Suppression Groups and Expressions.

Conclusion

PSRule is very powerful and provides a variety of configuration options to test and validate IaC deployments. In this post we have only scratched the surface of what PSRule can do.

Further Reading

Some further reading on the topics covered in this post: