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

Enable AWS Backup Vault lock #495

Merged
merged 20 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 19 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
37 changes: 34 additions & 3 deletions modules/backup/main.tf
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
locals {
cold_storage_after = 30
is_production = can(regex("production|default", terraform.workspace))
kms_master_key_id = (data.aws_region.current.name == "eu-west-2" && length(data.aws_kms_alias.securityhub-alarms) > 0) ? data.aws_kms_alias.securityhub-alarms[0].target_key_id : ""
}

# Fetch the current AWS region
data "aws_region" "current" {}

# Define the KMS alias, conditionally fetched if the region is eu-west-2
data "aws_kms_alias" "securityhub-alarms" {
count = data.aws_region.current.name == "eu-west-2" ? 1 : 0
name = "alias/securityhub-alarms-key-multi-region"
}

# Define the SNS topic, conditionally created if the region is eu-west-2 and is production
resource "aws_sns_topic" "backup_vault_topic" {
count = (local.is_production && data.aws_region.current.name == "eu-west-2") ? 1 : 0
kms_master_key_id = local.kms_master_key_id
name = var.backup_vault_lock_sns_topic_name
tags = merge(var.tags, {
Description = "This backup topic is so the MP team can subscribe to backup vault lock being turned off and member accounts can create their own subscriptions"
})
}


resource "aws_backup_vault" "default" {
#checkov:skip=CKV_AWS_166: "Ensure Backup Vault is encrypted at rest using KMS CMK - Tricky to implement, hence using AWS managed KMS key"

name = var.aws_backup_vault_name
tags = var.tags
}

# Backup vault lock
resource "aws_backup_vault_lock_configuration" "default" {
count = local.is_production ? 1 : 0
backup_vault_name = aws_backup_vault.default.name
min_retention_days = var.min_vault_retention_days
max_retention_days = var.max_vault_retention_days
}


# Production backups
resource "aws_backup_plan" "default" {
#checkov:skip=CKV_AWS_166: "Ensure Backup Vault is encrypted at rest using KMS CMK - Tricky to implement, hence using AWS managed KMS key"
Expand Down Expand Up @@ -116,7 +146,7 @@ resource "aws_backup_selection" "non_production" {
# SNS topic
# trivy:ignore:avd-aws-0136
resource "aws_sns_topic" "backup_failure_topic" {
kms_master_key_id = var.sns_backup_topic_key
kms_master_key_id = local.kms_master_key_id
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed, so that we actually get failure notifications now.

name = var.backup_aws_sns_topic_name
tags = merge(var.tags, {
Description = "This backup topic is so the MP team can subscribe to backup notifications from selected accounts and teams using member-unrestricted accounts can create their own subscriptions"
Expand All @@ -128,4 +158,5 @@ resource "aws_backup_vault_notifications" "aws_backup_vault_notifications" {
backup_vault_events = ["BACKUP_JOB_FAILED"]
backup_vault_name = aws_backup_vault.default.name
sns_topic_arn = aws_sns_topic.backup_failure_topic.arn
}
}

4 changes: 4 additions & 0 deletions modules/backup/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@ output "backup_aws_sns_topic_arn" {
value = aws_sns_topic.backup_failure_topic.arn
}

output "backup_vault_lock_sns_topic_name" {
value = length(aws_sns_topic.backup_vault_topic) > 0 ? aws_sns_topic.backup_vault_topic[0].arn : ""
}

20 changes: 19 additions & 1 deletion modules/backup/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,22 @@ variable "non_production_backup_selection_name" {
variable "backup_aws_sns_topic_name" {
default = "backup_failure_topic"
type = string
}
}

variable "backup_vault_lock_sns_topic_name" {
default = "backup_vault_failure_topic"
type = string
}

variable "max_vault_retention_days" {
default = 30
description = "AWS Backup Vault config value for the max retention in days"
type = number
}

variable "min_vault_retention_days" {
default = 30
description = "AWS Backup Vault config value for the min retention in days"
type = number
}

4 changes: 3 additions & 1 deletion test/backup-test/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ module "backup-test" {
non_production_backup_plan_name = var.non_production_backup_plan_name
non_production_backup_selection_name = var.non_production_backup_selection_name
backup_aws_sns_topic_name = var.backup_aws_sns_topic_name

max_vault_retention_days = var.max_vault_retention_days
min_vault_retention_days = var.min_vault_retention_days
backup_vault_lock_sns_topic_name = var.backup_vault_lock_sns_topic_name
}

/*
Expand Down
4 changes: 4 additions & 0 deletions test/backup-test/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@ output "aws_backup_selection_non_production" {

output "backup_aws_sns_topic_arn" {
value = module.backup-test.backup_aws_sns_topic_arn
}

output "backup_vault_lock_sns_topic_name" {
value = module.backup-test.backup_vault_lock_sns_topic_name
}
19 changes: 18 additions & 1 deletion test/backup-test/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,21 @@ variable "non_production_backup_selection_name" {
variable "backup_aws_sns_topic_name" {
default = "backup_failure_topic"
type = string
}
}

variable "max_vault_retention_days" {
default = 30
description = "AWS Backup Vault config value for the max retention in days"
type = number
}

variable "min_vault_retention_days" {
default = 30
description = "AWS Backup Vault config value for the min retention in days"
type = number
}

variable "backup_vault_lock_sns_topic_name" {
default = "backup_vault_failure_topic"
type = string
}
5 changes: 5 additions & 0 deletions test/baselines_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ func TestTerraformBackup(t *testing.T) {
NonProdBackupPlanName := fmt.Sprintf("backup-daily-cold-storage-monthly-retain-30-days-%s", uniqueId)
NonProdBackupSelectionName := fmt.Sprintf("non-production-backup-%s", uniqueId)
BackupSNSTopicName := fmt.Sprintf("backup_failure_topic-%s", uniqueId)
BackupLockSNSTopicName := fmt.Sprintf("backup_vault_lock_sns_topic_name-%s", uniqueId)

terraformOptions := &terraform.Options{
TerraformDir: terraformDir,
Expand All @@ -36,6 +37,7 @@ func TestTerraformBackup(t *testing.T) {
"non_production_backup_plan_name": NonProdBackupPlanName,
"non_production_backup_selection_name": NonProdBackupSelectionName,
"backup_aws_sns_topic_name": BackupSNSTopicName,
"backup_vault_lock_sns_topic_name": BackupLockSNSTopicName,
},
}
// Clean up resources with "terraform destroy" at the end of the test
Expand All @@ -54,11 +56,14 @@ func TestTerraformBackup(t *testing.T) {
AwsBackupSelectionProd := terraform.Output(t, terraformOptions, "aws_backup_selection_production")
AwsBackupSelectionNonProd := terraform.Output(t, terraformOptions, "aws_backup_selection_non_production")
AWSBackupSNSTopicArn := terraform.Output(t, terraformOptions, "backup_aws_sns_topic_arn")
AWSVaultSNSTopicName := terraform.Output(t, terraformOptions, "backup_vault_lock_sns_topic_name")

assert.Regexp(t, regexp.MustCompile(`^arn:aws:backup:eu-west-2:[0-9]{12}:backup-vault:everything-`+uniqueId), AwsBackupVaultArn)
assert.Regexp(t, regexp.MustCompile(`^arn:aws:backup:eu-west-2:[0-9]{12}:backup-plan:*`), AwsBackupPlanProd)
assert.Regexp(t, regexp.MustCompile(`^arn:aws:backup:eu-west-2:[0-9]{12}:backup-plan:*`), AwsBackupPlanNonProd)
assert.Regexp(t, regexp.MustCompile(`^*`), AwsBackupSelectionProd)
assert.Regexp(t, regexp.MustCompile(`^*`), AwsBackupSelectionNonProd)
assert.Regexp(t, regexp.MustCompile(`^arn:aws:sns:eu-west-2:[0-9]{12}:backup_failure_topic-`+uniqueId), AWSBackupSNSTopicArn)
assert.Regexp(t, regexp.MustCompile(`^arn:aws:sns:eu-west-2:[0-9]{12}:backup_vault_lock_sns_topic_name-`+uniqueId), AWSVaultSNSTopicName)

}
1 change: 1 addition & 0 deletions test/go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

module github.com/ministryofjustice/modernisation-platform-terraform-baselines

go 1.18
Expand Down
Loading