Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terraform tests #6

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions .github/workflows/ci-pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,50 @@ jobs:
- name: Install Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
terraform_version: 1.9.3
terraform_wrapper: false

- name: Terraform Init
run: terraform init -backend=false
run: |
BRANCH_NAME="${{ github.head_ref != '' && github.head_ref || github.ref }}"
TF_STATE_KEY="${BRANCH_NAME//\//_}.tfstate"

terraform init -backend=true -backend-config="resource_group_name=$TF_STATE_RESOURCE_GROUP" -backend-config="storage_account_name=$TF_STATE_STORAGE_ACCOUNT" -backend-config="container_name=github-actions" -backend-config="key=$TF_STATE_KEY"
working-directory: infrastructure
env:
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
TF_STATE_RESOURCE_GROUP: ${{ secrets.TF_STATE_RESOURCE_GROUP }}
TF_STATE_STORAGE_ACCOUNT: ${{ secrets.TF_STATE_STORAGE_ACCOUNT }}

- name: Terraform Validate
run: terraform validate
working-directory: infrastructure

- name: Run Integration Tests
run: |
terraform init -backend=false
terraform test
working-directory: tests/integration-tests

- name: Install Go
uses: actions/setup-go@v1
with:
go-version: 1.21

- name: Run End to End Tests
run: |
go mod tidy
go test -v -timeout 10m
working-directory: tests/end-to-end-tests
env:
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }}
ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }}
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

static-code-analysis:
name: Static Code Analysis
runs-on: ubuntu-latest
Expand All @@ -45,7 +79,7 @@ jobs:
- name: Install Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
terraform_version: 1.9.3

- name: Run Terraform Format
run: terraform fmt -check
Expand Down Expand Up @@ -81,4 +115,4 @@ jobs:
sudo apt-get install -y trivy

- name: Run Trivy Scan
run: trivy filesystem --security-checks vuln,config --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed .
run: trivy filesystem --security-checks vuln,config --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed .
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*.DS_Store
*.pem

# Terratest
.test-data/

# User-specific files
*.rsuser
Expand Down
117 changes: 108 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The following technologies are used:
* Azure CLI
* Azure Pipelines
* Terraform
* Go (used for end-to-end testing)

### Outstanding Questions

Expand Down Expand Up @@ -64,6 +65,12 @@ The following diagram illustrates the high level architecture

The repository consists of the following directories:

* `./.github`

Contains the GitHub workflows in `yaml` format.

[See the YAML schema documentation for more details.](https://learn.microsoft.com/en-us/azure/devops/pipelines/yaml-schema/?view=azure-pipelines)

* `./.pipelines`

Contains the Azure Pipelines in `yaml` format.
Expand All @@ -86,28 +93,31 @@ The repository consists of the following directories:

Contains scripts that are used to create and maintain the environment.

* `./tests`

Contains the different types of tests used to verify the solution.

## Developer Guide

### Environment Setup

The following are pre-reqs to working with the solution:

* An Azure subscription
* Azure CLI installed
* Terraform installed
* An Azure identity with the following roles:
* Contributor role on the subscription (required to create resources)
* RBAC Administrator role on the resources being backed up (required to assign roles on the resource to the backup vault managed identity)
* An Azure identity assigned the subscription Contributor role (required to create resources)
* [Azure CLI installed](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli-windows?tabs=azure-cli)
* [Terraform installed](https://developer.hashicorp.com/terraform/install)
* [Go installed (to run the end-to-end tests)](https://go.dev/dl/)

[See the following link for further information.](https://learn.microsoft.com/en-us/azure/developer/terraform/get-started-windows-powershell)
> Ensure all installed components have been added to the `%PATH%` - e.g. `az`, `terraform` and `go`.

### Getting Started

Take the following steps to get started in configuring and verify the infrastructure:
Take the following steps to get started in configuring and verifying the infrastructure for your development environment:

1. Login to Azure

Use the Azure CLI to login to Azure by running the following command:
Use Azure CLI to login to Azure by running the following command:

```pwsh
az login
Expand Down Expand Up @@ -167,6 +177,66 @@ Take the following steps to get started in configuring and verify the infrastruc

The repo contains an `example` module which can be utilised to further extend the sample infrastructure with some resources and backup instances. To use this module for dev/test purposes, include the module in `main.tf` and run `terraform apply` again.

### Running the Tests

#### Integration Tests

The test suite consists of a number Terraform HCL integration tests that use a mock azurerm provider.

[See this link for more information.](https://developer.hashicorp.com/terraform/language/tests)

Take the following steps to run the test suite:

1. Initialise Terraform

Change the working directory to `./tests/integration-tests`.

Terraform can now be initialised by running the following command:

````pwsh
terraform init -backend=false
````

> NOTE: There's no need to initialise a backend for the purposes of running the tests.

2. Run the Tests

Run the tests with the following command:

````pwsh
terraform test
````

#### End to End Tests

The end to end tests are written in go, and use the [terratest library](https://terratest.gruntwork.io/).

The tests depend on a connection to Azure so it can create an environment that the tests can be executed against - the environment is torn down once the test run has completed.

For the tests to run, you must complete the steps in the [getting started guide](#getting-started) to setup and initialise a terraform backend in Azure.

To run the tests, take the following steps:

1. Install go packages

You only need to do this once when setting up your environment.

Change the working directory to `./tests/end-to-end-tests`.

Run the following command:

````pwsh
go mod tidy
````

2. Run the Tests

Run the tests with the following command:

````pwsh
go test -v -timeout 10m
````

### Contributing

If you want to contribute to the project, raise a PR on GitHub.
Expand All @@ -185,4 +255,33 @@ We use pre-commit to run analysis and checks on the changes being committed. Tak
* Install pre-commit within the repository with the following command: `pre-commit install`
* Run `pre-commit run --all-files` to check pre-commit is working

> For full details [see this link](https://pre-commit.com/#installation)
> For full details [see this link](https://pre-commit.com/#installation)

## CI Pipeline

The CI pipeline builds and verifies the solution and runs a number of static code analysis steps on the code base.

### End to End Testing

Part of the build verification is the end to end testing step. This requires the pipeline to login to Azure in order to deploy an environment on which to execute the tests.

In order for the CI pipeline to login to Azure the following GitHub actions secret must be created called `AZURE_CREDENTIALS` set as a JSON object in the following structure:

```json
{
"clientSecret": "******",
"subscriptionId": "******",
"tenantId": "******",
"clientId": "******"
}
```

### Static Code Analysis

The following static code analysis checks are executed:

* [Terraform format](https://developer.hashicorp.com/terraform/cli/commands/fmt)
* [Terraform lint](https://github.com/terraform-linters/tflint)
* [Checkov scan](https://www.checkov.io/)
* [Gitleaks scan](https://github.com/gitleaks/gitleaks)
* [Trivy vulnerability scan](https://github.com/aquasecurity/trivy)
16 changes: 16 additions & 0 deletions infrastructure/backup_policy.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module "blob_storage_policy" {
source = "./modules/backup_policy/blob_storage"
policy_name = "bkpol-${var.vault_name}-blobstorage"
vault_id = azurerm_data_protection_backup_vault.backup_vault.id
retention_period = "P7D" # 7 days
# NOTE - this blob policy has been configured for operational backup
# only, which continuously backs up data and does not need a schedule
}

module "managed_disk_policy" {
source = "./modules/backup_policy/managed_disk"
policy_name = "bkpol-${var.vault_name}-manageddisk"
vault_id = azurerm_data_protection_backup_vault.backup_vault.id
retention_period = "P7D" # 7 days
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1D"] # Once per day at 00:00
}
11 changes: 11 additions & 0 deletions infrastructure/backup_vault.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
resource "azurerm_data_protection_backup_vault" "backup_vault" {
name = "bvault-${var.vault_name}"
resource_group_name = azurerm_resource_group.resource_group.name
location = var.vault_location
datastore_type = "VaultStore"
redundancy = var.vault_redundancy
soft_delete = "Off"
identity {
type = "SystemAssigned"
}
}
41 changes: 0 additions & 41 deletions infrastructure/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,4 @@ terraform {

provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "resource_group" {
location = var.vault_location
name = "rg-nhsbackup-${var.vault_name}"
}

# Create the vault
###########################################################################

resource "azurerm_data_protection_backup_vault" "backup_vault" {
name = "bvault-${var.vault_name}"
resource_group_name = azurerm_resource_group.resource_group.name
location = var.vault_location
datastore_type = "VaultStore"
redundancy = var.vault_redundancy
soft_delete = "Off"
identity {
type = "SystemAssigned"
}
}


# Create some backup policies
###########################################################################

module "blob_storage_policy" {
source = "./modules/backup_policy/blob_storage"
policy_name = "bkpol-${var.vault_name}-blobstorage"
vault_id = azurerm_data_protection_backup_vault.backup_vault.id
retention_period = "P7D" # 7 days
# NOTE - this blob policy has been configured for operational backup
# only, which continuously backs up data and does not need a schedule
}

module "managed_disk_policy" {
source = "./modules/backup_policy/managed_disk"
policy_name = "bkpol-${var.vault_name}-manageddisk"
vault_id = azurerm_data_protection_backup_vault.backup_vault.id
retention_period = "P7D" # 7 days
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1D"] # Once per day at 00:00
}
12 changes: 12 additions & 0 deletions infrastructure/modules/backup_policy/blob_storage/output.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
output "id" {
value = azurerm_data_protection_backup_policy_blob_storage.backup_policy.id
}

output "name" {
value = azurerm_data_protection_backup_policy_blob_storage.backup_policy.name
}

output "vault_id" {
value = azurerm_data_protection_backup_policy_blob_storage.backup_policy.vault_id
}

output "retention_period" {
value = azurerm_data_protection_backup_policy_blob_storage.backup_policy.operational_default_retention_duration
}
16 changes: 16 additions & 0 deletions infrastructure/modules/backup_policy/managed_disk/output.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
output "id" {
value = azurerm_data_protection_backup_policy_disk.backup_policy.id
}

output "name" {
value = azurerm_data_protection_backup_policy_disk.backup_policy.name
}

output "vault_id" {
value = azurerm_data_protection_backup_policy_disk.backup_policy.vault_id
}

output "retention_period" {
value = azurerm_data_protection_backup_policy_disk.backup_policy.default_retention_duration
}

output "backup_intervals" {
value = azurerm_data_protection_backup_policy_disk.backup_policy.backup_repeating_time_intervals
}
11 changes: 11 additions & 0 deletions infrastructure/output.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "vault_name" {
value = azurerm_data_protection_backup_vault.backup_vault.name
}

output "vault_location" {
value = azurerm_data_protection_backup_vault.backup_vault.location
}

output "vault_redundancy" {
value = azurerm_data_protection_backup_vault.backup_vault.redundancy
}
4 changes: 4 additions & 0 deletions infrastructure/resource_group.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
resource "azurerm_resource_group" "resource_group" {
location = var.vault_location
name = "rg-nhsbackup-${var.vault_name}"
}
Loading
Loading