LambdaとSSMでEC2からS3のオブジェクト取得させる

AWS環境で,Lambdaを用いてS3からEC2にオブジェクトを取得させる設定をしたのでメモがてら残しておく.

概要

Lambdaを使い,AWS Systems Manager(SSM)経由でEC2にAWSコマンドを実行させ,S3からオブジェクトを取得する.また,S3にあるオブジェクトは他AWSアカウントからPUTされたと想定する.以下に図を示す.

f:id:a-mochan:20200312213744j:plain

S3のバケットポリシーの設定

AWSアカウント間をまたぐS3バケットへのアップロードでは,オブジェクトの権限に気をつける.
例えば,AというAWSアカウントがS3バケットを作成したとして,Bという他のAWSアカウントからS3バケットへオブジェクトをPUTする.PUTする際にオプションを何も指定しなければ,S3バケットへPUTされたオブジェクトの所有者はBとなってしまい,AにあるEC2からはGETできないしマネージメントコンソールからもダウンロードできない.これを避けるため,PUTする際(aws-cliの場合)に--acl bucket-owner-full-controlオプションをつけて実行する.これにより,PUTしたオブジェクトの所有者がAアカウントになりAアカウントからGETすることが可能となる.詳しくは以下のブログが参考になった.

qiita.com

test-bucketというS3バケットを用意し,他のアカウントからPUTしてもらう.PUTしてもらう際に--acl bucket-owner-full-controlオプションをつけておかないとPUTできないようにConditionを設定したバケットポリシーを以下に示す.もっと制限をかけたければPrincipalCondtionを適宜追加する.

{
    "Version": "2012-10-17",
    "Id": "PolicyId2",
    "Statement": [
        {
            "Sid": "Test",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::test-bucket/*",
            "Condition": {
                "StringEquals": "s3:x-amz-acl": "bucket-owner-full-control"
            }
        }
    ]
}

EC2の設定

EC2では,S3からオブジェクトを取得するために,今回はAWSコマンドを使う.AWSコマンドがない場合はインストールを行う.また,LambdaでSSMを使うのでEC2インスタンスにSSMエージェントが入っていない場合もインストールしておく.さらに,SSMがEC2を扱うことができるようにAmazonEC2RoleforSSMポリシーが付与されたロールをEC2にアタッチしておく.

Lambdaの設定

Lambdaでは,SSMを使ってEC2上でAWSコマンドを実行してS3からオブジェクトをEC2上に配置する.まずは,LambdaがSSMを扱うことができるようにAmazonSSMFullAccessポリシーが付与されたロールをLambdaにアタッチする.また,EC2上で実行するAWSコマンドで必要なシークレットIDとシークレットキーは環境変数としてLambdaで渡すようにする.Pythonで記述したLambdaの例を以下に示す.

import boto3
import os

ACCESS_KEY_ID = os.environ['ACCESS_KEY_ID']
SECRET_ACCESS_KEY = os.environ['SECRET_ACCESS_KEY']

ssm = boto3.client('ssm')

def lambda_handler(event, context):
    bucket = 'test-bukect/'
    ec2_dir = '/var/tmp'
    s3_dir = 'test/'
    
    commands = [
        "export AWS_ACCESS_KEY_ID=" + ACCESS_KEY_ID,
        "export AWS_SECRET_ACCESS_KEY=" + SECRET_ACCESS_KEY,
        "export AWS_DEFAULT_REGION=ap-northeast-1",
        'aws s3 sync s3://' + bucket + s3_dir + " " + ec2_dir
    ]
    ssm.send_command(
            InstanceIds = ('i-123456789',),
            DocumentName = "AWS-RunShellScript",
            Parameters = {
                "commands": commands,
                "executionTimeout": ["3600"]
            }
    )

これで,Lambdaを実行すればtest-bucketの/testディレクトリ以下にある内容がEC2上の/var/tmp以下にコピーされる.

まとめ

  • LambdaとSSMを用いてEC2からS3のオブジェクト取得させた
  • 他アカウントからのS3へのPUTではbucket-owner-full-controlをつける