🌙

SSM経由でEC2にS3にファイルをDL&実行させるLambda関数

2023/04/22に公開

本記事に掲載しているLambdaは、以下のよう構成を想定したものです。

本記事に掲載しているLambdaが想定している構成図

本記事のLambdaを作るようになった経緯

この記事のLambdaを作る前に元々やりたかったことはEC2にある各種ログファイルを定期的にS3に移動させることです。
当初EventBridgeルールにファイル移動コマンドを定数で書いていましたが、
移動対象が増えるにつれコマンドがたくさん増えてしまいEventBridgeの画面でコマンド編集をするのが辛くなってきました。
こんな感じです。

EventBridgeのルールに定数で多数のコマンドが指定されている

EventBridgeのルールでコマンドを送る方法はお手軽なのはいいのですが、変更しようとするとコマンドを一旦削除して追加するしかないのでやりにくさがあります。
また、この方法ではワンライナーのコマンドを積み重ねることしかできないため、分岐が書きづらいです。

以上の理由により、ログファイルの移動関連の処理を見直すことになったのですが、
しっかりプログラムを書くのもちょっと・・・だし、処理内容を運用チームの方でちょこちょこ直すのでデプロイが伴うような構成も避けたいということで今後の利便性を考えて本記事のLamdaを作るに至りました。

Lambdaソースコード(Python)

https://github.com/satoshi256kbyte/aws-code/blob/master/lambda/execute_scripts_ec2.py

SAMなどは使ってないのでビルドは不要です。
単純にLambdaのコード画面で貼り付けるだけで動くコードです。

このLambda関数はEC2に対し、S3からファイルをDLして実行するように命令します。
ログファイルの移動などのちょっとしたシェルスクリプトを書いてS3に置いてもらえば、これを用いてEC2に定期的に実行させられますよという想定です。

スクリプトをダウンロードするためのバケット名・キー、スクリプトを実行させるEC2のインスタンスID、タイムアウト時間はEventのJSONで渡すようにします。
こんな感じで指定します。

{
  "s3_bucket": "バケット名",
  "s3_key": "スクリプトファイルのバケット上のキー",
  "instance_id": "EC2のインスタンスID",
  "timeout": "3600"
}

RunCommandの実行結果を一応見てはいますが、
実際のところエラーが発生すると殆どここに来ないようです。
実行させるスクリプトでエラーが起きると殆どwaiter.waitの時点で例外が発生してexcept Exception as e:の部分に飛びます。

# コマンドの実行結果判定
if command_result['Status'] != 'Success':
    raise Exception('Command execution failed.')

このLambdaに必要な権限

このLambdaを実行するのに必要な権限はこちらです。
Resourceの部分を緩めに書いてるので実際使う場合は対象がもっと絞られるようにした方が良いと思います。

本記事のLambdaはSessionManager経由でEC2にコマンドを送っています。
ssm:SendCommandは、コマンドを送るのに必要な権限で、
ssm:GetCommandInvocationはコマンドの実行結果を得るために必要な権限です。

なお、S3からファイルをダウンロードしてるのはEC2側なので、EC2の方にS3のGetObjectが必要になります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "policy1",
            "Effect": "Allow",
            "Action": [
                "ssm:SendCommand",
                "ssm:GetCommandInvocation"
            ],
            "Resource": "*"
        },
        {
            "Sid": "policy2",
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "arn:aws:logs:us-east-1:アカウントID:*"
        },
        {
            "Sid": "policy3",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:us-east-1:アカウントID:*:*:*"
        }
    ]
}

EventBridgeの設定

EventBridgeスケジュールでの例です。

ターゲットはLambdaを呼ぶので、AWS LambdaのInvokeです。

EventBridgeスケジュールの入力

Invokeの部分でLambda関数とバケット名などのパラメータを指定します。

EventBridgeスケジュールのターゲット

この他の設定には特別に書くようなものはなく、デフォルトのままで大丈夫です。

Discussion