Commit 44df8f25 authored by Sean Clerkin's avatar Sean Clerkin

Optionally create the S3 bucket with lifecycling

parent 3a8c8c0f
{
"aws": "2abc1bc3fffada67b4f0f4bf5c1ad9fbf965939e1da14a1a8d07ff5ca6293918",
"template": "a7a55a3db915e673d43d09ca92b609481f90cdd19520cbd47633002e58fc2d02"
}
\ No newline at end of file
......@@ -11,6 +11,8 @@ 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
- Optionally creates an S3 bucket to backup to with a lifecycle rule to delete
backups after a desired number of days
- 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
......@@ -19,7 +21,6 @@ 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
......
......@@ -29,80 +29,12 @@ data "template_file" "userdata" {
vars {
name = "${var.name}"
efs_mount_target = "${var.efs_mount_target}"
s3_bucket_path = "${var.s3_bucket_path}"
s3_bucket_path = "${var.s3_bucket_path == "" ? join("", aws_s3_bucket.efs_backup.*.id) : 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 = "${var.name}"
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
......@@ -140,7 +72,7 @@ resource "aws_autoscaling_schedule" "backup_efs_node" {
scheduled_action_name = "${var.name}-scale-up"
min_size = 0
max_size = 1
desired_capacity = 1
desired_capacity = 0
recurrence = "${var.recurrence}"
autoscaling_group_name = "${aws_autoscaling_group.backup_efs_node.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 == "" ? join("", aws_s3_bucket.efs_backup.*.id) : var.s3_bucket_path}",
"arn:aws:s3:::${var.s3_bucket_path == "" ? join("", aws_s3_bucket.efs_backup.*.id) : var.s3_bucket_path}/*",
]
}
statement {
actions = [
"s3:PutObject",
]
resources = [
"arn:aws:s3:::${var.s3_bucket_path == "" ? join("", aws_s3_bucket.efs_backup.*.id) : 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 = "${var.name}"
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_s3_bucket" "efs_backup" {
count = "${var.manage_s3_bucket ? 1 : 0}"
bucket = "${var.name}"
acl = "private"
lifecycle_rule {
id = "efs_backup_cleanup"
enabled = true
expiration {
days = "${var.backup_retention_period}"
}
}
}
data "aws_iam_policy_document" "efs_backup_always_enc" {
count = "${var.manage_s3_bucket ? 1 : 0}"
statement {
sid = "DenyIncorrectEncryptionHeader"
effect = "Deny"
actions = ["s3:PutObject"]
resources = ["${join("", aws_s3_bucket.efs_backup.*.arn)}/*"]
principals {
type = "AWS"
identifiers = ["*"]
}
condition {
test = "StringNotEquals"
variable = "s3:x-amz-server-side-encryption"
values = ["AES256"]
}
}
statement {
sid = "DenyUnEncryptedObjectUploads"
effect = "Deny"
actions = ["s3:PutObject"]
resources = ["${join("", aws_s3_bucket.efs_backup.*.arn)}/*"]
principals {
type = "AWS"
identifiers = ["*"]
}
condition {
test = "Null"
variable = "s3:x-amz-server-side-encryption"
values = ["true"]
}
}
}
resource "aws_s3_bucket_policy" "efs_backup" {
count = "${var.manage_s3_bucket ? 1 : 0}"
bucket = "${join("", aws_s3_bucket.efs_backup.*.id)}"
policy = "${data.aws_iam_policy_document.efs_backup_always_enc.json}"
}
......@@ -14,7 +14,7 @@ tar -zcvf ${backup_archive_name} /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
aws s3 cp --sse AES256 ${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
......@@ -28,6 +28,17 @@ variable "efs_mount_target" {
variable "s3_bucket_path" {
description = "The S3 bucket (and optionally directory) to backup to"
default = ""
}
variable "manage_s3_bucket" {
description = "Whether to create and manage the backup S3 bucket"
default = true
}
variable "backup_retention_period" {
description = "The number of days to keep backups for, only used when manage_s3_bucket = true"
default = 14
}
variable "backup_archive_name" {
......@@ -35,7 +46,8 @@ variable "backup_archive_name" {
}
variable "subnet_ids" {
type = "A list of subnet IDs for the temporary instance to launch into"
description = "A list of subnet IDs for the temporary instance to launch into"
type = "list"
}
variable "recurrence" {
......
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