diff --git a/.gitignore b/.gitignore index 77a4fad..5506e44 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ override.tf.json # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan # example: *tfplan* + +**/.infracost \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b9f4dc5..6b1867e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,6 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.4.0 hooks: - id: check-added-large-files args: ['--maxkb=500'] @@ -18,7 +18,7 @@ repos: args: ['--allow-missing-credentials'] - id: trailing-whitespace - repo: https://github.com/antonbabenko/pre-commit-terraform - rev: v1.76.0 + rev: v1.81.0 hooks: - id: terraform_fmt - id: terraform_docs diff --git a/README.md b/README.md index 07ef443..05f7465 100644 --- a/README.md +++ b/README.md @@ -86,14 +86,14 @@ Module managed by: | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.0.11 | -| [aws](#requirement\_aws) | >= 4.0.0 | +| [terraform](#requirement\_terraform) | >= 1.5.0 | +| [aws](#requirement\_aws) | >= 4.26.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 4.35.0 | +| [aws](#provider\_aws) | >= 4.26.0 | ## Modules @@ -112,6 +112,8 @@ No modules. | [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_backup_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | | [aws_iam_role_policy_attachment.main_role_restore_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.main_role_s3_backup_policy_attach](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.main_role_s3_restore_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 | @@ -131,6 +133,7 @@ No modules. | [plan\_name](#input\_plan\_name) | The display name of a backup plan | `string` | n/a | yes | | [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\_not\_resources](#input\_selection\_not\_resources) | An array of strings that either contain Amazon Resource Names (ARNs) or match patterns of resources to exclude from a backup plan. | `list(string)` | `[]` | 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\_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 | diff --git a/examples/exclusions/README.md b/examples/exclusions/README.md new file mode 100644 index 0000000..878683f --- /dev/null +++ b/examples/exclusions/README.md @@ -0,0 +1,8 @@ +## Example deployment flow + +```bash +terraform init +terraform validate +terraform plan +terraform apply --auto-approve +``` diff --git a/examples/exclusions/main.tf b/examples/exclusions/main.tf new file mode 100644 index 0000000..51962a0 --- /dev/null +++ b/examples/exclusions/main.tf @@ -0,0 +1,54 @@ +###### +# KMS +###### +data "aws_kms_key" "backup" { + key_id = "alias/aws/backup" +} + +resource "aws_s3_bucket" "example" { + bucket = "umotif-test-bucket" + + tags = { + Environment = "test" + } +} + +######### +# Backup +######### +module "backup" { + source = "../.." + + # Create a vault + vault_name = "${var.name_prefix}-vault-exclusions" + vault_kms_key_arn = data.aws_kms_key.backup.arn + + # Create a backup plan + plan_name = "${var.name_prefix}-backup-plan" + + rules = [ + { + name = "${var.name_prefix}-backup-rule" + schedule = "cron(0 12 * * ? *)" + start_window = "65" + completion_window = "180" + recovery_point_tags = { + Project = "test" + Region = "eu-west-1" + } + + lifecycle = { + delete_after = 90 + } + } + ] + + selection_name = "${var.name_prefix}-backup-selection" + + selection_resources = ["*"] + selection_not_resources = [aws_s3_bucket.example.arn] + + tags = { + Environment = "test" + } +} diff --git a/examples/exclusions/outputs.tf b/examples/exclusions/outputs.tf new file mode 100644 index 0000000..892ae99 --- /dev/null +++ b/examples/exclusions/outputs.tf @@ -0,0 +1,44 @@ +output "backup_vault_id" { + description = "The name of the AWS Backup Vault" + value = module.backup.backup_vault_id +} + +output "backup_vault_arn" { + description = "The Amazon Resource Name (ARN) that identifies the AWS Backup Vault" + value = module.backup.backup_vault_arn +} + +output "backup_vault_recovery_points" { + description = "The number of recovery points that are stored in a backup vault" + value = module.backup.backup_vault_recovery_points +} + +output "backup_plan_id" { + description = "The name of the backup plan" + value = module.backup.backup_plan_id +} + +output "backup_plan_arn" { + description = "The Amazon Resource Name (ARN) that identifies the backup plan" + value = module.backup.backup_plan_arn +} + +output "backup_plan_version" { + description = "Unique, randomly generated, Unicode, UTF-8 encoded string that serves as the version ID of the backup plan." + value = module.backup.backup_plan_version +} + +output "backup_selection_id" { + description = "The identifier of the backup selection" + value = module.backup.backup_selection_id +} + +output "backup_vault_iam_role_name" { + description = "The name of the backup IAM role" + value = module.backup.backup_vault_iam_role_name +} + +output "backup_vault_iam_role_arn" { + description = "The ARN of the backup IAM role" + value = module.backup.backup_vault_iam_role_arn +} \ No newline at end of file diff --git a/examples/exclusions/variables.tf b/examples/exclusions/variables.tf new file mode 100644 index 0000000..0519052 --- /dev/null +++ b/examples/exclusions/variables.tf @@ -0,0 +1,5 @@ +variable "name_prefix" { + description = "A prefix used for naming resources." + type = string + default = "example" +} diff --git a/examples/exclusions/versions.tf b/examples/exclusions/versions.tf new file mode 100644 index 0000000..3e08687 --- /dev/null +++ b/examples/exclusions/versions.tf @@ -0,0 +1,10 @@ +terraform { + required_version = "~> 1.5.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.26.0" + } + } +} diff --git a/examples/external-vault/versions.tf b/examples/external-vault/versions.tf index 40f827e..0de2e8e 100644 --- a/examples/external-vault/versions.tf +++ b/examples/external-vault/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0.11" + required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0.0" + version = ">= 4.26.0" } } -} +} \ No newline at end of file diff --git a/examples/multiple-dbs/versions.tf b/examples/multiple-dbs/versions.tf index 40f827e..0de2e8e 100644 --- a/examples/multiple-dbs/versions.tf +++ b/examples/multiple-dbs/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0.11" + required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0.0" + version = ">= 4.26.0" } } -} +} \ No newline at end of file diff --git a/examples/one-db/versions.tf b/examples/one-db/versions.tf index 40f827e..0de2e8e 100644 --- a/examples/one-db/versions.tf +++ b/examples/one-db/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0.11" + required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0.0" + version = ">= 4.26.0" } } -} +} \ No newline at end of file diff --git a/examples/vault/outputs.tf b/examples/vault/outputs.tf index 50f6f09..6b3a821 100644 --- a/examples/vault/outputs.tf +++ b/examples/vault/outputs.tf @@ -39,5 +39,5 @@ output "backup_vault_iam_role_name" { } output "backup_vault_iam_role_arn" { - output = module.backup.backup_vault_iam_role_name.arn + value = module.backup.backup_vault_iam_role_name.arn } \ No newline at end of file diff --git a/examples/vault/versions.tf b/examples/vault/versions.tf index 40f827e..0de2e8e 100644 --- a/examples/vault/versions.tf +++ b/examples/vault/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0.11" + required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0.0" + version = ">= 4.26.0" } } -} +} \ No newline at end of file diff --git a/main.tf b/main.tf index a85e148..419cc8b 100644 --- a/main.tf +++ b/main.tf @@ -18,6 +18,7 @@ resource "aws_backup_plan" "main" { dynamic "rule" { for_each = var.rules + content { rule_name = lookup(rule.value, "name") target_vault_name = var.vault_name != null ? aws_backup_vault.main[0].name : lookup(rule.value, "target_vault_name", "Default") @@ -29,6 +30,7 @@ resource "aws_backup_plan" "main" { dynamic "lifecycle" { for_each = length(lookup(rule.value, "lifecycle")) == 0 ? [] : [lookup(rule.value, "lifecycle", {})] + content { cold_storage_after = lookup(lifecycle.value, "cold_storage_after", 0) delete_after = lookup(lifecycle.value, "delete_after", 90) @@ -37,6 +39,7 @@ resource "aws_backup_plan" "main" { dynamic "copy_action" { for_each = length(lookup(rule.value, "copy_action", {})) == 0 ? [] : [lookup(rule.value, "copy_action", {})] + content { destination_vault_arn = lookup(copy_action.value, "destination_vault_arn", null) @@ -71,7 +74,8 @@ resource "aws_backup_selection" "main" { name = var.selection_name plan_id = aws_backup_plan.main.id - resources = var.selection_resources + resources = var.selection_resources + not_resources = var.selection_not_resources dynamic "selection_tag" { for_each = var.selection_tags @@ -128,6 +132,16 @@ resource "aws_iam_role_policy_attachment" "main_role_restore_policy_attach" { role = aws_iam_role.main.name } +resource "aws_iam_role_policy_attachment" "main_role_s3_backup_policy_attach" { + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AWSBackupServiceRolePolicyForS3Backup" + role = aws_iam_role.main.name +} + +resource "aws_iam_role_policy_attachment" "main_role_s3_restore_policy_attach" { + policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/AWSBackupServiceRolePolicyForS3Restore" + role = aws_iam_role.main.name +} + resource "aws_iam_policy" "main_custom_policy" { description = "AWS Backup Tag policy" policy = data.aws_iam_policy_document.main_custom_policy.json diff --git a/variables.tf b/variables.tf index 5d7c63d..4911a54 100644 --- a/variables.tf +++ b/variables.tf @@ -30,6 +30,12 @@ variable "selection_resources" { default = [] } +variable "selection_not_resources" { + description = "An array of strings that either contain Amazon Resource Names (ARNs) or match patterns of resources to exclude from a backup plan." + type = list(string) + default = [] +} + variable "selection_tags" { description = "A list of selection tags map" type = list(any) diff --git a/versions.tf b/versions.tf index 40f827e..d27d27b 100644 --- a/versions.tf +++ b/versions.tf @@ -1,10 +1,10 @@ terraform { - required_version = ">= 1.0.11" + required_version = ">= 1.5.0" required_providers { aws = { source = "hashicorp/aws" - version = ">= 4.0.0" + version = ">= 4.26.0" } } }