Skip to content
Merged
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
28 changes: 16 additions & 12 deletions .github/workflows/ci-pipeline.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@ on:
- main
pull_request:
workflow_dispatch:
inputs:
grype_version:
description: "Grype version to install"
Comment thread
khurram-rafiq marked this conversation as resolved.
default: "v0.110.0"
type: string
grype_commit_sha:
description: "Grype commit SHA for install script"
default: "dee8de483dfba5b4e0bc0aa8e4ab2ce52137e490"
type: string

jobs:
build-verification:
Expand All @@ -27,7 +36,7 @@ jobs:
with:
terraform_version: 1.9.3
terraform_wrapper: false

- name: Install Go
uses: actions/setup-go@v6
with:
Expand Down Expand Up @@ -97,17 +106,12 @@ jobs:
- name: Run GitLeaks Scan
run: gitleaks detect --source . --config .gitleaks.toml

- name: Install Trivy
- name: Install Grype
run: |
sudo apt-get update
sudo apt-get install -y wget apt-transport-https gnupg lsb-release
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install -y trivy
curl -sSfL https://raw.githubusercontent.com/anchore/grype/${{ inputs.grype_commit_sha || 'dee8de483dfba5b4e0bc0aa8e4ab2ce52137e490' }}/install.sh | bash -s -- -b /usr/local/bin ${{ inputs.grype_version || 'v0.110.0' }}

Comment thread
johncollinson2001 marked this conversation as resolved.
Comment thread
johncollinson2001 marked this conversation as resolved.
- name: Run Trivy Scan
run: trivy filesystem --security-checks vuln,config --exit-code 1 --severity HIGH,CRITICAL --ignore-unfixed .
- name: Run Grype Filesystem Scan
run: grype "dir:./" --fail-on high
Comment thread
johncollinson2001 marked this conversation as resolved.

publishing:
name: Publish Release
Expand All @@ -118,7 +122,7 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false # Disable default GITHUB_TOKEN persistence
persist-credentials: false # Disable default GITHUB_TOKEN persistence

- name: Create Semantic Release
uses: cycjimmy/semantic-release-action@v4.1.0
Expand All @@ -132,4 +136,4 @@ jobs:
echo ${{ steps.semantic-release.outputs.new_release_version }}
echo ${{ steps.semantic-release.outputs.new_release_major_version }}
echo ${{ steps.semantic-release.outputs.new_release_minor_version }}
echo ${{ steps.semantic-release.outputs.new_release_patch_version }}
echo ${{ steps.semantic-release.outputs.new_release_patch_version }}
14 changes: 7 additions & 7 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ module "my_backup" {
backup2 = {
backup_name = "storage2"
retention_period = "P30D"
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P2D"]
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1W"]
storage_account_id = azurerm_storage_account.my_storage_account_2.id
storage_account_containers = ["container1", "container2"]
backup_policy_naming_template = "nhsuk-{resource_abbreviation}-{resource_type}-{backup_name}"
Expand All @@ -100,7 +100,7 @@ module "my_backup" {
backup2 = {
backup_name = "disk2"
retention_period = "P30D"
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P2D"]
backup_intervals = ["R/2024-01-01T00:00:00+00:00/PT12H"]
managed_disk_id = azurerm_managed_disk.my_managed_disk_2.id
backup_policy_naming_template = "nhsuk-{resource_abbreviation}-{resource_type}-{backup_name}"
backup_instance_naming_template = "nhsuk-{resource_abbreviation}-{resource_type}-{backup_name}"
Expand All @@ -114,14 +114,14 @@ module "my_backup" {
backup1 = {
backup_name = "server1"
retention_period = "P7D"
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1D"]
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1W"]
server_id = azurerm_postgresql_flexible_server.my_server_1.id
server_resource_group_id = azurerm_resource_group.my_resource_group.id
}
backup2 = {
backup_name = "server2"
retention_period = "P30D"
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P2D"]
backup_intervals = ["R/2024-01-01T00:00:00+00:00/P1W"]
server_id = azurerm_postgresql_flexible_server.my_server_2.id
server_resource_group_id = azurerm_resource_group.my_resource_group.id
backup_policy_naming_template = "nhsuk-{resource_abbreviation}-{resource_type}-{backup_name}"
Expand Down Expand Up @@ -150,7 +150,7 @@ module "my_backup" {
| `blob_storage_backups.storage_account_containers` | A list of containers in the storage account that should be backed up. | Yes | n/a |
| `blob_storage_backups.backup_name` | The name of the backup, which must be unique across blob storage backups. | Yes | n/a |
| `blob_storage_backups.retention_period` | How long the backed up data will be retained for, which should be in `ISO 8601` duration format. This must be specified in days, and can be up to 7 days unless `use_extended_retention` is on. [See the following link for more information about the format](https://en.wikipedia.org/wiki/ISO_8601#Durations). | Yes | n/a |
| `blob_storage_backups.backup_intervals` | A list of intervals at which backups should be taken, which should be in `ISO 8601` duration format. [See the following link for the possible values](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals). | Yes | n/a |
| `blob_storage_backups.backup_intervals` | A list of intervals at which backups should be taken, in `ISO 8601` repeating interval format. The frequency (duration) part must be `P1D` (daily) or `P1W` (weekly). [See the Azure Blob backup documentation for supported schedules](https://learn.microsoft.com/en-us/azure/backup/blob-backup-configure-manage). | Yes | n/a |
| `blob_storage_backups.backup_policy_naming_template` | Naming template used to construct the blob backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkpol`, `{resource_type}` → `blob`, `{backup_name}` → value of `blob_storage_backups.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
| `blob_storage_backups.backup_instance_naming_template` | Naming template used to construct the blob backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkinst`, `{resource_type}` → `blob`, `{backup_name}` → value of `blob_storage_backups.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
| `blob_storage_backups.time_zone` | The time zone to apply to the backup policy schedule (eg. Europe/London). If not specified, Azure’s default time zone behaviour is used. | No | n/a |
Expand All @@ -159,14 +159,14 @@ module "my_backup" {
| `managed_disk_backups.managed_disk_id` | The id of the managed disk that should be backed up. | Yes | n/a |
| `managed_disk_backups.backup_name` | The name of the backup, which must be unique across managed disk backups. | Yes | n/a |
| `managed_disk_backups.retention_period` | How long the backed up data will be retained for, which should be in `ISO 8601` duration format. This must be specified in days, and can be up to 7 days unless `use_extended_retention` is on. [See the following link for more information about the format](https://en.wikipedia.org/wiki/ISO_8601#Durations). | Yes | n/a |
| `managed_disk_backups.backup_intervals` | A list of intervals at which backups should be taken, which should be in `ISO 8601` duration format. [See the following link for the possible values](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals). | Yes | n/a |
| `managed_disk_backups.backup_intervals` | A list of intervals at which backups should be taken, in `ISO 8601` repeating interval format. The frequency (duration) part must be one of `PT1H`, `PT2H`, `PT4H`, `PT6H`, `PT8H`, `PT12H` (hourly) or `P1D` (daily). [See the Azure Disk backup support matrix for supported schedules](https://learn.microsoft.com/en-us/azure/backup/disk-backup-support-matrix). | Yes | n/a |
| `managed_disk_backup.backup_policy_naming_template` | Naming template used to construct the disk backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkpol`, `{resource_type}` → `disk`, `{backup_name}` → value of `managed_disk_backup.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
| `managed_disk_backup.backup_instance_naming_template` | Naming template used to construct the disk backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkinst`, `{resource_type}` → `disk`, `{backup_name}` → value of `managed_disk_backup.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
| `postgresql_flexible_server_backups` | A map of postgresql flexible server backups that should be created. For each backup the following values should be provided: `backup_name`, `server_id`, `server_resource_group_id`, `retention_period` and `backup_intervals`. When no value is provided then no backups are created. | No | n/a |
| `postgresql_flexible_server_backups.backup_name` | The name of the backup, which must be unique across postgresql flexible server backups. | Yes | n/a |
| `postgresql_flexible_server_backups.server_id` | The id of the postgresql flexible server that should be backed up. | Yes | n/a |
| `postgresql_flexible_server_backups.server_resource_group_id` | The id of the resource group which the postgresql flexible server resides in. | Yes | n/a |
| `postgresql_flexible_server_backups.retention_period` | How long the backed up data will be retained for, which should be in `ISO 8601` duration format. This must be specified in days, and can be up to 7 days unless `use_extended_retention` is on. [See the following link for more information about the format](https://en.wikipedia.org/wiki/ISO_8601#Durations). | Yes | n/a |
| `postgresql_flexible_server_backups.backup_intervals` | A list of intervals at which backups should be taken, which should be in `ISO 8601` duration format. [See the following link for the possible values](https://en.wikipedia.org/wiki/ISO_8601#Time_intervals). | Yes | n/a |
| `postgresql_flexible_server_backups.backup_intervals` | A list of intervals at which backups should be taken, in `ISO 8601` repeating interval format. Only `P1W` (weekly) is supported. [See the Azure PostgreSQL Flexible Server backup support matrix for supported schedules](https://learn.microsoft.com/en-us/azure/backup/backup-azure-database-postgresql-flex-support-matrix). | Yes | n/a |
| `postgresql_flexible_server_backup.backup_policy_naming_template` | Naming template used to construct the pgflex server backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkpol`, `{resource_type}` → `pgflex`, `{backup_name}` → value of `postgresql_flexible_server_backup.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
| `postgresql_flexible_server_backup.backup_instance_naming_template` | Naming template used to construct the pgflex server backup instance name. The following placeholders are supported and will be replaced by the module: `{resource_abbreviation}` → `bkinst`, `{resource_type}` → `pgflex`, `{backup_name}` → value of `postgresql_flexible_server_backup.backup_name` | No | {resource_abbreviation}-{resource_type}-{backup_name} |
38 changes: 38 additions & 0 deletions infrastructure/variables.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
locals {
# The valid backup retention period - up to 7 days, which can be bypassed when use_extended_retention is set to true
valid_retention_periods = [for days in range(1, 8) : "P${days}D"]

# Valid backup interval frequencies per resource type
valid_blob_storage_intervals = ["P1D", "P1W"]
valid_managed_disk_intervals = ["PT1H", "PT2H", "PT4H", "PT6H", "PT8H", "PT12H", "P1D"]
valid_postgresql_flexible_server_intervals = ["P1W"]

# Repeating interval format: R/<RFC3339 timestamp>/<duration>
backup_interval_timestamp_pattern = "[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-9]{2}:[0-9]{2})"
blob_storage_interval_pattern = "^R/${local.backup_interval_timestamp_pattern}/(${join("|", local.valid_blob_storage_intervals)})$"
managed_disk_interval_pattern = "^R/${local.backup_interval_timestamp_pattern}/(${join("|", local.valid_managed_disk_intervals)})$"
postgresql_interval_pattern = "^R/${local.backup_interval_timestamp_pattern}/(${join("|", local.valid_postgresql_flexible_server_intervals)})$"
Comment on lines +11 to +14
}

variable "resource_group_name" {
Expand Down Expand Up @@ -75,6 +86,15 @@ variable "blob_storage_backups" {
error_message = "At least one backup interval must be provided."
}

validation {
condition = alltrue([
for k, v in var.blob_storage_backups : alltrue([
for interval in v.backup_intervals : can(regex(local.blob_storage_interval_pattern, interval))
])
])
error_message = "Invalid backup interval for blob storage: allowed frequencies are P1D (daily) or P1W (weekly). See https://learn.microsoft.com/en-us/azure/backup/blob-backup-configure-manage for details."
}

validation {
condition = alltrue([for k, v in var.blob_storage_backups : length(v.storage_account_containers) > 0])
error_message = "At least one storage account container must be provided."
Expand Down Expand Up @@ -108,6 +128,15 @@ variable "managed_disk_backups" {
error_message = "At least one backup interval must be provided."
}

validation {
condition = alltrue([
for k, v in var.managed_disk_backups : alltrue([
for interval in v.backup_intervals : can(regex(local.managed_disk_interval_pattern, interval))
])
])
error_message = "Invalid backup interval for managed disk: allowed frequencies are PT1H, PT2H, PT4H, PT6H, PT8H, PT12H (hourly) or P1D (daily). See https://learn.microsoft.com/en-us/azure/backup/disk-backup-support-matrix for details."
}

validation {
condition = var.use_extended_retention ? true : alltrue([for k, v in var.managed_disk_backups : contains(local.valid_retention_periods, v.retention_period)])
error_message = "Invalid retention period: valid periods are up to 7 days. If you require a longer retention period then please set use_extended_retention to true."
Expand All @@ -133,6 +162,15 @@ variable "postgresql_flexible_server_backups" {
error_message = "At least one backup interval must be provided."
}

validation {
condition = alltrue([
for k, v in var.postgresql_flexible_server_backups : alltrue([
for interval in v.backup_intervals : can(regex(local.postgresql_interval_pattern, interval))
])
])
error_message = "Invalid backup interval for PostgreSQL flexible server: only P1W (weekly) is allowed. See https://learn.microsoft.com/en-us/azure/backup/backup-azure-database-postgresql-flex-support-matrix for details."
}

validation {
condition = var.use_extended_retention ? true : alltrue([for k, v in var.postgresql_flexible_server_backups : contains(local.valid_retention_periods, v.retention_period)])
error_message = "Invalid retention period: valid periods are up to 7 days. If you require a longer retention period then please set use_extended_retention to true."
Expand Down
4 changes: 2 additions & 2 deletions tests/end-to-end-tests/blob_storage_backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,15 @@ func TestBlobStorageBackup(t *testing.T) {
blobStorageBackups := map[string]map[string]interface{}{
"backup1": {
"backup_name": "blob1",
"retention_period": "P1D",
"retention_period": "P6D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1D"},
"storage_account_id": *externalResources.StorageAccountOne.ID,
Comment thread
johncollinson2001 marked this conversation as resolved.
"storage_account_containers": []string{*externalResources.StorageAccountOneContainer.Name},
},
"backup2": {
"backup_name": "blob2",
"retention_period": "P7D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P2D"},
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1W"},
"storage_account_id": *externalResources.StorageAccountTwo.ID,
"storage_account_containers": []string{*externalResources.StorageAccountTwoContainer.Name},
},
Expand Down
6 changes: 3 additions & 3 deletions tests/end-to-end-tests/managed_disk_backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ func TestManagedDiskBackup(t *testing.T) {
managedDiskBackups := map[string]map[string]interface{}{
"backup1": {
"backup_name": "disk1",
"retention_period": "P1D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1D"},
"retention_period": "P6D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/PT6H"},
"managed_disk_id": *externalResources.ManagedDiskOne.ID,
Comment thread
johncollinson2001 marked this conversation as resolved.
"managed_disk_resource_group": map[string]interface{}{
"id": *externalResources.ResourceGroup.ID,
Expand All @@ -82,7 +82,7 @@ func TestManagedDiskBackup(t *testing.T) {
"backup2": {
"backup_name": "disk2",
"retention_period": "P7D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P2D"},
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1D"},
"managed_disk_id": *externalResources.ManagedDiskTwo.ID,
"managed_disk_resource_group": map[string]interface{}{
"id": *externalResources.ResourceGroup.ID,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ func TestPostgresqlFlexibleServerBackup(t *testing.T) {
PostgresqlFlexibleServerBackups := map[string]map[string]interface{}{
"backup1": {
"backup_name": "server1",
"retention_period": "P1D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1D"},
"retention_period": "P6D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1W"},
"server_id": *externalResources.PostgresqlFlexibleServerOne.ID,
Comment thread
johncollinson2001 marked this conversation as resolved.
"server_resource_group_id": *externalResources.ResourceGroup.ID,
},
"backup2": {
"backup_name": "server2",
"retention_period": "P7D",
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P2D"},
"backup_intervals": []string{"R/2024-01-01T00:00:00+00:00/P1W"},
"server_id": *externalResources.PostgresqlFlexibleServerTwo.ID,
"server_resource_group_id": *externalResources.ResourceGroup.ID,
},
Expand Down
2 changes: 2 additions & 0 deletions tests/integration-tests/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading