LoginSignup
18

More than 5 years have passed since last update.

S3の期限付きURLをLambdaで取得する

Last updated at Posted at 2017-02-04

概要

 S3には、ウェブサイトホスティングを有効にしないまま、期限付きのURLを発行して外部からアクセスできるようにする機能があります。今回は、Lambda(Node.js)からS3の期限付きURLを取得し、CURLで期限付きURLにアクセスしてみます。

用途

 Lambdaから期限付きURLを取得する処理は、サーバレス アーキテクチャでよく登場します。

■ サーバーレス アーキテクチャの認証の流れ

  ServerLess.png

  1. クライアントはAPI Gatewayにアクセスします。API Gatewayは外部からのアクセスに対して認証を行い、S3のファイルに対するアクセス権のチェックを行います。
  2. 認証に通ったことを確認したうえで内部ではLambdaがS3の期限つきURLを取得して応答します。
  3. クライアントはAPI Gatewayから応答されたS3の期限つきURLにアクセスします。

今回の「S3の期限付きURLをLambdaから取得する」は②の部分の処理になります。

GET Object

S3

バケットを作成し、ファイルをアップロードしておきます。
静的ウェブサイトホスティングは、外部から直接アクセスできないように
 ◎ ウェブサイトのホスティングを有効にしない
にセットします。

Lambda

■ IAMポリシー

S3バケット内のファイルに対するGET権限を与えます。

s3-getObject.policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::<バケット>/*"
        }
    ]
}

■ コード

node.js
exports.handler = (event, context, callback) => {
    let AWS = require('aws-sdk');
    let s3 = new AWS.S3();
    let params = {
                    Bucket: '<バケット>',
                    Key: '<オブジェクトキー>',
                    Expires: 秒数
    };
    s3.getSignedUrl('getObject', params, function (err, url) {
        callback(null, url);
    });
};

■ Lambdaのテスト

Lambdaのテストボタンを押してみます。
Execution result: succeeded に期限付きURLが表示されます。

ExecutionResult.png

CURLで期限付きURLにアクセス

■ 正常なアクセス

Lambdaのテストで表示された期限付きURLにCURLでアクセスしてみます。
クエリパラメータが複数あるのでURLを「""」で囲む必要があります。

$ curl -o <ファイル名> -X GET "<期限付きURL>"

期限内にURLにアクセスすると、<ファイル名>をダウンロードすることができました。

■ 期限切れ

期限が過ぎてからアクセスしてみます。
  期限(<Expires>)<サーバー時刻(<ServerTime>)
のエラーが返ってきてファイルが取得できなくなります。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Request has expired</Message>
    <Expires>2017-02-04T12:55:14Z</Expires>
    <ServerTime>2017-02-04T12:55:36Z</ServerTime>
    <RequestId>137B27F263A55608</RequestId>
    <HostId>ZrQWyt7Rf0sPwQPfUbYUy34wSFdWZxSBC3JFU8YGU6w0NT+18ibIdAHE5suoC6MoZttTwAI9dyQ=</HostId>
</Error>

■ URLを改竄

URLを改竄してみます。<エポック秒>を改竄してアクセスしてみます。
不正が検知されエラーが返ってきます。

<Error>
    <Code>InvalidToken</Code>
    <Message>The provided token is malformed or otherwise invalid.</Message>
    <Token-0>FQoDYXdzEOrFFFFFFFFFFwEaDDORFHT0g0nL4wg7oSLlAUy2ILzR33Szq98fHk8fOEKj89RBlkVLAsZITfBaKBndNj8MMS0HtKilZ3utMx8krPwFNBSBBBGwzBSAvBUutX4hRQR3qW0jvS4uL6VtTFPmxNyzSQBvdvHhWIZFnXeTp1cd1xxDunPVEaRiJNqwvegcmvVIiVfW1DLCIA1FNHSAp8FF9kKVvjTbtB5nv2BrnlTOcfphLtTyhAxMs1aeMATRc2cJ6fs068fxfJFIifTpfLLYcCQ4kbGhFBmjYB7Kr4U10rmdGY4rZeOenhc9YPeZShgv0QP5IabFBzFB6cFEFa5EQD8o5LLWxAUD</Token-0>
    <RequestId>0A2B6F8EC80D0A8F</RequestId>
    <HostId>P6VveqnTd9twOSxV94D7vtRvwmiS/k9LYqJh+9iLKtNJcLdNAeHtCrVEUws+Ftfb2bS9gQOItY8=</HostId>
</Error>

■ セキュリティトークンを改竄

セキュリティトークン(x-amz-security-token)を改竄してアクセスしてみます。
シグネチャが一致しないエラーになります。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>SignatureDoesNotMatch</Code>
    <Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
    <AWSAccessKeyId>XXXXXXXX</AWSAccessKeyId>
    <StringToSign>
        GET
        1486269940
        x-amz-security-token:YYYYYYYY
    </StringToSign>
    <SignatureProvided>rTfGRqWMWAKLixOm/92tqt6WVlA=</SignatureProvided>
    <StringToSignBytes>00 01  02 03 ...</StringToSignBytes><RequestId>A5962F972E4E3D14</RequestId>
    <HostId>do4mKLzPZZpVmH7eCDhF6cmsPaY53oPF5LYsoLuu65qKUaF2QcTpJXbpXVOEx42xQ/TflrL6cgw=</HostId>
</Error>

■ ファイルが存在しない

期限付きURL発効後にファイルが削除された場合は、「AccessDenied」になります。

<?xml version="1.0" encoding="UTF-8"?>
<Error>
    <Code>AccessDenied</Code>
    <Message>Access Denied</Message>
    <RequestId>9F6816DF55ACC3B4</RequestId>
    <HostId>vEh9mzdRPUHi8D3UAyzOn/lc3aV/Bz5aRZNRnbYTU8Vdrc+92Dpy65Kpb+yrnzw9fGHTbtpfsRQ=</HostId>
</Error>

PUT Object

S3

バケットを作成しておきます。
静的ウェブサイトホスティングは、外部から直接アクセスできないように
 ◎ ウェブサイトのホスティングを有効にしない
にセットします。

Lambda

■ IAMポリシー

s3-putObject.policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::<バケット>/*"
        }
    ]
}

■ コード

Lambda.js
exports.handler = function (event, context, callback) {
    "use strict";

    const AWS = require('aws-sdk');
    let s3 = new AWS.S3();
    const BUCKET = '<バケット>';
    const KEY = '<オブジェクトキー>';
    const CONTENT_TYPE = 'image/jpeg';  // image/png, image/tiff, etc...

    var params = {
        Bucket: BUCKET,
        Key: KEY,
        Body: '',
        ContentType: CONTENT_TYPE,
        Expires: 1800
    };

    s3.getSignedUrl('putObject', params, function (err, url) {
        if (err) {
            callback(err);
            return;
        }

        callback(null, url);
    });
};

■ Lambdaのテスト

Lambdaのテストボタンを押してみます。
Execution result: succeeded に期限付きURLが表示されます。

ExecutionResult_put.png

CURLで期限付きURLにアクセス

■ 正常なアクセス

ローカルの /path/to/file.jpg にファイルを用意し、curlを実行します。

curl -H "Content-Type: image/jpeg" --data-binary "@/path/to/file.jpg" -X PUT "<期限付きURL>"

期限内にアクセスすると、ファイルをS3にアップロードすることができました。

以上です。

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
18