August 21st, 2024

Securing your Azure deployments with PSRule

James Casey
Principal Product Manager

We love automation! With Bicep, you can effortlessly define the Azure infrastructure you need for your application. And with the Azure Developer CLI (azd), you can easily deploy both infrastructure and application code at the same time. Microsoft provides standard reusable components to be used with the Azure Developer CLI, such as Azure Verified Modules and a template gallery, containing example applications that you can use as starting points for defining your infrastructure.

While this approach allows you and your team to deploy applications quickly and consistently, you might not necessarily be a security expert. So, how can you be sure that your Bicep templates, or any sample templates you use as a starting point, are following best practices? There are lots of different knobs to tweak on Azure resources to make sure they are secure in the deployment—what’s a good way to see if you’re setting all the right options?

Today, I’m going to show you how you can automatically check that your Azure infrastructure is configured according to security best practices and how you can fit it in as part of your GitHub CI/CD workflows.

Introducing PSRule for Azure

PSRule for Azure is a tool designed to help you test and validate your Azure Infrastructure as Code (IaC). It provides a set of pre-built checks and remediation steps to help you ensure that your Azure solutions are configured correctly. These checks can be applied both before and after deployment to Azure, allowing you to validate the configuration of Azure resources defined in ARM templates or Bicep code.

The tool is particularly useful for validating IaC templates against best practices, such as those practices outlined in the Well-Architected Framework (WAF). This includes checking for cost, security, reliability, operational excellence, and performance. By integrating PSRule for Azure into your CI/CD pipeline, you can catch issues early in the development process and improve the quality of your IaC templates.

PSRule ships with over 400 tests, based on the Well-Architected Framework. You can also define your own tests, either declaratively in YAML or JSON, or with PowerShell.

Deep dive – Managed Identities 

To show how PSRule works, I’ll use a scenario we tackled recently ourselves at Microsoft. We’re on a company-wide drive to remove passwords and move to non-phishable credentials where possible. As part of this effort, we’ve removed passwords and certificates from code samples and replaced them with Managed Identities.

Managed identities provide an automatically managed identity in Microsoft Entra ID for applications to use when connecting to resources that support Microsoft Entra authentication, such as Azure services like AI Search and Storage. Applications can use managed identities to obtain Microsoft Entra tokens without having to manage any credentials. When you use Managed Identities:

  • You don’t need to manage individual credentials. Credentials aren’t even accessible to individual users.
  • You can use managed identities to authenticate to any resource that supports Microsoft Entra authentication, including your own applications.
  • You don’t pay any extra – managed identities are a platform feature that can be used at no extra cost.

PSRule has a set of tests, as part of the Identity and Access Management pillar, that will check if Azure services created via Bicep are using Managed Identities to authenticate to other Azure resources without storing credentials. For example, you can look at the details of the rule for ‘App Service apps use a Managed Identity’. Firstly, it describes why it is important to use Managed Identities, linking us to more documentation if we need more detail. Then it gives the exact Bicep configuration to enable it in our own Bicep templates. Finally, it even tells us that there is a pre-built Azure Verified Module we could use as part of our template rather than writing it from scratch.

PSRule Bicep configuration

Now that we know what PSRule is and what it does, let’s see how to integrate PSRule for Azure into GitHub Actions, in particular checking the Azure Security Pillar.

Checking GitHub Security with PSRule for Azure

To show how to integrate this into your code, we’ll use a sample that we recently developed for our Reactor series on securing your AI Applications. This is a Python application that uses Azure OpenAI to generate responses to user messages and uses Microsoft Entra for user authentication. The user sign-in functionality uses the built-in authentication feature of Azure Container Apps, which supports both Microsoft Entra ID and Microsoft Entra External ID.

The repository includes all the infrastructure and configuration needed to set up Microsoft Entra user authentication, provision Azure OpenAI resources (with keyless access), and deploy the app to Azure Container Apps using the Azure Developer CLI.

We haven’t added any validation of the Bicep templates used, so it’s a great starting point for showing all the steps to add PSRule for Azure.

We already have a GitHub action azure-bicep-validate.yaml in the .github/workflows template. As you see below, this will build the Bicep files which also runs the Bicep linter over the files. This runs on any code pushed to main, or any pull request which is being merged into main.

name: Validate bicep scripts 
on: 
  workflow_dispatch: 
  push: 
    branches: 
      - main 
  pull_request: 
    branches: 
      - main 

jobs: 
  build: 
    runs-on: ubuntu-latest 
    steps: 
      - name: Checkout 
        uses: actions/checkout@v4 

      - name: Azure CLI script 
        uses: azure/CLI@v2 
        with: 
          inlineScript: az bicep build -f infra/main.bicep 

We will add a second job into this workflow, psrule, which will use the microsoft/ps-rule action to run our Azure.Pillar.Security baseline and upload them as code, scanning results to GitHub Advanced Security so they appear on the Security tab in GitHub.

  psrule: 
    runs-on: ubuntu-latest 
    permissions: 
      security-events: write 
    steps: 
      - name: Checkout 
        uses: actions/checkout@v4 

      - name: Run PSRule analysis 
        uses: microsoft/ps-rule@v2.9.0 
        with: 
          modules: PSRule.Rules.Azure 
          baseline: Azure.Pillar.Security 
          inputPath: infra/*.test.bicep 
          outputFormat: Sarif 
          outputPath: reports/ps-rule-results.sarif 
          summary: true 
        continue-on-error: true 

        env: 
          PSRULE_CONFIGURATION_AZURE_BICEP_FILE_EXPANSION: 'true' 
          PSRULE_CONFIGURATION_AZURE_BICEP_FILE_EXPANSION_TIMEOUT: '30' 

      - name: Upload results to security tab 
        uses: github/codeql-action/upload-sarif@v3 
        with:
          sarif_file: reports/ps-rule-results.sarif 

In this job, you can see we are setting the inputPath to ‘infra/*.test.bicep’. This calls our test harness ‘main.test.bicep’ that wraps the ‘main.bicep’ entry point and hardcodes parameters like name, region, and features, that we want to use. This allows us to test specific scenarios when the Bicep code supports multiple deployment options. You can see the test harness below, which sets some required default values.

// This file is for doing static analysis and contains sensible defaults 
// for PSRule to minimise false-positives and provide the best results. 

// This file is not intended to be used as a runtime configuration file. 

targetScope = 'subscription' 

param location string = 'swedencentral' 

module main 'main.bicep' = { 
  name: 'main' 
  params: { 
    location: location 
    openAiResourceLocation: location 
    authTenantId: '00000000-0000-0000-0000-000000000000' 
    name: 'chatapp' 
  }
} 

Now, if we commit these changes to a branch and create a Pull Request to main, the GitHub action will run. It’ll take a few seconds and if you click on the action, you’ll be able to see the output from PSRule, like below:

PSRule output in GitHub action

You can see that we ran 102 rules in total and we currently have 7 issues. These are mostly around networking and logging and are all things we would want to fix before we deploy this application into production. For each error, there is a link which takes us to a details page on the PSRule website where we can see what we need to do in our Bicep code to remediate the issue. For example, we have an error with Azure KeyVault – Azure.KeyVault.Firewall, where we accept connections from clients on any network. The details page for this error shows us exactly what to do – set the properties.networkAcls.defaultAction property to Deny.

Merging the PR to get GitHub Security notifications

It’s useful to see the output during the GitHub Action run, but we want to have these as Security alerts on the repository where any developer or admin can easily find them. We have already configured this in the GitHub action, but to see them in the GitHub Security tab, we need to merge the PR to the main branch. Once this is done, the errors from running PSRule against the main branch now appear in the GitHub Security tab. If you navigate there and select ‘Code Scanning’, you can see the full list of alerts with links directly into the code, showing which Bicep resource is causing the issue.

PSRule in GitHub Security page

Summary and next steps

In this blog post, we have shown you how to use PSRule for Azure to check your Bicep deployment code against the Security pillar of the Well-Architected Framework. To ensure that you stay secure, we outlined how to call PSRule from a GitHub Action, so you get notified about any new security issues introduced by Pull Requests. If you want to check out all the changes we made, you can look at the Pull Request I created while writing this post.

You should now have all the knowledge you need to get started securing your own deployments. For more information on best practices for deploying to Azure, see:

To learn more and test out features in the Microsoft Entra portfolio, visit our developer center. Make sure you subscribe to the Identity developer blog for more insights and to keep up with the latest on all things Identity. And, follow us on YouTube for video overviews, tutorials, and deep dives.

Author

James Casey
Principal Product Manager

I'm a product manager work in the IDNA developer experience team, ensuring that developers have great experiences when using Microsoft Entra.

2 comments

Discussion is closed. Login to edit/delete existing comments.

  • Hans De Mulder

    Is the upload sarif option also available for Azure DevOps (with GitHub Advanced Security)?