New AWS Backup Features for Quick and Easy EC2 Instance Recovery

Simone Bennett
Contino Engineering
5 min readFeb 3, 2020

--

I’m working on a cloud migration project where most servers on-prem are “pets” that host critical business apps. While we can uplift the infrastructure and use PaaS services as much as possible, many of the third-party applications are stateful and still need to be hosted on EC2 instances, requiring manual installation and careful configuration.

With this kind of critical-pet application, disaster recovery (DR) is always a concern. To date, we’ve used EBS volume snapshots, custom AMIs or third-party backup tools to help the business recover in case of an outage. Each solution is workable but not as seamless as we’d like. Thankfully, the recent updates to AWS Backup make it the perfect candidate for this scenario.

AWS Backup is a fully-managed, centralised backup service simplifying the management of your backups for your Amazon Elastic Block Store (EBS) volumes, databases (Amazon Relational Database Service (RDS) or Amazon DynamoDB), AWS Storage Gateway, Amazon Elastic File System (EFS) filesystems and now, Amazon Elastic Compute Cloud (EC2) instances.

This is awesome because it means users can take a backup of their pet servers automatically. If required, they can have the EC2 instance and associated configuration restored into a new AZ quickly, without any additional configuration or re-run of user data (including domain joins).

Other notable features include:

  • One place to manage and configure backups across services
  • The ability to copy your backups to other AWS Regions for quick recovery
  • Easy restores of a full instance with all of its configuration
  • Automated lifecycle management for backups

To get started with AWS Backup:

Create a backup vault

Open the AWS Backup Console > backup vaults > create a backup vault

Create an AWS Backup Vault

Create a Backup Plan

Navigate to AWS Backup > Backup Plans > Create Backup Plan

Create an AWS Backup Plan

NB:

  • There are built-in plans, you can fully customise your own, or create one based on a JSON template
  • Useful things you can configure inside a backup plan include scheduled transitioning of backups to cold storage, deletion of old backups based on the rules you configure and automatically copying backups to a different Region.
  • You can also tag your recovery points to help make billing and admin easier.
  • Once the plan has been created, you can open it up and add resources using the “Resource Assignments” section.
  • You can run backups on demand or let them happen based on the jobs you’ve created.
  • The easiest way to manage backup plan resources is to use tags, so if new instances are created for any reason, they’ll be auto included in the backup plan.
Assign Resources to an AWS Backup Plan Based on Tags

Restore an EC2 instance

  1. From the AWS Backup console dashboard open “Restore Backup”
  2. Select the instance and recovery point
AWS Backup Recovery Points

3. AWS will pre-fill the restore configuration to match the original EC2 instance. You can change things like the AZ, subnet, security groups, user data or instance size before restoring if required.

4. In the tests I ran, the restored EC2 was domain joined and accessible without any additional work. Customisations to the instance were maintained, however, tags and CloudWatch alarms were not restored and will need to be applied post-restore.

5. Finally, when the instance was restored, it did not have a Private Key associated with it. When the AMI is created from AWS Backup you can SSH into the newly created instance with the same Private Key file you would use for the original instance.

NB:

Access Denied when trying to complete an AWS Backup Restore

We were initially getting an “access denied” error when attempting a restore job because our instances all have an instance profile attached to them. As advised by AWS support:

“To successfully do a restore with the original instance profile, you will need to make changes to the restore policy. If you apply instance profile during the restore, you must update the operator role and add PassRole permissions of the underlying instance profile role to EC2. Otherwise, Amazon EC2 won’t be able to authorize the instance launch and it will fail.”

Here is the policy you can attach to the AWS default Backup role “AWSBackupDefaultServiceRole” to work around this issue:

{
“Version”: “2012–10–17”,
“Statement”: [
{
“Sid”: “VisualEditor0”,
“Effect”: “Allow”,
“Action”: “iam:PassRole”,
“Resource”: “arn:aws:iam::<Account-ID>:role/*”
}]}

Building AWS Backup into your build

Realistically, if you can avoid manually configuring services in the portal they’re more likely to be rolled out consistently. This is an example of the Terraform code we used to build AWS Backup into our CI/CD pipeline:

AWSBackup.tf Module
# Create a Backup Vault for all EC2 Instances
resource "aws_backup_vault" "fake-app-awsbackup-vault" {name = "fake-app-awsbackup-vault"kms_key_arn = "${module.config.kms_key_arn[terraform.workspace]}"tags = "${merge(module.config.common_tags,map("Name", "fake-app-awsbackup-vault-${var.env}","Environment", "${var.env}","Function", "Application",))}"}# Create a Backup Plan to backup Every 24 Hoursresource "aws_backup_plan" "fake-app-awsbackup-plan" {name = "fake-app-awsbackup-plan"rule {rule_name = "NightlyFullBackup"target_vault_name = "${aws_backup_vault.fake-app-awsbackup-vault.name}"schedule = "cron(0 15 ? * * *)"start_window = 480completion_window = 600lifecycle {cold_storage_after = 14delete_after = 365}recovery_point_tags = "${merge(module.config.common_tags,map("Name", "fake-app-awsbackup-vault-${var.env}","Environment", "${var.env}","Function", "Application",))}"}tags = "${merge(module.config.common_tags,map("Name", "fake-app-awsbackup-vault-${var.env}","Environment", "${var.env}","Function", "Application",))}"}# Assign instances to the backup based on the awsbackupgroup tagresource "aws_backup_selection" "fake-app-awsbackup-selection" {iam_role_arn = "${module.config.iam_role_arn[terraform.workspace]}"name = "fake-app-${var.env}-awsbackup-selection"plan_id = "${aws_backup_plan.fake-app-awsbackup-plan.id}"selection_tag {type = "STRINGEQUALS"key = "awsbackupgroup"value = "fake-app-nightly"}}

example of the associated params.tf file

:) Simone & Adrian

--

--