Skip to content

Commit

Permalink
Initial attempt at preview environments in CloudFront
Browse files Browse the repository at this point in the history
  • Loading branch information
kberzinch committed Jun 19, 2024
1 parent c42f00d commit 1a209da
Show file tree
Hide file tree
Showing 6 changed files with 348 additions and 22 deletions.
61 changes: 39 additions & 22 deletions .github/workflows/build-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,42 @@ jobs:
name: Build Artifact
uses: ./.github/workflows/build-artifact.yml

deploy-github-pages:
name: Deploy to GitHub Pages
runs-on: ubuntu-24.04

needs: build-artifact

permissions:
pages: write
id-token: write

environment:
name: github-pages
url: https://bpm.robojackets.org

concurrency:
group: deploy-github-pages
cancel-in-progress: false

steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
terraform-apply:
name: Build CloudFront Environment
uses: ./.github/workflows/terraform-apply.yml
with:
ref: ${{ github.ref }}

cloudfront-deploy:
name: Deploy to CloudFront
uses: ./.github/workflows/cloudfront-deploy.yml
needs:
- build-artifact
- terraform-apply
with:
cloudfront_domain: ${{ needs.terraform-apply.outputs.cloudfront_domain }}
cloudfront_distribution_id: ${{ needs.terraform-apply.outputs.cloudfront_distribution_id }}
s3_bucket_name: ${{ needs.terraform-apply.outputs.s3_bucket_name }}

# deploy-github-pages:
# name: Deploy to GitHub Pages
# runs-on: ubuntu-24.04

# needs: build-artifact

# permissions:
# pages: write
# id-token: write

# environment:
# name: github-pages
# url: https://bpm.robojackets.org

# concurrency:
# group: deploy-github-pages
# cancel-in-progress: false

# steps:
# - name: Deploy to GitHub Pages
# id: deployment
# uses: actions/deploy-pages@v4
61 changes: 61 additions & 0 deletions .github/workflows/cloudfront-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
name: Deploy to CloudFront

on:
workflow_call:
inputs:
cloudfront_domain:
required: true
type: string

cloudfront_distribution_id:
required: true
type: string

s3_bucket_name:
required: true
type: string

jobs:
cloudfront-deploy:
name: Deploy to CloudFront
runs-on: ubuntu-24.04

permissions:
id-token: write
contents: read

environment:
name: preview
url: https://${{ inputs.cloudfront_domain }}

concurrency:
group: cloudfront-deploy-${{ cloudfront_distribution_id }}
cancel-in-progress: true

steps:
- name: Download GitHub Pages artifact
uses: actions/download-artifact@v4
with:
name: github-pages

- name: Unpack GitHub Pages artifact
run: tar xvf github-pages

- name: Get AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
role-to-assume: arn:aws:iam::771971951923:role/bpm-preview-provisioning
audience: sts.amazonaws.com
role-duration-seconds: 900

- name: Sync docs to S3
uses: docker://public.ecr.aws/aws-cli/aws-cli
with:
args: s3 sync --region us-east-1 github-pages s3://${{ inputs.s3_bucket_name }}

- name: Invalidate CloudFront cache
uses: docker://public.ecr.aws/aws-cli/aws-cli
with:
args: cloudfront create-invalidation --distribution-id ${{ inputs.cloudfront_distribution_id }} --paths "/*"
70 changes: 70 additions & 0 deletions .github/workflows/terraform-apply.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
name: Build CloudFront Environment

on:
workflow_call:
inputs:
ref:
required: true
type: string
outputs:
cloudfront_domain:
value: ${{ jobs.terraform-apply.outputs.cloudfront_domain }}
cloudfront_distribution_id:
value: ${{ jobs.terraform-apply.outputs.cloudfront_distribution_id }}
s3_bucket_name:
value: ${{ jobs.terraform-apply.outputs.s3_bucket_name }}

jobs:
terraform-apply:
name: Build CloudFront Environment
runs-on: ubuntu-24.04

permissions:
id-token: write
contents: read

concurrency:
group: terraform-apply-${{ inputs.ref }}
cancel-in-progress: false

outputs:
cloudfront_domain: ${{ steps.get_outputs.outputs.cloudfront_domain }}
cloudfront_distribution_id: ${{ steps.get_outputs.outputs.cloudfront_distribution_id }}
s3_bucket_name: ${{ steps.get_outputs.outputs.s3_bucket_name }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_wrapper: false

- name: Check Terraform format
run: terraform fmt -check

- name: Initialize Terraform
run: terraform init -backend-config="key=${{ inputs.ref }}.tfstate"

- name: Validate Terraform code
run: terraform validate

- name: Get AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-region: us-east-1
role-to-assume: arn:aws:iam::771971951923:role/bpm-preview-provisioning
audience: sts.amazonaws.com
role-duration-seconds: 900

- name: Terraform Apply
run: terraform apply -var=ref=${{ inputs.ref }}

- name: Get Terraform outputs
id: get_outputs
run: |
echo "cloudfront_domain=$(terraform output -raw cloudfront_domain)" >> $GITHUB_OUTPUT
echo "cloudfront_distribution_id=$(terraform output -raw cloudfront_distribution_id)" >> $GITHUB_OUTPUT
echo "s3_bucket_name=$(terraform output -raw s3_bucket_name)" >> $GITHUB_OUTPUT
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ cython_debug/
#.idea/

_build/
.terraform/
25 changes: 25 additions & 0 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

152 changes: 152 additions & 0 deletions preview.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
terraform {
backend "s3" {
bucket = "gatech-me-robojackets-bpm-preview-statefiles"
region = "us-east-1"
}

required_providers {
aws = {
source = "hashicorp/aws"
version = "5.54.1"
}
}
}

provider "aws" {
}

variable "ref" {
type = string
description = "The git ref being deployed"
}

locals {
s3_origin_id = "bpm-preview"
}

resource "aws_s3_bucket" "bucket" {
bucket = "gatech-me-robojackets-bpm-preview-${replace(var.ref, "/", "-")}"
}

resource "aws_s3_bucket_public_access_block" "block_public_access" {
bucket = aws_s3_bucket.bucket.id

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

data "aws_iam_policy_document" "s3_policy" {
statement {
actions = ["s3:GetObject"]
resources = ["${aws_s3_bucket.bucket.arn}/*"]

principals {
type = "Service"
identifiers = [
"cloudfront.amazonaws.com",
]
}

condition {
test = "StringEquals"
values = [
aws_cloudfront_distribution.cloudfront.arn
]
variable = "AWS:SourceArn"
}
}

statement {
actions = ["s3:ListBucket"]
resources = [aws_s3_bucket.bucket.arn]

principals {
type = "Service"
identifiers = [
"cloudfront.amazonaws.com",
]
}

condition {
test = "StringEquals"
values = [
aws_cloudfront_distribution.cloudfront.arn
]
variable = "AWS:SourceArn"
}
}
}

resource "aws_s3_bucket_policy" "bucket_policy" {
bucket = aws_s3_bucket.bucket.id
policy = data.aws_iam_policy_document.s3_policy.json
}

resource "aws_cloudfront_origin_access_control" "allow_cloudfront_access_to_s3" {
name = "bpm-preview-${replace(var.ref, "/", "-")}"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}

resource "aws_cloudfront_distribution" "cloudfront" {
origin {
domain_name = aws_s3_bucket.bucket.bucket_regional_domain_name
origin_id = local.s3_origin_id
origin_access_control_id = aws_cloudfront_origin_access_control.allow_cloudfront_access_to_s3.id
}

default_cache_behavior {
allowed_methods = ["HEAD", "GET", "OPTIONS"]
cached_methods = ["HEAD", "GET"]
compress = true
viewer_protocol_policy = "https-only"
target_origin_id = local.s3_origin_id

forwarded_values {
query_string = false

cookies {
forward = "none"
}
}

function_association {
event_type = "viewer-request"
function_arn = "arn:aws:cloudfront::771971951923:function/dirhtml-uri-support"
}
}

default_root_object = "index.html"
enabled = true
is_ipv6_enabled = true
price_class = "PriceClass_100"
http_version = "http3"
wait_for_deployment = false

restrictions {
geo_restriction {
restriction_type = "none"
}
}

viewer_certificate {
cloudfront_default_certificate = true
minimum_protocol_version = "TLSv1"
ssl_support_method = "sni-only"
}
}

output "s3_bucket_name" {
value = aws_s3_bucket.bucket.name
}

output "cloudfront_distribution_id" {
value = aws_cloudfront_distribution.cloudfront.id
}

output "cloudfront_domain" {
value = aws_cloudfront_distribution.cloudfront.domain_name
}

0 comments on commit 1a209da

Please sign in to comment.