0

I'm working on a system-wide backup solution to back up all EC2 instances that are running in an environment with AWS Backup. Some of them have attached EBS volumes that also seem to be backed up with the instance. Below is my terraform code that allows snapshots to be taken every week:

resource "aws_backup_region_settings" "legacy" {
  resource_type_opt_in_preference = {
    "Aurora"          = false
    "DynamoDB"        = false
    "EFS"             = false
    "FSx"             = false
    "RDS"             = false
    "Storage Gateway" = false
    "EBS"             = true
    "EC2"             = true
    "DocumentDB"      = false
    "Neptune"         = false
    "VirtualMachine"  = false
  }
}

resource "aws_backup_vault" "legacy" {
  name        = "Legacy${var.environment_tag}"
  kms_key_arn = aws_kms_key.mgn.arn

  tags = merge(
    local.tags, {
      "Name" = "Legacy${var.environment_tag}"
    }
  )
}

resource "aws_iam_role" "legacy_backup" {
  name                 = "AWSBackupService"
  permissions_boundary = data.aws_iam_policy.role_permissions_boundary.arn
  assume_role_policy   = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["sts:AssumeRole"],
      "Effect": "allow",
      "Principal": {
        "Service": ["backup.amazonaws.com"]
      }
    }
  ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "legacy_backup" {
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup"
  role       = aws_iam_role.legacy_backup.name
}

###############################################################################
##
## Weekly Backups
##
###############################################################################

resource "aws_backup_plan" "weekly" {
  name = "Legacy${var.environment_tag}Weekly"

  rule {
    enable_continuous_backup = false
    rule_name                = "Legacy${var.environment_tag}Weekly"
    target_vault_name        = aws_backup_vault.legacy.name
    schedule                 = var.backup_plan_weekly_schedule
    start_window             = 60  # minutes
    completion_window        = 180 # minutes

    lifecycle {
      cold_storage_after = 30  # days
      delete_after       = 120 # days
    }

    copy_action {
      destination_vault_arn = aws_backup_vault.legacy.arn

      lifecycle {
        cold_storage_after = 30  # days
        delete_after       = 120 # days
      }
    }

    copy_action {
      destination_vault_arn = aws_backup_vault.secondary.arn

      lifecycle {
        cold_storage_after = 30  # days
        delete_after       = 120 # days
      }
    }
  }

  advanced_backup_setting {
    backup_options = {
      WindowsVSS = "enabled"
    }
    resource_type = "EC2"
  }

  tags = merge(
    local.tags, {
      "Name" = "Legacy${var.environment_tag}Weekly"
    }
  )
}

resource "aws_backup_selection" "weekly" {
  iam_role_arn = aws_iam_role.legacy_backup.arn
  name         = "Legacy${var.environment_tag}Weekly"
  plan_id      = aws_backup_plan.weekly.id

  selection_tag {
    type  = "STRINGEQUALS"
    key   = "AWSBackup"
    value = "weekly"
  }

}

In the EC2 code, I will tag the instances with "AWSBackup" and "Weekly", and this seems to work fine - for all instances and attached volumes. If I don't want one of the EBS volumes backed up - is there a way to exclude it from being backed up?

BPS
  • 607
  • 8
  • 29

2 Answers2

1

It's possible but not yet in Terraform. The PR is created so it shouldn't take too long.

After the PR is merged you should be able to create an aws_backup_selection and use "NotResources" to exclude your EBS volume.

You can also tag all resources which need to be backed up. Then you can create a backup plan without an exclude.

lvthillo
  • 28,263
  • 13
  • 94
  • 127
1

tl:dr;

If you need to use the v3.xx for terraform-aws-provider then use at-least version 3.74.1.

For v4.xx, use at least v4.9.0.

Finally, use the following snippet (modified to answer OP's question) to exclude the EBS volume which must be tagged with aws:ResourceTag/ExcludeFromBackup = true :

resource "aws_backup_selection" "weekly" {
  iam_role_arn = aws_iam_role.legacy_backup.arn
  name         = "Legacy${var.environment_tag}Weekly"
  plan_id      = aws_backup_plan.weekly.id

  selection_tag {
    type  = "STRINGEQUALS"
    key   = "AWSBackup"
    value = "weekly"
  }
  
  condition {
    string_not_like {
      key   = "aws:ResourceTag/ExcludeFromBackup"
      value = "true"
    }
  }
}

Version 3.xx

This functionality (condition configuration block and not_resources argument) was first released in v3.72.0 of terraform-aws-provider. From the release notes:

resource/aws_backup_selection: Add condition configuration block and not_resources argument in support of fine-grained backup plan resource assignment (#22074)

However, I would recommend using atleast v3.74.1, since it has the following fix directly related to the above implementation:

resource/aws_backup_selection: Fix permanent diffs for condition and not_resources arguments causing resource recreation (#22882)

Version 4.xx

If you are using version 4.xx, then the first version which has both the original functionality and the fix is v4.9.0:

resource/aws_backup_selection: Fix permanent diffs for condition and not_resources arguments causing resource recreation (#22882) resource/aws_backup_selection: Add condition configuration block and not_resources argument in support of fine-grained backup plan resource assignment (#22074)


Examples (from the docs):

Selecting Backups By Conditions

resource "aws_backup_selection" "example" {
  iam_role_arn = aws_iam_role.example.arn
  name         = "tf_example_backup_selection"
  plan_id      = aws_backup_plan.example.id
  resources    = ["*"]

  condition {
    string_equals {
      key   = "aws:ResourceTag/Component"
      value = "rds"
    }
    string_like {
      key   = "aws:ResourceTag/Application"
      value = "app*"
    }
    string_not_equals {
      key   = "aws:ResourceTag/Backup"
      value = "false"
    }
    string_not_like {
      key   = "aws:ResourceTag/Environment"
      value = "test*"
    }
  }
}

Selecting Backups By Not Resource

resource "aws_backup_selection" "example" {
  iam_role_arn = aws_iam_role.example.arn
  name         = "tf_example_backup_selection"
  plan_id      = aws_backup_plan.example.id

  not_resources = [
    aws_db_instance.example.arn,
    aws_ebs_volume.example.arn,
    aws_efs_file_system.example.arn,
  ]
}
Ashutosh Jindal
  • 18,501
  • 4
  • 62
  • 91