Closed8

スポットインスタンスの停止をEventBridge+SNSで受け取る

not75743not75743

やりたいこと

スポットインスタンス中断の2分前の通知をEventBridgeで受け取りたい
EventBridgeで受け取れたら後はSNSなりLambdaなりで自由に料理出来る

not75743not75743

手動でやる

ひとまずEventBridge + SNSの構成を作る

  • SNSトピック設定
  • EventBridgeルール作成
    • ターゲットはSNSトピック
    • イベントパターンの指定はこんな感じ
{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 Spot Instance Interruption Warning"]
}

これで前回作ったFISを動かす

メール

SNSからメールが届く

こちらがSNSでそのまま送信されているようです

{
    "version": "0",
    "id": "12345678-1234-1234-1234-123456789012",
    "detail-type": "EC2 Spot Instance Interruption Warning",
    "source": "aws.ec2",
    "account": "123456789012",
    "time": "yyyy-mm-ddThh:mm:ssZ",
    "region": "us-east-2",
    "resources": ["arn:aws:ec2:us-east-2:123456789012:instance/i-1234567890abcdef0"],
    "detail": {
        "instance-id": "i-1234567890abcdef0",
        "instance-action": "action"
    }
}

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/spot-instance-termination-notices.html#ec2-spot-instance-interruption-warning-event

not75743not75743

Terraform化

SNS

resource "aws_sns_topic" "topic" {
  name = "spot-notice-topic"
  fifo_topic = false
}

resource "aws_sns_topic_subscription" "subscription" {
  topic_arn = aws_sns_topic.topic.arn
  protocol  = "email"
  endpoint  = var.email
}

実行したら指定したメールアドレスに確認のメールが飛ぶため、承認する

SNSトピックアクセスポリシー

デフォルトだとEventBridge→SNSの連携がうまく行かないため、こちらも明示的に設定する必要がある

 resource "aws_sns_topic_policy" "policy" {
   arn    = aws_sns_topic.topic.arn
   policy = data.aws_iam_policy_document.sns_topic_policy.json
 }

 data "aws_iam_policy_document" "sns_topic_policy" {
   statement {
     effect  = "Allow"
     actions = ["SNS:Publish"]

     principals {
       type        = "Service"
       identifiers = ["events.amazonaws.com"]
     }

     resources = [aws_sns_topic.topic.arn]
   }
 }

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-use-resource-based.html#eb-sns-permissions
https://zenn.dev/isosa/articles/0f3ce9234c04d1

not75743not75743

SNSアクセスポリシーはどうなっていたの?

明示的に指定しないと以下のようになっていました。

{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__default_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "SNS:GetTopicAttributes",
        "SNS:SetTopicAttributes",
        "SNS:AddPermission",
        "SNS:RemovePermission",
        "SNS:DeleteTopic",
        "SNS:Subscribe",
        "SNS:ListSubscriptionsByTopic",
        "SNS:Publish",
        "SNS:Receive"
      ],
      "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:spot-notice-topic",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "xxxxxxxxxxxx"
        }
      }
    }
  ]
}

"SNS:Publish"は存在しているので、Actionでは問題なさそうです。
おそらくCondition句でAWSアカウントを指定しているため、それに該当しないEventBridgeのイベントが弾かれた?と考えます

not75743not75743

EventBridge

ルールと、ターゲットの2つを設定します

resource "aws_cloudwatch_event_rule" "spot-interruption-rule" {
  name           = "spot-interruption-rule"
  event_bus_name = "default"

  tags = {
    Name = "spot-interruption-rule"
  }

  event_pattern = <<EOF
{
  "source": ["aws.ec2"],
  "detail-type": ["EC2 Spot Instance Interruption Warning"]
}
EOF
}

resource "aws_cloudwatch_event_target" "sns" {
  rule      = aws_cloudwatch_event_rule.spot-interruption-rule.name
  arn       = aws_sns_topic.topic.arn
}

公式ドキュメントのサンプルを参考にすればよいでしょう。
リソース名はaws_cloudwatch_event_ruleなんですね、過去の名残?

このスクラップは2023/06/09にクローズされました