Reputation: 494
The goal here is to create scheduled snapshots of EBS volumes. Looking at Terraform's documentation for aws_cloudwatch_event_target
it doesn't seem possible, but I could be missing something.
Upvotes: 8
Views: 4180
Reputation: 2321
I came up with this solution which is compatible with AWS CloudWatch Rules and Amazon EventBridge:
resource "aws_cloudwatch_event_rule" "volume_snapshot_rule" {
name = "ebs-volume-snapshot"
description = "Create an EBS volume snapshot every 6 hours"
schedule_expression = "rate(6 hours)"
}
resource "aws_cloudwatch_event_target" "volume_snapshot_target" {
target_id = "ebs-volume-snapshot-target"
rule = aws_cloudwatch_event_rule.volume_snapshot_rule.name
arn = "arn:aws:events:eu-central-1:${data.aws_caller_identity.current.account_id}:target/create-snapshot"
role_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/create-ebs-snapshot"
input = "\"${aws_ebs_volume.storage.id}\""
}
data "aws_caller_identity" "current" {}
And for the IAM role
resource "aws_iam_role" "create_ebs_snapshot" {
name = "create-ebs-snapshot"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = "sts:AssumeRole"
Effect = "Allow"
Sid = ""
Principal = {
Service = "events.amazonaws.com"
}
},
]
})
inline_policy {
name = "policy"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Action = ["ec2:CreateSnapshot"]
Effect = "Allow"
Resource = "*"
},
]
})
}
}
Upvotes: 0
Reputation: 111
I was able to get this working entirely in terraform by tweaking this response provided by D Swartz. I had to modify the aws_cloudwatch_event_target
resource in a few ways:
The arn
field needs to point to the target/create-snapshot
event instead of the action/EBSCreateSnapshot
automation action.
The input
field needs to be set to the desired volume's id
rather than its arn
.
The role_arn
needs to be set to the arn
of the aws_iam_role
that will be running the event.
The updated aws_cloudwatch_event_target
resource looks like this:
resource "aws_cloudwatch_event_target" "example_event_target" {
target_id = "example"
rule = "${aws_cloudwatch_event_rule.snapshot_example.name}"
arn = "arn:aws:events:${var.aws_region}:${var.account_id}:target/create-snapshot"
input = "${jsonencode("${aws_ebs_volume.example.id}")}"
role_arn = "${aws_iam_role.snapshot_permissions.arn}"
}
Full code snippet below:
resource "aws_cloudwatch_event_rule" "snapshot_example" {
name = "example-snapshot-volumes"
description = "Snapshot EBS volumes"
schedule_expression = "rate(24 hours)"
}
resource "aws_cloudwatch_event_target" "example_event_target" {
target_id = "example"
rule = "${aws_cloudwatch_event_rule.snapshot_example.name}"
arn = "arn:aws:events:${var.aws_region}:${var.account_id}:target/create-snapshot"
input = "${jsonencode("${aws_ebs_volume.example.id}")}"
role_arn = "${aws_iam_role.snapshot_permissions.arn}"
}
resource "aws_iam_role" "snapshot_permissions" {
name = "example"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "automation.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "snapshot_policy" {
name = "example-snapshot-policy"
description = "grant ebs snapshot permissions to cloudwatch event rule"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:RebootInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:CreateSnapshot"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "snapshot_policy_attach" {
role = "${aws_iam_role.snapshot_permissions.name}"
policy_arn = "${aws_iam_policy.snapshot_policy.arn}"
}
edit: I'm not entirely clear if this is directly supported by AWS or not - based on their documentation it seems like this may not be an intended feature:
Creating rules with built-in targets is supported only in the AWS Management Console.
Upvotes: 4
Reputation: 155
The previous answer was enough to get everything except for the IAM permissions on the event targets (i.e. go into the console, edit the rule, and in "Step 2", for the "AWS Permissions" section, create a new role, etc). To get this working in terraform, I just added a few resources:
resource "aws_cloudwatch_event_rule" "snapshot_example" {
name = "example-snapshot-volumes"
description = "Snapshot EBS volumes"
schedule_expression = "rate(24 hours)"
}
resource "aws_cloudwatch_event_target" "example_event_target" {
target_id = "example"
rule = "${aws_cloudwatch_event_rule.snapshot_example.name}"
arn = "arn:aws:automation:${var.aws_region}:${var.account_id}:action/EBSCreateSnapshot/EBSCreateSnapshot_example-snapshot-volumes"
input = "${jsonencode("arn:aws:ec2:${var.aws_region}:${var.account_id}:volume/${aws_ebs_volume.example.id}")}"
}
resource "aws_iam_role" "snapshot_permissions" {
name = "example"
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "automation.amazonaws.com"
},
"Effect": "Allow",
"Sid": ""
}
]
}
EOF
}
resource "aws_iam_policy" "snapshot_policy" {
name = "example-snapshot-policy"
description = "grant ebs snapshot permissions to cloudwatch event rule"
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:Describe*",
"ec2:RebootInstances",
"ec2:StopInstances",
"ec2:TerminateInstances",
"ec2:CreateSnapshot"
],
"Resource": "*"
}
]
}
EOF
}
resource "aws_iam_role_policy_attachment" "snapshot_policy_attach" {
role = "${aws_iam_role.snapshot_permissions.name}"
policy_arn = "${aws_iam_policy.snapshot_policy.arn}"
}
Upvotes: 3
Reputation: 56839
Cloudwatch Events built-in targets just seem to require an input parameter as well as the ARN that is shown for adding a message to an SNS queue in the example for aws_cloudwatch_event_rule
or sending to a Kinesis stream in aws_cloudwatch_event_target
.
So we should just be able to do something like this:
resource "aws_cloudwatch_event_target" "ebs_vol_a" {
target_id = "ebs_vol_a"
rule = "${aws_cloudwatch_event_rule.snap_ebs.name}"
arn = "arn:aws:automation:${var.region}:${var.account_id}:action/EBSCreateSnapshot/EBSCreateSnapshot_ebs_vol_a"
input = "\"arn:aws:ec2:${var.region}:${var.account_id}:volume/vol-${var.ebs_vol_a_id}\""
}
resource "aws_cloudwatch_event_rule" "snap_ebs" {
name = "snap-ebs-volumes"
description = "Snapshot EBS volumes"
schedule_expression = "rate(6 hours)"
}
I haven't yet tested this but it should work. Obviously you probably want to get the EBS volume IDs from the resource you created them but that's beyond the scope of the question. I've also guessed at the ARN after creating a rule in the AWS console and then looking at the output of aws events list-targets-by-rule
where it seems to add the rule name to the ARN of the target but that may not always be true/necessary.
Upvotes: 5