Initial Setup
When setting up GitHub Actions within a repository for deployment to Azure there are a number of steps that need to be completed. Some common considerations include:
- What environments are required?
- How to structure the repository?
- What credentials will be used?
- How will the workflow be triggered?
- How can I pre-validate my code?
It’s common to want to be able to validate changes safely to confirm they have the desired effect before they are officially made to your production environment.
We recommend separating these environments to minimize the risk of accidentally mixing them up and deploying unvalidated changes to production.
This environment exists to give developers a means of deploying and testing code that may be broken or partially working. We recommend optimizing for developer productivity by:
- Supporting multiple copies of this environment, to allow developers to operate independently of one another.
- Fully automating the setup and teardown of development environments.
This environment should serve as a final validation before you deploy to Production. It should again be separated from Production, but should represent the real environment as accurately as possible. We recommend:
- Consider it as a “clean slate”. Only deploy changes if they have already been deemed “Production-ready” and merged to your
main
branch. - If possible, separate it from your Development environment. Ideally, it should be inaccessible to anyone with permissions to Development. If this is too complex, then at minimum, put process into place to avoid deploying unvalidated code to it.
This is your live environment. Only code that has been merged to main
and validated successfully in Staging should be deployed here.
It’s common to want a manual approval stage in Production after running validation or What-If, and prior to deploying.
One way to achieve this is to create a separate environment named “Manual Approval (Production)”, and enable the deployment protection rule by:
- Check the “Required reviewers” and add reviewers.
- [Optional] Check the “Wait timer” and set a max waiting time for the approval.
A stage with this environment will not run until the reviewers approve the deployment.
There are other options for approvals out there, such as this Marketplace Action. However, this Action pauses a workflow with a worker actively running, whereas the deployment protection rule method waits for an approval before a worker is allocated, which is more cost effective. You should also exercise your own judgement when taking a dependency on any open-source solution.
When considering how to structure the infrastrucutre as code your repository, key considerations include:
- Easy to understand — the structure should be easy to understand and navigate.
- Consider mapping the structure to Azure to make it easier to understand when moving back and forth between the code and the Azure Portal.
- Graular controls — the structure should allow for granular review and approval of changes.
- GitHub supports code ownership and branch protection rules that can be used to control who can approve changes to specific directories.
- Consider using separate directories for each environment.
For example:
/
- Repository rootdeployments
- Directory for Azure deployments.dev
- Directory for deployments to the development environment.rg-app-dev-001
- Directory for a deployment to a specific resource group.deploy.bicep
- The Bicep file for the deployment.
prod
- Directory for deployments to the production environment.rg-app-prod-001
- Directory for a deployment to a specific resource group.deploy.bicep
- The Bicep file for the deployment.
See OpenID Connect for instructions on how to configure your GitHub Workflows to connect securely to Azure.
When developing Bicep deployments it is important to test the code before it is deployed to an environment. Performing tests on Bicep deployments can help to identify issues early and reduce the risk of later promblems.
A key DevOps concept called shifting-left, means that testing is performed as early as possible in the development process. By identifying issues early, the cost of fixing them is reduced. Cost is a generic term that can be applied to time, money, or risk. For example, if an issue is identified later in the process such as during deployment or in production:
- There may be more rework required to fix the issue.
- Elapsed time to fix the issue may affect the delivery schedule or cause downtime to a live service.
Bicep supports a number of different ways to validate code, including:
- Bicep linter — is a static analysis feature of the Bicep langauge and CLI used during the development process to identify issues with the code.
- Many of the issues identified by the linter are related to the syntax and structure of Bicep code.
- Additionally, the Bicep linter will identify some security issues such as outputing a secret value in a deployment.
- The linter will report error, warning, or informational issues.
In most cases, rule severity can be configured to change the level of reporting by setting the
level
inbicepconfig.json
.
- PSRule for Azure — is a static analysis tool that can be used to test Bicep deployments.
PSRule for Azure emulates how Azure Resource Manager (ARM) processes a deployment, then tests the resulting Azure resources.
- Using PSRule for Azure, you can write your own tests, and/ or use a set of almost 400 built-in tests.
- The built-in tests cover a wide range of scenarios including security, reliability, and best practices aligned to the Azure Well-Architected Framework.
If you use PSRule for Azure, running the Bicep linter separately is not required as any Bicep linter issues that generate an error will also be flagged by PSRule for Azure.
Consider using these tools in your workflow along with the following security tools to identify issues early:
Note: Bicep assertions and tests are currently in development.
Configure Workflow environment variables to pin to the same version tool versions across your workflow:
env:
AZCLI_VERSION: 2.52.0
BICEP_VERSION: 0.21.1
PSRULE_BASELINE: Azure.GA_2023_06
Here is an example of a workflow job to test your Bicep deployment:
jobs:
lint:
name: 🧪 Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Install Bicep
run: az bicep install --version v${{ env.BICEP_VERSION }}
- name: Run PSRule and lint
uses: microsoft/ps-rule@v2.9.0
with:
modules: PSRule.Rules.Azure
baseline: ${{ env.PSRULE_BASELINE }}
To accompany this configure PSRule options within the ps-rule.yaml
file at the root of the repository:
#
# PSRule configuration
#
# Please see the documentation for all configuration options:
# https://aka.ms/ps-rule/options
# https://aka.ms/ps-rule-azure/options
requires:
PSRule: '@pre >=2.9.0'
PSRule.Rules.Azure: '@pre >=1.29.0'
include:
module:
- PSRule.Rules.Azure
output:
culture:
- en-US
input:
pathIgnore:
- '**'
- '!deployments/**/*.bicepparam'
- '!deployments/**/deploy.bicep'
configuration:
AZURE_BICEP_FILE_EXPANSION: true
AZURE_BICEP_PARAMS_FILE_EXPANSION: true
AZURE_RESOURCE_GROUP:
tags:
env: test
GitHub Dependabot is a GitHub feature that creates pull requests automatically to update dependencies in your repository. For example, if a new version of a GitHub Action is released, Dependabot will create a pull request to update the version in your workflow.
To enable Dependabot, configure a .github/dependabot.yml
file in your repository:
#
# Dependabot configuration
#
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/getting-started/dependabot-quickstart-guide
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: github-actions
directory: '/'
schedule:
interval: daily