diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index de07ffd..7bc1c4f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: args: ['--allow-missing-credentials'] - id: trailing-whitespace - repo: git://github.com/antonbabenko/pre-commit-terraform - rev: v1.48.0 + rev: v1.50.0 hooks: - id: terraform_fmt - id: terraform_docs diff --git a/CHANGELOG.md b/CHANGELOG.md index da3f69a..8692282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,16 @@ All notable changes to this project will be documented in this file. ## [Unreleased] -- Documentation updates -- Use default KMS keys -- Introduce Terratest +- Add SNS Notifications to Backup Vault +- Add continuous backup feature ([#8](https://github.com/umotif-public/terraform-aws-backup/issues/8)) +- Update README.md +- Add github actions workflow for Terratest ([#6](https://github.com/umotif-public/terraform-aws-backup/issues/6)) + + + +## [1.2.0] - 2020-12-15 + +- Module testing ([#5](https://github.com/umotif-public/terraform-aws-backup/issues/5)) @@ -30,6 +37,7 @@ All notable changes to this project will be documented in this file. - Initial commit -[Unreleased]: https://github.com/umotif-public/terraform-aws-backup/compare/1.1.0...HEAD +[Unreleased]: https://github.com/umotif-public/terraform-aws-backup/compare/1.2.0...HEAD +[1.2.0]: https://github.com/umotif-public/terraform-aws-backup/compare/1.1.0...1.2.0 [1.1.0]: https://github.com/umotif-public/terraform-aws-backup/compare/1.0.1...1.1.0 [1.0.1]: https://github.com/umotif-public/terraform-aws-backup/compare/1.0.0...1.0.1 diff --git a/README.md b/README.md index 5af341f..54f843f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ [![Lint and Validate](https://github.com/umotif-public/terraform-aws-backup/workflows/Lint%20and%20Validate/badge.svg)](https://github.com/umotif-public/terraform-aws-backup/actions?query=workflow%3A%22Lint+and+Validate%22) [![Terratest](https://github.com/umotif-public/terraform-aws-backup/workflows/Terratest/badge.svg)](https://github.com/umotif-public/terraform-aws-backup/actions?query=workflow%3ATerratest) - # Terraform AWS Backup Terraform module to provision [AWS Backup](https://aws.amazon.com/backup/) resources. @@ -86,56 +85,84 @@ Module managed by: | Name | Version | |------|---------| -| terraform | >= 0.13 | -| aws | >= 3.11 | +| [terraform](#requirement\_terraform) | >= 0.13 | +| [aws](#requirement\_aws) | >= 3.11 | ## Providers | Name | Version | |------|---------| -| aws | >= 3.11 | +| [aws](#provider\_aws) | >= 3.11 | ## Modules -No Modules. +No modules. ## Resources -| Name | -|------| -| [aws_backup_plan](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_plan) | -| [aws_backup_selection](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_selection) | -| [aws_backup_vault](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault) | -| [aws_iam_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | -| [aws_iam_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | -| [aws_iam_role_policy_attachment](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | +| Name | Type | +|------|------| +| [aws_backup_plan.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_plan) | resource | +| [aws_backup_selection.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_selection) | resource | +| [aws_backup_vault.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault) | resource | +| [aws_backup_vault_notifications.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/backup_vault_notifications) | resource | +| [aws_iam_policy.main_custom_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | +| [aws_iam_role.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.main_custom_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.main_role_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_sns_topic.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic) | resource | +| [aws_sns_topic_policy.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_policy) | resource | +| [aws_iam_policy_document.main](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.main_custom_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_iam_policy_document.sns_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| advanced\_backup\_settings | An object that specifies backup options for each resource type | `any` | `[]` | no | -| iam\_role\_name | Name of IAM Role to associate to the Backup Plan | `string` | `null` | no | -| plan\_name | The display name of a backup plan | `string` | n/a | yes | -| rules | A list of rules mapping rule configurations for a backup plan | `any` | `[]` | no | -| selection\_name | The display name of a resource selection document | `string` | `null` | no | -| selection\_resources | A list of strings that either contain Amazon Resource Names (ARNs) or match patterns of resources to assign to a backup plan | `list(string)` | `[]` | no | -| selection\_tags | A list of selection tags map | `list(any)` | `[]` | no | -| tags | A mapping of tags to assign to the resource | `map(string)` | `{}` | no | -| vault\_kms\_key\_arn | The server-side encryption key that is used to protect your backups | `string` | `null` | no | -| vault\_name | Name of the backup vault to create. If not given, AWS use default | `string` | `null` | no | +| [advanced\_backup\_settings](#input\_advanced\_backup\_settings) | An object that specifies backup options for each resource type | `any` | `[]` | no | +| [backup\_vault\_events](#input\_backup\_vault\_events) | An array of events that indicate the status of jobs to back up resources to the backup vault. | `list(string)` |
[
"BACKUP_JOB_STARTED",
"BACKUP_JOB_COMPLETED",
"BACKUP_JOB_SUCCESSFUL",
"BACKUP_JOB_FAILED",
"BACKUP_JOB_EXPIRED",
"RESTORE_JOB_STARTED",
"RESTORE_JOB_COMPLETED",
"RESTORE_JOB_SUCCESSFUL",
"RESTORE_JOB_FAILED",
"COPY_JOB_STARTED",
"COPY_JOB_SUCCESSFUL",
"COPY_JOB_FAILED",
"RECOVERY_POINT_MODIFIED",
"BACKUP_PLAN_CREATED",
"BACKUP_PLAN_MODIFIED"
]
| no | +| [create\_sns\_topic](#input\_create\_sns\_topic) | Create SNS Topic | `bool` | `true` | no | +| [enable\_sns\_notifications](#input\_enable\_sns\_notifications) | Enable Backup Vault Notifications | `bool` | `false` | no | +| [iam\_role\_name](#input\_iam\_role\_name) | Name of IAM Role to associate to the Backup Plan | `string` | `null` | no | +| [plan\_name](#input\_plan\_name) | The display name of a backup plan | `string` | n/a | yes | +| [rule\_completion\_window](#input\_rule\_completion\_window) | The amount of time AWS Backup attempts a backup before canceling the job and returning an error | `number` | `null` | no | +| [rule\_copy\_action\_destination\_vault\_arn](#input\_rule\_copy\_action\_destination\_vault\_arn) | An Amazon Resource Name (ARN) that uniquely identifies the destination backup vault for the copied backup. | `string` | `null` | no | +| [rule\_copy\_action\_lifecycle](#input\_rule\_copy\_action\_lifecycle) | The lifecycle defines when a protected resource is copied over to a backup vault and when it expires. | `map(any)` | `{}` | no | +| [rule\_lifecycle\_cold\_storage\_after](#input\_rule\_lifecycle\_cold\_storage\_after) | Specifies the number of days after creation that a recovery point is moved to cold storage | `number` | `null` | no | +| [rule\_lifecycle\_delete\_after](#input\_rule\_lifecycle\_delete\_after) | Specifies the number of days after creation that a recovery point is deleted. Must be 90 days greater than `cold_storage_after` | `number` | `null` | no | +| [rule\_name](#input\_rule\_name) | An display name for a backup rule | `string` | `null` | no | +| [rule\_recovery\_point\_tags](#input\_rule\_recovery\_point\_tags) | Metadata that you can assign to help organize the resources that you create | `map(string)` | `{}` | no | +| [rule\_schedule](#input\_rule\_schedule) | A CRON expression specifying when AWS Backup initiates a backup job | `string` | `null` | no | +| [rule\_start\_window](#input\_rule\_start\_window) | The amount of time in minutes before beginning a backup | `number` | `null` | no | +| [rules](#input\_rules) | A list of rules mapping rule configurations for a backup plan | `any` | `[]` | no | +| [selection\_name](#input\_selection\_name) | The display name of a resource selection document | `string` | `null` | no | +| [selection\_resources](#input\_selection\_resources) | A list of strings that either contain Amazon Resource Names (ARNs) or match patterns of resources to assign to a backup plan | `list(string)` | `[]` | no | +| [selection\_tag\_key](#input\_selection\_tag\_key) | The key in a key-value pair | `string` | `null` | no | +| [selection\_tag\_type](#input\_selection\_tag\_type) | An operation, such as StringEquals, that is applied to a key-value pair used to filter resources in a selection | `string` | `null` | no | +| [selection\_tag\_value](#input\_selection\_tag\_value) | The value in a key-value pair | `string` | `null` | no | +| [selection\_tags](#input\_selection\_tags) | A list of selection tags map | `list(any)` | `[]` | no | +| [sns\_topic\_arn](#input\_sns\_topic\_arn) | The Amazon Resource Name (ARN) that specifies the topic for a backup vault’s events | `string` | `null` | no | +| [tags](#input\_tags) | A mapping of tags to assign to the resource | `map(string)` | `{}` | no | +| [vault\_kms\_key\_arn](#input\_vault\_kms\_key\_arn) | The server-side encryption key that is used to protect your backups | `string` | `null` | no | +| [vault\_name](#input\_vault\_name) | Name of the backup vault to create. If not given, AWS use default | `string` | `null` | no | +| [vault\_sns\_kms\_key\_arn](#input\_vault\_sns\_kms\_key\_arn) | The server-side encryption key that is used to protect SNS messages for backups | `string` | `null` | no | ## Outputs | Name | Description | |------|-------------| -| backup\_plan\_arn | The Amazon Resource Name (ARN) that identifies the backup plan | -| backup\_plan\_id | The name of the backup plan | -| backup\_plan\_version | Unique, randomly generated, Unicode, UTF-8 encoded string that serves as the version ID of the backup plan. | -| backup\_selection\_id | The identifier of the backup selection | -| backup\_vault\_arn | The Amazon Resource Name (ARN) that identifies the AWS Backup Vault | -| backup\_vault\_id | The name of the AWS Backup Vault | -| backup\_vault\_recovery\_points | The number of recovery points that are stored in a backup vault | +| [backup\_plan\_arn](#output\_backup\_plan\_arn) | The Amazon Resource Name (ARN) that identifies the backup plan | +| [backup\_plan\_id](#output\_backup\_plan\_id) | The name of the backup plan | +| [backup\_plan\_version](#output\_backup\_plan\_version) | Unique, randomly generated, Unicode, UTF-8 encoded string that serves as the version ID of the backup plan. | +| [backup\_selection\_id](#output\_backup\_selection\_id) | The identifier of the backup selection | +| [backup\_sns\_topic\_arn](#output\_backup\_sns\_topic\_arn) | The Amazon Resource Name (ARN) that specifies the topic for a backup vault’s events | +| [backup\_vault\_arn](#output\_backup\_vault\_arn) | The Amazon Resource Name (ARN) that identifies the AWS Backup Vault | +| [backup\_vault\_events](#output\_backup\_vault\_events) | An array of events that indicate the status of jobs to back up resources to the backup vault. | +| [backup\_vault\_id](#output\_backup\_vault\_id) | The name of the AWS Backup Vault | +| [backup\_vault\_recovery\_points](#output\_backup\_vault\_recovery\_points) | The number of recovery points that are stored in a backup vault | ## License diff --git a/data.tf b/data.tf new file mode 100644 index 0000000..6a47332 --- /dev/null +++ b/data.tf @@ -0,0 +1,59 @@ +data "aws_region" "current" {} +data "aws_partition" "current" {} + +data "aws_iam_policy_document" "sns_policy" { + count = var.enable_sns_notifications ? 1 : 0 + + statement { + sid = "AllowSNSPublish" + + actions = [ + "SNS:Publish", + ] + + effect = "Allow" + + principals { + type = "Service" + identifiers = [ + "backup.amazonaws.com" + ] + } + + resources = var.create_sns_topic ? [aws_sns_topic.main[0].arn] : [var.sns_topic_arn] + } +} + +data "aws_iam_policy_document" "main" { + statement { + sid = "AllowBackupService" + + actions = [ + "sts:AssumeRole", + ] + + effect = "Allow" + + principals { + type = "Service" + identifiers = [ + "backup.amazonaws.com" + ] + } + } +} + +data "aws_iam_policy_document" "main_custom_policy" { + statement { + sid = "AllowTaggingResources" + + actions = [ + "backup:TagResource", + "backup:ListTags", + "backup:UntagResource", + "tag:GetResources" + ] + + resources = ["*"] + } +} \ No newline at end of file diff --git a/examples/multiple-dbs/main.tf b/examples/multiple-dbs/main.tf index b3dc006..6daeb11 100644 --- a/examples/multiple-dbs/main.tf +++ b/examples/multiple-dbs/main.tf @@ -32,6 +32,10 @@ data "aws_kms_key" "rds" { key_id = "alias/aws/rds" } +data "aws_kms_key" "sns_backup" { + key_id = "alias/aws/sns" +} + ############# # RDS Aurora ############# @@ -120,16 +124,11 @@ module "backup" { module.aurora-postgresql.rds_cluster_arn ] - selection_tags = [ - { - type = "STRINGEQUALS" - key = "Project" - value = "Test" - }, - { - type = "STRINGEQUALS" - key = "Environment" - value = "test" - } + # Enable SNS Backup Notifications + enable_sns_notifications = true + vault_sns_kms_key_arn = data.aws_kms_key.sns_backup.arn + backup_vault_events = [ + "BACKUP_JOB_FAILED", + "BACKUP_JOB_EXPIRED", ] } diff --git a/examples/multiple-dbs/outputs.tf b/examples/multiple-dbs/outputs.tf index 502b584..4c52959 100644 --- a/examples/multiple-dbs/outputs.tf +++ b/examples/multiple-dbs/outputs.tf @@ -31,4 +31,14 @@ output "backup_plan_version" { output "backup_selection_id" { description = "The identifier of the backup selection" value = module.backup.backup_selection_id +} + +output "backup_sns_topic_arn" { + description = "The Amazon Resource Name (ARN) that specifies the topic for a backup vault's events" + value = module.backup.backup_sns_topic_arn +} + +output "backup_vault_events" { + description = "An array of events that indicate the status of the jobs to back up resources to the backup vault." + value = module.backup.backup_vault_events } \ No newline at end of file diff --git a/examples/one-db/main.tf b/examples/one-db/main.tf index 4c2b1f5..2f519bb 100644 --- a/examples/one-db/main.tf +++ b/examples/one-db/main.tf @@ -2,9 +2,6 @@ provider "aws" { region = "eu-west-1" } -data "aws_caller_identity" "current" {} -data "aws_region" "current" {} - ##### # VPC and subnets ##### @@ -91,16 +88,6 @@ module "backup" { selection_name = "${var.name_prefix}-backup-selection" selection_resources = [module.aurora.rds_cluster_arn] - selection_tags = [ - { - type = "STRINGEQUALS" - key = "Project" - value = "Test" - }, - { - type = "STRINGEQUALS" - key = "Environment" - value = "test" - } - ] + # Enable SNS Backup Notifications + enable_sns_notifications = true } diff --git a/examples/one-db/outputs.tf b/examples/one-db/outputs.tf index 9589675..4c52959 100644 --- a/examples/one-db/outputs.tf +++ b/examples/one-db/outputs.tf @@ -32,3 +32,13 @@ output "backup_selection_id" { description = "The identifier of the backup selection" value = module.backup.backup_selection_id } + +output "backup_sns_topic_arn" { + description = "The Amazon Resource Name (ARN) that specifies the topic for a backup vault's events" + value = module.backup.backup_sns_topic_arn +} + +output "backup_vault_events" { + description = "An array of events that indicate the status of the jobs to back up resources to the backup vault." + value = module.backup.backup_vault_events +} \ No newline at end of file diff --git a/examples/vault/outputs.tf b/examples/vault/outputs.tf index 9589675..502b584 100644 --- a/examples/vault/outputs.tf +++ b/examples/vault/outputs.tf @@ -31,4 +31,4 @@ output "backup_plan_version" { output "backup_selection_id" { description = "The identifier of the backup selection" value = module.backup.backup_selection_id -} +} \ No newline at end of file diff --git a/main.tf b/main.tf index 2cff09b..27b63a3 100644 --- a/main.tf +++ b/main.tf @@ -82,55 +82,50 @@ resource "aws_backup_selection" "main" { } } +####### +# SNS Backup Notifications +####### +resource "aws_sns_topic" "main" { + count = var.create_sns_topic ? 1 : 0 + + name = var.vault_name != null ? "${aws_backup_vault.main[0].name}-events" : "backup-vault-events" + kms_master_key_id = var.vault_sns_kms_key_arn +} + +resource "aws_sns_topic_policy" "main" { + count = var.enable_sns_notifications ? 1 : 0 + + arn = var.create_sns_topic ? aws_sns_topic.main[0].arn : var.sns_topic_arn + policy = data.aws_iam_policy_document.sns_policy[0].json +} + +resource "aws_backup_vault_notifications" "main" { + count = var.enable_sns_notifications ? 1 : 0 + + backup_vault_name = var.vault_name != null ? aws_backup_vault.main[0].name : "Default" + sns_topic_arn = var.create_sns_topic ? aws_sns_topic.main[0].arn : var.sns_topic_arn + backup_vault_events = var.backup_vault_events +} + ##### # IAM Role ##### resource "aws_iam_role" "main" { name = var.iam_role_name != null ? var.iam_role_name : "aws-backup-plan-${var.plan_name}-role" - assume_role_policy = <