以下に示すステップバイステップの手順に従い、サーバーレスバックエンドを構築します。各ステップの番号をクリックして、セクションを展開してください。

  • ステップ 1:カスタム IAM ロールの IAM ポリシーを作成する

    ウェブサイトのバックエンドリクエストを処理するために Lambda の権限を付与するには、AWS のサービスに次のアクションを実行できる権限を付与するカスタム IAM ポリシーを作成します。

    • AppStream 2.0 でストリーミング URL を作成します。ユーザーが Example Corp. のウェブサイトにサインインすると、このストリーミング URL にリダイレクトされます。
    • Amazon SES では、Example Corp. のオンラインソフトウェアトライアルにサインアップすると、ユーザーに E メールが送信されます。
    • Amazon CloudWatch のログ記録が有効になります。

    カスタム IAM ポリシーを作成するには、次の手順を実行します。
    1. IAM コンソールを https://console.aws.amazon.com/iam/ で開きます。
    2. ナビゲーションペインで、[Policies] を選択します。
    3. [Policies] を初めて選択した場合、[Welcome to Managed Policies] ページが表示されます。[Get Started] を選択します。
    4. [Create policy] を選択します。
    5. [JSON] タブを選択します。
    6. 次の JSON ポリシーをコピーして、ポリシードキュメントのフィールドに貼り付けます。
    {
        "Version": "2012-10-17",
        "Statement": [{
                "Effect": "Allow",
                "Action": "appstream:CreateStreamingURL",
                "Resource": [
                    "arn:aws:appstream:REGION-CODE:ACCOUNT-ID-WITHOUT-HYPHENS:fleet/FLEET-NAME",
                    "arn:aws:appstream:REGION-CODE:ACCOUNT-ID-WITHOUT-HYPHENS:stack/STACK-NAME"
                ]
            },
            {
                "Effect": "Allow",
                "Action": "ses:SendEmail",
                "Resource": "*"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "*"
            }
        ]
    }
    

    7.AppStream 2.0 のスタックとフリートがある AWS Region を表す REGION-CODE の値を選択します。ACCOUNT-ID-WITHOUT-HYPHENS は自身の AWS アカウント ID に置き換えます。STACK-NAMEFLEET-NAME は、スタック名とフリート名に置き換えます。
    8.完了したら、[Get Started] をクリックします。
    9.[Name] には、新しいポリシーの名前を 「examplecorp_lambda_tin_policy」と入力します。
    10.[Create policy] を選択します。

  • ステップ 2:IAM サービスロールを作成し、Lambda 関数で AWS のサービスを呼び出せるようにする

    Lambda がユーザーに代わって他のサービスのリソースにアクセスできるようにするには、IAM サービスロールが必要です。次の手順を実行して IAM サービスロールを作成し、作成したポリシーをこのロールにアタッチします。

    1.IAM コンソールを https://console.aws.amazon.com/iam/ で開きます。
    2.ナビゲーションペインで [Roles] をクリックしてから [Create role] をクリックします。
    3.[Select type of trusted entity] では、[AWS service] を選択したままにします。
    4.[Lambda] を選択してから [Next: Permissions] をクリックします。
    5.[Filter policies] の検索ボックスに、「examplecorp_lambda_tin_policy」と入力します。該当するポリシーがリストに表示されたら、ポリシー名の横のチェックボックスをオンにします。
    6.[Next: Tags] を選択します。ここではポリシーのタグを指定できますが、この例では不要です。
    7.[Next: Review] を選択します。
    8.[Role name] に、「examplecorp_lambda_tin_role」と入力します。
    9.[Create role] を選択します。

  • ステップ 3:Lambda 関数を作成および設定する

    以下の手順を実行して Lambda 関数を作成します。

    1.Lambda コンソールを https://console.aws.amazon.com/lambda/ で開きます。
    2.以下のいずれかを行います。
        • 初めて Lambda 関数を作成する場合、[Getting Started] ページが表示されます。[Getting Started] の [Create a function] をクリックします。
        • Lambda 関数を作成したことがある場合、[Functions] ページの右上隅にある [Create function] をクリックします。
    3.[Create a function] ページでは、[Author from scratch] が選択されていることを確認します。
    4.[Basic information] で以下を実行します。
        • [Name] に「examplecorp_lambda_tin_function」と入力します。
        • [Runtime] で [Node.js 8.10] を選択します。
    5.[Permissions] で、[Choose or create an execution role] の横のアイコンをクリックします。次に、以下を実行します。
        • [Execution role] で [Use an existing role] を選択します。
        • [Existing role] で、リストから [examplecorp_lambda_tin_role] を選択します。
    6.[Create function] を選択します。
    7.[Function code] セクションの [index.js] タブに、プレースホルダーコードが表示されます。プレースホルダーコードを削除し、次のコードをコピーしてタブに貼り付けます。

    // Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
    // SPDX-License-Identifier: Apache-2.0
    
    const AWS = require('aws-sdk');
    const appstream = new AWS.AppStream;
    const ses = new AWS.SES();
    const crypto = require('crypto');
    
    exports.handler = (event, context, callback) => {
        var eventdata = JSON.parse(event.body);
    
        var length = 16; //Adjust this value to shorten or lengthen the AS2 username - 32 chars is max length an AS2 username can be
        var username = crypto.randomBytes(Math.ceil(length / 2)).toString('hex').slice(0, length); //generates a random string
        
        /* 
        Username could also be the name or email parameter from the event body
    
        var username = eventdata.name
        var username = eventdata.email
    
        */
        
        console.log("username: " + username);
    
        var params = { 
            FleetName: '<Fleet-Name>', /* required */
            StackName: '<Stack-Name>', /* required */
            UserId: username,
            Validity: 5 //TTL of URL
    
        };
    
        createas2streamingurl(params, eventdata, context.awsRequestId, callback);
    
    };
    
    function errorResponse(errorMessage, awsRequestId, callback) { //Function for handling error messaging back to client
        callback(null, {
            statusCode: 500,
            body: JSON.stringify({
                Error: errorMessage,
                Reference: awsRequestId,
            }),
            headers: {
                'Access-Control-Allow-Origin': '<origin-domain>', //This should be the domain of the website that originated the request, example: amazonaws.com
            },
        });
    }
    
    function createas2streamingurl(params, sesdata, awsRequestId, callback) {
        var request = appstream.createStreamingURL(params);
        request.
            on('success', function (response) { //Successful Response
                console.log("Success! AS2 Streaming URL created.");
                var output = response.data;
                var url = output.StreamingURL;
                sendEmail(sesdata); //With a successful AS2 URL generated, trigger the SES SendEmail function
                callback(null, {
                    statusCode: 201,
                    body: JSON.stringify({
                        Message: url,
                        Reference: awsRequestId,
                    }),
                    headers: {
                        'Access-Control-Allow-Origin': '<origin-domain>', //This should be the domain of the website that originated the request, example: amazonaws.com
                    },
                });
            }).
            on('error', function (response) { //an error occoured 
                console.log("error: "  + JSON.stringify(response.message));
                errorResponse('Error creating AS2 streaming URL.', awsRequestId, callback);
    
            }).
            send();
    }
    
    function sendEmail(data) {
        var sender = "<sender@example.com>"; //Sender needs to be a verified address in SES
        var receiver = data.email.trim(); /*Trim the string of any preceding and trailing whitespaces*/
        var name = data.name.trim();
        var params = {
            Destination: {
                ToAddresses: [receiver]
            },
            Message: {
                Body: {
                    Text: {
                        Data: 'Hello ' + name + ',' + '\n\nThank you for trying Example Corp\'s Application Suite.',
                        Charset: 'UTF-8'
                    }
                },
                Subject: {
                    Data: 'Thank you for trying Example Corp ' + name,
                    Charset: 'UTF-8'
                }
            },
            Source: sender
        };
        console.log("Sending Email.");
        ses.sendEmail(params, function (err, data) {
            if (err) console.log(err, err.stack); // an error occurred
            else console.log(data);           // successful response
        });
    }
    

    8.以下の変数を独自の値に置き換えます。

    • <Stack-Name>
    • <Fleet-Name>
    • <origin-domain>

    各パラメータの意味は次のとおりです。
    • <Stack-Name> は、ストリーミング URL を作ろうとしているスタックの名前です。
    • <Fleet-Name> は、この関数でストリーミング URL を作成しようとしているスタックに関連するフリートの名前です。
    • <origin-domain> は、API ゲートウェイにリクエストを送るウェブサイトのドメインです。ここでは、このプロジェクト用に設定した S3 ウェブサイトのフル URL (http://bucket-name.s3-website.region.amazonaws.com) になります。

    9.関数を保存して Lambda コンソールを閉じます。