Skip to content

cloudposse-examples/app-cloudfront-s3

Repository files navigation

app-cloudfront-s3

Latest ReleaseSlack CommunityGet Support

Example static Single Page Application (SPA) deployed to AWS S3 and CloudFront.

Introduction

  • S3 for storing static assets
  • CloudFront for global CDN distribution
  • ACM for SSL/TLS certificates
  • Route53 for DNS management
  • Atmos for infrastructure configuration management
  • OpenTofu for infrastructure as code

Usage

Static App Deployment System

A deployment system for static web applications using GitHub Actions, Atmos, and OpenTofu for automated deployment across multiple environments.

Architecture Overview

This system provides a complete CI/CD pipeline for deploying static web applications to AWS using:

  • GitHub Actions: Automated workflows for building and deploying static assets
  • Atmos: Configuration management for multi-environment deployments
  • OpenTofu/Terraform: Infrastructure as Code for S3, CloudFront, ACM, and Route53

Repository Structure

├── public/                        # Static HTML/CSS/JS assets
├── terraform/
│   ├── components/
│   │   └── spa-s3-cloudfront/     # Terraform component for S3+CloudFront
│   └── stacks/                    # Atmos stack configurations
│       ├── _default.yaml          # Default variables
│       ├── defaults/app.yaml      # App component defaults
│       ├── deps/                   # Remote state dependencies
│       ├── dev.yaml               # Development environment
│       ├── preview.yaml           # PR preview environments
│       ├── staging.yaml           # Staging environment
│       └── prod.yaml              # Production environment
├── profiles/
│   └── github/                    # GitHub Actions OIDC authentication
└── .github/workflows/             # GitHub Actions workflows

Deployment Workflows

Workflow Trigger Environment Actions
main-branch.yaml Push to main dev Build, deploy infra, sync to S3, invalidate cache, create draft release
feature-branch.yml PR to main with deploy label preview Build, deploy isolated preview (per PR), sync and invalidate
release.yaml Published GitHub release stagingproduction Build, deploy to staging, then production
preview-cleanup.yml PR closed or deploy label removed preview Destroy preview environment infrastructure

Infrastructure Components

S3 + CloudFront CDN

The spa-s3-cloudfront Terraform component creates:

  • S3 Bucket: Origin for static assets with encryption
  • CloudFront Distribution: Global CDN with HTTPS
  • ACM Certificate: SSL/TLS certificate (in us-east-1)
  • Route53 Record: DNS alias to CloudFront

Stack Configuration

Environment stacks inherit from defaults/app.yaml which maps the app component to spa-s3-cloudfront:

components:
  terraform:
    app:
      metadata:
        component: spa-s3-cloudfront
      vars:
        name: app-cloudfront-s3
        parent_zone_name: !terraform.state dns-delegated .default_domain_name
        parent_zone_id: !terraform.state dns-delegated .default_dns_zone_id
        web_acl_id: !terraform.state waf/cloudfront .arn

Remote State Dependencies

The app reads from remote state for:

  • dns-delegated: Parent DNS zone name and ID
  • waf/cloudfront: WAF ACL ARN for CloudFront protection

Getting Started

Prerequisites

  • AWS Account with Route53 hosted zone
  • GitHub repository with OIDC configured for AWS access
  • Atmos CLI installed
  • OpenTofu installed (version in .opentofu-version)

GitHub Actions Variables

Configure these in your repository settings:

ATMOS_VERSION: Version of Atmos to install

Authentication

GitHub Actions authenticate via OIDC. Configure IAM roles in profiles/github/atmos.yaml:

auth:
  providers:
    github-oidc:
      kind: github/oidc
      region: us-east-2
      spec:
        audience: sts.amazonaws.com

  identities:
    plat-dev/terraform:
      kind: aws/assume-role
      via:
        provider: github-oidc
      principal:
        assume_role: arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME

Deploy Your Application

  1. Add static content to public/ directory
  2. Push to main branch: Deploys to dev environment
  3. Create PR with deploy label: Deploys to isolated preview environment
  4. Publish release: Deploys to staging then production

Environment Deployment Flow

graph LR
    A[Push to main] --> B[Build Assets]
    B --> C[Deploy to dev]
    C --> D[Create Draft Release]

    E[Publish Release] --> F[Deploy to staging]
    F --> G[Deploy to production]

    H[PR with deploy label] --> I[Deploy to preview]
    J[PR closed] --> K[Destroy preview]
Loading

Local Development

Build

mkdir -p dist && cp -r public/* dist/

Infrastructure Commands

# Plan changes
atmos terraform plan app -s dev

# Deploy
atmos terraform deploy app -s dev

# Get outputs
atmos terraform output app -s dev --skip-init -- -raw url

Related Projects

Check out these related projects.

License

License

Preamble to the Apache License, Version 2.0

Complete license is available in the LICENSE file.

Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.

Trademarks

All other trademarks referenced herein are the property of their respective owners.

README footer

Beacon

About

Example app to deploy on SPA on Cloudfront + S3

Resources

License

Stars

Watchers

Forks

Packages

No packages published