やりたいこと
LambdaでS3によってデフォルト暗号化されたファイルを読み込みたい。LambdaでS3上のデータを取得してガチャガチャするのに必要な処理。
テスト用S3バケット作成
まずはS3バケットの作成。今回はアップロードするファイルが機密性の高いものと想定して、デフォルト暗号化を有効にする。
デフォルト暗号化とは
アップロードしたファイルをS3側で暗号化して保存してくれる。クライアント側で暗号化する必要がないため、クライアント側の負荷が上がることはない。ただし、S3側で暗号化処理が実行される分のオーバーヘッドが発生する可能性は考慮する必要がある。
バケット作成&ファイルアップロード
S3バケットを作成してテスト用のファイルを配置する。デフォルト暗号化の暗号鍵は SSE-S3
を利用。
Boto3を利用してS3のファイルを読み込む
Lambda関数作成
テストスクリプト
import json import boto3 import logging client = boto3.client('s3') def lambda_handler(event, context): # set logging logger = logging.getLogger() logger.setLevel(logging.INFO) # set "bucket name" and "object name" BUCKET = "waneal-test" TEST_FILE = "hoge.txt" # get s3 object try: response = client.get_object(Bucket = BUCKET, Key = TEST_FILE) except Exception as e: return logger.error("Failed to get object: {}".format(e)) return { "statusCode": 200, "body": "object body is {}".format(response['Body'].read().decode('utf-8')) }
Lambdaのログ出力は print
か logger
を利用できる。どちらもCloudwatchlogsに出力され、コンソールにも表示される。loggerを利用したほうがログレベル、タイムスタンプが含まれるため便利
存在しないファイルにアクセスすると Access Denied
が返ってくる。少し紛らわしい。
response['Body']は文字列型ではなく botocore.response.StreamingBody
なので、ストリームからの呼び出しが必要。一度読み込むと2度目以降は読み込めないので注意。これは意図された仕様で、理由は文字列型にしてしまうと、数GBのデータをLambda上のメモリで保持する可能性が出るため。
実行結果
感想
ストリームのところの仕様が把握できてなくて少しハマった。ちゃんとドキュメントを読むべし。
Lambdaで暗号化したファイルを読み込む際、特に復号化処理は意識しなくてもいい。逆に言うと同じアカウント内であれば暗号化したファイルを利用可能なので、SSE-S3による暗号化で防げるのは バケットの公開設定を誤った場合
のみになるのかな?内部でアクセスを制限したい場合、KMSによる鍵管理やIAMユーザ権限管理が必要なんだと思う。