diff --git a/.github/workflows/terraspace.yaml b/.github/workflows/terraspace.yaml new file mode 100644 index 00000000..ca9ba687 --- /dev/null +++ b/.github/workflows/terraspace.yaml @@ -0,0 +1,238 @@ +name: Terraspace + +permissions: + contents: read + id-token: write + +on: + pull_request: + branches: + - main + paths: + - terraspace/infra-prj-a/**.tf + - terraspace/infra-prj-a/**.tfvars + +env: +# ROLE_ARN: arn:aws:iam::${{ secrets.ACCOUNT_ID }}:role/managed-oidc-service-github-actions + ROLE_SESSION_NAME: github-actions-runner + AWS_REGION: us-west-2 # TODO this should be dynamic + TF_IN_AUTOMATION: 1 + +jobs: + tflint: + runs-on: ubuntu-latest + name: TFLint + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} # Makes sure we get the latest commit from the PR + + - name: ASDF - Install + uses: asdf-vm/actions/setup@v1 + with: + asdf_branch: v0.9.0 + + - name: ASDF - Cache Tools + uses: actions/cache@v2 + env: + cache-name: cache-asdf-tools + with: + # asdf cache files are stored in `~/.asdf` on Linux/macOS + path: | + ~/.asdf/installs + ~/.asdf/plugins + ~/.asdf/shims + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/.tool-versions') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: TFLint - Cache Plugins + uses: actions/cache@v2 + with: + path: ~/.tflint.d/plugins + key: ${{ runner.os }}-tflint-${{ hashFiles('**/.tflint.hcl') }} + + - name: ASDF - Install Tools + working-directory: terraspace/infra-prj-a + run: | + cut -d' ' -f1 .tool-versions | grep -v '#' | xargs -n1 asdf plugin add || true + asdf install + terraform --version + ruby --version + + - name: Bundle - Install + working-directory: terraspace/infra-prj-a + run: bundle install + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + +# - name: Configure AWS credentials +# uses: aws-actions/configure-aws-credentials@v1 +# with: +# role-to-assume: ${{ env.ROLE_ARN }} +# role-session-name: ${{ env.ROLE_SESSION_NAME }} +# aws-region: ${{ env.AWS_REGION }} + + - name: Terraspace - All Init + working-directory: terraspace/infra-prj-a + run: terraspace all init + + - name: Terraspace - All Init Logs + working-directory: terraspace/infra-prj-a + run: terraspace logs init -a --no-timestamps + + - name: TFLint - Init + working-directory: terraspace/infra-prj-a + run: tflint --init + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: TFLint - Scan + working-directory: terraspace/infra-prj-a + run: | + find .terraspace-cache -maxdepth 4 -mindepth 4 -type d | grep stacks | xargs -I '{}' -n1 sh -c 'echo "Scanning: {}" && tflint {}' + + + + tf-sec: + runs-on: ubuntu-latest + name: TFSec + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} # Makes sure we get the latest commit from the PR + + - name: ASDF - Install + uses: asdf-vm/actions/setup@v1 + with: + asdf_branch: v0.9.0 + + - name: ASDF - Cache Tools + uses: actions/cache@v2 + env: + cache-name: cache-asdf-tools + with: + # asdf cache files are stored in `~/.asdf` on Linux/macOS + path: | + ~/.asdf/installs + ~/.asdf/plugins + ~/.asdf/shims + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/.tool-versions') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: ASDF - Install Tools + working-directory: terraspace/infra-prj-a + run: | + cut -d' ' -f1 .tool-versions | grep -v '#' | xargs -n1 asdf plugin add || true + asdf install + terraform --version + ruby --version + + - name: Bundle - Install + working-directory: terraspace/infra-prj-a + run: bundle install + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + +# - name: Configure AWS credentials +# uses: aws-actions/configure-aws-credentials@v1 +# with: +# role-to-assume: ${{ env.ROLE_ARN }} +# role-session-name: ${{ env.ROLE_SESSION_NAME }} +# aws-region: ${{ env.AWS_REGION }} + + - name: Terraspace - All Init + working-directory: terraspace/infra-prj-a + run: terraspace all init + + - name: Terraspace - All Init Logs + working-directory: terraspace/infra-prj-a + run: terraspace logs init -a --no-timestamps + + - name: TFSec + working-directory: terraspace/infra-prj-a/.terraspace-cache + run: tfsec . + + plan: + runs-on: ubuntu-latest + name: Plan + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.sha }} # Makes sure we get the latest commit from the PR + + - name: ASDF - Install + uses: asdf-vm/actions/setup@v1 + with: + asdf_branch: v0.9.0 + + - name: ASDF - Cache Tools + uses: actions/cache@v2 + env: + cache-name: cache-asdf-tools + with: + # asdf cache files are stored in `~/.asdf` on Linux/macOS + path: | + ~/.asdf/installs + ~/.asdf/plugins + ~/.asdf/shims + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/.tool-versions') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: ASDF - Install Tools + working-directory: terraspace/infra-prj-a + run: | + cut -d' ' -f1 .tool-versions | grep -v '#' | xargs -n1 asdf plugin add || true + asdf install + terraform --version + ruby --version + + - name: Bundle - Install + working-directory: terraspace/infra-prj-a + run: bundle install + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ${{ env.AWS_REGION }} + +# - name: Configure AWS credentials +# uses: aws-actions/configure-aws-credentials@v1 +# with: +# role-to-assume: ${{ env.ROLE_ARN }} +# role-session-name: ${{ env.ROLE_SESSION_NAME }} +# aws-region: ${{ env.AWS_REGION }} + + - name: Terraspace - All Plan + id: ts_all_plan + working-directory: terraspace/infra-prj-a + continue-on-error: true + run: terraspace all plan --out ":MOD_NAME.plan" + + - name: Terraspace - All Plan Logs + if: steps.ts_all_plan.conclusion != 'skipped' + working-directory: terraspace/infra-prj-a + run: terraspace logs plan -a --no-timestamps diff --git a/terraspace/infra-prj-a/.gitignore b/terraspace/infra-prj-a/.gitignore new file mode 100644 index 00000000..eeaa2f04 --- /dev/null +++ b/terraspace/infra-prj-a/.gitignore @@ -0,0 +1,39 @@ +# Terraform files +.terraform +terraform.tfstate +terraform.tfvars +*.tfstate* + +.terraspace-cache +*.plan + +# OS X files +.history +.DS_Store + +# Terraspace +/vendor + +# Common ruby files +*.gem +*.rbc +.env* +.idea +/.bundle +/.config +/.yardoc +/_yardoc +/coverage +/doc/ +/Gemfile.lock +/InstalledFiles +/lib/bundler/man +/log +/output +/pkg +/rdoc +/spec/fixtures/project/output +/spec/reports +/test/tmp +/test/version_tmp +/tmp diff --git a/terraspace/infra-prj-a/.tflint.hcl b/terraspace/infra-prj-a/.tflint.hcl new file mode 100644 index 00000000..b591de88 --- /dev/null +++ b/terraspace/infra-prj-a/.tflint.hcl @@ -0,0 +1,73 @@ +config { + module = false + force = false + disabled_by_default = false +} + +plugin "aws" { + enabled = true + version = "0.13.2" + source = "github.com/terraform-linters/tflint-ruleset-aws" +} + +rule "terraform_comment_syntax" { + enabled = true +} + +rule "terraform_deprecated_index" { + enabled = true +} + +rule "terraform_deprecated_interpolation" { + enabled = true +} + +rule "terraform_documented_outputs" { + enabled = true +} + +rule "terraform_documented_variables" { + enabled = true +} + +rule "terraform_module_pinned_source" { + enabled = true +} + +rule "terraform_module_version" { + enabled = true +} + +rule "terraform_naming_convention" { + enabled = true +} + +rule "terraform_required_providers" { + enabled = true +} + +rule "terraform_required_version" { + enabled = true +} + +rule "terraform_standard_module_structure" { + enabled = true +} + +rule "terraform_typed_variables" { + enabled = true +} + +rule "terraform_unused_declarations" { + enabled = true +} + +rule "terraform_unused_required_providers" { + # We share a common versions.tf file across our stacks so some + # stacks may end up declaring a provider which is not used + enabled = false +} + +rule "terraform_workspace_remote" { + enabled = true +} diff --git a/terraspace/infra-prj-a/.tool-versions b/terraspace/infra-prj-a/.tool-versions new file mode 100644 index 00000000..37384218 --- /dev/null +++ b/terraspace/infra-prj-a/.tool-versions @@ -0,0 +1,4 @@ +ruby 3.1.1 +terraform 1.1.7 +tfsec 1.9.0 +tflint 0.35.0 diff --git a/terraspace/infra-prj-a/Gemfile b/terraspace/infra-prj-a/Gemfile new file mode 100644 index 00000000..20540313 --- /dev/null +++ b/terraspace/infra-prj-a/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +gem "terraspace", '~> 1.1.7' +gem "rspec-terraspace" +gem "terraspace_plugin_aws" diff --git a/terraspace/infra-prj-a/README.md b/terraspace/infra-prj-a/README.md new file mode 100644 index 00000000..9dcf4933 --- /dev/null +++ b/terraspace/infra-prj-a/README.md @@ -0,0 +1,17 @@ +# Terraspace Project + +This is a Terraspace project. It contains code to provision Cloud infrastructure built with [Terraform](https://www.terraform.io/) and the [Terraspace Framework](https://terraspace.cloud/). + +## Deploy + +To deploy all the infrastructure stacks: + + AWS_PROFILE=pl-account-x AWS_REGION=us-east-1 TS_ENV=prod terraspace all up + +To deploy individual stacks: + + terraspace up demo # where demo is app/stacks/demo + +## Terrafile + +To use more modules, add them to the [Terrafile](https://terraspace.cloud/docs/terrafile/). diff --git a/terraspace/infra-prj-a/Terrafile b/terraspace/infra-prj-a/Terrafile new file mode 100644 index 00000000..ea2c93b7 --- /dev/null +++ b/terraspace/infra-prj-a/Terrafile @@ -0,0 +1,14 @@ +# Starter Terrafile +# More info: https://terraspace.cloud/docs/terrafile/ +# +# org "boltopspro" # set default github org +# +# Use modules from your org +# mod "instance", source: "terraform-aws-instance", version: "v0.1.0" +# mod "elb", source: "terraform-aws-elb" +# +# Use modules and specify org explicitly +# mod "vpc", source: "boltops-tools/terraform-aws-vpc", version: "master" +# +# Use modules from the Terraform registry +# mod "sqs", source: "terraform-aws-modules/sqs/aws" diff --git a/terraspace/infra-prj-a/app/stacks/network-base/main.tf b/terraspace/infra-prj-a/app/stacks/network-base/main.tf new file mode 100644 index 00000000..c68c3f78 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/main.tf @@ -0,0 +1,20 @@ +resource "aws_vpc" "this" { + cidr_block = var.cidr_block + + tags = merge( + var.vpc_tags, + { + Name = var.vpc_name + } + ) +} + +resource "aws_subnet" "private" { + for_each = var.private_subnets + cidr_block = each.value.cidr + vpc_id = aws_vpc.this.id + availability_zone = each.value.az + tags = { Name = each.value.name } +} + + diff --git a/terraspace/infra-prj-a/app/stacks/network-base/outputs.tf b/terraspace/infra-prj-a/app/stacks/network-base/outputs.tf new file mode 100644 index 00000000..d2029f21 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/outputs.tf @@ -0,0 +1,7 @@ +output "vpc_id" { + value = aws_vpc.this.id +} + +output "private_subnet_ids" { + value = [for s in aws_subnet.private : s.id] +} diff --git a/terraspace/infra-prj-a/app/stacks/network-base/tfvars/base.tfvars b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/base.tfvars new file mode 100644 index 00000000..227d9a99 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/base.tfvars @@ -0,0 +1 @@ +vpc_name = "nw-<%= Terraspace.env %>" diff --git a/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-east-1/dev.tfvars b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-east-1/dev.tfvars new file mode 100644 index 00000000..3deac6a0 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-east-1/dev.tfvars @@ -0,0 +1,18 @@ +cidr_block = "10.0.0.0/22" +private_subnets = { + a = { + name = "nw-a" + az = "us-east-1a" + cidr = "10.0.0.0/27" + }, + b = { + name = "nw-b" + az = "us-east-1b" + cidr = "10.0.0.32/27" + }, + c = { + name = "nw-c" + az = "us-east-1c" + cidr = "10.0.0.64/27" + }, +} diff --git a/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-west-2/dev.tfvars b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-west-2/dev.tfvars new file mode 100644 index 00000000..462dda58 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/tfvars/us-west-2/dev.tfvars @@ -0,0 +1,18 @@ +cidr_block = "10.0.4.0/22" +private_subnets = { + a = { + name = "nw-a" + az = "us-west-2a" + cidr = "10.0.4.0/27" + }, + b = { + name = "nw-b" + az = "us-west-2b" + cidr = "10.0.4.32/27" + }, + c = { + name = "nw-c" + az = "us-west-2c" + cidr = "10.0.4.64/27" + }, +} diff --git a/terraspace/infra-prj-a/app/stacks/network-base/variables.tf b/terraspace/infra-prj-a/app/stacks/network-base/variables.tf new file mode 100644 index 00000000..c3543f05 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/network-base/variables.tf @@ -0,0 +1,23 @@ +variable "vpc_name" { + description = "Name of the VPC" + type = string +} + +variable "vpc_tags" { + description = "Tags to associate to the VPC" + type = map(string) + default = {} +} + +variable "cidr_block" { + description = "CIDR block for the VPC" + type = string +} + +variable "private_subnets" { + type = map(object({ + name = string + cidr = string + az = string + })) +} diff --git a/terraspace/infra-prj-a/app/stacks/server/main.tf b/terraspace/infra-prj-a/app/stacks/server/main.tf new file mode 100644 index 00000000..e3ceac46 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/server/main.tf @@ -0,0 +1,5 @@ +resource "aws_alb" "this" { + subnets = var.subnet_ids + load_balancer_type = "application" + internal = true +} diff --git a/terraspace/infra-prj-a/app/stacks/server/outputs.tf b/terraspace/infra-prj-a/app/stacks/server/outputs.tf new file mode 100644 index 00000000..2056b6a2 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/server/outputs.tf @@ -0,0 +1 @@ +# This is where you put your outputs declaration diff --git a/terraspace/infra-prj-a/app/stacks/server/tfvars/base.tfvars b/terraspace/infra-prj-a/app/stacks/server/tfvars/base.tfvars new file mode 100644 index 00000000..2bc0ca86 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/server/tfvars/base.tfvars @@ -0,0 +1,2 @@ +subnet_ids = <%= output("network-base.private_subnet_ids", mock: []) %> + diff --git a/terraspace/infra-prj-a/app/stacks/server/variables.tf b/terraspace/infra-prj-a/app/stacks/server/variables.tf new file mode 100644 index 00000000..f0ee95c9 --- /dev/null +++ b/terraspace/infra-prj-a/app/stacks/server/variables.tf @@ -0,0 +1,3 @@ +variable "subnet_ids" { + description = "subnet IDs to associate to the loadbalancer" +} diff --git a/terraspace/infra-prj-a/config/app.rb b/terraspace/infra-prj-a/config/app.rb new file mode 100644 index 00000000..5f613915 --- /dev/null +++ b/terraspace/infra-prj-a/config/app.rb @@ -0,0 +1,4 @@ +# Docs: https://terraspace.cloud/docs/config/reference/ +Terraspace.configure do |config| + config.logger.level = :info +end diff --git a/terraspace/infra-prj-a/config/terraform/backend.tf b/terraspace/infra-prj-a/config/terraform/backend.tf new file mode 100644 index 00000000..0541dd8b --- /dev/null +++ b/terraspace/infra-prj-a/config/terraform/backend.tf @@ -0,0 +1,9 @@ +terraform { + backend "s3" { + bucket = "<%= expansion('tf-state-:ACCOUNT-:REGION-:ENV') %>" + key = "<%= expansion(':REGION/:ENV/:BUILD_DIR/terraform.tfstate') %>" + region = "<%= expansion(':REGION') %>" + encrypt = true + dynamodb_table = "terraform_locks" + } +} diff --git a/terraspace/infra-prj-a/config/terraform/provider.tf b/terraspace/infra-prj-a/config/terraform/provider.tf new file mode 100644 index 00000000..a82ad589 --- /dev/null +++ b/terraspace/infra-prj-a/config/terraform/provider.tf @@ -0,0 +1,28 @@ +# Docs: https://www.terraform.io/docs/providers/aws/index.html +# +# If AWS_PROFILE and AWS_REGION is set, then the provider is optional. Here's an example anyway: +# +# provider "aws" { +# region = "us-east-1" +# } + +provider "aws" { + default_tags { + tags = { + automation = "Terraspace" + repo = "ipfs-elastic-provider-infrastructure" + project = "infra-prj-a" + owner = "nearform" + env = "<%= Terraspace.env %>" + } + } +} + + +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace plan network-base +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace plan server +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace all plan +// +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace up network-base +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace up server +//AWS_PROFILE=protocol-labs-prod AWS_REGION=us-west-2 TS_ENV=dev bundle exec terraspace all up \ No newline at end of file diff --git a/terraspace/infra-prj-a/config/terraform/versions.tf b/terraspace/infra-prj-a/config/terraform/versions.tf new file mode 100644 index 00000000..c6f3bb00 --- /dev/null +++ b/terraspace/infra-prj-a/config/terraform/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + aws = { + source = "hashicorp/aws" + version = "~> 4.4" + } + } +}