Learn about our RFC process, Open RFC meetings & more.Join in the discussion! »

@litexa/deploy-aws

0.5.0 • Public • Published

Litexa Deploy AWS

NOTE: For full documentation on deployment, please see the book. For information on the command line interface, please run litexa deploy --help.

This module implements Litexa deployment to Amazon Web Services, with the following structure:

  • Assets are copied into a new or existing S3 bucket of your choice
  • Permanent data store is written to a new DynamoDB table
  • Skill endpoint is hosted in a Lambda
  • Logging is directed to Cloudwatch

Before You Start

Let's take a closer look at your Litexa config (the litexa.config.js/ts/json/coffee in your project root). It probably looks something like this:

{
  "deployments": {
    "development": {
      "module": "@litexa/deploy-aws",
      "s3Configuration": {
        "bucketName": "suncoast-assets"
      },
      "askProfile": "suncoast",
      "awsProfile": "prototyping"
    }
  }
}

You will see that there is a key called development under the deployments key. This is called a deployment target. A deployment target is a named configuration for the deployment of your skill. It determines where, how, and with what settings a skill will be deployed.

You can name your deployment targets whatever you want and have as many as you want. The development target is just the one litexa generate creates for you to get started.

Alexa skill deployment is comprised of 2 parts. The first part is deployment of your skill logic, or backend deployment. This is what a deploy module takes care of for you, and what this README will be about. For the second part, read the litexa module's README or the Book's chapter on ASK deployment.

In your Litexa config, you'll notice that within a deployment target, there is a module field. This field indicates the name of the node module your Litexa skill will use for its backend deployment. The module implements what sort of hosting, persistent data storage, and logging your skill code will use during execution. At this time, there is one official deployment module called @litexa/deploy-aws (this one!), which is already set in the Litexa config for your convenience.

Installation

Run

npm install -g @litexa/deploy-aws

to install this package side by side with your litexa package. This will then let you specify @litexa/deploy-aws as a deployment module in any of your projects.

Authorization

AWS access is piped through the aws-sdk module (installed as a @litexa/deploy-aws node_module dependency), so all of its configuration mechanisms are supported , e.g. setting environment variables.

The simplest way to authorize AWS is to complete the aws-cli installation, and then use the profile name you set up in the awsProfile field in your Litexa config.

See: Installing the AWS CLI for more information.

You can alternatively provide credentials local to a particular project by creating a aws-config.json file in your project root containing the following credentials:

{
  "development": {
    "accessKeyId": "someAccessKeyId",
    "secretAccessKey": "theSecretAccessKeyForThatAccessKeyId",
    "region": "us-east-1"
  }
}

where development is the name of the deployment target you want this configuration for.

Implementation detail: If you have neither an awsProfile field in your Litexa config nor a local aws-config.json file, @litexa/deploy-aws will attempt to use the aws-cli profile named default.

Bear in mind you want to keep your aws-config file local though, you don't want to be sharing that with other people! We've generated a .gitignore for you that includes it, but if you use a different source code sharing solution, you may want to configure prevention on uploading this file.

There is one more thing you need to set up for authorization, and that is permissions. AWS permissions are bundled together in what's called a policy. A policy is then attached to your IAM user, which is the credentials that get used for deployment. To get that set up, go to the AWS Permissions section.

Diving Deeper on AWS Security

In the long run, it will be beneficial to follow secure credential management guidelines. For a starting point on what AWS security credentials are, you can begin here. For secure AWS credential management, you may consider reading Best Practices for Managing AWS Access Keys and IAM User-specific Credential Management.

AWS Configuration

This deploy module requires you to fill out one more field in your litexa config called s3Configuration.bucketName. There are also some optional LambdaConfiguration parameters you can put into your configuration for further project customization.

S3 Configuration

The deploy module uses S3 to host your skill's assets, which can be sounds and images. Assets are deployed to the S3 bucket with the name you put in the s3Configuration.bucketName field in your Litexa config.

If this bucket doesn't exist yet, the module will automatically create it for you. If you create your own bucket:

  • The bucket itself does not need to be marked public. Individual files will be marked public on upload.

  • The bucket does need to have default CORS correctly configured. See: Cross-Origin Resource Sharing (CORS)

Upload Parameters

You can specify S3 upload parameters to groups of your assets by utilizing the optional s3Configuration.uploadParams object list.

A Litexa config that utilizes s3Configuration.uploadParams might look like:

const deploymentConfiguration = {
  name: 'my-skill',
  deployments: {
    production: {
      module: '@litexa/deploy-aws',
      s3Configuration: {
        bucketName: 'my-skill-bucket',
        uploadParams: [
          {
            filter: ['*.mp3'],
            params: {
              // check for file change every 10 minutes
              // (useful for content files that are regularly updated)
              CacheControl: 'max-age=600'
            }
          },
          {
            filter: ['*.jpg', '*.png'],
            params: {
              // always check for file change
              // (useful during development)
              CacheControl: 'no-cache'
            }
          },
          {
            params: {
              // no file filter -> applies 1 hour age
              // to all files that aren't caught by the
              // above 2 filters
              CacheControl: 'max-age=3600'
            }
          }
        ]
      }
    }
  }
}

S3 Configuration Schema

The schema for the s3Configuration object is as follows:

  • bucketName - (String)
    • The name of the bucket that your assets are deployed to.
  • uploadParams - (Array<Object>) - Optional
    • filter - (Array<String>) - Optional
      • A list of glob patterns that, when matched to your assets, the upload params are applied to. Litexa uses the minimatch NPM package to implement the file pattern matching.
    • params - (Object)
      • An object that is passed into Litexa's call on the AWS SDK S3 Client's #upload() function.
        • To understand what keys are acceptable in the params object, read more about the AWS SDK S3 Client's #upload() function in the AWS SDK docs.

Tip: You can define default upload params. An uploadParams object that either has no filter specified, or includes a '*' filter, will be treated as a default set of upload parameters. All assets that do not match any other filters will use these params.

Tip: The order of upload params matters. Any uploadParams objects that are not default upload parameters (see above) are applied in order. This means that individual assets will be set to use the first, and only the first, matching filter's params.

Warning: You may not use the Key, Body, ContentType, and ACL keys. These keys are reserved by Litexa, so you may not use them as part of an uploadParams object. If you attempt to use them, the Litexa deployment process will fail.

Asset Deployment Location

Assets will be deployed to subdirectories of your bucket, isolating specific deployments of specific projects from each other, copying the contents of your litexa/assets folder to the following location:

https://s3.{REGION}.amazonaws.com/{BUCKETNAME}/{SKILLNAME}/{DEPLOYMENTTARGET}/

Note: Use one S3 bucket across your Litexa projects.

S3 bucket names are globally unique. This means that any AWS account cannot create a bucket of the same name as an existing bucket until it is deleted. Your AWS account also has a limit on the number of buckets you can create. See here for bucket restrictions and limitations.

Within this location, your assets will be organized by the locales in that folder, with the assets in the top level going into the default folder. So if you have a Litexa project named CatsVsCucumbers and you're deploying the development target, your project folder will look like this locally:

.
├── litexa
|   └── assets
|       ├── intro.mp3
|       ├── introScreen.jpg
|       └── en-GB
|           ├── intro.mp3
|           └── resultScreen.jpg

And your S3 bucket would look like this:

.
├── CatsVsCucumbers
|   └── development
|       ├── default
|       |   ├── intro.mp3
|       |   └── introScreen.jpg
|       └── en-GB
|           ├── intro.mp3
|           └── resultScreen.jpg

By default, Litexa will upload Alexa-usable files from your assets directory and ignore any file types it does not recognize. These files must have the file extensions: .png, .jpeg, .jpg, .mp3, .json, or.txt. Litexa extensions may add to that list.

Lambda Configuration (optional)

The @litexa/deploy-aws module deploys your skill to AWS Lambda. It sets a few defaults, but you are welcome to override these settings with your own in the Litexa config. Here is an example with all the supported Lambda configuration options:

{
  "deployments": {
    "development": {
      "module": "@litexa/deploy-aws",
      "s3Configuration": {
        "bucketName": "suncoast-assets"
      },
      "askProfile": "suncoast",
      "awsProfile": "prototyping",
      "lambdaConfiguration": {
        "MemorySize": 128,
        "Timeout": 240,
        "Environment": {
          "Variables": {
            "mySpecialVariable": 13
          }
        }
      }
    }
  }
}

The lambdaConfiguration object gets merged into the generated configuration that will be used to call Lambda's updateFunctionConfiguration. You can use this to modify the Lambda's timeout, change the memory size, or add your own environment variables. All sub keys are optional.

CloudWatch Logging

Litexa uses an environment variable called loggingLevel to determine what to log. In this deploy module, logs are recorded in CloudWatch Logs. There are 3 possible values you can set for this variable:

  • terse: This is the default setting. Will log the relevant part of the skill request and the full skill response.
  • verbose: Will log the full skill request and the full skill response.
  • (empty string): Will not log skill requests and responses.

See the Lambda Configuration section above for how to set this variable.

If you have any logging output in your litexa project though, those will still be logged to CloudWatch independently of this setting.

You can retrieve your logs via the litexa logs command for a specified deployment target. This will retrieve logs after the timestamp of the command itself. The deploy module will download your skill's CloudWatch Logs and format them as skill requests and responses. The downloaded logs will be available in the project's .logs/{DEPLOYMENTTARGET} directory.

Use the log command in development, not production

If your skill becomes popular, running litexa logs may produce very large log files of requests and responses happening in parallel. That may make it difficult to trace a single skill interaction. It may also cause a significant performance hit while it is running. We recommend using the command for when you are testing your skill on a device or the simulator instead.

It is safe (won't cause Litexa project issues) to delete the .logs directory and any files within.

For more information on the log command line interface, please run litexa logs --help.

Local Caching of Deployment Artifacts

A deployment will use a directory named after that deployment target inside the project's ephemeral .deploy directory to cache intermediate files before uploading, as well as additional files to aid in debugging deployed artifacts.

For speed, the local cache usually doesn't validate the contents of the .deploy directory, and builds incremental changes on top of it. If you have modified this directory in any way, deploy results are undefined.

Conversely, you can safely delete each deployment target directory inside the .deploy directory at any time; this module will detect the cache as empty and rebuild it as necessary. If you'd like to delete all deployment caches, you can also just delete the .deploy directory.

If you modify the contents of your Litexa config during development, Litexa will automatically wipe the .deploy and .test temporary directories to perform a clean deployment.

Extra Note: The production Deployment Target Name

There is a special deployment target name called production. For deployment targets that are not this, a \ (development) will be automatically appended to the name of your skill, with development specified as your named deployment target. We recommend creating and using this deployment target for your live skill.

Also:

We recommend changing the DynamoDB settings for your live skill to ensure that it does not throttle your skill's persistent storage read and writes, which would have an impact of added latency for your customers. Increasing the provisioned capacity units, enabling Auto Scaling, or switching the table to On-Demand capacity are all ways you can make your skill's experience more robust.

See DynamoDB Capacity Modes for more information.

Default AWS Settings

This module configures the following settings:

IAM

  • Creates an IAM role called litexa_handler_lambda for your Lambda to use. It has the policies: CloudWatchFullAccess, AmazonDynamoDBFullAccess, and AWSLambdaBasicExecutionRole.

DynamoDB

  • Provisioned read capacity units: 10 (Auto Scaling Disabled)
  • Provisioned write capacity units: 10 (Auto Scaling Disabled)
  • Primary key is a String called userId - the litexa module gives this the skill requests's context.System.device.deviceId field, by default.

Lambda

  • Creates/uses an alias, which is included as part of the skill endpoint
  • The deployment target's alias is set to point to $LATEST on every deployment
  • Memory size of 256 MB
  • 10 second timeout (maximum runtime)
  • Some environment variables related to your skill configuration
    • loggingLevel = terse

S3

  • If the litexa deploy command generates a bucket for you, it does so with all default settings.
  • Objects in the bucket will be marked public on upload.

CloudWatch Logs

  • If the Lambda's log group doesn't exist yet (will be the case for a newly-generated Lambda), it will create it and then apply a 30 day retention policy to it.

AWS Permissions

Your IAM user will require the following minimum permissions. You can create a custom policy to define these permissions and attach it to your user. There is a sample policy at the end you can use and modify for your own account.

IAM

The following permissions all apply to the role litexa_handler_lambda.

  • AttachRolePolicy
  • CreateRole
  • GetRole
  • ListAttachedRolePolicies
  • PassRole

Lambda

The following permissions all apply to the Lambda function name structure *_*_litexa_handler, where * is a wildcard.

  • AddPermission
  • CreateAlias
  • CreateFunction
  • GetAlias
  • GetFunctionConfiguration
  • GetPolicy
  • ListAliases
  • RemovePermission
  • UpdateFunctionCode
  • UpdateFunctionConfiguration

DynamoDB

The following permissions all apply to the DynamoDB table name structure *_*_litexa_handler_state, where * is a wildcard.

  • CreateTable
  • DescribeTable

S3

This permission automatically applies to all resources.

  • ListAllMyBuckets

The following permissions apply to the S3 bucket defined in the s3Configuration.bucketName field in your litexa.config.coffee/js/ts/json file.

  • CreateBucket
  • ListBucket

The following permissions apply to all objects in the S3 bucket defined in the s3Configuration.bucketName field in your litexa.config.coffee/js/ts/json file.

  • PutObject
  • PutObjectAcl

CloudWatch Logs

This permission applies to all Cloudwatch log groups.

  • DescribeLogGroups

This permission automatically applies to all resources.

  • CreateLogGroup

These permissions apply to CloudWatch log streams with the log group name structure *_*_litexa_handler, where * is a wildcard.

  • DescribeLogStreams
  • PutRetentionPolicy

This permission requires the above resource plus wildcards for the log stream and log stream name sections.

  • GetLogEvents

Minimum Permissions

Any resources with wildcards * can be replaced by the specific ARN, but the wildcards are practical for creating multiple Litexa projects in the same AWS account.

Sample Policy Document

Remember to replace myAccountId and myBucketName with your AWS account ID number and S3 bucket, respectively.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "IAMRole",
            "Effect": "Allow",
            "Action": [
                "iam:AttachRolePolicy",
                "iam:CreateRole",
                "iam:GetRole",
                "iam:ListAttachedRolePolicies",
                "iam:PassRole"
            ],
            "Resource": "arn:aws:iam::myAccountId:role/litexa_handler_lambda"
        },
        {
            "Sid": "Lambda",
            "Effect": "Allow",
            "Action": [
                "lambda:AddPermission",
                "lambda:CreateAlias",
                "lambda:CreateFunction",
                "lambda:GetAlias",
                "lambda:GetFunctionConfiguration",
                "lambda:GetPolicy",
                "lambda:ListAliases",
                "lambda:RemovePermission",
                "lambda:UpdateFunctionConfiguration",
                "lambda:UpdateFunctionCode"
            ],
            "Resource": "arn:aws:lambda:*:myAccountId:function:*_*_litexa_handler"
        },
        {
            "Sid": "DynamoDB",
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:DescribeTable"
            ],
            "Resource": "arn:aws:dynamodb:*:myAccountId:table/*_*_litexa_handler_state"
        },
        {
            "Sid": "CreateLogGroupListS3Buckets",
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "s3:ListAllMyBuckets"
            ],
            "Resource": "*"
        },
        {
            "Sid": "S3BucketActions",
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:ListBucket"
            ],
            "Resource": "arn:aws:s3:::myBucketName"
        },
        {
            "Sid": "S3BucketObjectActions",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::myBucketName/*"
        },
        {
            "Sid": "DescribeLogGroups",
            "Effect": "Allow",
            "Action": "logs:DescribeLogGroups",
            "Resource": "arn:aws:logs:*:myAccountId:log-group:*"
        },
        {
            "Sid": "LogStreamActions",
            "Effect": "Allow",
            "Action": [
              "logs:DescribeLogStreams",
              "logs:PutRetentionPolicy"
            ],
            "Resource": "arn:aws:logs:*:myAccountId:log-group:/aws/lambda/*_*_litexa_handler:log-stream:"
        },
        {
            "Sid": "GetLogEvents",
            "Effect": "Allow",
            "Action": "logs:GetLogEvents",
            "Resource": "arn:aws:logs:*:myAccountId:log-group:/aws/lambda/*_*_litexa_handler:*:*"
        }
    ]
}

Install

npm i @litexa/[email protected]

Version

0.5.0

License

Apache-2.0

Unpacked Size

139 kB

Total Files

24

Homepage

litexa.com

Last publish

Collaborators

  • avatar
  • avatar