зеркало из
1
0
Форкнуть 0

Added expansion from Bicep source files #848 #670 (#850)

This commit is contained in:
Bernie White 2021-08-04 11:52:56 +10:00 коммит произвёл GitHub
Родитель 6c63026449
Коммит 58cf1e5bf7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
35 изменённых файлов: 967 добавлений и 32 удалений

Просмотреть файл

@ -141,18 +141,22 @@ stages:
displayName: 'PowerShell coverage'
coverage: 'true'
publishResults: 'false'
platform: linux
bicepIntegration: 'true'
- template: jobs/test.yaml
parameters:
name: macOS_10_15
displayName: 'PowerShell 7.1 - macOS-10.15'
imageName: 'macOS-10.15'
platform: macos
- template: jobs/test.yaml
parameters:
name: windows
displayName: 'PowerShell 5.1 - win2016'
imageName: 'vs2017-win2016'
platform: windows
- template: jobs/testContainer.yaml
parameters:

Просмотреть файл

@ -8,6 +8,8 @@ parameters:
imageName: ''
coverage: 'false'
publishResults: 'true'
platform: 'linux'
bicepIntegration: 'false'
jobs:
- job: ${{ parameters.name }}
@ -20,6 +22,10 @@ jobs:
skipComponentGovernanceDetection: true
steps:
# - template: ../steps/installBicep.yaml
# parameters:
# platform: ${{ parameters.platform }}
# Install pipeline dependencies
- powershell: ./.azure-pipelines/pipeline-deps.ps1
displayName: 'Install dependencies'
@ -35,6 +41,7 @@ jobs:
- powershell: Invoke-Build TestModule -Configuration ${{ parameters.buildConfiguration }} -Build $(Build.BuildNumber)
env:
COVERAGE: ${{ parameters.coverage }}
RUN_BICEP_INTEGRATION: ${{ parameters.bicepIntegration }}
displayName: 'Test module'
# Pester test results

Просмотреть файл

@ -27,6 +27,10 @@ jobs:
skipComponentGovernanceDetection: true
steps:
# - template: ../steps/installBicep.yaml
# parameters:
# platform: linux
# Install pipeline dependencies
- powershell: ./.azure-pipelines/pipeline-deps.ps1
displayName: 'Install dependencies'

Просмотреть файл

@ -0,0 +1,45 @@
parameters:
- name: platform
type: string
default: linux
steps:
- ${{ if eq(parameters.platform, 'linux') }}:
- script: |
apt-get install sudo
# Fetch the latest Bicep CLI binary
curl -Lo bicep.bin https://github.com/Azure/bicep/releases/latest/download/bicep-linux-x64
# Mark it as executable
chmod +x ./bicep.bin
# Add bicep to your PATH (requires admin)
sudo mv ./bicep.bin /usr/local/bin/bicep
displayName: 'Install Bicep'
- ${{ if eq(parameters.platform, 'macos') }}:
- script: |
# Fetch the latest Bicep CLI binary
curl -Lo bicep https://github.com/Azure/bicep/releases/latest/download/bicep-osx-x64
# Mark it as executable
chmod +x ./bicep
# Add Gatekeeper exception (requires admin)
sudo spctl --add ./bicep
# Add bicep to your PATH (requires admin)
sudo mv ./bicep /usr/local/bin/bicep
displayName: 'Install Bicep'
- ${{ if eq(parameters.platform, 'windows') }}:
- pwsh: |
# Create the install folder
$installPath = "$env:USERPROFILE\.bicep"
$installDir = New-Item -ItemType Directory -Path $installPath -Force
$installDir.Attributes += 'Hidden'
# Fetch the latest Bicep CLI binary
(New-Object Net.WebClient).DownloadFile("https://github.com/Azure/bicep/releases/latest/download/bicep-win-x64.exe", "$installPath\bicep.exe")
# Add bicep to your PATH
$currentPath = (Get-Item -path "HKCU:\Environment" ).GetValue('Path', '', 'DoNotExpandEnvironmentNames')
if (-not $currentPath.Contains("%USERPROFILE%\.bicep")) { setx PATH ($currentPath + ";%USERPROFILE%\.bicep") }
if (-not $env:path.Contains($installPath)) { $env:path += ";$installPath" }
displayName: 'Install Bicep'

1
.vscode/settings.json поставляемый
Просмотреть файл

@ -20,6 +20,7 @@
"files.associations": {
"**/.azure-pipelines/*.yaml": "azure-pipelines",
"**/.azure-pipelines/jobs/*.yaml": "azure-pipelines",
"**/.azure-pipelines/steps/*.yaml": "azure-pipelines",
"**/tests/**/Resources*.Template*.json": "arm-template"
},
"cSpell.words": [

Просмотреть файл

@ -7,6 +7,14 @@ See [troubleshooting guide] for a workaround to this issue.
## Unreleased
What's changed since pre-release v1.6.0-B2107028:
- New features:
- **Experimental**: Added support for expansion from Bicep source files. [#848](https://github.com/Azure/PSRule.Rules.Azure/issues/848) [#670](https://github.com/Azure/PSRule.Rules.Azure/issues/670)
- Bicep support is currently experimental.
- To opt-in set the `AZURE_BICEP_FILE_EXPANSION` configuration to `true`.
- For more information see [Using Bicep](https://azure.github.io/PSRule.Rules.Azure/using-bicep/).
## v1.6.0-B2107028 (pre-release)
What's changed since v1.5.1:

Просмотреть файл

@ -16,3 +16,22 @@
--md-success-invert-color: #fff;
--md-success-color: #107c10;
}
:root {
--md-admonition-icon--experimental: url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill-rule="evenodd" d="M8 8.807V3.5h-.563a.75.75 0 0 1 0-1.5h9.125a.75.75 0 0 1 0 1.5H16v5.307l5.125 9.301c.964 1.75-.302 3.892-2.299 3.892H5.174c-1.998 0-3.263-2.142-2.3-3.892L8 8.807zM14.5 3.5h-5V9a.75.75 0 0 1-.093.362L7.127 13.5h9.746l-2.28-4.138A.75.75 0 0 1 14.5 9V3.5zM4.189 18.832 6.3 15h11.4l2.111 3.832a1.125 1.125 0 0 1-.985 1.668H5.174a1.125 1.125 0 0 1-.985-1.668z"/></svg>')
}
.md-typeset .admonition.experimental,
.md-typeset details.experimental {
border-color: rgb(124, 77, 255)
}
.md-typeset .experimental > .admonition-title,
.md-typeset .experimental > summary {
background-color: rgba(124,77,255,.1);;
border-color: rgb(124, 77, 255);
}
.md-typeset .experimental > .admonition-title::before,
.md-typeset .experimental > summary::before {
background-color: rgb(124, 77, 255);
-webkit-mask-image: var(--md-admonition-icon--experimental);
mask-image: var(--md-admonition-icon--experimental);
}

Просмотреть файл

@ -55,6 +55,8 @@ Configuration options for PSRule for Azure are set within the `ps-rule.yaml` fil
### Expand template parameter files
[:octicons-book-24: Docs][1]
PSRule for Azure can automatically expand Azure template parameter files.
When enabled, PSRule for Azure automatically resolves parameter and template file context at runtime.
@ -67,6 +69,26 @@ configuration:
AZURE_PARAMETER_FILE_EXPANSION: true
```
[1]: setup/configuring-expansion.md#parameterfileexpansion
### Expand Bicep source files
[:octicons-book-24: Docs][2]
PSRule for Azure can automatically expand Bicep source files.
When enabled, PSRule for Azure automatically expands and analyzes Azure resource from `.bicep` files.
To enabled this feature, set the `Configuration.AZURE_BICEP_FILE_EXPANSION` to `true`.
This option can be set within the `ps-rule.yaml` file.
```yaml
configuration:
# Enable automatic expansion of bicep source files
AZURE_BICEP_FILE_EXPANSION: true
```
[2]: setup/configuring-expansion.md#bicepsourceexpansion
### Ignoring rules
To prevent a rule executing you can either:

Просмотреть файл

@ -3,9 +3,13 @@
// Bicep documentation examples
@description('The location resources will be deployed.')
param location string = resourceGroup().location
// An example NSG with a single rule to deny outbound management traffic
resource nsg 'Microsoft.Network/networkSecurityGroups@2021-02-01' = {
name: 'nsg-001'
location: location
properties: {
securityRules: [
{
@ -30,6 +34,7 @@ resource nsg 'Microsoft.Network/networkSecurityGroups@2021-02-01' = {
// An example App Gateway v2 with WAF enabled
resource appGw 'Microsoft.Network/applicationGateways@2021-02-01' = {
name: 'appGw-001'
location: location
properties: {
sku: {
name: 'WAF_v2'

66
docs/examples.json Normal file
Просмотреть файл

@ -0,0 +1,66 @@
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"metadata": {
"_generator": {
"name": "bicep",
"version": "0.4.412.5873",
"templateHash": "1973047202237601172"
}
},
"parameters": {
"location": {
"type": "string",
"defaultValue": "[resourceGroup().location]",
"metadata": {
"description": "The location resources will be deployed."
}
}
},
"functions": [],
"resources": [
{
"type": "Microsoft.Network/networkSecurityGroups",
"apiVersion": "2021-02-01",
"name": "nsg-001",
"location": "[parameters('location')]",
"properties": {
"securityRules": [
{
"name": "deny-hop-outbound",
"properties": {
"priority": 200,
"access": "Deny",
"protocol": "Tcp",
"direction": "Outbound",
"sourceAddressPrefix": "VirtualNetwork",
"destinationAddressPrefix": "*",
"destinationPortRanges": [
"3389",
"22"
]
}
}
]
}
},
{
"type": "Microsoft.Network/applicationGateways",
"apiVersion": "2021-02-01",
"name": "appGw-001",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "WAF_v2",
"tier": "WAF_v2"
},
"webApplicationFirewallConfiguration": {
"enabled": true,
"firewallMode": "Prevention",
"ruleSetType": "OWASP",
"ruleSetVersion": "3.0"
}
}
}
]
}

Просмотреть файл

@ -25,8 +25,9 @@ PSRule for Azure supports two methods for analyzing Azure resources:
- Implement checks within Pull Requests (PRs).
- Improve alignment of resources to WAF recommendations.
- Identify issues that prevent successful resource deployments on Azure.
- Integrate continual improvement and standardization of Azure resource configurations.
- Implement release gates between environments.
- **In-flight** &mdash; After resource are deployed to an Azure subscription.
- **In-flight** &mdash; After resources are deployed to an Azure subscription.
Use _in-flight_ analysis to:
- Implement release gates between environments for non-native tools such as Terraform.
- Performing offline analysis in split-environments.

Просмотреть файл

@ -139,16 +139,18 @@ This build script will compile the module and documentation then output the resu
#### Development dependencies
The following PowerShell modules will be automatically install if the required versions are not present:
The following dependencies will be automatically installed if the required versions are not present:
- PlatyPS
- Pester
- PSScriptAnalyzer
- PowerShellGet
- PackageManagement
- InvokeBuild
- PowerShell modules:
- PlatyPS
- Pester
- PSScriptAnalyzer
- PowerShellGet
- PackageManagement
- InvokeBuild
- Bicep CLI
These additional modules are only required for building PSRule for Azure.
These dependencies are only required for building and running tests for PSRule for Azure.
Additionally .NET Core SDK v3.1 is required.
.NET Core will not be automatically downloaded and installed.

Просмотреть файл

@ -1,6 +1,10 @@
---
author: BernieWhite
---
# Configuring expansion
PSRule for Azure can automatically resolve template and parameter file context at runtime.
PSRule for Azure can automatically resolve Azure resource context at runtime from infrastructure code.
This feature can be enabled by using the following configuration options.
## Configuration
@ -43,6 +47,38 @@ configuration:
AZURE_PARAMETER_FILE_EXPANSION: true
```
### Bicep source expansion
:octicons-milestone-24: v1.6.0 · :octicons-beaker-24: Experimental
This configuration option determines if Azure Bicep source files will automatically be expanded.
By default, Bicep files will not be automatically expanded.
Bicep files are expanded when PSRule cmdlets with the `-Format File` parameter are used.
Syntax:
```yaml
configuration:
AZURE_BICEP_FILE_EXPANSION: bool
```
Default:
```yaml
# YAML: The default AZURE_BICEP_FILE_EXPANSION configuration option
configuration:
AZURE_BICEP_FILE_EXPANSION: false
```
Example:
```yaml
# YAML: Set the AZURE_BICEP_FILE_EXPANSION configuration option to enable expansion
configuration:
AZURE_BICEP_FILE_EXPANSION: true
```
### Deployment resource group
:octicons-milestone-24: v1.1.0
@ -129,4 +165,3 @@ Example:
AZURE_SUBSCRIPTION:
displayName: 'My test subscription'
```

Просмотреть файл

@ -1,3 +1,7 @@
---
author: BernieWhite
---
# Configuring options
PSRule for Azure comes with many configuration options.

Просмотреть файл

@ -1,3 +1,7 @@
---
author: BernieWhite
---
# Configuring rule defaults
PSRule for Azure include several rules that can be configured.

130
docs/setup/setup-bicep.md Normal file
Просмотреть файл

@ -0,0 +1,130 @@
---
author: BernieWhite
---
# Setup Bicep
To expand Azure resources for analysis from Bicep source files the Bicep CLI is required.
The Bicep CLI is already installed on hosted runners and agents used by GitHub Action and Azure Pipelines.
!!! Abstract
This topic covers setting up support for analyzing Azure resources within Bicep source file.
## Installing Bicep CLI
PSRule for Azure requires a minimum of Bicep CLI version **0.4.451**.
You may need to install or upgrade the Bicep CLI in the following scenarios:
- Your Bicep source files require a newer version of the CLI then supported by hosted agents.
The Bicep CLI version can be found in the [included software][1] list for each supported platform.
- You are using self-hosted runners with your GitHub Actions workflow.
- You are using self-hosted agents with Azure Pipelines.
- You are performing local validation or using a different CI platform.
The Bicep CLI can be installed on MacOS, Linux, and Windows.
For installation instructions see [Setup your Bicep development environment][2].
[1]: https://github.com/actions/virtual-environments
[2]: https://github.com/Azure/bicep/blob/main/docs/installing.md
!!! Tip
When installing Bicep using the Azure CLI, Bicep is not added to the `PATH` environment variable.
To use PSRule for Azure with the Azure CLI set the `PSRULE_AZURE_BICEP_USE_AZURE_CLI` to `true`.
Setting this environment variable is explained in the next section.
## Setting environment variables
When expanding Bicep files, the path to the Bicep binary is required.
By default, the `PATH` environment variable will be used to discover the binary path.
When using this option, add the sub-directory containing the Bicep binary to the environment variable.
Alternatively, the path can be overridden by setting the `PSRULE_AZURE_BICEP_PATH` environment variable.
When setting `PSRULE_AZURE_BICEP_PATH` specify the full path to the Bicep binary including the file name.
File names used for Bicep binaries include `bicep`, or `bicep.exe`.
For example:
```bash
# Bash: Setting environment variable
export PSRULE_AZURE_BICEP_PATH='/usr/local/bin/bicep'
```
```powershell
# PowerShell: Setting environment variable
$Env:PSRULE_AZURE_BICEP_PATH = '/usr/local/bin/bicep';
```
```yaml
# GitHub Actions: Setting environment variable
env:
PSRULE_AZURE_BICEP_PATH: '/usr/local/bin/bicep'
```
```yaml
# Azure Pipelines: Setting environment variable
variables:
- name: PSRULE_AZURE_BICEP_PATH
value: '/usr/local/bin/bicep'
```
### Using Azure CLI
By default, PSRule for Azure uses the Bicep CLI directly.
An additional option is to use the Azure CLI to invoke the Bicep CLI.
When using this option the required version of the CLI must be installed prior to using PSRule for Azure.
This is explained in [Setup your Bicep development environment][3].
To enable this option, set the `PSRULE_AZURE_BICEP_USE_AZURE_CLI` environment variable to `true`.
For example:
```bash
# Bash: Setting environment variable
export PSRULE_AZURE_BICEP_USE_AZURE_CLI=true
```
```powershell
# PowerShell: Setting environment variable
$Env:PSRULE_AZURE_BICEP_USE_AZURE_CLI = 'true'
```
```yaml
# GitHub Actions: Setting environment variable
env:
PSRULE_AZURE_BICEP_USE_AZURE_CLI: true
```
```yaml
# Azure Pipelines: Setting environment variable
variables:
- name: PSRULE_AZURE_BICEP_USE_AZURE_CLI
value: true
```
[3]: https://github.com/Azure/bicep/blob/main/docs/installing.md#install-and-manage-via-azure-cli-easiest
### Additional arguments
For configuration, additional arguments can be passed to the Bicep CLI.
This is intended to improve forward compatibility with Bicep CLI.
To configure additional arguments, set the `PSRULE_AZURE_BICEP_ARGS` environment variable.
## Configuring expansion
[:octicons-book-24: Docs][4] · :octicons-beaker-24: Experimental
PSRule for Azure can automatically expand Bicep source files.
When enabled, PSRule for Azure automatically expands and analyzes Azure resource from `.bicep` files.
To enabled this feature, set the `Configuration.AZURE_BICEP_FILE_EXPANSION` to `true`.
This option can be set within the `ps-rule.yaml` file.
```yaml
configuration:
# Enable automatic expansion of bicep source files
AZURE_BICEP_FILE_EXPANSION: true
```
[4]]: configuring-expansion.md#bicepsourceexpansion

47
docs/using-bicep.md Normal file
Просмотреть файл

@ -0,0 +1,47 @@
---
author: BernieWhite
---
# Using Bicep source
PSRule for Azure also supports analyzing Azure resources contained within Bicep source files.
!!! Experimental
Support for Bicep source files is currently an experimental feature.
It is not recommended for production use.
Please give us [feedback] on this feature and report any [issues] you encounter.
!!! Abstract
This topic covers how to use use PSRule for Azure to validate Azure resources within Bicep source.
## Source file expansion
Bicep source files provide an additional option to define Azure resources.
Bicep provides a abstraction layer on top of Azure Resource Manager (ARM) that is more human readable.
When Azure resources are built from Bicep source files, an ARM template is generated.
PSRule for Azure automates this in memory to allow analysis of Azure resources from `.bicep` files.
### Feature support
Expansion of Azure resources contained within Bicep source files is supported.
For details on how this works and limitations see [Using templates][1].
In addition, currently the following limitation apply to using Bicep source files:
- The Bicep CLI must be installed.
- PSRule for Azure will only expand Bicep source files without mandatory parameters.
[1]: using-templates.md#featuresupport
### Setup Bicep
To expand Azure resources for analysis from Bicep source files the Bicep CLI is required.
For details on how to configure Bicep for PSRule for Azure see [Setup Bicep][2].
[2]: setup/setup-bicep.md
*[WAF]: Well-Architected Framework
*[ARM]: Azure Resource Manager
[feedback]: https://github.com/Azure/PSRule.Rules.Azure/discussions
[issues]: https://github.com/Azure/PSRule.Rules.Azure/issues

Просмотреть файл

@ -2,13 +2,13 @@
author: BernieWhite
---
# Using metadata
# Using templates
PSRule for Azure detects Azure template and parameter files in your repository based on their schemas.
This provides template and parameter file linting for structure and general usage.
!!! Abstract
This topic covers how to use metadata to improve the success of Azure deployments.
This topic covers how to use Azure templates and metadata to improve the success of Azure deployments.
## Parameter file expansion
@ -16,14 +16,15 @@ In additional to template and parameter file linting,
PSRule for Azure can automatically resolve template and parameter file context at runtime.
Resolved context provides some unique benefits such as:
- **As deployed** &mdash; Analysis of Azure resources as if they are deployed.
- **Improve success** &mdash; Templates are resolved before deployment.
- Detect issues with invalid resource names, missing parameters, and JSON structure.
- Increases success of deployments by finding errors earlier such as within a PR.
- **As deployed** &mdash; Analysis of Azure resources against Azure WAF as if they are deployed.
- Parameters, conditional resources, functions (built-in and user defined), variables,
and copy loops are resolved.
- Azure resource names are shown in passing and failing results.
Resolving issues with resource configurations can be targeted by resource.
- Resource file locations for template and parameter files are included in results.
- **Unassigned parameters** &mdash; Detection of missing mandatory parameters.
- Increases success of deployments by finding these errors earlier such as within a PR.
- **Suppression by resource name** &mdash; Azure resource names can be used to apply exceptions.
- Suppression allows for individual resources to be excluded from rules by name.
@ -35,6 +36,45 @@ PSRule for Azure uses links to achieve this.
It is not enabled by default to preserve the default behavior prior to PSRule for Azure v1.4.0.
[Creating your pipeline][1] covers how to enable this in a CI pipeline.
### Feature support
Expansion of Azure template parameter files works with Azure Resource Manager (ARM) features.
By default this is an offline process, requiring no connectivity to Azure.
Some functions that may be included in templates dynamically query Azure for current state.
For these functions standard placeholder values are used by default.
Functions that use placeholders include `reference`, `list*`.
The `subscription()` function will return the following unless overridden:
- subscriptionId: 'ffffffff-ffff-ffff-ffff-ffffffffffff'
- tenantId: 'ffffffff-ffff-ffff-ffff-ffffffffffff'
- displayName: 'PSRule Test Subscription'
- state: 'NotDefined'
The `resourceGroup()` function will return the following unless overridden:
- name: 'ps-rule-test-rg'
- location: 'eastus'
- tags: { }
- properties:
- provisioningState: 'Succeeded'
To override, set the `AZURE_SUBSCRIPTION` and `AZURE_RESOURCE_GROUP` in configuration.
Currently the following limitations apply:
- Nested templates are expanded, external templates are not.
- Deployment resources that link to an external template are returned as a resource.
- Sub-resources such as diagnostic logs or configurations are automatically nested.
Automatic nesting a sub-resource requires:
- The parent resource is defined in the same template.
- The sub-resource depends on the parent resource.
- The `pickZones` template function is not supported.
- The `environment` template function always returns values for Azure public cloud.
- References to Key Vault secrets are not expanded.
A placeholder value is used instead.
- Multi-line strings are not supported.
## Template links
PSRule for Azure automatically detects parameter files and uses the following logic to associate templates.
@ -112,7 +152,9 @@ When linking using naming convention, the template and the parameter file must b
!!! Example
A parameter file named `azuredeploy.parameters.json` links to the template file named `azuredeploy.json`.
[1]: creating-your-pipeline.md#expandtemplateparameterfiles
*[WAF]: Well-Architected Framework
*[ARM]: Azure Resource Manager
*[CI]: continuous integration
*[PR]: Pull Request
[1]: creating-your-pipeline.md#expandtemplateparameterfiles

Просмотреть файл

@ -8,13 +8,15 @@ While preparing infrastructure code artifacts, Azure resources can be validated
PSRule for Azure can be installed locally on MacOS, Linux, and Windows for local validation.
!!! Tip
If you haven't already, follow the instructions on [installing locally][1] before continuing.
If you haven't already, follow the instructions on [Installing locally][1] before continuing.
If analyzing Azure resources from Bicep source files, complete [Setup Bicep][2].
[1]: install-instructions.md#installinglocally
[2]: setup/setup-bicep.md
## With Visual Studio Code
[:octicons-download-24: Extension][2]
[:octicons-download-24: Extension][3]
An extension for Visual Studio Code is available for an integrated experience using PSRule for Azure.
The Visual Studio Code extension includes a built-in `PSRule: Run analysis` task.
@ -69,5 +71,5 @@ To use PSRule for Azure with the built-in `PSRule: Run analysis` task, insert th
}
```
[2]: https://marketplace.visualstudio.com/items?itemName=bewhite.psrule-vscode
[3]: https://code.visualstudio.com/docs/editor/tasks
[3]: https://marketplace.visualstudio.com/items?itemName=bewhite.psrule-vscode
[4]: https://code.visualstudio.com/docs/editor/tasks

Просмотреть файл

@ -1,3 +1,6 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
site_name: PSRule for Azure
site_url: https://azure.github.io/PSRule.Rules.Azure
site_description: Ready to go validation and governance controls for Azure Infrastructure as Code (IaC).
@ -9,13 +12,9 @@ edit_uri: blob/main/docs/
repo_issue: https://github.com/Azure/PSRule.Rules.Azure/issues
repo_discussion: https://github.com/Azure/PSRule.Rules.Azure/discussions
# copyright: MIT License - Copyright &copy; Microsoft Corporation
extra_css:
- assets/stylesheets/extra.css
# extra_templates:
# - home.html
theme:
language: en
name: material
@ -41,7 +40,8 @@ nav:
- Getting started:
- Overview: features.md
- Installation: install-instructions.md
- Using metadata: using-metadata.md
- Using templates: using-templates.md
- Using Bicep source: using-bicep.md
- Creating your pipeline: creating-your-pipeline.md
- Validating locally: validating-locally.md
- Customization:
@ -61,6 +61,7 @@ nav:
- Configuring options: setup/configuring-options.md
- Configuring rule defaults: setup/configuring-rules.md
- Configuring expansion: setup/configuring-expansion.md
- Setup Bicep: setup/setup-bicep.md
- Reference:
- By pillar: en/rules/module.md
- By resource: en/rules/resource.md
@ -95,6 +96,9 @@ plugins:
on_nav: "docs.hooks:build_reference_nav"
- search
- git-revision-date
- redirects:
redirect_maps:
'using-metadata.md': 'using-templates.md'
extra:
version:

Просмотреть файл

@ -260,7 +260,7 @@ task CopyModule MinifyData, {
# Synopsis: Build modules only
task BuildModule BuildDotNet, CopyModule
task TestModule ModuleDependencies, Pester, PSScriptAnalyzer, {
task TestModule ModuleDependencies, Pester, PSScriptAnalyzer, BicepIntegrationTests, {
# Run Pester tests
$pesterParams = @{ Path = (Join-Path -Path $PWD -ChildPath tests/PSRule.Rules.Azure.Tests); OutputFile = 'reports/pester-unit.xml'; OutputFormat = 'NUnitXml'; PesterOption = @{ IncludeVSCodeMarker = $True }; PassThru = $True; };
@ -307,6 +307,27 @@ task IntegrationTest ModuleDependencies, Pester, PSScriptAnalyzer, {
}
}
task BicepIntegrationTests {
if ($Env:RUN_BICEP_INTEGRATION -eq 'true') {
# Run Pester tests
$pesterParams = @{ Path = (Join-Path -Path $PWD -ChildPath tests/Bicep); OutputFile = 'reports/bicep-integration.xml'; OutputFormat = 'NUnitXml'; PesterOption = @{ IncludeVSCodeMarker = $True }; PassThru = $True; };
if (!(Test-Path -Path reports)) {
$Null = New-Item -Path reports -ItemType Directory -Force;
}
$results = Invoke-Pester @pesterParams;
# Throw an error if pester tests failed
if ($Null -eq $results) {
throw 'Failed to get Pester test results.';
}
elseif ($results.FailedCount -gt 0) {
throw "$($results.FailedCount) tests failed.";
}
}
}
# Synopsis: Run validation
task Rules PSRule, {
$assertParams = @{

Просмотреть файл

@ -12,6 +12,12 @@ input:
- '*.Designer.cs'
- '*.resx'
- '*.sln'
- '*.txt'
- '*.html'
- '*.ico'
include:
path: []
output:
culture:

Просмотреть файл

@ -5,3 +5,4 @@ mike==1.0.1
mkdocs-simple-hooks==0.1.3
mkdocs-git-revision-date-plugin==0.3.1
mdx-truly-sane-lists==1.2
mkdocs-redirects==1.0.3

Просмотреть файл

@ -0,0 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
namespace PSRule.Rules.Azure
{
internal sealed class EnvironmentHelper
{
public static readonly EnvironmentHelper Default = new EnvironmentHelper();
internal bool TryBool(string key, out bool value)
{
value = default;
return TryVariable(key, out string variable) && TryParseBool(variable, out value);
}
private bool TryVariable(string key, out string variable)
{
variable = Environment.GetEnvironmentVariable(key);
return variable != null;
}
private static bool TryParseBool(string variable, out bool value)
{
if (bool.TryParse(variable, out value))
return true;
if (int.TryParse(variable, out int ivalue))
{
value = ivalue > 0;
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,203 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PSRule.Rules.Azure.Configuration;
using PSRule.Rules.Azure.Data.Template;
using PSRule.Rules.Azure.Pipeline;
using PSRule.Rules.Azure.Resources;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Management.Automation;
using System.Runtime.InteropServices;
using System.Threading;
namespace PSRule.Rules.Azure.Data.Bicep
{
internal sealed class BicepHelper
{
private static readonly char[] LINUX_PATH_ENV_SEPARATOR = new char[] { ':' };
private static readonly char[] WINDOWS_PATH_ENV_SEPARATOR = new char[] { ';' };
private readonly PipelineContext Context;
private readonly ResourceGroupOption _ResourceGroup;
private readonly SubscriptionOption _Subscription;
public BicepHelper(PipelineContext context, ResourceGroupOption resourceGroup, SubscriptionOption subscription)
{
Context = context;
_ResourceGroup = resourceGroup;
_Subscription = subscription;
}
internal PSObject[] ProcessFile(string sourcePath)
{
if (!File.Exists(sourcePath))
throw new FileNotFoundException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.TemplateFileNotFound, sourcePath), sourcePath);
var json = ReadFile(sourcePath);
if (json == null)
return Array.Empty<PSObject>();
return ProcessJson(json, sourcePath);
}
internal PSObject[] ProcessJson(JObject templateObject, string sourcePath)
{
var visitor = new RuleDataExportVisitor();
// Load context
var templateContext = new TemplateVisitor.TemplateContext(Context, _Subscription, _ResourceGroup);
// Process
try
{
templateContext.SetSource(sourcePath, null);
visitor.Visit(templateContext, "helper", templateObject);
}
catch (Exception inner)
{
throw new TemplateReadException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.BicepExpandInvalid, sourcePath, inner.Message), inner, sourcePath, null);
}
// Return results
var results = new List<PSObject>();
var serializer = new JsonSerializer();
serializer.Converters.Add(new PSObjectJsonConverter());
foreach (var resource in templateContext.GetResources())
results.Add(resource.Value.ToObject<PSObject>(serializer));
return results.ToArray();
}
private JObject ReadFile(string path)
{
var bicep = GetBicep(path);
if (bicep == null)
throw new BicepCompileException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.BicepNotFound), null, path);
try
{
if (!bicep.HasExited)
bicep.WaitForExit();
if (bicep.ExitCode != 0)
{
var error = bicep.StandardError.ReadToEnd();
throw new BicepCompileException(string.Format(Thread.CurrentThread.CurrentCulture, PSRuleResources.BicepCompileError, path, error), null, path);
}
using (var reader = new JsonTextReader(bicep.StandardOutput))
{
return JObject.Load(reader);
}
}
finally
{
bicep.Dispose();
}
}
private Process GetBicep(string sourcePath)
{
var useAzCLI = false;
if (!(TryBicepPath(out string binPath) || TryAzCLIPath(out binPath, out useAzCLI)) || string.IsNullOrEmpty(binPath))
return null;
var args = GetBicepBuildArgs(sourcePath, useAzCLI);
var startInfo = new ProcessStartInfo(binPath, args)
{
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
WorkingDirectory = PSRuleOption.GetWorkingPath(),
};
//Context.Writer.WriteDebug(Diagnostics.DebugRunningBicep, binaryPath);
var p = Process.Start(startInfo);
return p;
}
private static bool TryBicepPath(out string binPath)
{
if (TryBicepEnvVariable(out binPath))
return true;
return TryBinaryPath(GetBicepBinaryName(), out binPath);
}
private static bool TryAzCLIPath(out string binPath, out bool useAzCLI)
{
useAzCLI = false;
binPath = null;
if (!UseAzCLI())
return false;
return TryBinaryPath(GetAzBinaryName(), out binPath);
}
private static bool TryBinaryPath(string bin, out string binPath)
{
var paths = GetPathEnv();
for (var i = 0; paths != null && i < paths.Length; i++)
{
binPath = Path.Combine(paths[i], bin);
if (File.Exists(binPath))
return true;
}
binPath = null;
return false;
}
private static string[] GetPathEnv()
{
var envPath = System.Environment.GetEnvironmentVariable("PATH");
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return envPath.Split(LINUX_PATH_ENV_SEPARATOR, StringSplitOptions.RemoveEmptyEntries);
return envPath.Split(WINDOWS_PATH_ENV_SEPARATOR, StringSplitOptions.RemoveEmptyEntries);
}
private static bool TryBicepEnvVariable(out string binaryPath)
{
binaryPath = System.Environment.GetEnvironmentVariable("PSRULE_AZURE_BICEP_PATH");
return !string.IsNullOrEmpty(binaryPath);
}
private static string GetBicepBinaryName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return "bicep";
return "bicep.exe";
}
private static string GetAzBinaryName()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
return "az";
return "az.exe";
}
private static string GetBicepBuildArgs(string sourcePath, bool useAzCLI)
{
GetBicepBuildAdditionalArgs(out string args);
return string.Concat("build --stdout ", args, useAzCLI ? " --file" : string.Empty , " \"", sourcePath, "\"");
}
private static void GetBicepBuildAdditionalArgs(out string args)
{
args = System.Environment.GetEnvironmentVariable("PSRULE_AZURE_BICEP_ARGS") ?? string.Empty;
}
private static bool UseAzCLI()
{
return EnvironmentHelper.Default.TryBool("PSRULE_AZURE_BICEP_USE_AZURE_CLI", out bool value) ? value : false;
}
}
}

Просмотреть файл

@ -117,8 +117,14 @@ namespace PSRule.Rules.Azure.Pipeline
private TemplateReadException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
/// <summary>
/// The file path to an Azure Template.
/// </summary>
public string TemplateFile { get; }
/// <summary>
/// The file path to an Azure Template parameter file.
/// </summary>
public string ParameterFile { get; }
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
@ -171,4 +177,44 @@ namespace PSRule.Rules.Azure.Pipeline
base.GetObjectData(info, context);
}
}
/// <summary>
/// An exception related to compiling Bicep source files.
/// </summary>
[Serializable]
public sealed class BicepCompileException : PipelineException
{
public BicepCompileException()
{
}
public BicepCompileException(string message)
: base(message) { }
public BicepCompileException(string message, Exception innerException)
: base(message, innerException) { }
internal BicepCompileException(string message, Exception innerException, string sourceFile)
: base(message, innerException)
{
SourceFile = sourceFile;
}
private BicepCompileException(SerializationInfo info, StreamingContext context)
: base(info, context) { }
/// <summary>
/// The file path to an Azure Bicep source file.
/// </summary>
public string SourceFile { get; }
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new ArgumentNullException(nameof(info));
base.GetObjectData(info, context);
}
}
}

Просмотреть файл

@ -31,6 +31,12 @@ namespace PSRule.Rules.Azure.Pipeline.Output
internal PSPipelineWriter(PSRuleOption option)
: base(null, option) { }
internal PSPipelineWriter(PSRuleOption option, PSCmdlet commandRuntime)
: base(null, option)
{
UseCommandRuntime(commandRuntime);
}
internal void UseCommandRuntime(PSCmdlet commandRuntime)
{
if (commandRuntime == null)

Просмотреть файл

@ -60,6 +60,15 @@ namespace PSRule.Rules.Azure.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Running bicep from &apos;{0}&apos;..
/// </summary>
internal static string DebugRunningBicep {
get {
return ResourceManager.GetString("DebugRunningBicep", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Searching for files in &apos;{0}&apos;..
/// </summary>

Просмотреть файл

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="DebugRunningBicep" xml:space="preserve">
<value>Running bicep from '{0}'.</value>
</data>
<data name="VerboseFindFiles" xml:space="preserve">
<value>Searching for files in '{0}'.</value>
</data>

Просмотреть файл

@ -114,6 +114,33 @@ namespace PSRule.Rules.Azure.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Bicep compilation of &apos;{0}&apos; failed with: {1}.
/// </summary>
internal static string BicepCompileError {
get {
return ResourceManager.GetString("BicepCompileError", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Unable to expand resources because the source file &apos;{0}&apos; was not valid. {1}.
/// </summary>
internal static string BicepExpandInvalid {
get {
return ResourceManager.GetString("BicepExpandInvalid", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Bicep CLI can not be found. Consider installing Bicep or setting the PSRULE_AZURE_BICEP_PATH environment variable to resolve this issue..
/// </summary>
internal static string BicepNotFound {
get {
return ResourceManager.GetString("BicepNotFound", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to An error occured evaluating expression &apos;{0}&apos; line {1}. {2}.
/// </summary>

Просмотреть файл

@ -135,6 +135,15 @@
<data name="ArgumentsOutOfRange" xml:space="preserve">
<value>The number of arguments '{1}' is not within the allowed range for '{0}'.</value>
</data>
<data name="BicepCompileError" xml:space="preserve">
<value>Bicep compilation of '{0}' failed with: {1}</value>
</data>
<data name="BicepExpandInvalid" xml:space="preserve">
<value>Unable to expand resources because the source file '{0}' was not valid. {1}</value>
</data>
<data name="BicepNotFound" xml:space="preserve">
<value>Bicep CLI can not be found. Consider installing Bicep or setting the PSRULE_AZURE_BICEP_PATH environment variable to resolve this issue.</value>
</data>
<data name="ExpressionEvaluateError" xml:space="preserve">
<value>An error occured evaluating expression '{0}' line {1}. {2}</value>
</data>

Просмотреть файл

@ -2,10 +2,11 @@
// Licensed under the MIT License.
using PSRule.Rules.Azure.Configuration;
using PSRule.Rules.Azure.Data.Bicep;
using PSRule.Rules.Azure.Data.Network;
using PSRule.Rules.Azure.Data.Template;
using PSRule.Rules.Azure.Pipeline;
using System;
using PSRule.Rules.Azure.Pipeline.Output;
using System.Management.Automation;
namespace PSRule.Rules.Azure.Runtime
@ -31,7 +32,6 @@ namespace PSRule.Rules.Azure.Runtime
public static PSObject[] GetResources(string parameterFile)
{
var context = GetContext();
var linkHelper = new TemplateLinkHelper(context, PSRuleOption.GetWorkingPath(), true);
var link = linkHelper.ProcessParameterFile(parameterFile);
if (link == null)
@ -41,6 +41,13 @@ namespace PSRule.Rules.Azure.Runtime
return helper.ProcessTemplate(link.TemplateFile, link.ParameterFile, out _);
}
public static PSObject[] GetBicepResources(string bicepFile, PSCmdlet commandRuntime)
{
var context = GetContext(commandRuntime);
var bicep = new BicepHelper(context, context.Option.Configuration.ResourceGroup, context.Option.Configuration.Subscription);
return bicep.ProcessFile(bicepFile);
}
public static INetworkSecurityGroupEvaluator GetNetworkSecurityGroup(PSObject[] securityRules)
{
var builder = new NetworkSecurityGroupEvaluator();
@ -50,10 +57,10 @@ namespace PSRule.Rules.Azure.Runtime
#region Helper methods
private static PipelineContext GetContext()
private static PipelineContext GetContext(PSCmdlet commandRuntime = null)
{
var option = PSRuleOption.FromFileOrDefault(PSRuleOption.GetWorkingPath());
var context = new PipelineContext(option, null);
var context = new PipelineContext(option, commandRuntime != null ? new PSPipelineWriter(option, commandRuntime) : null);
return context;
}

Просмотреть файл

@ -26,9 +26,11 @@ spec:
resourceGroupName: [ 'ResourceGroupName' ]
configuration:
AZURE_PARAMETER_FILE_EXPANSION: false
AZURE_BICEP_FILE_EXPANSION: false
convention:
include:
- 'Azure.ExpandTemplate'
- 'Azure.ExpandBicep'
output:
culture:
- en

Просмотреть файл

@ -30,3 +30,26 @@ Export-PSRuleConvention 'Azure.ExpandTemplate' -If { $Configuration.AZURE_PARAME
Write-Error -Message "Failed to expand parameter file '$($TargetObject.FullName)'. $($_.Exception.Message)" -ErrorId 'Azure.ExpandTemplate.ConventionException';
}
}
#region Bicep
Export-PSRuleConvention 'Azure.ExpandBicep' -If { $Configuration.AZURE_BICEP_FILE_EXPANSION -eq $True -and $TargetObject.Extension -eq '.bicep' } -Begin {
Write-Verbose "[Azure.ExpandBicep] -- Expanding bicep source: $($TargetObject.FullName)";
try {
$data = [PSRule.Rules.Azure.Runtime.Helper]::GetBicepResources($TargetObject.FullName, $PSCmdlet);
if ($Null -ne $data) {
$PSRule.Import($data);
}
}
catch [PSRule.Rules.Azure.Pipeline.BicepCompileException] {
Write-Error -Exception $_.Exception;
}
catch [System.IO.FileNotFoundException] {
Write-Error -Exception $_.Exception;
}
catch {
Write-Error -Message "Failed to expand bicep source '$($TargetObject.FullName)'. $($_.Exception.Message)" -ErrorId 'Azure.ExpandBicep.ConventionException';
}
}
#endregion Bicep

Просмотреть файл

@ -0,0 +1,83 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
#
# Unit tests for Azure conventions
#
[CmdletBinding()]
param ()
# Setup error handling
$ErrorActionPreference = 'Stop';
Set-StrictMode -Version latest;
if ($Env:SYSTEM_DEBUG -eq 'true') {
$VerbosePreference = 'Continue';
}
# Setup tests paths
$rootPath = $PWD;
Import-Module (Join-Path -Path $rootPath -ChildPath out/modules/PSRule.Rules.Azure) -Force;
$here = (Resolve-Path $PSScriptRoot).Path;
Describe 'Bicep' -Tag 'Bicep' {
Context 'Azure.ExpandBicep convention' {
It 'Expands Bicep source files' {
$invokeParams = @{
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
WarningAction = 'Ignore'
ErrorAction = 'Stop'
}
# Default
$sourceFile = Join-Path -Path $rootPath -ChildPath 'docs/examples.bicep';
$result = @(Invoke-PSRule @invokeParams -InputPath $sourceFile -Format File);
$result | Should -BeNullOrEmpty;
# Expand source files
$option = @{
'Configuration.AZURE_BICEP_FILE_EXPANSION' = $True
}
$result = @(Invoke-PSRule @invokeParams -InputPath $sourceFile -Format File -Option $option);
$result.Length | Should -BeGreaterThan 1;
$resource = $result | Where-Object { $_.TargetType -eq 'Microsoft.Network/networkSecurityGroups' };
$resource | Should -Not -BeNullOrEmpty;
$resource.TargetName | Should -BeIn 'nsg-001'
}
It 'Expands Bicep source files with Azure CLI' {
$invokeParams = @{
Baseline = 'Azure.All'
Module = 'PSRule.Rules.Azure'
WarningAction = 'Ignore'
ErrorAction = 'Stop'
}
# Default
$sourceFile = Join-Path -Path $rootPath -ChildPath 'docs/examples.bicep';
$result = @(Invoke-PSRule @invokeParams -InputPath $sourceFile -Format File);
$result | Should -BeNullOrEmpty;
try {
# Install CLI
az bicep install
# Expand source files
$option = @{
'Configuration.AZURE_BICEP_FILE_EXPANSION' = $True
}
$Env:PSRULE_AZURE_BICEP_USE_AZURE_CLI = 'true';
$result = @(Invoke-PSRule @invokeParams -InputPath $sourceFile -Format File -Option $option);
$result.Length | Should -BeGreaterThan 1;
$resource = $result | Where-Object { $_.TargetType -eq 'Microsoft.Network/networkSecurityGroups' };
$resource | Should -Not -BeNullOrEmpty;
$resource.TargetName | Should -BeIn 'nsg-001'
}
finally {
Remove-Item 'Env:PSRULE_AZURE_BICEP_USE_AZURE_CLI' -Force;
}
}
}
}