我可以通过 Terraform 将 CloudWatch 事件规则附加到 'built-in target' 吗?

Can I attach a CloudWatch event rule to a 'built-in target' via Terraform?

此处的目标是创建 EBS 卷的计划快照。查看 Terraform 的 aws_cloudwatch_event_target 文档似乎不可能,但我可能遗漏了一些东西。

Cloudwatch Events 内置目标似乎只需要一个输入参数以及在 aws_cloudwatch_event_rule or sending to a Kinesis stream in aws_cloudwatch_event_target.

的示例中显示的用于将消息添加到 SNS 队列的 ARN

所以我们应该能够做这样的事情:

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)"
}

我还没有对此进行测试,但它应该 有效。显然,您可能想从您创建它们的资源中获取 EBS 卷 ID,但这超出了问题的范围。在 AWS 控制台中创建规则然后查看 aws events list-targets-by-rule 的输出后,我还猜测了 ARN,它似乎将规则名称添加到目标的 ARN,但可能并不总是 true/necessary.

前面的答案足以获得除事件目标上的 IAM 权限之外的所有内容(即进入控制台,编辑规则,并在 "Step 2" 中,对于 "AWS Permissions" 部分,创建新角色等)。为了让它在 terraform 中工作,我刚刚添加了一些资源:

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}"
}

通过调整 provided by D Swartz,我能够完全在 terraform 中运行它。我不得不通过几种方式修改 aws_cloudwatch_event_target 资源:

  1. arn 字段需要指向 target/create-snapshot 事件而不是 action/EBSCreateSnapshot 自动化操作。

  2. input 字段需要设置为所需卷的 id 而不是其 arn

  3. 需要将 role_arn 设置为 aws_iam_rolearn,这将是 运行 事件。

更新后的 aws_cloudwatch_event_target 资源如下所示:

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_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}"
}

编辑: 我不完全清楚这是否由 AWS 直接支持 - 基于 their documentation 看来这可能不是预期的功能:

Creating rules with built-in targets is supported only in the AWS Management Console.

我想出了这个与 AWS CloudWatch Rules 和 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" {}

对于 IAM 角色

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 = "*"
        },
      ]
    })
  }
}