Terraform template to enable Snapshot on EBS volumes of Instances created by ASG

This note will explain, how to configure scheduled Snapshot of attached EBS volumes using terraform, Cloudwatch Events with builtin target EC2 CreateSnapshot API.
We can use Cloudwatch event to schedule snapshot of EBS volume.
For this we need to create Schedule based Cloudwatch Event Rule with Specific Cron expression.
Then attach EC2 CreateSnapshot API target with appropriate Volume ID and IAM Role.
Challenge – When we launch EC2 instances with ASG and terraform, we normally attach additional volumes using “ebs_block_device” terraform resource. Due to this we can not get volume ID / Attachment ID easily using resource for eg. ${aws_instance.example.id}.
Normally we can assign tags to volume in “aws_instance” resource, however we can not assign tags to volume, in Launch Configuration or ASG.
We need to get volume ID to take snapshot of. To achieve this, we need to filter first instances on basis of tags using terraform data aws_instance. Then we need to get VolumeIDs using terraform data aws_ebs_volume and filter with attachment and volume ID.
data "aws_instances" "selected" {
  instance_tags = {
    <Instance Tag key> = "<Instance Tag value>"
  }
}
data "aws_ebs_volume" "selected" {
  count = "${length(data.aws_instances.selected.ids)}"
  filter {
    name   = "attachment.instance-id"
    values = ["${element(data.aws_instances.selected.ids,count.index)}"]
  }
  filter {
    name   = "attachment.device"
    values = ["/dev/xvdc"]
  }
}
We can use these volume IDs in Cloudwatch Event Target.
Define IAM Role with appropriate Policy:
IAM Role with Trust relationships with events.
resource "aws_iam_role" "ebs_snapshot_role" {
 name = "ebs-snapshot-role"
 assume_role_policy = <<;EOF
 {
   "Version": "2012-10-17",
   "Statement": [
   {
     "Effect": "Allow",
     "Principal": {
        "Service": "events.amazonaws.com"
      },
     "Action": "sts:AssumeRole"
   }
   ]
 }
EOF
}

resource "aws_iam_role_policy" "ebs_snapshot_policy" {
  name = "ebs-snapshot-policy"
  role = "${aws_iam_role.ebs_snapshot_role.id}"
  policy = <<EOF
  {
    "Version": "2012-10-17",
    "Statement": [
    {
      "Effect": "Allow",
      "Action": [
         "ec2:CreateSnapshot"
      ],
      "Resource": [
         "*"
      ]
   }
   ]
  }
EOF
}

Create Schedule based Cloudwatch Event Rule:
resource "aws_cloudwatch_event_rule" "ebs_snapshot_rule" {
  name                = "ebs-snapshot-rule"
  description         = "Schedule EBS Snapshot"
  schedule_expression = "cron(00 10 * * ? *)"
  is_enabled          = "true"
}
Attach target to Cloudwatch Event Rule:
resource "aws_cloudwatch_event_target" "ebs_snapshot_target_xvdc" {
  count    = "${length(data.aws_instances.selected.ids)}"
  rule     = "${aws_cloudwatch_event_rule.ebs_snapshot_rule.name}"
  role_arn = "${aws_iam_role.ebs_snapshot_role.arn}"
  arn      = "arn:aws:events:&lt;AWS Region&gt;:&lt;AWS Account ID&gt;:target/create-snapshot"
  input    = "${jsonencode("${element(data.aws_ebs_volume.selected.*.id, count.index)}")}"
}

 

Using this template, we can launch Cloudwatch event rule to create EBS Snapshot of attached EBS Volumes of Instances launched by ASG.

Neelesh Gurjar has written 122 articles

Leave a Reply