AWS Lambda function から S3 へアップロードする [Serverless Framework 編]
Serverless Framework で AWS Lambda へ deploy した function から S3 へアップロードする方法をご紹介します。
本サイトの記事 Serverless Framework で AWS Lambda へ deploy する | CodeNote を元にセットアップしているとします。
Serverless Framework のデフォルト設定のままだと Lambda function から S3 を使おうとすると InvalidAccessKeyId: The AWS Access Key Id you provided does not exist in our records. というエラーが発生してしまいます。
{
InvalidAccessKeyId: The AWS Access Key Id you provided does not exist in our records.
at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:585:35)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)
at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)
at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:683:14)
at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)
at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)
at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10
at Request. (/var/task/node_modules/aws-sdk/lib/request.js:38:9)
at Request. (/var/task/node_modules/aws-sdk/lib/request.js:685:12)
at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:116:18)
message: 'The AWS Access Key Id you provided does not exist in our records.',
code: 'InvalidAccessKeyId',
region: null,
time: 2018-12-22T15:40:48.422Z,
requestId: 'A7BA76D679AA0908',
extendedRequestId: 'BgpkYpdh88xEFW1IOdb6E1hKS484X3ZVcsymi0TL2S/x5nTF0CNsZQ18MkIE5yYn/6WjJz2KaSc=',
cfId: undefined,
statusCode: 403,
retryable: false,
retryDelay: 41.81325093666113
}
私が開発してる Set up AWS S3 / Crawling the target site and save as HTML to S3 · Pull Request #4 に沿って、手順をご紹介します。
npm install --save aws-sdk
serverless.yml の provider: に environment: を以下のように定義することで、serverless.yml からは ${self:provider.environment.S3_BUCKET} というように環境変数を利用できます。
provider:
# you can define service wide environment variables here
environment:
S3_BUCKET: your-bucket-name-${opt:stage, self:provider.stage}
S3 Management Console から S3 bucket を作成するのでもいいですが、せっかく Serverless Framework を利用してるなら serverless.yml に以下のような設定を追加して CloudFormation 経由で S3 bucket を作成するのがおすすめです。
# you can add CloudFormation resource templates here
resources:
Resources:
S3BucketResource:
Type: AWS::S3::Bucket
Properties:
BucketName: ${self:provider.environment.S3_BUCKET}
Outputs:
S3BucketOutput:
Description: "Description for the output"
Value: S3BucketResource
上記までだと S3 bucket 作成しただけで、Lambda function から作成した S3 bucket への権限がなにもありません。
serverless.yml の provider: iamRoleStatements: を以下のように修正すると、Lambda function から S3 へアクセス
provider:
# you can add statements to the Lambda function's IAM Role here
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:ListBucket"
- "s3:GetObject"
- "s3:PutObject"
- "s3:DeleteObject"
Resource:
Fn::Join:
- ""
- - "arn:aws:s3:::"
- ${self:provider.environment.S3_BUCKET}
- "/*"
最後に、上記で作成、IAM 権限付与した S3 bucket へ Lambda function から HTML ファイルをアップロードするサンプルコードをご紹介します。
'use strict';
const AWS = require('aws-sdk');
module.exports.putS3 = async (event, context) => {
try {
const html = 'Hello world
';
AWS.config.update({
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.AWS_SEECRET_ACCESS_KEY,
region: process.env.AWS_REGION
});
const s3 = new AWS.S3();
const response = await s3.putObject({
Bucket: process.env.S3_BUCKET,
Key: `${Date.now()}.html`,
ContentType: 'text/html',
Body: html
}).promise();
console.log({
result: 'OK',
s3response: response
});
} catch (err) {
console.error(err);
console.log({
result: 'NG'
});
}
};
以上、Serverless Framework で deploy した AWS Lambda function から S3 を操作したい、現場からお送りしました。