はじめに
こんにちは!入社一年目の牛塚です。今回はAWS SSM Automationを自作したので、学んだことをまとめてみました。 「SSMAutomationとはなんだろう?」という方や「AWSが提供するドキュメントじゃ要件を満たせない」と考えている方におすすめの内容となってます。
SSM Automationとは
SSM Automationとはメンテナンスやデプロイを簡素化するAWS Systems Manager (SSM)の機能の一つです。AWSリソースの大規模デプロイ、設定、管理などの作業を自動化することが出来ます。
例えば、複数台のEC2インスタンスをまとめて起動する必要があるとき、マネジメントコンソールから一台ずつ起動していくと時間や手間がかかってしまいます。
そこでSSMAutomationを実行することで特定のタグがついたインスタンスを一斉に起動することが出来ます。
上記の例はほんの一例ですが、SSMAutomationは複数のリソースをまとめて操作する、同じ作業の繰り返すを自動化できるなど利点があります。
ランブックについて
SSMAutomationはランブックと呼ばれるドキュメントを実行することで起動します。 ランブックはJSONまたはYAMLで記述します。 ランブックには以下の要素を記載していきます。
description: <ランブックの説明文> schemaVersion: <スキーマのバージョン> parameters: <入力パラメータ(ランブックへの引数)> mainSteps: <各ステップを記載する>
この他にもランブックの出力(戻り値)を記載したりすることが出来ます。
詳細は以下の公式ドキュメントをご覧ください。
データ要素とパラメータ - AWS Systems Manager
SSM Automationを実行するとmainSteps内に記載されたステップを上から順番に実行していきます。
ステップごとに実行するアクションを定義します。アクションはリソースを特定したり、APIを実行したりと様々なものが用意されています。
詳しくは以下をご覧ください。
Systems Manager Automation アクションのリファレンス - AWS Systems Manager
このような構成で記載されているランブックですが、 AWSが提供している定義済みのランブックも存在し様々なタスクを実行出来ます。 具体的には以下のようなことが実現可能です。
- 複数のEC2、RDSの一括起動・停止
- CloudFormationのスタックの削除
- 実行中のインスタンスからAMIを作成する
- など
「AWSが提供しているランブックじゃやりたいことができないよ~」という人はランブックを自作することが出来ます。
今回自作するランブック
今回はEC2インスタンスを作成するランブックを自作します。このランブックは次のような利用シーンに活用出来ます。
複数人のユーザーそれぞれに必要な時に必要な時だけ個別のインスタンスを作成する必要があるときに、 マネジメントコンソール上でAMIやサブネットなどを選択し作成するとヒューマンエラーが発生しやすくなります。 そこでSSMAutomationを使用することで最低限の操作だけでインスタンスを作成することが出来ます。
AWSが事前定義しているランブックは停止状態のインスタンスを起動するものはありますが、インスタンスを一から作成するものは現時点でありません(2024年3月7日時点)。 今回はインスタンスを作成するだけではなく、承認フローやインスタンス作成完了メールも組み込んでみました。
依頼者(ユーザー)が承認者に申請をしてSSMAutomationは承認がおりたら、インスタンスの作成を始めます。ユーザーごとにSNSトピックをあらかじめ作成しており、インスタンスが作成された後、ユーザーへ 作成完了を知らせるメールが送信されます。
以下のようなステップで構成されています
- ユーザーのSNSトピックの特定
- 承認依頼・承認
- EC2インスタンスの作成
- EC2のプライベートIPを取得
- インスタンスの作成完了メール送信
サンプルコード
入力パラメータ
SSMAutomationのパラメータですが、今回はユーザーネームを入力する仕様にしました。のちに出てくるユーザーごとのSNSトピックのタグに紐づけられて、ユーザーのSNSトピックを特定するときに使用されます。
description: Create and launch an EC2 instance after approval schemaVersion: '0.3' parameters: UserName: type: String description: (Required) UserName
SNSTopicの特定 Step
SNSトピックのタグにはユーザーネームが設定されており、入力パラメータに指定されたユーザーネームからユーザー固有のSNSトピックを検索します。
mainSteps: - name: IdentifyTopicsonSNS action: aws:executeAwsApi nextStep: approve isEnd: false inputs: Service: resourcegroupstaggingapi Api: GetResources TagFilters: - Key: UserName Values: - '{{UserName}}' ResourceTypeFilters: - sns outputs: - Name: SNSTopicArn Selector: $.ResourceTagMappingList[0].ResourceARN Type: String - Name: UserName Selector: $.ResourceTagMappingList[0].Tags[0].Value
承認Step
承認者へ承認依頼のメールを送信します。
- name: approve action: aws:approve nextStep: launchInstance isEnd: false onFailure: Abort inputs: NotificationArn: arn:aws:sns:ap-northeast-1:hogehoge Message: '{{UserName}} is requesting authorization to launch an EC2 instance' MinRequiredApprovals: 1 Approvers: - arn:aws:iam::hugahuga
インスタンス作成Step
インスタンスを作成します。AMIやロールは事前に作成されたものを指定します。
- name: launchInstance action: aws:runInstances maxAttempts: 3 timeoutSeconds: 1200 nextStep: GetEC2InstanceIP isEnd: false onFailure: Abort inputs: ImageId: ami-hugohugo InstanceType: t2.micro MinInstanceCount: 1 MaxInstanceCount: 1 IamInstanceProfileName: sample_role TagSpecifications: - ResourceType: instance Tags: - Key: LaunchedBy Value: SSMAutomation - Key: CreatedBy Value: '{{UserName}}' - Key: Name Value: '{{UserName}}' outputs: - Name: myInstanceId Selector: $.InstanceIds Type: StringList
インスタンスの情報抽出Step
ユーザーへ送信するメールに記載するプライベートIPを抽出します。
- name: GetEC2InstanceIP action: aws:executeAwsApi nextStep: SendNotification isEnd: false inputs: Service: ec2 Api: DescribeInstances InstanceIds: '{{launchInstance.myInstanceId}}' outputs: - Name: PrivateIP Selector: $.Reservations[0].Instances[0].PrivateIpAddress Type: String
作成完了メール送信Step
ユーザーへインスタンス作成が完了したことをSNSTopicを使用して通知します。
- name: SendNotification action: aws:executeAwsApi isEnd: true inputs: Service: sns Api: Publish Subject: PrivateIP Message: PrivateIP is '{{GetEC2InstanceIP.PrivateIP}}' | UserName is '{{UserName}}' | TopicArn: '{{IdentifyTopicsonSNS.SNSTopicArn}}'
苦戦した点
各ステップからステップへ値を渡す際にはoutputとして出力する必要があり、APIを使用するステップでは出力の仕方がわからず苦戦しました。 例えばサンプルコードのIdentifyTopicsonSNS、GetEC2InstanceIPのステップです。 実行するAPIごとに出力の仕方が決まっているのでBoto3のドキュメントを参照して解決できました。
例えば「⑤インスタンスのIP取得」ではApi: DescribeInstancesを使用しているので、EC2>describe_instances>Response Syntaxを見ると、プライベートIPの型と出力方法を知ることが出来ます。
感想
今回ははじめてSSM Automationを自作してみました。 アクションは様々なものが用意されており、非常に汎用性の高いサービスだなと感じました。 はじめは書き方などわからないことも多かったのですが、公式ドキュメントなどを参照しながら完成することが出来ました。 同じく書き方に戸惑っている人の助けに少しでもなればうれしいです。 今回作成したものはユーザーネームを入力する仕様ですが、SSM Automationを実行するユーザーの情報を抽出してよりセキュアにもできそうです。