In this project, we will deploy an on-demand video streaming platform utilizing AWS services and infrastructure automation with Terraform. The solution will incorporate AWS Route 53 for DNS management, CloudFront as a Content Delivery Network (CDN) to optimize content delivery, AWS Certificate Manager for SSL certificates, and Amazon S3 for video file storage. The following diagram outlines the infrastructure architecture that will be implemented.
Prerequisites:
- Domain name
- Knowledge of Terraform
Note: Before we move forward, make sure you have Terraform set up on your local machine, including the necessary provider, and that you’ve initialized your project. If you’re all set, let’s get started!
1. Register a domain on route53
First, log into the AWS Management Console and head over to the Route 53 service. From there, find the “Registered Domains” section and click on “Register Domain.”
Type in the domain name you want and check its availability. If it’s available, just fill in your details, and AWS will email you a verification link. Once verified, your new domain should be ready within a few minutes to an hour.
2. Create some variables
Let's create a vars.tf file and add some variables to it which will be used by other resources.
vars.tf
variable "domain" {
type = string
default = "your-domain.com"
}
variable "cloudfront_priceClass" {
type = string
default = "PriceClass_100"
}
variable "environment" {
type = string
default = "dev"
}
3. Create the S3 bucket
Next, we need to create an S3 bucket to store our video or videos we wanna serve to our users. In your text editor, create a S3.tf file where our S3 configuration is going to be written.
# Create an S3 bucket
resource "aws_s3_bucket" "video_bucket" {
bucket = "kemzzy-new-video-bucket"
tags = {
Name = "Video bucket"
}
}
# Enable versioning
resource "aws_s3_bucket_versioning" "video_bucket_versioning" {
bucket = aws_s3_bucket.video_bucket.id
versioning_configuration {
status = "Enabled"
}
}
This creates our bucket and also enables versioning on it.
4. Upload a video to the S3 bucket
Next we upload our video to the created S3 bucket
# replace with the path to the video you want to upload
resource "aws_s3_object" "new_video" {
bucket = aws_s3_bucket.video_bucket.id
key = "awesome-video"
source = "path-to-your-video-file"
etag = filemd5("path-to-your-video-file")
content_type = "video/mp4"
depends_on = [aws_s3_bucket.video_bucket]
}
make sure to upload a mp4 video format otherwise you might have an issue (Speaking from personal experience )
5. Create and verify a SSL certificate with ACM
In other to use our domain with cloudfront we need a domain with SSL enabled. You can use the following terraform config to create and validate your SSL certificate for your domain.
Create an ACM certificate
resource "aws_acm_certificate" "video_cert" {
domain_name = var.domain
validation_method = "DNS"
lifecycle {
create_before_destroy = true
}
}
# Cert validation
resource "aws_acm_certificate_validation" "validate_cert" {
certificate_arn = aws_acm_certificate.video_cert.arn
validation_record_fqdns = [for record in aws_route53_record.certificate_validation : record.fqdn]
depends_on = [ aws_route53_record.certificate_validation ]
}
# create a record to use for validation
resource "aws_route53_record" "certificate_validation" {
for_each = {
for dvo in aws_acm_certificate.video_cert.domain_validation_options : dvo.domain_name => {
name = dvo.resource_record_name
record = dvo.resource_record_value
type = dvo.resource_record_type
}
}
allow_overwrite = true
name = each.value.name
records = [each.value.record]
ttl = 60
type = each.value.type
zone_id = aws_route53_zone.primary.zone_id
depends_on = [ aws_acm_certificate.video_cert ]
}
6. Create a CloudFront origin access identity
Now we can proceed to create our OAI for our cloudfront distribution. Create another file called main.tf
resource "aws_cloudfront_origin_access_identity" "cloudfront_OAI" {
comment = "OAI for video streaming S3 bucket"
}
Great, now that we’ve tackled that part, let’s move on to creating our CloudFront distribution!
resource "aws_cloudfront_distribution" "s3_distribution" {
origin {
domain_name = aws_s3_bucket.video_bucket.bucket_regional_domain_name
origin_id = aws_s3_bucket.video_bucket.id
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.cloudfront_OAI.cloudfront_access_identity_path
}
}
enabled = true
is_ipv6_enabled = true
comment = "play video"
aliases = [var.subdomain]
default_cache_behavior {
allowed_methods = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.video_bucket.id
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "allow-all"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
}
price_class =var.cloudfront_priceClass
restrictions {
geo_restriction {
restriction_type = "none"
locations = []
}
}
tags = {
Environment = var.environment
}
viewer_certificate {
acm_certificate_arn = data.aws_acm_certificate.cert.arn
ssl_support_method = "sni-only"
}
}
6. Access the video through the CloudFront distribution
To set this up, we’ll create a bucket policy that restricts read access exclusively to our CloudFront service. This setup adds a layer of security by making sure users can only access content through CloudFront, not directly from the bucket. Simply add this policy to your *s3.tf * file.
# Bucket policy to allow read access from CloudFront and prevent direct access to our bucket
resource "aws_s3_bucket_policy" "video_stream" {
bucket = aws_s3_bucket.video_bucket.id
policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowLegacyOAIReadOnly",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity ${aws_cloudfront_origin_access_identity.cloudfront_OAI.id}"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::${aws_s3_bucket.video_bucket.bucket}/*"
}
]
}
POLICY
}
7. Create an outputs file to get your outputs (optional)
Create an output.tf file and add these outputs
output "cloudfront_url" {
value = aws_cloudfront_distribution.s3_distribution.domain_name
}
output "domain_url" {
value = aws_route53_record.video_subdomain.name
}
8. Deploy your infrastructure
Phew! That was a journey, but you’ve made it to the finish line. Now, it’s time to bring your project to life! Run terraform validate
to check for any issues, then use terraform plan -out="tfplan"
to generate a plan, and finally, terraform apply "tfplan"
to deploy your infrastructure to AWS.
Now, to watch the video, just use your domain name, like your-domain.com/awesome-video, or the CloudFront URL provided in the output. Enjoy!
Conclusion
Congratulations on completing this tutorial. Make sure your you run terraform destroy
when you are done to avoid accumulating any bills.