🦁

Amazon EventBridgeでCloudFormationのCreate StackとDelete Stackを自動化したい

2023/11/04に公開

はじめに

皆さんはAmazon EventBridgeのスケジューラ機能使っていますでしょうか。EC2を自動停止したり、特定のLambdaを自動実行したりできてとても便利ですよね。しかし、設定時に記載するjsonパラメータには制約が多く、複雑な処理はできずに使用を断念、、、なんてこともあるのではないでしょうか。本ブログではCloudFormationのCreateStack APIを使用して複雑な処理を自動実行する方法を紹介します

忙しい人向けのまとめ

  1. EventBridgeのスケジューラ機能でCloudFormationのCreateStack APIを自動実行できる
  2. この機能により、大量のリソースを自動作成できる。またリソース間の依存関係も気にせず作成できる
  3. EventBridgeがAssumeするIAMロールに紐づけるポリシーには"s3:GetObject"、及び"iam:PassRole"が必要
  4. 削除もDeleteStack APIを自動実行することで実現可能

今回やること

今回は、以下のリソースの自動作成を行います。もちろん、CloudFormationで表現できることならなんでもOKです。

  1. NATゲートウェイ
  2. Elastic IP(NATゲートウェイ用)
  3. セキュリティグループのアウトバウンドルール(既存のセキュリティグループにアタッチ)
  4. ルートテーブルのルート(既存のルートテーブルにNATゲートウェイ宛のルールを追加)

以下のようなユースケースをイメージしています

  • EC2は原則としてインターネットを行ってはならない
  • その為、インターネットアクセスが可能となってしまうサービスは原則として作成不可(セキュリティグループやルートテーブル)
  • ただし、ソフトウェアアップデートの為に週に1回だけインターネットアクセスを許可する必要がある
  • 毎週NATゲートウェイ作って、ルートテーブル変更して、、、だとあまりにも大変なので自動化したい

やってみる

CloudFormationテンプレートの作成

以下のようなymlファイルを用意します
セキュリティグループ・ルートテーブルは作成済みであることが前提です

テンプレートはこちら(折りたたんであります)
AWSTemplateFormatVersion: 2010-09-09
Description: EventBridgetest
Parameters:
  SecurityGroupId:
    Type: String
  RouteTableId:
    Type: String
  PublicSubnetId:
    Type: String

Resources: 
# ------------------------------------------------------------#
#  OutBoundSecurityGroupRule
# ------------------------------------------------------------#   
  SecurityGroupForEC2ToAllowHTTP:
    Type: AWS::EC2::SecurityGroupEgress
    Properties: 
      GroupId: !Ref SecurityGroupId 
      IpProtocol: tcp
      FromPort: 80
      ToPort: 80
      CidrIp: 0.0.0.0/0

  SecurityGroupForEC2ToAllowHTTPS:
    Type: AWS::EC2::SecurityGroupEgress
    Properties: 
      GroupId: !Ref SecurityGroupId 
      IpProtocol: tcp
      FromPort: 443
      ToPort: 443
      CidrIp: 0.0.0.0/0

# ------------------------------------------------------------#
#  Routing
# ------------------------------------------------------------#    

# PrivateRouteA Create
  PrivateRouteA: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref RouteTableId
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NATGatewayID




# ------------------------------------------------------------#
# NatGateway
# ------------------------------------------------------------#

# NATGateway Create
  NATGatewayID:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId: !GetAtt NATGatewayCEIP.AllocationId 
      SubnetId: !Ref PublicSubnetId


# NATGateway For EIP Create
  NATGatewayCEIP:
    Type: "AWS::EC2::EIP"
    Properties:
      Domain: vpc

S3の作成及びテンプレートのアップロード

今回のケースではローカルPCからテンプレートをアップロードすることはできません。その為、S3を作成し、そこにテンプレートをアップロードします。
詳細は後述しますが、EventBridgeが引き受けるロールがGetObjectできるようにバケットポリシーを設定します

バケットポリシーはこちら(折りたたんであります)
{
    "Version":"2012-10-17",
    "Statement":[
       {
          "Principal":{
             "AWS":"arn:aws:iam::AccountID:role/RoleNameForEventBridge"
          },
          "Effect":"Allow",
          "Action":[
             "s3:GetObject"
          ],
          "Resource":"arn:aws:s3:::bucketname/*"
       }
    ]
 }

※以下はよしなに編集してから使用してください

  • AccountID(実行するアカウントのID)
  • bucketname(CloudFormationをアップロードするバケット名)
  • RoleNameForEventBridge(EventBridgeがAssumeするIAMロール名)

s3バケットに作成したCloudFormationテンプレートをアップロードし、S3のURLを取得しておきましょう(後で使います)
※s3 urlではなく オブジェクトURL をコピーしてください

CloudFotmation用IAMロールの作成

CloudFormation用のIAMロールを作成します。

ロールの信頼関係はこちら(折りたたんであります)
{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Sid": "",
           "Effect": "Allow",
           "Principal": {
               "Service": "cloudformation.amazonaws.com"
           },
           "Action": "sts:AssumeRole"
       }
   ]
}
ポリシーはこちら(折りたたんであります)
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "VisualEditor0",
          "Effect": "Allow",
          "Action": [
              "ec2:DisassociateAddress",
              "ec2:DescribeAddresses",
              "ec2:CreateNatGateway",
              "ec2:DescribeAddressesAttribute",
              "ec2:ReplaceRoute",
              "ec2:UnassignPrivateNatGatewayAddress",
              "ec2:AssociateRouteTable",
              "ec2:CreateRoute",
              "ec2:RevokeSecurityGroupEgress",
              "ec2:UnassignPrivateIpAddresses",
              "ec2:DescribeRouteTables",
              "ec2:ReleaseAddress",
              "ec2:AuthorizeSecurityGroupEgress",
              "ec2:AssociateNatGatewayAddress",
              "ec2:UpdateSecurityGroupRuleDescriptionsEgress",
              "ec2:ResetAddressAttribute",
              "ec2:CreateTags",
              "ec2:DeleteRoute",
              "ec2:ModifySecurityGroupRules",
              "ec2:DescribeNatGateways",
              "ec2:AssignPrivateIpAddresses",
              "ec2:DisassociateRouteTable",
              "ec2:AllocateAddress",
              "ec2:DescribeSecurityGroups",
              "ec2:DisassociateNatGatewayAddress",
              "ec2:DescribeSecurityGroupRules",
              "ec2:DescribeSecurityGroupReferences",
              "ec2:DeleteSecurityGroup",
              "ec2:DeleteNatGateway",
              "ec2:AssociateAddress"
          ],
          "Resource": "*"
      }
  ]
}

EventBridge用IAMロールの作成

EventBridge用のIAMロールを作成します

ロールの信頼関係はこちら(折りたたんであります)
{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Principal": {
               "Service": "scheduler.amazonaws.com"
           },
           "Action": "sts:AssumeRole"
       }
   ]
}
ポリシーはこちら(折りたたんであります)
{
  "Version": "2012-10-17",
  "Statement": [
      {
          "Sid": "VisualEditor0",
          "Effect": "Allow",
          "Action": [
              "s3:GetObject",
              "iam:PassRole",
              "cloudformation:CreateStack",
              "cloudformation:DeleteStack"
          ],
          "Resource": "*"
      }
  ]
}

※後でDeleteもするので合わせてポリシーを記載しています

ここでのポイントはIAMポリシーにs3:GetObjectiam:PassRoleが必要であることです
管理コンソールで操作しているときは意識しづらいポイントではありますが、EventBridgeがCloudFormationのCreateStackを実行するときに

  • S3からテンプレートファイルを取得する
  • CloudFormation用のロールをpassする

という2つの動作を実行する為です

EventBridgeスケジューラの設定

  1. "スケジュール"セクションの"スケジュールを作成"を押下

  2. スケジュール名・スケジュールのパターンを設定します。ここはよしなに設定してもらえれば。
    ちなみに、スクリーンショットの設定の場合は"平日の午前0時"に自動で実行します

  3. "ターゲットの選択"では"すべてのAPI"を選択し、"CloudFormation"と検索の上、選択します

  4. CreateStackを選択し、jsonパラメータを入力します

jsonパラメータはこちら(折りたたんであります)
{
"StackName": "EventBridgeTest",
"TemplateURL": "https://xxxxxxxxxx",
"RoleARN": "arn:aws:iam::xxxxxxxxxxxxx:role/eventbridgetest",
"Parameters": [
  {
    "ParameterKey": "SecurityGroupId",
    "ParameterValue": "xxxxxxxxxxxxx"
  },
  {
    "ParameterKey": "RouteTableId",
    "ParameterValue": "xxxxxxxxxxxx"
  },
  {
    "ParameterKey": "PublicSubnetId",
    "ParameterValue": "xxxxxxxxxxxx"
  }
]
}
  • テンプレートのURLはこちらの手順で取得したものを使用
  • Role ARNはこちらの手順で作成したものを使用
  • パラメータセクションはこちらのパラメータに基づいて記載
  1. "アクセス許可"セクションのロールはこちらで作成したものを使用

結果の確認

事前に設定した時刻にCloudFormationのコンソールを確認すると、スタックが作成されていることがわかります

おまけ_テンプレートの削除

EventBridgeスケジューラの設定画面にてDeleteStackを選択し、jsonファイルパラメータにスタック名と引き受けるロール名を選択することで実現可能です

jsonパラメータはこちら(折りたたんであります)
{
"StackName": "StackName",
"RoleARN": "arn:aws:iam::xxxxx/xxxxxx"
}

まとめ

今回はEventBridgeスケジュール×CloudFormationを使用して大量リソースを同時に作成・削除する手順を紹介しました。
最近ではIaCといえばTerraformという風潮が強いですが、今回のケースのようにCloudFormationを使うべきこともまだまだあるのではないかと思っています。

Discussion