Secure AWS Video Streaming With HLS and CloudFront

- Serving an MP4 directly from S3 does not provide adaptive bitrate streaming.
- HLS divides a video into small segments and creates multiple quality variants.
- AWS Elemental MediaConvert can generate the HLS segments and playlists.
- The output S3 bucket should remain private.
- CloudFront should deliver the video instead of exposing S3 URLs.
- Signed cookies are generally more suitable than signed URLs for HLS because a stream contains many files.
- HLS encryption protects the segments, but it should not be confused with a complete DRM system.
- No browser-based streaming setup can guarantee that authorized viewers will never capture the content.
Streaming video directly from Amazon S3 sounds straightforward: upload an MP4 file, retrieve its URL, and give that URL to the video player.
That was our initial approach when we built an on-demand video platform for a client at F22 Labs. However, our first test revealed two problems: the application downloaded the entire video before playing it, and anyone who discovered the S3 URL could download the original file.
We needed a better setup that could:
- Adapt the video quality to the viewer’s internet connection.
- Prevent users from accessing the original video through a public S3 URL.
- Restrict video playback to authorized users.
- Keep the infrastructure reasonably simple and cost-effective.
Our original implementation used Amazon Elastic Transcoder. AWS discontinued that service on November 13, 2025, so new projects should use AWS Elemental MediaConvert instead. This article explains the architecture we used, what we learned, and how the same workflow should be implemented today.
Why Directly Streaming an MP4 From S3 Did Not Work
For our first test, we stored the original MP4 file in an S3 bucket and passed its URL to an iOS video player.
Instead of beginning playback progressively, the test application downloaded the complete two-minute video. Playback started only after the download had finished, which took approximately one minute.
The setup also exposed the source file. Anyone who obtained the MP4 URL through browser developer tools, application logs, or network inspection could reuse it to download the video.
The problem was not S3 itself. S3 is an object storage service, not a complete adaptive streaming solution. We needed to package the video in a format designed for streaming.
How HLS Video Streaming Works
HTTP Live Streaming, or HLS, divides a video into a sequence of smaller media segments. A video player downloads these segments as they are needed instead of downloading one large MP4 file before playback.
A typical HLS package contains:
- Several copies of the video encoded at different resolutions and bitrates.
- Small media segments for each quality level.
- A variant playlist for every rendition.
- A master playlist that references all available renditions.
For example, the output could contain 1080p, 720p, 480p, and 360p versions of the same video. If the viewer’s internet connection becomes slower, the player can switch to a lower-bitrate rendition. When the connection improves, it can move back to a higher-quality version.
The master playlist normally uses the .m3u8 extension. It tells the player which quality levels are available and where their corresponding playlists can be found.
This process is known as adaptive bitrate streaming.
Our AWS Video Streaming Architecture
The original project used Elastic Transcoder, S3, HLS encryption, and CloudFront. The modern equivalent uses the following AWS services:
- Amazon S3 stores the original and processed video files.
- AWS Elemental MediaConvert converts the original video into multiple HLS renditions.
- Amazon CloudFront delivers the playlists and video segments.
- CloudFront signed cookies or signed URLs restrict access to authorized viewers.
- AWS IAM controls which services can read from and write to the S3 buckets.
The application authenticates the viewer before granting temporary access to the CloudFront distribution.
Step 1: Create the S3 Buckets
Start by creating separate S3 buckets, or clearly separated prefixes within a bucket, for:
- Original uploaded videos
- Transcoded HLS output
- Generated thumbnails
Keeping the original and processed content separate makes access control, lifecycle management, and cleanup easier.
The buckets should not be publicly accessible. Enable S3 Block Public Access and allow MediaConvert and CloudFront to access only the resources they require.
For CloudFront, use Origin Access Control so viewers cannot bypass CloudFront and request the files directly from S3.
Step 2: Upload the Source Video
Upload the original video to the input location in S3.
For a production application, this process can be automated. A backend service can generate a presigned upload URL, allowing the client to upload the video without receiving permanent AWS credentials.
Build, Scale, and Optimize on AWS
We design, build, and manage scalable cloud solutions on AWS, secure, cost-efficient, and ready to grow with your business.
An S3 event, Amazon EventBridge event, or application request can then start the transcoding workflow.
Step 3: Create a MediaConvert IAM Role
MediaConvert requires an IAM service role that allows it to:
- Read the source video from the input bucket.
- Write playlists, segments, and thumbnails to the output bucket.
- Access encryption resources when encryption is enabled.
- Publish relevant job events or metrics when required.
Follow the principle of least privilege. Avoid granting access to every S3 bucket in the account when the job only needs access to two specific locations.
Step 4: Create a MediaConvert Job
Open AWS Elemental MediaConvert and create a new job.
Select the uploaded S3 video as the input. Then add an Apple HLS output group and enter the S3 destination where the processed files should be stored.
MediaConvert creates a master HLS manifest for the output group and adds the selected video renditions to it.
Step 5: Configure Multiple Video Renditions
Create several outputs for different network conditions and devices.
A practical ladder could include:
| Resolution | Approximate bitrate | Suitable for |
| 1080p | 4–6 Mbps | Large screens and fast connections |
| 720p | 2–3 Mbps | Standard broadband playback |
| 480p | 1–1.5 Mbps | Mobile and moderate connections |
| 360p | 500–800 Kbps | Slow or unstable connections |
These are starting points rather than universal settings. The appropriate bitrate depends on the content, frame rate, codec, target devices, and expected visual quality.
For example, a screen recording with little movement may require less bandwidth than a sports video at the same resolution.
Step 6: Configure HLS Segments and Playlists
MediaConvert packages each rendition into media segments and generates the necessary HLS manifests.
Shorter segments can help the player react more quickly to changes in bandwidth, but they also create more files and requests. Longer segments reduce request volume but may make switching between quality levels slower.
Our Elastic Transcoder implementation used 10-second segments. For a new workflow, test the segment duration against your playback requirements rather than assuming one value will suit every application.
After the job finishes, the output location should contain:
- A master
.m3u8playlist - One or more variant playlists
- The corresponding media segments
- Optional thumbnail files
Your player should load the master playlist, not an individual rendition.
Step 7: Add Content Encryption Where Required
HLS content can be encrypted so that the downloaded segments cannot be played without the required key.
However, encryption alone does not decide who should receive the key. The key endpoint and authorization flow must also be protected. If both the encrypted segments and decryption key are publicly available, encryption provides little practical protection.
It is also important to distinguish HLS AES encryption from full Digital Rights Management. Services such as Apple FairPlay, Google Widevine, and Microsoft PlayReady provide stronger licence-based controls for supported platforms.
Use proper DRM when your licensing agreements or business model require more than basic access protection.
Step 8: Deliver the Stream Through CloudFront
Create a CloudFront distribution with the private output bucket as its origin.
Configure the distribution so that:
- Viewers access the files through CloudFront.
- Direct requests to the S3 origin are blocked.
- HTTPS is enforced.
- The correct content types are returned for playlists and segments.
- Caching behaviour matches the way your application publishes videos.
CloudFront reduces the distance between viewers and the video files by caching content at edge locations. It also provides the access-control layer needed to keep the HLS files private.
Step 9: Protect the Stream With Signed Access
A private S3 bucket does not automatically mean that only authenticated application users can watch the video. CloudFront must also verify that each viewer is authorized.
CloudFront supports signed URLs and signed cookies.
A signed URL works well when access must be granted to one specific file. HLS playback, however, normally requests a master playlist, one or more variant playlists, and many media segments.
For that reason, signed cookies are often the better option for HLS. They can authorize access to a group of files under a path without modifying every URL inside the playlists.
A typical request flow looks like this:
- The viewer signs in to the application.
- The backend verifies that the viewer can access the requested video.
- The backend creates short-lived CloudFront signed cookies.
- The browser requests the HLS playlist through CloudFront.
- CloudFront validates the cookies before returning the playlist and segments.
- Access expires automatically after the configured period.
CloudFront recommends trusted key groups for managing the public keys used to validate signed requests.
What This Setup Can and Cannot Protect
This architecture provides meaningful access control:
- The original S3 objects are not public.
- The HLS files are delivered only through CloudFront.
- Access can expire after a short period.
- URLs copied without the required signature or cookies will not work.
- Encryption can prevent raw segments from playing without a key.
Build, Scale, and Optimize on AWS
We design, build, and manage scalable cloud solutions on AWS, secure, cost-efficient, and ready to grow with your business.
However, describing the content as “impossible to download” would be inaccurate.
An authorized viewer’s device must eventually receive and decode the media to display it. A determined user may still capture the screen, inspect playback requests, or use compromised client software.
The realistic goal is to prevent casual downloading, block unauthorized access, reduce URL sharing, and make large-scale scraping more difficult. Stronger content protection requires a supported DRM system alongside application-level authorization.
Suggested read: How to Analyse Documents Using AWS Services
What Happened to Amazon Elastic Transcoder?
Our initial implementation used Amazon Elastic Transcoder because it could create multiple HLS outputs, generate a master playlist, and apply HLS content protection.
AWS ended support for Elastic Transcoder on November 13, 2025. Its console and resources are no longer available, so the original step-by-step console instructions cannot be followed today.
AWS now recommends Elemental MediaConvert for file-based transcoding workflows and provides migration guidance for converting Elastic Transcoder presets and pipelines.
If you still have an old architecture document or codebase that references Elastic Transcoder, treat it as a migration task rather than attempting to recreate the original pipeline.
Final Thoughts
Our first attempt taught us an important lesson: uploading an MP4 to S3 is not the same as building a video-streaming system.
HLS solved the playback problem by dividing the video into segments and providing several bitrate options. MediaConvert now handles the transcoding and packaging, while CloudFront provides efficient delivery and temporary access control.
For a modern AWS video-on-demand workflow, the practical foundation is:
Private S3 storage + MediaConvert HLS output + CloudFront delivery + signed access + optional encryption or DRM.
This does not make video piracy impossible, but it offers a considerably safer and more reliable solution than exposing the original MP4 file.
Frequently Asked Questions
Can Amazon S3 stream video directly?
S3 can serve video files over HTTP, but it does not automatically create adaptive bitrate streams. For HLS playback, the source video must first be transcoded and packaged into playlists and media segments.
What replaced Amazon Elastic Transcoder?
AWS Elemental MediaConvert is the recommended replacement for Elastic Transcoder. It supports file-based video processing, multiple output formats, HLS packaging, automated bitrate selection, captions, and content-encryption integrations.
What is adaptive bitrate streaming?
Adaptive bitrate streaming provides multiple versions of a video at different quality levels. The player automatically switches between them according to the viewer’s available bandwidth and playback conditions.
Should I use CloudFront signed URLs or signed cookies for HLS?
Signed cookies are generally more convenient because HLS playback requests multiple playlists and media segments. One cookie policy can authorize access to all files associated with a particular video path.
Does HLS encryption prevent video downloads?
It prevents encrypted segments from playing without the appropriate key, but it cannot completely stop an authorized viewer from capturing content. Stronger protection requires carefully secured keys and, when necessary, a DRM platform.
Is CloudFront required for HLS streaming?
No, but it improves global delivery, caching, and access control. It also allows you to keep the underlying S3 bucket private and provide temporary access through signed URLs or signed cookies.



