Creating EBS Volume Snapshots with Lambda and Terraform
In this tutorial, we will cover setting up a Scheduled Event that will trigger a Lambda Function to create an EBS volume snapshot. Amazon CloudWatch Events are near real time events that describe changes with your AWS resources. These events can be used to trigger actions such as running a lambda function or sending an SMS message. These events can also be scheduled to run on a cron like schedule. This tutorial will cover creating an Amazon CloudWatch Event using a cron like schedule to trigger a Lambda Function that will create the EBS volume snapshot.
Dependencies
There are several requirements that need to be installed or configured prior to continuing with this tutorial.
- AWS Account
- AWS IAM user with permissions to create resources and api access
- AWS CLI installation instructions here
- AWS CLI Configured [instructions](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html
- Terraform installation instructions here
- Git installation instructions here
- ide or text editor
Skills Required:
- General Understanding on AWS
- Comfortable with using the command line interface
- General Understanding of Linux
- Ability to install applications
Clone the Repository and Create the Base Infrastructure
Clone the AWS-CloudWatch-Scheduled-Events-With-Terraform repository. Once you have cloned the repository open it in your editor of choice and go to the ebs-volumes/ebs-volume-snapshot-incomplete directory and run the following command and follow the prompts to have terraform create the basic infrastructure needed to continue on with this tutorial.
terraform init
terraform apply
Next we will create our lambda function. Open the ebs-volumes/ebs-volume-snapshot-incomplete/ebs-snapshot.tf file and lets start building it.
We will need to create the zip file of the python code that will be executed.
resource "null_resource" "build_lambda_zip" {
triggers = {
key = uuid()
}
provisioner "local-exec" {
working_dir = "."
command = <<EOF
mkdir ${path.module}/lambda
mkdir ${path.module}/tmp
cp ${path.module}/create_snapshot.py ${path.module}/tmp/create_snapshot.py
EOF
}
}
data "archive_file" "lambda_zip" {
type = "zip"
source_dir = "${path.module}/tmp"
output_path = "${path.module}/lambda/tmp.zip"
depends_on = [
null_resource.build_lambda_zip
]
}
Next we will create the IAM Role that will be attached to the Lambda function. The IAM Role will grant the Lambda function the permissions it will need to create the ebs volume snapshot. The Permissions for this are not set for production security requirements. This is for educational purposes only.
data "aws_iam_policy_document" "create_ebs_volume_snapshot_assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}
resource "aws_iam_role" "create_ebs_volume_snapshot" {
name = "create-ebs-volume-snapshot"
assume_role_policy = data.aws_iam_policy_document.create_ebs_volume_snapshot_assume_role_policy.json
}
data "aws_caller_identity" "current" {}
data "aws_iam_policy_document" "create_ebs_volume_snapshot" {
statement {
effect = "Allow"
sid = "CreateEBSVolumeSnapshot"
actions = [
"ec2:*",
]
resources = [
"*",
]
}
}
resource "aws_iam_role_policy" "create_ebs_volume_iam_role_policy_lambda" {
name = "create_ebs_volume"
role = aws_iam_role.create_ebs_volume_snapshot.id
policy = data.aws_iam_policy_document.create_ebs_volume_snapshot.json
}
Create the Lambda function.
resource "aws_lambda_function" "create_ebs_volume_snapshot" {
function_name = "create-ebs-volume-snapshot"
filename = "${path.module}/lambda/tmp.zip"
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
role = aws_iam_role.create_ebs_volume_snapshot.arn
runtime = "python3.6"
handler = "create_snapshot.lambda_handler"
timeout = "60"
publish = true
depends_on = [
data.archive_file.lambda_zip
]
environment {
variables = {
VOLUME_ID = tolist(aws_instance.this.ebs_block_device)[0]["volume_id"]
}
}
tags = {
Terraform = true
}
}
Create the the CloudWatch Schedule Event to trigger the Lambda Function.
resource "aws_cloudwatch_event_rule" "ebs_snapshot" {
name = "ebs-snapshot"
description = "Cronlike scheduled for creating daily ebs volume snapshot."
schedule_expression = var.cron_expression
}
resource "aws_cloudwatch_event_target" "ebs_backup" {
rule = aws_cloudwatch_event_rule.ebs_snapshot.name
target_id = aws_lambda_function.create_ebs_volume_snapshot.id
arn = aws_lambda_function.create_ebs_volume_snapshot.arn
}
resource "aws_lambda_permission" "allow_cloudwatch" {
statement_id = "AllowExecutionFromCloudWatchCreateEBSVolumeSnapshot"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.create_ebs_volume_snapshot.arn
principal = "events.amazonaws.com"
source_arn = aws_cloudwatch_event_rule.ebs_snapshot.arn
}
The Lambda function will create a EBS Volume Snapshot based on the scheduled expression. To view the next scheduled times the Lambda function will be triggered go to AWS Console > CloudWatch > Rules > ebs-snapshot.
Clean up
Now it is time to destroy our resources to avoid unwanted charges. Go to the ebs-volumes/ebs-volume-snapshot-incomplete directory and run the following command and follow the prompts to remove the AWS Resources created.
terraform destroy