Skip to main content

Module: efs-backup

Terraform module designed to easily backup EFS filesystems to S3 using DataPipeline.

The workflow is simple:

  • Periodically launch resource (EC2 instance) based on schedule
  • Execute the shell command defined in the activity on the instance
  • Sync data from Production EFS to S3 Bucket by using aws-cli
  • The execution log of the activity is stored in S3
  • Publish the success or failure of the activity to an SNS topic
  • Automatically rotate the backups using S3 lifecycle rule

Usage

Include this module in your existing terraform code:

module "efs_backup" {
source = "git::https://github.com/cloudposse/terraform-aws-efs-backup.git?ref=master"

name = "${var.name}"
stage = "${var.stage}"
namespace = "${var.namespace}"
vpc_id = "${var.vpc_id}"
efs_mount_target_id = "${var.efs_mount_target_id}"
use_ip_address = "false"
noncurrent_version_expiration_days = "${var.noncurrent_version_expiration_days}"
ssh_key_pair = "${var.ssh_key_pair}"
datapipeline_config = "${var.datapipeline_config}"
modify_security_group = "true"
}

output "efs_backup_security_group" {
value = "${module.efs_backup.security_group_id}"
}

Integration with EFS

To enable connectivity between the DataPipeline instances and the EFS, use one of the following methods to configure Security Groups:

  1. Explicitly add the DataPipeline SG (the output of this module security_group_id) to the list of the ingress rules of the EFS SG. For example:
module "elastic_beanstalk_environment" {
source = "git::https://github.com/cloudposse/terraform-aws-elastic-beanstalk-environment.git?ref=master"
namespace = "${var.namespace}"
name = "${var.name}"
stage = "${var.stage}"
delimiter = "${var.delimiter}"
attributes = ["${compact(concat(var.attributes, list("eb-env")))}"]
tags = "${var.tags}"

# ..............................
}

module "efs" {
source = "git::https://github.com/cloudposse/terraform-aws-efs.git?ref=tmaster"
namespace = "${var.namespace}"
name = "${var.name}"
stage = "${var.stage}"
delimiter = "${var.delimiter}"
attributes = ["${compact(concat(var.attributes, list("efs")))}"]
tags = "${var.tags}"

# Allow EB/EC2 instances and DataPipeline instances to connect to the EFS
security_groups = ["${module.elastic_beanstalk_environment.security_group_id}", "${module.efs_backup.security_group_id}"]
}

module "efs_backup" {
source = "git::https://github.com/cloudposse/terraform-aws-efs-backup.git?ref=master"
name = "${var.name}"
stage = "${var.stage}"
namespace = "${var.namespace}"
delimiter = "${var.delimiter}"
attributes = ["${compact(concat(var.attributes, list("efs-backup")))}"]
tags = "${var.tags}"

# Important to set it to `false` since we added the `DataPipeline` SG (output of the `efs_backup` module) to the `security_groups` of the `efs` module
# See NOTE below for more information
modify_security_group = "false"

# ..............................
}
  1. Set modify_security_group attribute to true so the module will modify the EFS SG to allow the DataPipeline to connect to the EFS

NOTE: Do not mix these two methods together. Terraform does not support using a Security Group with in-line rules in conjunction with any Security Group Rule resources. https://www.terraform.io/docs/providers/aws/r/security_group_rule.html

NOTE on Security Groups and Security Group Rules: Terraform currently provides both a standalone Security Group Rule resource (a single ingress or egress rule), and a Security Group resource with ingress and egress rules defined in-line. At this time you cannot use a Security Group with in-line rules in conjunction with any Security Group Rule resources. Doing so will cause a conflict of rule settings and will overwrite rules.

Requirements

No requirements.

Providers

NameVersion
awsn/a

Modules

NameSourceVersion
backups_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
datapipeline_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
logs_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
resource_role_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
role_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1
sns_labelgit::https://github.com/cloudposse/terraform-null-label.gittags/0.3.1

Resources

NameType
aws_cloudformation_stack.datapipelineresource
aws_cloudformation_stack.snsresource
aws_iam_instance_profile.resource_roleresource
aws_iam_role.resource_roleresource
aws_iam_role.roleresource
aws_iam_role_policy_attachment.resource_roleresource
aws_iam_role_policy_attachment.roleresource
aws_s3_bucket.backupsresource
aws_s3_bucket.logsresource
aws_security_group.datapipelineresource
aws_security_group_rule.datapipeline_efs_ingressresource
aws_ami.amazon_linuxdata source
aws_efs_mount_target.defaultdata source
aws_iam_policy_document.resource_roledata source
aws_iam_policy_document.roledata source
aws_region.defaultdata source
aws_subnet_ids.defaultdata source
aws_vpc.defaultdata source

Inputs

NameDescriptionTypeDefaultRequired
attributesAdditional attributes (e.g. efs-backup)list(string)[]no
datapipeline_configDataPipeline configuration optionsmap(string)
{
"email": "",
"instance_type": "t2.micro",
"period": "24 hours",
"timeout": "60 Minutes"
}
no
datapipeline_security_groupOptionally specify a security group to use for the datapipeline instancesstring""no
delimiterDelimiter to be used between name, namespace, stage, etc.string"-"no
efs_mount_target_idEFS Mount Target ID (e.g. fsmt-279bfc62)stringn/ayes
modify_security_groupShould the module modify the EFS security groupstring"false"no
nameThe Name of the application or solution (e.g. bastion or portal)anyn/ayes
namespaceNamespace (e.g. cp or cloudposse)anyn/ayes
noncurrent_version_expiration_daysS3 object versions expiration period (days)string"35"no
region(Optional) AWS Region. If not specified, will be derived from 'aws_region' data sourcestring""no
ssh_key_pairSSH key that will be deployed on DataPipeline's instancestringn/ayes
stageStage (e.g. prod, dev, staging)anyn/ayes
subnet_idOptionally specify the subnet to usestring""no
tagsAdditional tags (e.g. map('BusinessUnit,XYZ)map(string){}no
use_ip_addressIf set to true, will use IP address instead of DNS name to connect to the EFSstring"false"no
vpc_idVPC IDstring""no

Outputs

NameDescription
backups_bucket_nameBackups bucket name
datapipeline_idsDatapipeline ids
logs_bucket_nameLogs bucket name
security_group_idSecurity group id
sns_topic_arnBackup notification SNS topic ARN