Skip to content

Commit

Permalink
Merge pull request #13 from hearchco/gh-actions
Browse files Browse the repository at this point in the history
feat: production and CI/CD
  • Loading branch information
aleksasiriski authored Apr 11, 2024
2 parents 81aa67f + 71eee86 commit c3ec998
Show file tree
Hide file tree
Showing 39 changed files with 1,264 additions and 21 deletions.
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
- package-ecosystem: "terraform"
directory: "/"
schedule:
interval: "daily"
17 changes: 17 additions & 0 deletions .github/workflows/ci-terraform.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Pre-commit checks for Terraform

on:
pull_request:
branches: ["main"]

jobs:
pre-commit:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
- uses: terraform-linters/setup-tflint@v4
- uses: pre-commit/[email protected]
96 changes: 96 additions & 0 deletions .github/workflows/deploy-backend.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: Deploy backend on trigger from the backend repository

on:
repository_dispatch:
types: [deploy-backend]

env:
AWS_WORK_DIR: "./aws/${{ github.event.client_payload.environment }}/backend"
VERSION: ${{ github.event.client_payload.version }}
DOWNLOAD_URL_AMD64: ${{ github.event.client_payload.download_url_amd64 }}
DOWNLOAD_URL_ARM64: ${{ github.event.client_payload.download_url_arm64 }}

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
ref: ${{ github.event.client_payload.sha }}

# AWS
## AWS (shared)
- name: Configure AWS credentials for shared TF state
id: shared-tf-state
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.TF_SHARED_ROLE }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Configure AWS Credentials File
run: |
mkdir -p ~/.aws
echo "[${{ steps.shared-tf-state.outputs.aws-account-id }}_TFStateLock]" >> ~/.aws/credentials
echo "aws_access_key_id=${{ steps.shared-tf-state.outputs.aws-access-key-id }}" >> ~/.aws/credentials
echo "aws_secret_access_key=${{ steps.shared-tf-state.outputs.aws-secret-access-key }}" >> ~/.aws/credentials
echo "aws_session_token=${{ steps.shared-tf-state.outputs.aws-session-token }}" >> ~/.aws/credentials
## AWS (prod)
- name: Configure AWS credentials for deployment (prod)
if: github.event.client_payload.environment == 'prod'
id: prod-deployment
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.BACKEND_PROD_ROLE }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Configure AWS Credentials File (prod)
if: github.event.client_payload.environment == 'prod'
run: |
echo "[${{ steps.prod-deployment.outputs.aws-account-id }}_Admin]" >> ~/.aws/credentials
echo "aws_access_key_id=${{ steps.prod-deployment.outputs.aws-access-key-id }}" >> ~/.aws/credentials
echo "aws_secret_access_key=${{ steps.prod-deployment.outputs.aws-secret-access-key }}" >> ~/.aws/credentials
echo "aws_session_token=${{ steps.prod-deployment.outputs.aws-session-token }}" >> ~/.aws/credentials
## AWS (dev)
- name: Configure AWS credentials for deployment (dev)
if: github.event.client_payload.environment == 'dev'
id: dev-deployment
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.BACKEND_DEV_ROLE }}
aws-region: ${{ secrets.AWS_REGION }}

- name: Configure AWS Credentials File (dev)
if: github.event.client_payload.environment == 'dev'
run: |
echo "[${{ steps.dev-deployment.outputs.aws-account-id }}_Admin]" >> ~/.aws/credentials
echo "aws_access_key_id=${{ steps.dev-deployment.outputs.aws-access-key-id }}" >> ~/.aws/credentials
echo "aws_secret_access_key=${{ steps.dev-deployment.outputs.aws-secret-access-key }}" >> ~/.aws/credentials
echo "aws_session_token=${{ steps.dev-deployment.outputs.aws-session-token }}" >> ~/.aws/credentials
# Terraform
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3

- name: Initialize Terraform modules
run: terraform init
working-directory: ${{ env.AWS_WORK_DIR }}

# Binary
- name: Download latest binary from the backend repository
run: |
mkdir tmp
curl -sSL -o tmp/bootstrap ${{ env.DOWNLOAD_URL_ARM64 }}
working-directory: ${{ env.AWS_WORK_DIR }}
shell: bash

# Deploy
- name: Apply Terraform changes (with the new binary)
run: terraform apply -auto-approve
working-directory: ${{ env.AWS_WORK_DIR }}
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
default_install_hook_types:
- pre-commit

repos:
- repo: https://github.com/antonbabenko/pre-commit-terraform
rev: v1.86.0
hooks:
- id: terraform_fmt
- id: terraform_validate
- id: terraform_tflint

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: end-of-file-fixer
63 changes: 63 additions & 0 deletions aws/dev/github/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
terraform {
backend "s3" {
profile = "992382822186_TFStateLock"
region = "eu-central-1"
dynamodb_table = "hearchco-shared-tf-state"
bucket = "hearchco-shared-tf-state"
key = "aws/dev/github/terraform.tfstate"
encrypt = "true"
}
}

provider "aws" {
profile = var.aws_profile
region = "eu-central-1"
}

module "github_oidc" {
source = "../../modules/github/oidc"
}

data "aws_caller_identity" "current" {}

locals {
account_id = data.aws_caller_identity.current.account_id
}

module "github_backend_deploy" {
source = "../../modules/github/role"

name = "github-auth-backend-deploy"
repository = "hearchco/hearchco"

statements = [
{
actions = [
"s3:Get*",
"s3:List*",
"route53:Get*",
"route53:List*",
"apigateway:GET",
"acm:List*",
"acm:Describe*",
"cloudfront:Get*",
"cloudfront:List*",
"lambda:Get*",
"lambda:List*",
"iam:Get*",
"iam:List*"
]
resources = ["*"]
},
{
actions = [
"s3:PutObject",
"lambda:UpdateFunctionCode"
]
resources = [
"arn:aws:s3:::*/*",
"arn:aws:lambda:*:*:function:*"
]
}
]
}
4 changes: 4 additions & 0 deletions aws/dev/github/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
variable "aws_profile" {
type = string
default = "891377085136_Admin"
}
9 changes: 9 additions & 0 deletions aws/dev/github/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
3 changes: 2 additions & 1 deletion aws/modules/backend/s3/locals.tf
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
data "aws_region" "current" {}
data "aws_caller_identity" "current" {}

locals {
bucket_name = "${var.bucket_name}-${data.aws_region.current.name}"
bucket_name = "${var.bucket_name}-${data.aws_region.current.name}-${data.aws_caller_identity.current.account_id}"
binary_name = "bootstrap"
binary_key = "${local.binary_name}.zip"
source_file = "${var.path}/${local.binary_name}"
Expand Down
5 changes: 5 additions & 0 deletions aws/modules/github/oidc/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
resource "aws_iam_openid_connect_provider" "oidc_provider" {
url = var.url
client_id_list = toset([var.audience])
thumbprint_list = var.thumbprint_list
}
14 changes: 14 additions & 0 deletions aws/modules/github/oidc/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
variable "url" {
type = string
default = "https://token.actions.githubusercontent.com"
}

variable "audience" {
type = string
default = "sts.amazonaws.com"
}

variable "thumbprint_list" {
type = list(string)
default = ["6938fd4d98bab03faadb97b34396831e3780aea1", "1c58a3a8518e8759bf075b76b750d4f2df264fcd"]
}
9 changes: 9 additions & 0 deletions aws/modules/github/oidc/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
48 changes: 48 additions & 0 deletions aws/modules/github/role/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
data "aws_caller_identity" "current" {}

data "aws_iam_policy_document" "instance_assume_role_policy" {
statement {
effect = "Allow"
actions = ["sts:AssumeRoleWithWebIdentity"]

principals {
type = "Federated"
identifiers = ["arn:aws:iam::${data.aws_caller_identity.current.account_id}:oidc-provider/token.actions.githubusercontent.com"]
}

condition {
test = "ForAnyValue:StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = [var.audience]
}

condition {
test = "ForAnyValue:StringLike"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:${var.repository}:${var.scope}"]
}
}
}

data "aws_iam_policy_document" "inline_policy" {
dynamic "statement" {
for_each = var.statements
content {
sid = statement.value.sid
effect = statement.value.effect
actions = statement.value.actions
resources = statement.value.resources
}
}
}

resource "aws_iam_role" "iam_role" {
name = var.name
path = var.path
assume_role_policy = data.aws_iam_policy_document.instance_assume_role_policy.json

inline_policy {
name = "${var.name}-inline-policy"
policy = data.aws_iam_policy_document.inline_policy.json
}
}
33 changes: 33 additions & 0 deletions aws/modules/github/role/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
variable "name" {
type = string
}

variable "path" {
type = string
default = "/"
}

variable "audience" {
type = string
default = "sts.amazonaws.com"
}

// "<org_name>/<repo_name>"
variable "repository" {
type = string
}

// to allow all branches use "ref:refs/heads/*", to allow everything from the repo use "*"
variable "scope" {
type = string
default = "ref:refs/heads/main"
}

variable "statements" {
type = set(object({
sid = optional(string)
effect = optional(string, "Allow")
actions = set(string)
resources = set(string)
}))
}
9 changes: 9 additions & 0 deletions aws/modules/github/role/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
17 changes: 17 additions & 0 deletions aws/prod/backend/locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
locals {
# Lambda
environment = tomap({
HEARCHCO_SERVER_FRONTENDURLS = "http://localhost:5173,https://hearch.co,https://frontend-*-hearchco.vercel.app"
HEARCHCO_SERVER_CACHE_TYPE = "none" # currently caching has some bugs so it's disabled
})
# Not inside environment because it's a secret
proxy_salt = module.salt.string

# API Gateway
api_domain_name = "api.${var.domain_name}"
api_gateway_domain_name = "gateway.${local.api_domain_name}"
routes = toset([
"/search",
"/proxy",
])
}
Loading

0 comments on commit c3ec998

Please sign in to comment.