AWS Media Blog

Using Amazon CloudFront and AWS Media Services

AWS Media Services are a group of managed services that make it easy to build reliable, broadcast-quality video workflows in the Cloud. These services create media suitable for streaming, both live and on-demand, and optimized for your viewers’ playback devices. In this post, I shall explain how you can deliver the content created with the AWS Media Services using Amazon CloudFront.

Amazon CloudFront is a global Content Delivery Network (CDN) that securely delivers web content to your users with low latency and high transfer speeds. CloudFront consists of over 120 Edge Locations located close to your viewers. CloudFront lowers the latency of delivering content using caching, request-collapsing and TCP optimization across Amazon’s global infrastructure. In addition, CloudFront includes Regional Edge Caches (RECs), located within most of our AWS regions, to provide features such as mid-tier caching.

Since the launch of AWS Media Services last year, we have seen our customers use them and CloudFront to inform and entertain their audiences, including TVNZ’s coverage of the 2018 Commonwealth Games, and Sky News’s coverage of the UK Royal Wedding.

We’ve recently added two new integrations between AWS Media Services and Amazon CloudFront:

  1. When creating AWS Elemental MediaPackage channels, you have the option to create a CloudFront distribution for distributing it to your users.
  2. You can select any of your AWS Elemental MediaPackage channels and AWS Elemental MediaStore containers as custom origins from the dropdown list within the CloudFront console.

As well as supporting the delivery of websites, web APIs and software downloads, CloudFront has long supported delivery of media content. CloudFront’s RTMP distributions support the RTMP protocol to deliver media on-demand to Adobe Flash applications. CloudFront’s Web distributions support progressive downloads and adaptive HTTP protocols such as HLS, DASH, CMAF and Smooth Streaming, using Amazon S3 or custom origins running streaming server applications. CloudFront has native support for On-Demand Smooth Streaming when the origin itself doesn’t have Smooth Streaming support (such as S3 or a static webserver). If the origin does support Smooth Streaming (such as AWS Elemental MediaPackage), CloudFront’s own support should not be enabled. For more information on configuring CloudFront for media delivery, see the documentation. In this post, I will be concentrating on the use of CloudFront’s Web distributions to deliver media.

I will describe the configuration necessary to use CloudFront to deliver streaming media, though I encourage you to consider configuring other CloudFront features that are applicable to all types of content delivery:

Deliver on-demand content using Amazon CloudFront

AWS Elemental MediaConvert is a file-based video processing service that formats and compresses media content. This content can be stored in your Amazon S3 bucket which can be configured as an origin for CloudFront.

  • Smooth Streaming output from MediaConvert can be delivered using CloudFront On-Demand Smooth Streaming.
  • With HLS’s and DASH’s ability to be served by standard HTTP services, the content can be served using CloudFront default configuration.
  • Other formats can be delivered by CloudFront using progressive downloads.

Deliver live content using Amazon CloudFront

For live content, CloudFront is configured to use a custom origin rather than an S3 one. There are three AWS media services that can act as origins for live content:

  1. AWS Elemental MediaStore is a media storage service and can be a CloudFront origin for your live streams.
  2. AWS Elemental MediaPackage is a media packaging and origination service that provides additional features to that of AWS Elemental MediaStore, including the ability to dynamically repackage content into multiple streaming protocols (such as HLS, DASH, CMAF and Smooth Streaming), protect content using Digital Rights Management (DRM) and add time-shifting features like start-over and catch-up TV for the end users.
  3. AWS Elemental MediaTailor is a media personalization and monetization service. It takes the content from another origin service (such as AWS Elemental MediaStore, AWS Elemental MediaPackage or a third-party streaming server) and integrates with an Ad Decision Server (ADS) to insert advertisements tailored to the viewer.

For all three services, you need a transcoder to encode the live media streams into the various codecs, bitrates, and resolutions so that the player can optimize. AWS Elemental MediaLive is a live media transcoding service that can be used to deliver the encoded media to these services. In preparation for this blog post, I used the instructions detailed in this blog post to set up OBS Studio to feed a live stream into an AWS Elemental MediaLive channel. I will now describe how to configure AWS Elemental MediaStore, AWS Elemental MediaPackage and CloudFront to deliver live content.

Deliver live content with AWS Elemental MediaStore and Amazon CloudFront

In this section, I will configure AWS Elemental MediaStore as an origin for Amazon CloudFront, using the ‘Custom’ origin type.

First, I go to the AWS Elemental MediaStore console and create a new container – I will call it ‘blogdemo’.

After a few minutes, the container is ready and I select it from the list. I make a note of the ‘Data Endpoint’ found in the ‘Info’ section – for my container, it’s https://suiv5ajqn2gown.data.mediastore.eu-west-1.amazonaws.com.

Each AWS Elemental MediaStore container has an IAM resource policy, similar to S3 bucket policies. And just like S3 buckets, AWS Elemental MediaStore containers are private by default so I need to edit the policy to allow CloudFront to retrieve objects from it. I will use a custom origin type for my AWS Elemental MediaStore container but, unlike S3 origins, I can’t use an Origin Access Identity to configure access to a custom origin. Therefore, I use IAM Policy Conditions to require a shared secret to be passed by CloudFront on each request to AWS Elemental MediaStore. I edit the container policy to allow public access but I also set an IAM Condition that the HTTP User-Agent header must have the value of a shared secret (in this case, I generated the random text string 749DY68208KU77OOAAUJ). The container policy is shown below with additional statement in bold. If you copy this statement, please edit for your container’s resource ARN – and your shared secret!


{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "MediaStoreFullAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:root"
      },
      "Action": "mediastore:*",
      "Resource": "arn:aws:mediastore:eu-west-1:123456789012:container/blogdemo/*",
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "true"
        }
      }
    },
    {
      "Sid": "CloudFrontRead",
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "mediastore:GetObject",
        "mediastore:DescribeObject"
      ],
      "Resource": "arn:aws:mediastore:eu-west-1:123456789012:container/blogdemo/*",
      "Condition": {
        "StringEquals": {
          "aws:UserAgent": "749DY68208KU77OOAAUJ"
        },
        "Bool": {
          "aws:SecureTransport": "true"
        }
      }
    }
  ]
}

With my AWS Elemental MediaStore container configured, I now go to the CloudFront console, click ‘Create Distribution’, then ‘Get Started’ under the description of Web distributions. On the ‘Create Distribution’ page, I select the container’s domain name from ‘MediaStore Containers’ section in the dropdown that appears when I click on the ‘Origin Domain Name’ textbox (suiv5ajqn2gown.data.mediastore.eu-west-1.amazonaws.com). I set the Origin Protocol Policy to be HTTPS Only and specify an Origin Custom Header with the name User-Agent and value 749DY68208KU77OOAAUJ – my shared secret! I then click ‘Create Distribution’.

In order to reduce the load on an origin, CloudFront by default caches 4xx and 5xx error responses for five minutes. Some media players may attempt to request media segments before they are available on the live streaming origin. If the content is not yet available, the origin will return an HTTP 404 “Not Found” status and the player will typically repeat the request a few moments later. CloudFront’s default five-minute caching of the 404 response could cause playback issues since it will return that cached response to the player for some time after the segment becomes available. Therefore, I will configure CloudFront’s “Error Caching Minimum TTL” to a lower value. I select my distribution in the console and select the ‘Error Pages’ tab and click ‘Create Custom Error Response’. I select ‘404: Not Found’ for the HTTP Error Code, 1 second for ‘Error Caching Minimum TTL’ and click ‘Create’.

This has completed the configuration of the AWS Elemental MediaStore container and CloudFront distribution and I can now deliver my live stream to end users via CloudFront. The live stream I deliver into my AWS Elemental MediaStore container has the name blogdemo/live.m3u8, the CloudFront domain name is d3nyydyvkfisf9.cloudfront.net so the URL for playback is https://d3nyydyvkfisf9.cloudfront.net/blogdemo/live.m3u8.

Deliver live content with AWS Elemental MediaPackage and Amazon CloudFront

AWS Elemental MediaPackage provides just-in-time package and DVR-like features as well as origination for live video streams. The output endpoint of an AWS Elemental MediaPackage channel can be HLS, DASH, CMAF or Smooth Streaming, all delivered over HTTP.

I go to the Elemental MediaPackage console and create a new channel:

I create my channel blogdemo and configure endpoints for DASH, Smooth Streaming and HLS, and reconfigure my AWS Elemental MediaLive channel to deliver content to it.

While I’m creating the MediaPackage channel, the easiest option is to create a CloudFront distribution at the same time.

Once the CloudFront distribution has been created (it usually takes a few minutes), the MediaPackage console provides details of the channel’s CloudFront distribution and its endpoints’ CloudFront URLs when clicking ‘Show CloudFront URL’.

But what if I don’t want MediaPackage to create my CloudFront distribution? Perhaps I created my channel or distribution before this feature was available, or I prefer to create the distribution myself with my own parameters; or perhaps I want to integrate multiple origins into the same distribution (for example, the webserver hosting static content for my website). In that case, I can just create a MediaPackage channel without creating a CloudFront distribution.

When I do that, my channel’s endpoints have MediaPackage URLs only, without CloudFront URLs associated to them:

All of the endpoints have the same domain name, c223d9abb67d57c7.mediapackage.eu-west-1.amazonaws.com, so I only need to create a single origin in my CloudFront distribution and use the default CloudFront cache behavior to forward requests to it.

I create a CloudFront Web Distribution similar to the one I did for MediaStore earlier. I select the endpoint’s domain name from the ‘MediaPackage Origins’ section in the dropdown that appears when I click on the ‘Origin Domain Name’ textbox and select HTTPS Only.

By default, CloudFront does not forward the query string of a request to the origin. As MediaPackage uses the query string values ‘m’, ‘start’ and ‘end’, I configure CloudFront to forward these and click the ‘Create Distribution’ button at the bottom.

I configure the distribution’s custom error responses to set a low caching TTL for 404 errors, as described for the earlier distribution I created for MediaStore.

MediaPackage controls access by restricting IP address via a whitelist, so you have the possibility to restrict access to the IP addresses used by CloudFront. These IP addresses are published in the JSON file that is updated regularly – be sure to update the IP access of your AWS Elemental MediaPackage channel when the JSON file is updated. See AWS IP Address Ranges for more information.

This has completed the configuration of the AWS Elemental MediaPackage channel and CloudFront distribution and I can now deliver my live stream to end users via CloudFront using its domain name. For example, the DASH endpoint is now available via CloudFront by substituting the channel’s domain name for that of the distribution – https://dq3czjb5i9win.cloudfront.net/out/v1/5f0bf817ce1f4ac7846f9fad427b15f2/index.mpd.

About Cross-Origin Resource Sharing (CORS)

Most web browsers restrict a web page hosted on one ‘origin’ from accessing content on another ‘origin’. In this context, ‘origin’ means a website (the URL’s scheme and authority, such as https://www.test.com, to be precise) not a CDN origin. Many browsers support Common Origins Resource Sharing (CORS) which provides the referenced origin owner a mechanism to allow access.

If you host both the player web page and your media streams on the same domain, CORS is not required. You can use a single CloudFront distribution to do exactly this by configuring multiple CloudFront origins for the web content (using either a fleet of webservers behind a load balancer or an S3 bucket) and for the media content.

If you do require to support multiple referencing CORS origins – for example, you syndicate your content across sites – you can use the CORS features built into our services.

  • Both S3 and AWS Elemental MediaStore support the configuration of CORS policies on buckets and containers – see the documentation for S3 and AWS Elemental MediaStore for more details.
  • Elemental MediaPackage supports CORS by default. It will return an ‘Access-Control-Allow-Origin’ HTTP response header set to the request’s ‘Origin’ header value if it is set, or to ‘*’ if not.

You need to configure CloudFront to respect the CORS configuration by following these instructions. If you want to restrict access to content from specific CORS origins, you can utilize AWS WAF to deny access unless those CORS origins are specified in HTTP request’ headers.

Summary

In this post, I have described the necessary configurations to use Amazon CloudFront to securely deliver your streaming media content created by AWS Media Services.