Testing infrastructure#
You can use PSRule to create tests for Infrastructure as Code (IaC). Each test is called a rule.
PSRule allows you to write rules using YAML, JSON, or PowerShell. Regardless of the format you choose, any combination of YAML, JSON, or PowerShell rules can be used together.
Abstract
This topic covers how to create a rule using YAML, JSON, and PowerShell by example. This example, while fictitious is indicative of common testing and validation scenarios for IaC.
Sample data#
To get started authoring a rule, we will be working with a sample file settings.json
.
This sample configuration file configures an application.
For the purpose of this example, one configuration setting supportsHttpsTrafficOnly
is set.
This configuration setting can be either true
or false
.
When set to true
, Transport Layer Security (TLS) is enforced.
When set to false
, the application permits insecure communication with HTTP.
Contents of settings.json
Create a settings.json
file in the root of your repository with the following contents.
{
"type": "app1",
"version": 1,
"configure": {
"supportsHttpsTrafficOnly": false
}
}
Define a rule#
To meet the requirements of our organization we want to write a rule to:
- Enforce secure traffic by requiring
supportsHttpsTrafficOnly
to betrue
. - Enforce use of TLS 1.2 as a minimum by requiring
minTLSVersion
to be1.2
.
In this section the same rule will be authored using YAML, JSON, and PowerShell.
Tip
To make you editing experience even better, consider installing the Visual Studio Code extension.
Create a .ps-rule/Local.Rule.yaml
file in your repository with the following contents.
---
# Synopsis: An example rule to require TLS.
apiVersion: github.com/microsoft/PSRule/v1
kind: Rule
metadata:
name: 'Local.YAML.RequireTLS'
spec:
condition:
field: 'configure.supportsHttpsTrafficOnly'
equals: true
- Use a short
Synopsis:
to describe your rule in a line comment above your rule. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name.
- The
condition
property determines the checks PSRule will use to testsettings.json
. Specifically, the object pathconfigures.supportsHttpsTrafficOnly
must exist and be set totrue
.
Create a .ps-rule/Local.Rule.jsonc
file in your repository with the following contents.
[
{
// Synopsis: An example rule to require TLS.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Rule",
"metadata": {
"name": "Local.JSON.RequireTLS"
},
"spec": {
"condition": {
"field": "configure.supportsHttpsTrafficOnly",
"equals": true
}
}
}
]
- Use a short
Synopsis:
to describe your rule in a line comment above your rule. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name.
- The
condition
property determines the checks PSRule will use to testsettings.json
. Specifically, the object pathconfigures.supportsHttpsTrafficOnly
must exist and be set totrue
.
Create a .ps-rule/Local.Rule.ps1
file in your repository with the following contents.
# Synopsis: An example rule to require TLS.
Rule 'Local.PS.RequireTLS' {
$Assert.HasFieldValue($TargetObject, 'configure.supportsHttpsTrafficOnly', $True)
}
- Use a short
Synopsis:
to describe your rule in a line comment above your rule. For this to be interpreted by PSRule, only a single line is allowed. - Name your rule with a unique name.
- The condition contained within the curly braces
{ }
determines the checks PSRule will use to testsettings.json
. - The
$Assert.HasFieldValue
method checks the object pathconfigures.supportsHttpsTrafficOnly
exists and is set totrue
.
Tip
To learn more about recommended file and naming conventions for rules, continue reading Storing and naming rules.
Using multiple conditions#
Each rule must have at least one condition. Additional conditions can be combined to check multiple test cases.
In the example a minTLSVersion
configuration setting does not exist and is not set.
Update .ps-rule/Local.Rule.yaml
in your repository with the following contents.
---
# Synopsis: An example rule to require TLS.
apiVersion: github.com/microsoft/PSRule/v1
kind: Rule
metadata:
name: 'Local.YAML.RequireTLS'
spec:
condition:
allOf:
- field: 'configure.supportsHttpsTrafficOnly'
equals: true
- field: 'configure.minTLSVersion'
equals: '1.2'
- Using the
allOf
expression requires that all conditions be true for the rule to pass. This expression allows an array of one or more conditions to be provided. UsinganyOf
would pass the rule if any single condition is true.
Update .ps-rule/Local.Rule.jsonc
in your repository with the following contents.
[
{
// Synopsis: An example rule to require TLS.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Rule",
"metadata": {
"name": "Local.JSON.RequireTLS"
},
"spec": {
"condition": {
"allOf": [
{
"field": "configure.supportsHttpsTrafficOnly",
"equals": true
},
{
"field": "configure.minTLSVersion",
"equals": "1.2"
}
]
}
}
}
]
- Using the
allOf
expression requires that all conditions be true for the rule to pass. This expression allows an array of one or more conditions to be provided. UsinganyOf
would pass the rule if any single condition is true.
Update .ps-rule/Local.Rule.ps1
in your repository with the following contents.
# Synopsis: An example rule to require TLS.
Rule 'Local.PS.RequireTLS' {
$Assert.HasFieldValue($TargetObject, 'configure.supportsHttpsTrafficOnly', $True)
$Assert.HasFieldValue($TargetObject, 'configure.minTLSVersion', '1.2')
}
- An additional,
$Assert.HasFieldValue
assertion helper method can be called. The rule will pass if all of the conditions return true.
Testing#
Testing manually#
To test the rule manually, run the following command.
Assert-PSRule -f ./settings.json
Advanced usage#
Severity level#
v2.0.0
When defining a rule, you can specify a severity level.
The severity level is used if the rule fails.
By default, the severity level for a rule is Error
.
Error
- A serious problem that must be addressed before going forward.Warning
- A problem that should be addressed.Information
- A minor problem or an opportunity to improve the code.
In a continuous integration (CI) pipeline, severity level is particularly important.
If any rule fails with a severity level of Error
the pipeline will fail.
This helps prevent serious problems from being introduced into the code base or deployed.
The following example shows how to set the severity level to Warning
.
---
# Synopsis: An example rule to require TLS.
apiVersion: github.com/microsoft/PSRule/v1
kind: Rule
metadata:
name: 'Local.YAML.RequireTLS'
spec:
level: Warning
condition:
allOf:
- field: 'configure.supportsHttpsTrafficOnly'
equals: true
- field: 'configure.minTLSVersion'
equals: '1.2'
[
{
// Synopsis: An example rule to require TLS.
"apiVersion": "github.com/microsoft/PSRule/v1",
"kind": "Rule",
"metadata": {
"name": "Local.JSON.RequireTLS"
},
"spec": {
"level": "Warning",
"condition": {
"allOf": [
{
"field": "configure.supportsHttpsTrafficOnly",
"equals": true
},
{
"field": "configure.minTLSVersion",
"equals": "1.2"
}
]
}
}
}
]
Update .ps-rule/Local.Rule.ps1
in your repository with the following contents.
# Synopsis: An example rule to require TLS.
Rule 'Local.PS.RequireTLS' -Level Warning {
$Assert.HasFieldValue($TargetObject, 'configure.supportsHttpsTrafficOnly', $True)
$Assert.HasFieldValue($TargetObject, 'configure.minTLSVersion', '1.2')
}