Navy Boards

Navy Boards

Developing Narrative
Experiences for
Amazon Alexa

© 2020

How To Configure Presigned URLs (for S3) With Python How To Configure Presigned URLs (for S3) With Python - Adventures In Developing For Alexa

How To Configure Presigned URLs (for S3) With Python

This is a very quick wrap-up post because this took me a LOT of time yesterday to sort out. I couldn’t find a single place containing all information necessary, and it’s one of those border areas where log files just don’t really exist to help when things aren’t working.

What are presigned URLs?

First things first - you want to use presigned URLs with AWS Lambda functions for Alexa skills because they grant temporary access via a special URL to assets in S3. This means that your files in S3 don’t need to be accessible to the public. Security is good.

How do you make them work?

There’s actually only a few steps required. Here we go.

1. Configure the policy for your Lambda function

Your AWS Lambda function needs to have the appropriate privileges in order to be able to create a presigned URL. There’s very thorough documentation for this process on Amazon’s support site.

2. Generate the URL using the AWS client

def create__presigned_url(object_name):
  """Generate a presigned URL to share an S3 object with a capped expiration of 60 seconds

  :param object_name: string
  :return: Presigned URL as string. If error, returns None.
  """
  s3_client = boto3.client('s3')
  try:
      response = s3_client.generate_presigned_url('get_object',
                                                  Params={'Bucket': 'pointandclick',
                                                          'Key': object_name},
                                                  ExpiresIn=60*10)
      logger.debug("URL is '{}'".format(response))
  except ClientError as e:
      logging.error(e)
      return None

Important things to call out here:

s3_client = boto3.client('s3')

  • This line is super-important! There’s likely a lot of nuance behind the reason for additional parameters, but I lost a lot of time to using a code-snippet that supplied additional and un-needed parameters for the instantiation of the client.
  • I’ve supplied the name of the bucket I’m using as a hard-coded value here, but going forward it’ll likely be changed to an environment variable for the Lambda function (to provide more elegant reuse)
  • I’ve set the duration for the URL to be 10 minutes as a default, and am generating the URL each time. Going forward I’d look at implementing a cache of some sort to avoid generating URLs for every request. Partially for performance, and partially because AWS has a limit on the number of presigned URLs allowed for an individual resource.

3. Escaping the URL

The last step. This code will see you right:

html.escape(audio_url)

That’s it! Not a lot of steps, but getting them wrong leads to cryptic errors akin to Alexa just not wanting to eat vegetables because of the look of them. There may be more elaborate tools for getting diagnostics back from Alexa in those cases, and if so, I look forward to discovering them.

Let me know if this ends up saving you from grief in your own Alexa journeys!

Tags: