Follow the step-by-step instructions below to build a serverless backend. Click on each step number to expand the section.

  • Step 1. Create an IAM policy for a custom IAM role

    To grant Lambda permissions to handle backend requests for your website, you create a custom IAM policy that grants permissions for AWS services to perform the following actions:

    • AppStream 2.0 updates the image permissions to share your preconfigured image.
    • Amazon SES sends your customers an email when they sign up to receive access to the image.
    • Amazon CloudWatch logging is enabled.
       

    Complete the following steps to create the custom IAM policy.
    1. Open the IAM console at https://console.aws.amazon.com/iam/.
    2. In the navigation pane, choose Policies.
    3. If this is your first time choosing Policies, the Welcome to Managed Policies page appears. Choose Get Started.
    4. Choose Create policy.
    5. Choose the JSON tab.
    6. Copy and paste the following JSON policy into the policy document field.
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "appstream:UpdateImagePermissions",
                "Resource": "arn:aws:appstream:REGION-CODE:ACCOUNT-ID-WITHOUT-HYPHENS:image/IMAGE-NAME"
            },
            {
                "Effect": "Allow",
                "Action": "ses:SendEmail",
                "Resource": "*"
            },
            {
                "Effect": "Allow",
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "*"
            }
        ]
    }

    7. Replace the following variables with your own values:

    • REGION-CODE
    • ACCOUNT-ID-WITHOUT-HYPHENS
    • IMAGE-NAME

    Where:

    • REGION-CODE is the AWS Region where your AppStream 2.0 image exists.
    • ACCOUNT-ID-WITHOUT-HYPHENS is your 12-digit AWS account ID.
    • IMAGE-NAME is the name of the image.

    8. When you’re done, choose Review policy.  

    9. For Name, type the following name for your new policy: examplecorp_lambda_si_policy.

    10. Choose Create policy.

  • Step 2. Create an IAM service role that allows Lambda functions to call AWS services

    Lambda requires an IAM service role to allow the service to access resources in other services on your behalf. Complete the following steps to create an IAM service role and attach the policy that you created to this role.

    1. Open the IAM console at https://console.aws.amazon.com/iam/.
    2. In the navigation pane, under Roles, choose Create role.
    3. For Select type of trusted entity, keep AWS service selected.
    4. Choose Lambda, and then choose Next: Permissions.
    5. In the Filter policies search box, type examplecorp_lambda_si_policy. When the policy appears in the list, select the check box next to the policy name.
    6. Choose Next:Tags. Although you can specify a tag for the policy, a tag is not required.
    7. Choose Next: Review.
    8. For Role name, type examplecorp_lambda_si_role.
    9. Choose Create role.

  • Step 3. Create and configure a Lambda function

    Complete the following steps to create a Lambda function.

    1. Open the Lambda console at https://console.aws.amazon.com/lambda/.
    2. Do one of the following:
        • If you haven’t created any Lambda functions, a Getting Started page displays. Under Getting Started, choose Create a function.
        • If you have created a Lambda function, in the upper right corner of the Functions page, choose Create a function.
    3. On the Create function page, keep Author from scratch selected.
    4. Under Basic information, do the following:
        • For Name, type examplecorp_lambda_si_function.
        • For Runtime, choose Node.js 8.10.
    5. Under Permissions, choose the icon next to Choose or create an execution role. Then do the following:
        • For Execution role, choose Use an existing role.
        • For Existing role, choose examplecorp_lambda_si_role from the list.
    6. Choose Create function.
    7. In the Function code section, on the index.js tab, the placeholder code displays. Delete the placeholder code, and copy and paste the following code onto the tab:

    // 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();
    
    exports.handler = (event, context, callback) => { //Event should contain the Name, Email and AWS Account ID
    
        var eventdata = JSON.parse(event.body); //Parses the JSON from the event body 
        var params = {
            ImagePermissions: { /* required */
                allowFleet: true, //Boolean
                allowImageBuilder: true //Boolean
            },
            Name: '<IMAGE_NAME>', /* required */
            SharedAccountId: eventdata.account //AWS Account ID parsed from the JSON body
        };
    
        shareas2image(params, eventdata, context.awsRequestId, callback); //Share image function call
    
    };
    
    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 shareas2image(params, eventdata, awsRequestId, callback) {
        var request = appstream.updateImagePermissions(params);
        request.
            on('success', function (response) {
                console.log("Success. " + JSON.stringify(response.data));
                sendEmail(eventdata);
                callback(null, {
                    statusCode: 201,
                    body: JSON.stringify({
                        Message: "Success",
                        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) {
                console.log("error: " + JSON.stringify(response.message));
                errorResponse('Error sharing AS2 Image.', 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 trialing 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. We have shared a preconfigured AppStream 2.0 image with all of Example Corp\'s applications to your AWS Account.',
                        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
        });
    }

    Important

    This function automatically shares an AppStream 2.0 image with the AWS account ID that the end user specifies. The function does not verify AWS account ownership before granting image access permissions to the account. If you deploy your solution to production, we recommend that you include your own validations if desired. For example, you may want to validate the end user's identity or AWS account ownership.

    8. Replace the following variables with your own values:

    • <Image-Name>
    • <origin-domain>
    • sender@example.com

    Where:

    • <Image-Name> is the name of the AppStream 2.0 image that you want to share.
    • <origin-domain> is the domain of the website originating the request to API Gateway, in this case the full S3 website URL (ex. http://bucket-name.s3-website.region.amazonaws.com), that you set up for this project.
    • The sender email address is the email address that you added and verified in Amazon SES.

     


    9. Save the function and close the Lambda console.