From 516adbc96bdcfc47725d583166bfa0b8824f58b3 Mon Sep 17 00:00:00 2001 From: Jarrod Lowe <41766555+jarrod-lowe@users.noreply.github.com> Date: Sat, 10 Aug 2024 20:15:48 +1200 Subject: [PATCH] Re-org with a rw and ro environment (#16) * Re-org with a rw and ro environment * Add ENVIRONMENT variable * Grant s3:HeadObject * Fix S3 permissions * Fix S3 permissions for real * Some linter ignores * Some linter ignores --- .../workflows/environment-main-deploy.yaml | 8 +- .github/workflows/environment-main-plan.yaml | 8 +- .github/workflows/terraform.yaml | 4 +- README.md | 61 ++++--- terraform/environment/aws/.terraform.lock.hcl | 24 +++ terraform/environment/aws/deploy.sh | 39 ++++ terraform/environment/aws/main.tf | 46 +++++ terraform/environment/aws/roles.tf | 168 ++++++++++++++++++ terraform/environment/aws/s3.tf | 61 +++++++ .../environment/github/.terraform.lock.hcl | 56 ++---- terraform/environment/github/deploy.sh | 41 +++++ terraform/environment/github/main.tf | 155 ++++++++++++++-- .../environment/wildsea/.terraform.lock.hcl | 43 +++++ terraform/environment/wildsea/main.tf | 32 ++++ 14 files changed, 657 insertions(+), 89 deletions(-) create mode 100644 terraform/environment/aws/.terraform.lock.hcl create mode 100755 terraform/environment/aws/deploy.sh create mode 100644 terraform/environment/aws/main.tf create mode 100644 terraform/environment/aws/roles.tf create mode 100644 terraform/environment/aws/s3.tf create mode 100755 terraform/environment/github/deploy.sh create mode 100644 terraform/environment/wildsea/.terraform.lock.hcl create mode 100644 terraform/environment/wildsea/main.tf diff --git a/.github/workflows/environment-main-deploy.yaml b/.github/workflows/environment-main-deploy.yaml index 127f42f1..0c9cc4bb 100644 --- a/.github/workflows/environment-main-deploy.yaml +++ b/.github/workflows/environment-main-deploy.yaml @@ -14,7 +14,7 @@ jobs: envtest: name: Environment Main - Apply runs-on: ubuntu-latest - environment: main + environment: primary-rw env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -23,13 +23,13 @@ jobs: - name: Configure AWS Access uses: aws-actions/configure-aws-credentials@39228ca2bffc0bfc8f7761ce893f5b80e7eaaf8f with: - role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT }}:role/GitHubAction-Wildsea-${{ vars.ENVIRONMENT }} - role-session-name: GitHubDeploy + role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT }}:role/${{ vars.AWS_ROLE }} + role-session-name: GitHubDeploy-${{ vars.ENVIRONMENT }} aws-region: ${{ vars.AWS_REGION }} - name: terraform apply uses: dflook/terraform-apply@7d435d4d115a11e5db1e710ac969f5382f0f6f9f with: - path: terraform/environment/github + path: terraform/environment/wildsea variables: | aws_account="${{ vars.AWS_ACCOUNT }}" aws_region="${{ vars.AWS_REGION }}" diff --git a/.github/workflows/environment-main-plan.yaml b/.github/workflows/environment-main-plan.yaml index 4949f42d..49bfe1e5 100644 --- a/.github/workflows/environment-main-plan.yaml +++ b/.github/workflows/environment-main-plan.yaml @@ -12,7 +12,7 @@ jobs: envtest: name: Environment Main - Plan runs-on: ubuntu-latest - environment: main + environment: primary-ro env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: @@ -21,13 +21,13 @@ jobs: - name: Configure AWS Access uses: aws-actions/configure-aws-credentials@39228ca2bffc0bfc8f7761ce893f5b80e7eaaf8f with: - role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT }}:role/GitHubAction-Wildsea - role-session-name: GitHubTest + role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT }}:role/${{ vars.AWS_ROLE }} + role-session-name: GitHubTest-${{ vars.ENVIRONMENT }} aws-region: ${{ vars.AWS_REGION }} - name: terraform plan uses: dflook/terraform-plan@b0877a1bf56160160ab482f4aff8a12fff35fe06 with: - path: terraform/environment/github + path: terraform/environment/wildsea variables: | aws_account="${{ vars.AWS_ACCOUNT }}" aws_region="${{ vars.AWS_REGION }}" diff --git a/.github/workflows/terraform.yaml b/.github/workflows/terraform.yaml index 9a8cf977..3dea7ea7 100644 --- a/.github/workflows/terraform.yaml +++ b/.github/workflows/terraform.yaml @@ -3,7 +3,7 @@ name: Terraform Validation on: pull_request: paths: - - terraform/environment/github/** + - terraform/environment/wildsea/** push: branches: - main @@ -18,5 +18,5 @@ jobs: - name: Validate Terraform uses: dflook/terraform-validate@93108d6d37b2fd79d527ec77c190105de1429bb5 with: - path: terraform/environment/github + path: terraform/environment/wildsea \ No newline at end of file diff --git a/README.md b/README.md index af9d3dc3..6614be4b 100644 --- a/README.md +++ b/README.md @@ -2,38 +2,43 @@ Wildsea companion app -## Repository Setup +## Setup -To set up a github repository: +* Clone `git@github.com:jarrod-lowe/wildsea.git` and then `cd wildsea` +* Configure git: + ```bash + git config gpg.format ssh + git config user.signingkey ~/.ssh/id_rsa + git config commit.gpgsign true + ``` + +* Create an AWS Account for deployment + * Define a profile in your `~/.aws/config` to access it as admin for the initial setup deploys +* Create an S3 bucket `terraform-state-` +* Create `terraform/environment/aws/terraform.tfvars` + * Add `workspace = ""` to the vars file +* Run `.AWS_PROFILE= ./terraform/environment/github/aws.sh ` * Log into Codacy, and connect the repo * Configure the rule to maximum -* Create a branch restriction rule called "main": - * Enforcement: Active - * Target Branches: Include default branch - * Tick Restrict creations - * Tick Restrict deletions - * Tick Require linear history - * Tick Require a pull request before merging - * Require 0 Approvals - * Require review from code owners - * Tick Require status checks to pass - * Tick require branches to be up to date before merging - * Add "Codacy Static Code Analysis" to status checks that are required - * Block force pushes - * TODO: Require code scanning results +* In Codacy, in the repo, go to code patterns, and edit the coding standard: + * Set the languages to: CSS, Go, JSON, Javascript, Markdown, Python, Shell, Terraform, Typescript, XML, YAML + * Select every tool that is: + * NOT client-side + * NOT deprecated + * NOT remark-lint + * Matches one of the above languages +* Log into Github and create a personal access token with the "repo" scope, and 7 days expiry +* Create `terraform/environment/github/terraform.tfvars` + * Add `token = ""` to the vars file + * Add `workspace = ""` to the vars file +* Run `.AWS_PROFILE= ./terraform/environment/github/deploy.sh ` + * Install into the repo -* Under settings, "Set up code scanning" - * Enable everything exeept Dependabot version updates + +To automate: + +* In Github, Under settings, "Set up code scanning" + * Enable everything except Dependabot version updates * Set up CodeQL to default * Set the Protection rules to Any/Any -* Create an AWS Account for deployment - * Set up OIDC as per - * Restrict it to the repo and branch main - * Add AdministratorAccess, for now, and call it GitHubAccess-Wildsea-main - * Add another role with ReadyOnlyAccess, don't restrict the branch, and call it GitHubAccess-Wildsea -* Add an environment "main" - * Add an Environment Variable in the environment "AWS_ACCOUNT" with the ID of the AWS Account - * Add an Environment Variable in the environment "AWS_REGION" with the AWS Region you want to use - * Add an Environment Variable in the environment "STATE_BUCKET" with the name of the state bucket you created - * Add an Environment Variable in the environment "ENVIRONMENT" with the name of the environment diff --git a/terraform/environment/aws/.terraform.lock.hcl b/terraform/environment/aws/.terraform.lock.hcl new file mode 100644 index 00000000..169a35a3 --- /dev/null +++ b/terraform/environment/aws/.terraform.lock.hcl @@ -0,0 +1,24 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.62.0" + hashes = [ + "h1:8tevkFG+ea/sNZYiQ2GQ02hknPcWBukxkrpjRCodQC0=", + "zh:1f366cbcda72fb123015439a42ab19f96e10ce4edb404273f4e1b7e06da20b73", + "zh:25f098454a34b483279e0382b24b4f42e51c067222c6e797eda5d3ec33b9beb1", + "zh:4b59d48b527e3cefd73f196853bfc265b3e1e57b55c1c8a2d12ff6e3534b4f07", + "zh:7bb88c1ca95e2b3f0f1fe8636925133b9813fc5b137cc467ba6a233ddf4b360e", + "zh:8a93dece40e816c92647e762839d0370e9cad2aa21dc4ca95baee9385f116459", + "zh:8dfe82c55ab8f633c1e2a39c687e9ca8c892d1c2005bf5166ac396ce868ecd05", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:a754952d69b4860480d5207390e3ab42350c964dbca9a5ac0c6912dd24b4c11d", + "zh:b2a4dbf4abee0e9ec18c5d323b99defdcd3c681f8c4306fb6e02cff7de038f85", + "zh:b57d84be258b571c04271015f03858ab215768b82e47c11ecd86e789d577030a", + "zh:be811b03289407c8d59e6b199bf16e6071165565ffe502148172d0886cf849c4", + "zh:d4144c7366c840eff1ac15ba13d96063f798f0983d24053a832362033624fe6f", + "zh:d88612856d453c4e10c49c76e4ef522b7d068b4f7c3e2e0b03dd74540986eecd", + "zh:e8bd231a5d0786cc4aab8471bb6dabd5a5df1c598afda077a9f27987ada57b67", + "zh:ffb40a66b4d000a8ee4c54227eeb998f887ad867419c3af7d3981587788de074", + ] +} diff --git a/terraform/environment/aws/deploy.sh b/terraform/environment/aws/deploy.sh new file mode 100755 index 00000000..b12ca90f --- /dev/null +++ b/terraform/environment/aws/deploy.sh @@ -0,0 +1,39 @@ +#!/bin/bash -eu +if [ -z "${1:-}" ] ; then + echo >&2 "Usage: $0 [environment] [region]" + echo >&2 "Eg: $0 0123456789012" + exit 2 +fi + +DIR="$( dirname "$0" )" +cd "${DIR}" + +ACCOUNT_ID="$1" +ENVIRONMENT="${2:-primary}" +AWS_REGION="${3:-ap-southeast-2}" +STATE_BUCKET="terraform-state-${ACCOUNT_ID}" + +if ! aws help >/dev/null ; then + echo >&2 "Error: aws cli not installed" + exit 3 +fi + +if ! aws sts get-caller-identity >/dev/null ; then + echo >&2 "Error: not logged into AWS" + exit 4 +fi + +if ! aws s3 ls "s3://${STATE_BUCKET}/" >/dev/null ; then + echo >&2 "Error: AWS Role does not have access to the state bucket" + aws sts get-caller-identity + exit 5 +fi + +terraform init \ + -backend-config="bucket=${STATE_BUCKET}" \ + -backend-config="key=${ENVIRONMENT}/aws.tfstate" \ + -backend-config="region=${AWS_REGION}" + +terraform apply \ + -var environment="${ENVIRONMENT}" \ + -var state_bucket="${STATE_BUCKET}" diff --git a/terraform/environment/aws/main.tf b/terraform/environment/aws/main.tf new file mode 100644 index 00000000..d95a9f8c --- /dev/null +++ b/terraform/environment/aws/main.tf @@ -0,0 +1,46 @@ +data "aws_partition" "current" {} +data "aws_caller_identity" "current" {} + +variable "app_name" { + default = "Wildsea" +} + +variable "action_prefix" { + default = "GitHubAction" +} + +variable "workspace" { + description = "Github Organisation name" + type = string +} + +variable "repo" { + description = "Repository name" + type = string + default = "wildsea" +} + +variable "state_bucket" { + description = "State Bucket to use for deploys" + type = string +} + +variable "environment" { + description = "Unique name for the deployment" + type = string + default = "primary" +} + +terraform { + backend "s3" { + // region, bucket and key come from -backend-config + } +} + +provider "aws" { + default_tags { + tags = { + Application = "Wildsea-setup-${var.environment}" + } + } +} diff --git a/terraform/environment/aws/roles.tf b/terraform/environment/aws/roles.tf new file mode 100644 index 00000000..056cc91a --- /dev/null +++ b/terraform/environment/aws/roles.tf @@ -0,0 +1,168 @@ +resource "aws_iam_openid_connect_provider" "oidc" { + url = "https://token.actions.githubusercontent.com" + client_id_list = [ + "sts.${data.aws_partition.current.dns_suffix}" + ] + thumbprint_list = [ + "d89e3bd43d5d909b47a18977aa9d5ce36cee184c" + ] +} + +resource "aws_iam_role" "ro" { + name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" + assume_role_policy = data.aws_iam_policy_document.ro_assume.json + + tags = { + Name = "${var.action_prefix}-${var.app_name}-ro-${var.environment}" + } +} + +data "aws_iam_policy_document" "ro_assume" { + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = [ aws_iam_openid_connect_provider.oidc.arn ] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.${data.aws_partition.current.dns_suffix}"] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-ro"] + } + } +} + +resource "aws_iam_policy" "ro" { + name = aws_iam_role.ro.name + policy = data.aws_iam_policy_document.ro.json + + tags = { + Name = aws_iam_role.ro.name + } +} + +resource "aws_iam_role_policy_attachment" "ro-ro" { + role = aws_iam_role.ro.name + policy_arn = aws_iam_policy.ro.arn +} + +data "aws_iam_policy_document" "ro" { + statement { + sid = "ReadState" + actions = [ + "s3:GetObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" + ] + } + + statement { + sid = "ListState" + actions = [ + "s3:ListBucket" + ] + resources = [ + aws_s3_bucket.state.arn + ] + } +} + +resource "aws_iam_role" "rw" { + name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" + assume_role_policy = data.aws_iam_policy_document.rw_assume.json + permissions_boundary = aws_iam_policy.rw_boundary.arn + + tags = { + Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}" + } +} + +data "aws_iam_policy_document" "rw_assume" { + statement { + actions = ["sts:AssumeRoleWithWebIdentity"] + principals { + type = "Federated" + identifiers = [ aws_iam_openid_connect_provider.oidc.arn ] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:aud" + values = ["sts.${data.aws_partition.current.dns_suffix}"] + } + condition { + test = "StringEquals" + variable = "token.actions.githubusercontent.com:sub" + values = ["repo:${var.workspace}/${var.repo}:environment:${var.environment}-rw"] + } + } +} + +resource "aws_iam_policy" "rw" { + name = aws_iam_role.rw.name + policy = data.aws_iam_policy_document.rw.json + + tags = { + Name = aws_iam_role.rw.name + } +} + +resource "aws_iam_role_policy_attachment" "rw-ro" { + role = aws_iam_role.rw.name + policy_arn = aws_iam_policy.ro.arn +} + +resource "aws_iam_role_policy_attachment" "rw-rw" { + role = aws_iam_role.rw.name + policy_arn = aws_iam_policy.rw.arn +} + +data "aws_iam_policy_document" "rw" { + statement { + sid = "WriteState" + actions = [ + "s3:PutObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate" + ] + } +} + +resource "aws_iam_policy" "rw_boundary" { + name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" + policy = data.aws_iam_policy_document.rw_boundary.json + + tags = { + Name = "${var.action_prefix}-${var.app_name}-rw-${var.environment}-boundary" + } +} + +data "aws_iam_policy_document" "rw_boundary" { + statement { + sid = "s3" + actions = [ + "s3:GetObject", + "s3:PutObject" + ] + resources = [ + "${aws_s3_bucket.state.arn}/${var.environment}/terraform.tfstate", + "arn:${data.aws_partition.current.id}:s3:::${var.app_name}-${var.environment}-*/*" + ] + } + + statement { + sid = "ListState" + actions = [ + "s3:ListBucket" + ] + resources = [ + aws_s3_bucket.state.arn + ] + } +} diff --git a/terraform/environment/aws/s3.tf b/terraform/environment/aws/s3.tf new file mode 100644 index 00000000..fc107e38 --- /dev/null +++ b/terraform/environment/aws/s3.tf @@ -0,0 +1,61 @@ +import { + to = aws_s3_bucket.state + id = var.state_bucket +} + +resource "aws_s3_bucket" "state" { + # checkov:skip=CKV_AWS_18:Access logging is overkill for us + # checkov:skip=CKV_AWS_144:Cross-Region replication not required + # checkov:skip=CKV2_AWS_62:Event notifications not required + # checkov:skip=CKV_AWS_145:AWS Key is sufficient + bucket = "terraform-state-${data.aws_caller_identity.current.account_id}" + force_destroy = false + + tags = { + Name = "terraform-state-${data.aws_caller_identity.current.account_id}" + } +} + +resource "aws_s3_bucket_lifecycle_configuration" "state" { + bucket = aws_s3_bucket.state.id + depends_on = [ aws_s3_bucket_versioning.state ] + + rule { + id = "clean" + noncurrent_version_expiration { + noncurrent_days = 30 + } + abort_incomplete_multipart_upload { + days_after_initiation = 7 + } + status = "Enabled" + } +} + +resource "aws_s3_bucket_public_access_block" "state" { + bucket = aws_s3_bucket.state.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "state" { + bucket = aws_s3_bucket.state.id + + rule { + bucket_key_enabled = true + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_versioning" "state" { + bucket = aws_s3_bucket.state.id + + versioning_configuration { + status = "Enabled" + } +} diff --git a/terraform/environment/github/.terraform.lock.hcl b/terraform/environment/github/.terraform.lock.hcl index 0d365aee..89f32fa5 100644 --- a/terraform/environment/github/.terraform.lock.hcl +++ b/terraform/environment/github/.terraform.lock.hcl @@ -1,43 +1,25 @@ # This file is maintained automatically by "terraform init". # Manual edits may be lost in future updates. -provider "registry.terraform.io/hashicorp/aws" { - version = "5.62.0" +provider "registry.terraform.io/integrations/github" { + version = "6.2.3" + constraints = "~> 6.0" hashes = [ - "h1:8tevkFG+ea/sNZYiQ2GQ02hknPcWBukxkrpjRCodQC0=", - "zh:1f366cbcda72fb123015439a42ab19f96e10ce4edb404273f4e1b7e06da20b73", - "zh:25f098454a34b483279e0382b24b4f42e51c067222c6e797eda5d3ec33b9beb1", - "zh:4b59d48b527e3cefd73f196853bfc265b3e1e57b55c1c8a2d12ff6e3534b4f07", - "zh:7bb88c1ca95e2b3f0f1fe8636925133b9813fc5b137cc467ba6a233ddf4b360e", - "zh:8a93dece40e816c92647e762839d0370e9cad2aa21dc4ca95baee9385f116459", - "zh:8dfe82c55ab8f633c1e2a39c687e9ca8c892d1c2005bf5166ac396ce868ecd05", - "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:a754952d69b4860480d5207390e3ab42350c964dbca9a5ac0c6912dd24b4c11d", - "zh:b2a4dbf4abee0e9ec18c5d323b99defdcd3c681f8c4306fb6e02cff7de038f85", - "zh:b57d84be258b571c04271015f03858ab215768b82e47c11ecd86e789d577030a", - "zh:be811b03289407c8d59e6b199bf16e6071165565ffe502148172d0886cf849c4", - "zh:d4144c7366c840eff1ac15ba13d96063f798f0983d24053a832362033624fe6f", - "zh:d88612856d453c4e10c49c76e4ef522b7d068b4f7c3e2e0b03dd74540986eecd", - "zh:e8bd231a5d0786cc4aab8471bb6dabd5a5df1c598afda077a9f27987ada57b67", - "zh:ffb40a66b4d000a8ee4c54227eeb998f887ad867419c3af7d3981587788de074", - ] -} - -provider "registry.terraform.io/hashicorp/null" { - version = "3.2.2" - hashes = [ - "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=", - "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7", - "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a", - "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3", - "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606", - "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546", - "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539", - "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452", - "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", - "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422", - "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae", - "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1", - "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e", + "h1:nHTegsQYYUJZbaTnU1aMJBgnZUbR2zsfCl7DsL/kZjQ=", + "zh:05874671652a260b12d784cc46b0eea156f493a5f12e00368d1f6cb319156257", + "zh:0c7a3cae5a66e5c5efc3b25ba646a0d46bfe1fd3edba1f5a75f51aede85a9d1b", + "zh:174310010d08f13e36e53ff18e44a21dd040c89884ef190a192c6ce27926a912", + "zh:23d1d8731e518354ce6a83419f49101aece63882b0ca7c489f3c598cc6ea5d5e", + "zh:4e88953816daf11ab1681c32c7988d4e29476fc44f0959fe03173532cf5044de", + "zh:6fab07734ccf27f5afee4442abae2d33245eabf35519032ce1e2aad6961a640a", + "zh:7b2f324b918e161c892c29ee80d36c48ca8b891b8047e132fc701ca741e5ae72", + "zh:8ef4f0d691ade98082ef1f6b36e556468e5ab26e60021f0de0fb22e3acdfd990", + "zh:8f0f3e139faa8f2b9075bb9978dd683f4bab5ac91171bbb969addd04d7f0b90f", + "zh:97cb6d7fdf640237cc2f0ab830db8f878770968c59fd28298e9dddb8b9e6294d", + "zh:a17038d8747c6bb660e4c5981e8ffbbc33c66ba164868fd35d442e7f828a1e01", + "zh:aa9f4b7d947f7b11277b4e9ba7147f5594cf60a6589b7aac4344f73d1400d1c0", + "zh:c780b951e14d583ef6ffef9a934831b56ee157c50ed8e969c676a636810f7db1", + "zh:d8497bb2986fd76107b7208b33cc39281797164fdea09453e987b969a461befb", + "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25", ] } diff --git a/terraform/environment/github/deploy.sh b/terraform/environment/github/deploy.sh new file mode 100755 index 00000000..98ba6a3a --- /dev/null +++ b/terraform/environment/github/deploy.sh @@ -0,0 +1,41 @@ +#!/bin/bash -eu +if [ -z "${1:-}" ] ; then + echo >&2 "Usage: $0 [environment] [region]" + echo >&2 "Eg: $0 0123456789012" + exit 2 +fi + +DIR="$( dirname "$0" )" +cd "${DIR}" + +ACCOUNT_ID="$1" +ENVIRONMENT="${2:-primary}" +AWS_REGION="${3:-ap-southeast-2}" +STATE_BUCKET="terraform-state-${ACCOUNT_ID}" + +if ! aws help >/dev/null ; then + echo >&2 "Error: aws cli not installed" + exit 3 +fi + +if ! aws sts get-caller-identity >/dev/null ; then + echo >&2 "Error: not logged into AWS" + exit 4 +fi + +if ! aws s3 ls "s3://${STATE_BUCKET}/" >/dev/null ; then + echo >&2 "Error: AWS Role does not have access to the state bucket" + aws sts get-caller-identity + exit 5 +fi + +terraform init \ + -backend-config="bucket=${STATE_BUCKET}" \ + -backend-config="key=${ENVIRONMENT}/github.tfstate" \ + -backend-config="region=${AWS_REGION}" + +terraform apply \ + -var aws_account="${ACCOUNT_ID}" \ + -var aws_region="${AWS_REGION}" \ + -var environment="${ENVIRONMENT}" \ + -var state_bucket="${STATE_BUCKET}" diff --git a/terraform/environment/github/main.tf b/terraform/environment/github/main.tf index 7d3f2f77..b7362d6f 100644 --- a/terraform/environment/github/main.tf +++ b/terraform/environment/github/main.tf @@ -1,25 +1,49 @@ -resource "null_resource" "test" {} +terraform { + required_providers { + github = { + source = "integrations/github" + version = "~> 6.0" + } + } +} + +variable "token" { + description = "Github Token" + sensitive = true + type = string +} + +variable "workspace" { + description = "Github Organisation name" + type = string +} + +variable "repo" { + description = "Repository name" + type = string + default = "wildsea" +} variable "aws_account" { - description = "ID of the AWS Account" - type = string - sensitive = true + description = "AWS Account ID" + type = string } variable "aws_region" { - description = "AWS Region name" - type = string - sensitive = true + description = "AWS Region" + type = string + default = "ap-southeast-2" } variable "state_bucket" { - description = "Name of the S3 state bucket" - type = string + description = "State Bucket to use for deploys" + type = string } variable "environment" { - description = "Name of the Environment" - type = string + description = "Unique name for the deployment" + type = string + default = "primary" } terraform { @@ -28,8 +52,111 @@ terraform { } } -provider "aws" { - assume_role { - role_arn = "arn:aws:iam::${var.aws_account}:role/GitHubAction-Wildsea" +provider "github" { + token = var.token +} + +data "github_user" "current" { + username = "" +} + +data "github_repository" "repo" { + full_name = "${var.workspace}/${var.repo}" +} + +resource "github_repository_ruleset" "ruleset" { + name = "primary" + repository = data.github_repository.repo.name + target = "branch" + enforcement = "active" + + rules { + creation = true + deletion = true + non_fast_forward = true + required_linear_history = true + required_signatures = true + pull_request { + dismiss_stale_reviews_on_push = true + require_code_owner_review = true + require_last_push_approval = false + required_approving_review_count = 0 + required_review_thread_resolution = true + } + required_deployments { + required_deployment_environments = [ + # github_repository_environment.ro.id + ] + } + required_status_checks { + strict_required_status_checks_policy = true + required_check { + context = "Codacy Static Code Analysis" + } + } + } + + conditions { + ref_name { + exclude = [] + include = [ + "~DEFAULT_BRANCH" + ] } + } +} + +locals { + rw_vars = { + AWS_ROLE = "GitHubAction-Wildsea-rw-${var.environment}" + AWS_ACCOUNT = var.aws_account + AWS_REGION = var.aws_region + STATE_BUCKET = var.state_bucket + ENVIRONMENT = var.environment + } + ro_vars = { + AWS_ROLE = "GitHubAction-Wildsea-ro-${var.environment}" + AWS_ACCOUNT = var.aws_account + AWS_REGION = var.aws_region + STATE_BUCKET = var.state_bucket + ENVIRONMENT = var.environment + } +} + +resource "github_repository_environment" "rw" { + environment = "${var.environment}-rw" + repository = data.github_repository.repo.name + deployment_branch_policy { + protected_branches = false + custom_branch_policies = true + } +} + +resource "github_repository_environment_deployment_policy" "rw" { + environment = github_repository_environment.rw.environment + repository = data.github_repository.repo.name + branch_pattern = "main" +} + +resource "github_repository_environment" "ro" { + environment = "${var.environment}-ro" + repository = data.github_repository.repo.name +} + +resource "github_actions_environment_variable" "rw" { + for_each = local.rw_vars + + environment = github_repository_environment.rw.environment + repository = data.github_repository.repo.name + variable_name = each.key + value = each.value +} + +resource "github_actions_environment_variable" "ro" { + for_each = local.ro_vars + + environment = github_repository_environment.ro.environment + repository = data.github_repository.repo.name + variable_name = each.key + value = each.value } diff --git a/terraform/environment/wildsea/.terraform.lock.hcl b/terraform/environment/wildsea/.terraform.lock.hcl new file mode 100644 index 00000000..0d365aee --- /dev/null +++ b/terraform/environment/wildsea/.terraform.lock.hcl @@ -0,0 +1,43 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/aws" { + version = "5.62.0" + hashes = [ + "h1:8tevkFG+ea/sNZYiQ2GQ02hknPcWBukxkrpjRCodQC0=", + "zh:1f366cbcda72fb123015439a42ab19f96e10ce4edb404273f4e1b7e06da20b73", + "zh:25f098454a34b483279e0382b24b4f42e51c067222c6e797eda5d3ec33b9beb1", + "zh:4b59d48b527e3cefd73f196853bfc265b3e1e57b55c1c8a2d12ff6e3534b4f07", + "zh:7bb88c1ca95e2b3f0f1fe8636925133b9813fc5b137cc467ba6a233ddf4b360e", + "zh:8a93dece40e816c92647e762839d0370e9cad2aa21dc4ca95baee9385f116459", + "zh:8dfe82c55ab8f633c1e2a39c687e9ca8c892d1c2005bf5166ac396ce868ecd05", + "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", + "zh:a754952d69b4860480d5207390e3ab42350c964dbca9a5ac0c6912dd24b4c11d", + "zh:b2a4dbf4abee0e9ec18c5d323b99defdcd3c681f8c4306fb6e02cff7de038f85", + "zh:b57d84be258b571c04271015f03858ab215768b82e47c11ecd86e789d577030a", + "zh:be811b03289407c8d59e6b199bf16e6071165565ffe502148172d0886cf849c4", + "zh:d4144c7366c840eff1ac15ba13d96063f798f0983d24053a832362033624fe6f", + "zh:d88612856d453c4e10c49c76e4ef522b7d068b4f7c3e2e0b03dd74540986eecd", + "zh:e8bd231a5d0786cc4aab8471bb6dabd5a5df1c598afda077a9f27987ada57b67", + "zh:ffb40a66b4d000a8ee4c54227eeb998f887ad867419c3af7d3981587788de074", + ] +} + +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.2" + hashes = [ + "h1:zT1ZbegaAYHwQa+QwIFugArWikRJI9dqohj8xb0GY88=", + "zh:3248aae6a2198f3ec8394218d05bd5e42be59f43a3a7c0b71c66ec0df08b69e7", + "zh:32b1aaa1c3013d33c245493f4a65465eab9436b454d250102729321a44c8ab9a", + "zh:38eff7e470acb48f66380a73a5c7cdd76cc9b9c9ba9a7249c7991488abe22fe3", + "zh:4c2f1faee67af104f5f9e711c4574ff4d298afaa8a420680b0cb55d7bbc65606", + "zh:544b33b757c0b954dbb87db83a5ad921edd61f02f1dc86c6186a5ea86465b546", + "zh:696cf785090e1e8cf1587499516b0494f47413b43cb99877ad97f5d0de3dc539", + "zh:6e301f34757b5d265ae44467d95306d61bef5e41930be1365f5a8dcf80f59452", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:913a929070c819e59e94bb37a2a253c228f83921136ff4a7aa1a178c7cce5422", + "zh:aa9015926cd152425dbf86d1abdbc74bfe0e1ba3d26b3db35051d7b9ca9f72ae", + "zh:bb04798b016e1e1d49bcc76d62c53b56c88c63d6f2dfe38821afef17c416a0e1", + "zh:c23084e1b23577de22603cff752e59128d83cfecc2e6819edadd8cf7a10af11e", + ] +} diff --git a/terraform/environment/wildsea/main.tf b/terraform/environment/wildsea/main.tf new file mode 100644 index 00000000..4b1419dc --- /dev/null +++ b/terraform/environment/wildsea/main.tf @@ -0,0 +1,32 @@ +resource "null_resource" "test" {} + +variable "aws_account" { + description = "ID of the AWS Account" + type = string + sensitive = true +} + +variable "aws_region" { + description = "AWS Region name" + type = string + sensitive = true +} + +variable "state_bucket" { + description = "Name of the S3 state bucket" + type = string +} + +variable "environment" { + description = "Name of the Environment" + type = string +} + +terraform { + backend "s3" { + // region, bucket and key come from -backend-config + } +} + +provider "aws" { +} \ No newline at end of file