Commit 6a58ec30 authored by Sean Clerkin's avatar Sean Clerkin

Initial commit of module

parent 24034989
tf_mod_aws_efs_backup
=====================
A terraform module to backup a desired EFS mount to a desired S3 bucket.
What this module does
---------------------
- Creates an autoscaling group to launch a short lived backup instance on a
schedule
- Creates the schedule to scale up at the desired time
- Creates a launch configuration with a shell script passed as userdata to
trigger the backup
- Creates an IAM instance profile to grant the backup instance `s3:PutObject`
rights to the desired S3 bucket and `autoscaling:SetDesiredCapacity` rights to
set the autoscaling group's desired capacity back to zero after the instance has
finished the backup
What this module doesn't do
---------------------------
- Create the S3 bucket
- Create the security group for the backup instance to access the EFS mount
- Monitor the successful running of the backup, suggest setting a Cloudwatch
alarm on the number of puts to the desired backup S3 bucket over a period of
time
data "aws_region" "current" {
current = true
}
data "aws_ami" "ami" {
most_recent = true
filter {
name = "name"
values = ["${var.ami_name_pattern}"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
owners = ["${var.ami_owner}"]
}
data "template_file" "userdata" {
template = "${file("${path.module}/userdata.tpl")}"
vars {
name = "${var.name}"
efs_mount_target = "${var.efs_mount_target}"
s3_bucket_path = "${var.s3_bucket_path}"
backup_archive_name = "${var.backup_archive_name}"
region = "${data.aws_region.current.name}"
}
}
resource "aws_iam_instance_profile" "backup_efs_node" {
name = "${var.name}"
role = "${aws_iam_role.backup_efs_node.name}"
}
data "aws_iam_policy_document" "backup_efs_node_policy" {
statement {
actions = [
"s3:ListBucket",
]
resources = [
"arn:aws:s3:::${var.s3_bucket_path}",
"arn:aws:s3:::${var.s3_bucket_path}/*",
]
}
statement {
actions = [
"s3:PutObject",
]
resources = [
"arn:aws:s3:::${var.s3_bucket_path}/*",
]
}
statement {
actions = [
"autoscaling:SetDesiredCapacity",
]
resources = [
"${aws_autoscaling_group.backup_efs_node.arn}",
]
}
}
data "aws_iam_policy_document" "backup_efs_node_assume" {
statement {
actions = [
"sts:AssumeRole",
]
principals {
type = "Service"
identifiers = ["ec2.amazonaws.com"]
}
}
}
resource "aws_iam_role" "backup_efs_node" {
name = "${var.name}"
path = "/"
assume_role_policy = "${data.aws_iam_policy_document.backup_efs_node_assume.json}"
}
resource "aws_iam_policy" "backup_efs_node" {
name = "sean-efs-to-s3-backup-test"
description = "sean-efs-to-s3-backup-test"
policy = "${data.aws_iam_policy_document.backup_efs_node_policy.json}"
}
resource "aws_iam_policy_attachment" "backup_efs_node" {
name = "${var.name}"
roles = ["${aws_iam_role.backup_efs_node.name}"]
policy_arn = "${aws_iam_policy.backup_efs_node.arn}"
}
resource "aws_launch_configuration" "backup_efs_node" {
lifecycle {
create_before_destroy = true
}
name_prefix = "${var.name}"
image_id = "${data.aws_ami.ami.id}"
instance_type = "${var.instance_type}"
security_groups = ["${var.security_groups}"]
iam_instance_profile = "${aws_iam_instance_profile.backup_efs_node.arn}"
key_name = "${var.key_name}"
user_data = "${data.template_file.userdata.rendered}"
root_block_device {
volume_size = "${var.root_volume_size}"
}
}
resource "aws_autoscaling_group" "backup_efs_node" {
name = "${var.name}"
max_size = 1
min_size = 0
desired_capacity = 0
launch_configuration = "${aws_launch_configuration.backup_efs_node.name}"
vpc_zone_identifier = ["${var.subnet_ids}"]
tags {
key = "Name"
value = "${var.name}"
propagate_at_launch = true
}
}
resource "aws_autoscaling_schedule" "backup_efs_node" {
scheduled_action_name = "${var.name}-scale-up"
min_size = 0
max_size = 1
desired_capacity = 1
recurrence = "${var.recurrence}"
autoscaling_group_name = "${aws_autoscaling_group.backup_efs_node.name}"
}
#!/bin/bash
# mount efs
mkdir /efs
mount -t nfs4 -o nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ${efs_mount_target}:/ /efs
# create archive
cd /
mkdir efs_backup
cd efs_backup
tar -zcvf ${backup_archive_name} /efs
# unmount efs
umount /efs
# copy archive to s3
aws s3 cp ${backup_archive_name} s3://${s3_bucket_path}/${backup_archive_name}.`date +"%Y%m%d-%H%M"`.tar.gz
# self terminate by changing the desired ASG capacity to zero
aws autoscaling --region ${region} set-desired-capacity --auto-scaling-group-name ${name} --desired-capacity 0 --no-honor-cooldown
variable "name" {
description = "The name of the AWS resources created by this module"
}
variable "ami_name_pattern" {
description = "The name pattern of the AMI to launch the backup instance from"
default = "amzn-ami-hvm-2017*"
}
variable "ami_owner" {
description = "The owner of the AMI to launch the backup instance from"
default = "amazon"
}
variable "instance_type" {
description = "The instance type of the backup instance"
default = "t2.micro"
}
variable "security_groups" {
description = "A list of security group IDs for the backup instance to be a member of"
type = "list"
}
variable "efs_mount_target" {
description = "The DNS endpoint of the EFS volume to backup"
}
variable "s3_bucket_path" {
description = "The S3 bucket (and optionally directory) to backup to"
}
variable "backup_archive_name" {
description = "The name of the resulting backup archive, a timestamp will be added to the end"
}
variable "subnet_ids" {
type = "A list of subnet IDs for the temporary instance to launch into"
}
variable "recurrence" {
description = "The cron schedule to use for the backup"
default = "0 1 * * *"
}
variable "root_volume_size" {
description = "The size of the backup instances root volume, needs to be larger than the EFS to be backed up"
default = 10
}
variable "key_name" {
description = "An optional SSH key pair to launch the backup instance with"
default = ""
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment