Deploying and Running an App on S3 and CloudFront Using Terraform - Explore

S3
CloudFront
Terraform
AWS and CDN
Deploying and Running an App on S3 and CloudFront Using Terraform

by: Ashish Sharma

January 02, 2025

titleImage

Introduction

This blog provides a comprehensive guide on how to deploy and host a web application on AWS using a private S3 bucket and CloudFront, leveraging Terraform for infrastructure automation. The private S3 bucket securely stores your application files, while CloudFront acts as a Content Delivery Network (CDN) to serve your application globally with low latency.

Additionally, the guide covers integrating CI/CD pipelines to automate deployments, ensuring that updates to your application are seamless and efficient. This process not only simplifies deployment but also enforces security best practices by using a private S3 bucket, access-controlled CloudFront distribution, and automated workflows to prevent human errors.

By the end of this guide, you’ll have a secure and scalable infrastructure for your web application, complete with error handling, geo-restrictions, and an automated deployment process that aligns with modern DevOps practices.


Folder Structure

Here is the folder structure used in this setup:

provisioning/
├── common/
│   ├── locals.tf
│   ├── main.tf
│   ├── variables.tf
├── dev/
│   ├── main.tf
│   ├── provider.tf
│   ├── state.tf
│   ├── variables.tf
  • common/: Contains reusable Terraform modules and shared configuration.
  • dev/: Environment-specific configurations for development.

Step 1: S3 Bucket and CloudFront Setup

Terraform Code: common/main.tf

resource "aws_s3_bucket" "app" {
  bucket = local.s3_bucket_name

  tags = merge(local.tags, {
    Name = local.s3_bucket_name
  })
}

resource "aws_s3_bucket_ownership_controls" "app" {
  bucket = aws_s3_bucket.app.id
  rule {
    object_ownership = "BucketOwnerPreferred"
  }
}

resource "aws_s3_bucket_acl" "app" {
  depends_on = [aws_s3_bucket_ownership_controls.app]
  bucket = aws_s3_bucket.app.id
  acl    = "private"
}

resource "aws_s3_bucket_policy" "app_bucket_policy" {
  bucket = aws_s3_bucket.app.id

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowCloudFrontAccess",
      "Effect": "Allow",
      "Principal": {
        "Service": "cloudfront.amazonaws.com"
      },
      "Action": "s3:GetObject",
      "Resource": "${aws_s3_bucket.app.arn}/*",
      "Condition": {
        "StringEquals": {
          "AWS:SourceArn": "arn:aws:cloudfront::${var.account_id}:distribution/${aws_cloudfront_distribution.cf_distribution.id}"
        }
      }
    }
  ]
}
EOF
}

CloudFront Distribution

resource "aws_cloudfront_distribution" "cf_distribution" {
  origin {
    domain_name = aws_s3_bucket.app.bucket_regional_domain_name
    origin_id   = local.s3_origin_id

    s3_origin_config {
      origin_access_identity = aws_cloudfront_origin_access_identity.oai.cloudfront_access_identity_path
    }
  }

  enabled             = true
  default_root_object = "index.html"

  default_cache_behavior {
    allowed_methods        = ["GET", "HEAD"]
    cached_methods         = ["GET", "HEAD"]
    target_origin_id       = local.s3_origin_id
    viewer_protocol_policy = "redirect-to-https"
  }

  viewer_certificate {
    acm_certificate_arn = var.certificate_arn
    ssl_support_method  = "sni-only"
  }

  custom_error_response {
    error_code         = 403
    response_code      = 200
    response_page_path = "/index.html"
  }
}

Step 2: Environment-Specific Configuration

dev/main.tf

module "s3_cloudfront" {
  source        = "../common"
  environment   = "dev"
  s3_bucket_name = "myapp-dev-bucket"
  certificate_arn = "arn:aws:acm:region:account-id:certificate/certificate-id"
}

dev/provider.tf

provider "aws" {
  region  = "us-east-1"
  profile = "default"
}

Step 3: Deploy the Terraform Infrastructure

  1. Navigate to the Dev Folder:

    cd provisioning/dev
  2. Initialize Terraform:

    terraform init
  3. Plan the Deployment:

    terraform plan
  4. Apply the Configuration:

    terraform apply

Step 4: Setting Up CI/CD

GitHub Actions Workflow for CI/CD

Create a .github/workflows/deploy.yml file:

name: Deploy to AWS S3 and CloudFront

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Deploy Terraform
        run: |
          cd provisioning/dev
          terraform init
          terraform apply -auto-approve

Step 5: Test the Deployment

  1. Upload Files to S3:

    • Use the AWS CLI to upload your web app files to the private S3 bucket:
      aws s3 cp ./build s3://myapp-dev-bucket/ --recursive
  2. Access the Application:

    • Open the CloudFront distribution domain name in the browser.

Key Features

  1. Private S3 Bucket:

    • Ensures your files are secure and accessible only via CloudFront.
  2. Custom Error Pages:

    • Routes 403/404 errors to index.html.
  3. Geo-Restrictions:

    • Limits access to specific countries.
  4. CI/CD Integration:

    • Automates deployment with GitHub Actions.

**Conclusion

In this guide, we explored the complete process of deploying a web application using a private S3 bucket and CloudFront, with Terraform as the infrastructure-as-code tool. By combining these powerful AWS services, you can securely store your application files in an S3 bucket while leveraging CloudFront to deliver them efficiently to users across the globe.

We also integrated CI/CD pipelines using GitHub Actions, enabling seamless deployments and reducing manual intervention. This setup not only streamlines your deployment process but also enforces security and scalability, which are critical for modern web applications.

With these steps, you now have a robust, secure, and automated infrastructure ready to host your web applications. Whether you're deploying a small-scale project or a large enterprise app, this approach ensures best practices in security, efficiency, and ease of maintenance.

Start deploying your application confidently, and take advantage of AWS and Terraform to build scalable solutions!

contact us

Get started now

Get a quote for your project.
logofooter
title_logo

USA

Edstem Technologies LLC
254 Chapman Rd, Ste 208 #14734
Newark, Delaware 19702 US

INDIA

Edstem Technologies Pvt Ltd
Office No-2B-1, Second Floor
Jyothirmaya, Infopark Phase II
Ernakulam, Kerala 682303
iso logo

© 2024 — Edstem All Rights Reserved

Privacy PolicyTerms of Use