7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

LambdaからSystems Managerを実行してEC2のバックアップを取得する

Posted at

はじめに

EC2の定期バックアップを取得をするのに良い方法はないかと思っていたところ、SSMでスナップショットが取得できることを知ったので、Lambdaから実行してみました。
サーバーの作成は省略しますが、Systems Managerを使用するので、SSMエージェントがデフォルトインストールされているWindows Server 2019を使用しています。

参考
Windows インスタンスで SSM エージェント をインストールし設定する

やったこと

  • Windowsサーバーの作成
  • Systems Managerからバックアップ取得
  • LambdaからSystems Manager ドキュメントの実行

Windowsサーバーの作成とIAMロール設定

バックアップを取得するため、EC2を1台作成します。
image.png

セキュリティグループは最低限しか設定していません。
image.png

EC2が作成できたら、Systems Managerがインスタンスで実行できるようにIAMロールをアタッチします。
今回は検証のため、EC2FullAccess(スナップショット取得用)とSSMManagedInstanceCore(SSM実行用)のみ設定
image.png

※必要なポリシーについては以下参照
IAM インスタンスプロファイルを Amazon EC2 インスタンスにアタッチする

EC2を作成して数分経つとSystems Managerのマネージドインスタンスから、対象のインスタンスが確認できます。
image.png

Systems Managerからバックアップ取得

さっそくLambdaでバックアップを取得...といきたいところですが、まずはSystems Managerからバックアップが取得できることを確認します。

コマンドの実行ボタンを押下します。
image.png

今回はAWSが作成している「AWSEC2-CreateVssSnapshot」ドキュメントを使用します。
image.png

ターゲットの項目から、先ほどのサーバーを選択してドキュメントを実行します。
image.png

コマンド履歴から実行コマンドのステータスが成功になっていることを確認します。
image.png

スナップショットが無事に取得できました。
image.png

LambdaからSystems Manager ドキュメントの実行

Systems Managerからバックアップが取得できたところで、今度はLambdaからSystems Managerを実行してみます。

まずはLambda実行用のIAMロールを作成します。
Lambdaの実行権限のみから開始して、エラーを解消しながら進めていきます。
image.png

ちなみにLambdaのコードはこんな感じ(Pythonで書いています)

lambda_function.py
import json
import traceback
import boto3
import logging
from datetime import datetime

logger = logging.getLogger()
logger.setLevel(logging.INFO)

instance_id = 'i-0bec94e365078de8c'
document_name = 'AWSEC2-CreateVssSnapshot'
exec_date = datetime.now().strftime("%Y/%m/%d_%H:%M:%S")
snapshot_name = 'testserver-snapshot-' + exec_date

def lambda_execute_ssm(event):
    
    ssm = boto3.client('ssm')
    
    logger.info("Start Get Snapshot")

    ssm_result = ssm.send_command(
        InstanceIds = [ instance_id ],
        DocumentName = document_name,
        Parameters = {
            'ExcludeBootVolume': [
                'False',
            ],
            'description': [
                'Ssm Execute Document',
            ],
            'tags': [
                'Key=Name,Value={}'.format(snapshot_name),
            ]
        }
    )
    logger.info("exec lambda result -> {}".format(ssm_result))    
    logger.info("Completed!")

def lambda_handler(event, context):
    try:
        lambda_execute_ssm(event)
    except Exception:
        logger.error('Exception -> {}'.format(traceback.format_exc()))

この状態でLambdaを実行してみると以下のエラーが発生

botocore.exceptions.ClientError: An error occurred (AccessDeniedException) when calling the SendCommand operation: User: arn:aws:sts::XXXXXXXXXXXX:assumed-role/lambda-ssm-handler/ssm-execution is not authorized to perform: ssm:SendCommand on resource: arn:aws:ec2:ap-northeast-1:XXXXXXXXXXXX:instance/i-0bec94e365078de8c

エラー内容を読む限りだと、SSMのSendCommandを実行しようとしているが、Lambda側にその権限がないのが原因っぽい?

LambdaのロールにSSMのSendCommand権限が許可されるポリシー(AmazonSSMMaintenanceWindowRole )をアタッチして再度Lambdaを実行すると、無事に正常終了しました。
image.png

スナップショットも作成されているため、特に問題はなさそうです。
image.png

結論やわかったことに対する補足

Lambdaからバックアップは取得できたので、CloudEvent等でスケジュール実行させたら定期取得はできそうです。

このやり方だと削除用のLambdaも作成する必要があるので、その点だとライフサイクルマネージャーのほうが良いのかもしれませんが、ライフサイクルマネージャーは取得にタイムラグがあったり、CloudWatchEventのcronでする柔軟なスケジュール設定ができないので、それが必要ならLambda実行にしたほうがいいですね。

本当はSSMのコマンド失敗時にSNS通知させるところまでを作ろうと思いましたが、SNS通知のためのロールを渡すところでエラーが多発したため、一旦スナップショットを取得するところまでにしました。
IAMロール回りが中々理解できない。。

7
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?