diff --git a/.gitattributes b/.gitattributes index 1f16008051d..5fed3e476ed 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,6 @@ scripts/docker/** linguist-vendored scripts/githooks/** linguist-vendored scripts/reports/** linguist-vendored -scripts/terraform/** linguist-vendored scripts/tests/test.mk linguist-vendored scripts/init.mk linguist-vendored scripts/shellscript-linter.sh linguist-vendored diff --git a/.github/actions/lint-terraform/action.yaml b/.github/actions/lint-terraform/action.yaml deleted file mode 100644 index d5dfe35d19c..00000000000 --- a/.github/actions/lint-terraform/action.yaml +++ /dev/null @@ -1,20 +0,0 @@ -name: "Lint Terraform" -description: "Lint Terraform" -inputs: - root-modules: - description: "Comma separated list of root module directories to validate, content of the 'infrastructure/environments' is checked by default" - required: false -runs: - using: "composite" - steps: - - name: "Check Terraform format" - shell: bash - run: | - check_only=true scripts/githooks/check-terraform-format.sh - - name: "Validate Terraform" - shell: bash - run: | - stacks=${{ inputs.root-modules }} - for dir in $(find infrastructure/environments -maxdepth 1 -mindepth 1 -type d; echo ${stacks//,/$'\n'}); do - dir=$dir make terraform-validate - done diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 17ef311a361..7706a6d418e 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -21,8 +21,3 @@ updates: directory: "/" schedule: interval: "daily" - - - package-ecosystem: "terraform" - directory: "/" - schedule: - interval: "daily" diff --git a/.github/workflows/cicd-1-pull-request.yaml b/.github/workflows/cicd-1-pull-request.yaml index cd068ec0682..d741ea42031 100644 --- a/.github/workflows/cicd-1-pull-request.yaml +++ b/.github/workflows/cicd-1-pull-request.yaml @@ -21,7 +21,6 @@ jobs: build_epoch: ${{ steps.variables.outputs.build_epoch }} nodejs_version: ${{ steps.variables.outputs.nodejs_version }} python_version: ${{ steps.variables.outputs.python_version }} - terraform_version: ${{ steps.variables.outputs.terraform_version }} version: ${{ steps.variables.outputs.version }} does_pull_request_exist: ${{ steps.pr_exists.outputs.does_pull_request_exist }} steps: @@ -38,7 +37,6 @@ jobs: echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT echo "nodejs_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT echo "python_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT - echo "terraform_version=$(grep "^terraform" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT - name: "Check if pull request exists for this branch" id: pr_exists @@ -62,7 +60,6 @@ jobs: export BUILD_EPOCH="${{ steps.variables.outputs.build_epoch }}" export NODEJS_VERSION="${{ steps.variables.outputs.nodejs_version }}" export PYTHON_VERSION="${{ steps.variables.outputs.python_version }}" - export TERRAFORM_VERSION="${{ steps.variables.outputs.terraform_version }}" export VERSION="${{ steps.variables.outputs.version }}" export DOES_PULL_REQUEST_EXIST="${{ steps.pr_exists.outputs.does_pull_request_exist }}" make list-variables @@ -76,7 +73,6 @@ jobs: build_epoch: "${{ needs.metadata.outputs.build_epoch }}" nodejs_version: "${{ needs.metadata.outputs.nodejs_version }}" python_version: "${{ needs.metadata.outputs.python_version }}" - terraform_version: "${{ needs.metadata.outputs.terraform_version }}" version: "${{ needs.metadata.outputs.version }}" secrets: inherit test-stage: # Recommended maximum execution time is 5 minutes @@ -89,7 +85,6 @@ jobs: build_epoch: "${{ needs.metadata.outputs.build_epoch }}" nodejs_version: "${{ needs.metadata.outputs.nodejs_version }}" python_version: "${{ needs.metadata.outputs.python_version }}" - terraform_version: "${{ needs.metadata.outputs.terraform_version }}" version: "${{ needs.metadata.outputs.version }}" secrets: inherit build-stage: # Recommended maximum execution time is 3 minutes @@ -103,7 +98,6 @@ jobs: build_epoch: "${{ needs.metadata.outputs.build_epoch }}" nodejs_version: "${{ needs.metadata.outputs.nodejs_version }}" python_version: "${{ needs.metadata.outputs.python_version }}" - terraform_version: "${{ needs.metadata.outputs.terraform_version }}" version: "${{ needs.metadata.outputs.version }}" secrets: inherit acceptance-stage: # Recommended maximum execution time is 10 minutes @@ -117,6 +111,5 @@ jobs: build_epoch: "${{ needs.metadata.outputs.build_epoch }}" nodejs_version: "${{ needs.metadata.outputs.nodejs_version }}" python_version: "${{ needs.metadata.outputs.python_version }}" - terraform_version: "${{ needs.metadata.outputs.terraform_version }}" version: "${{ needs.metadata.outputs.version }}" secrets: inherit diff --git a/.github/workflows/cicd-2-publish.yaml b/.github/workflows/cicd-2-publish.yaml index 5717ee9b552..0be8b6f76b0 100644 --- a/.github/workflows/cicd-2-publish.yaml +++ b/.github/workflows/cicd-2-publish.yaml @@ -18,7 +18,6 @@ jobs: build_epoch: ${{ steps.variables.outputs.build_epoch }} nodejs_version: ${{ steps.variables.outputs.nodejs_version }} python_version: ${{ steps.variables.outputs.python_version }} - terraform_version: ${{ steps.variables.outputs.terraform_version }} version: ${{ steps.variables.outputs.version }} steps: - name: "Checkout code" @@ -32,7 +31,6 @@ jobs: echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT echo "nodejs_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT echo "python_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT - echo "terraform_version=$(grep "^terraform" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT # TODO: Get the version, but it may not be the .version file as this should come from the CI/CD Pull Request Workflow echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT - name: "List variables" @@ -42,7 +40,6 @@ jobs: export BUILD_EPOCH="${{ steps.variables.outputs.build_epoch }}" export NODEJS_VERSION="${{ steps.variables.outputs.nodejs_version }}" export PYTHON_VERSION="${{ steps.variables.outputs.python_version }}" - export TERRAFORM_VERSION="${{ steps.variables.outputs.terraform_version }}" export VERSION="${{ steps.variables.outputs.version }}" make list-variables publish: diff --git a/.github/workflows/cicd-3-deploy.yaml b/.github/workflows/cicd-3-deploy.yaml index 2745b380137..95c88dd248b 100644 --- a/.github/workflows/cicd-3-deploy.yaml +++ b/.github/workflows/cicd-3-deploy.yaml @@ -19,7 +19,6 @@ jobs: build_epoch: ${{ steps.variables.outputs.build_epoch }} nodejs_version: ${{ steps.variables.outputs.nodejs_version }} python_version: ${{ steps.variables.outputs.python_version }} - terraform_version: ${{ steps.variables.outputs.terraform_version }} version: ${{ steps.variables.outputs.version }} tag: ${{ steps.variables.outputs.tag }} steps: @@ -34,7 +33,6 @@ jobs: echo "build_epoch=$(date --date=$datetime -u +'%s')" >> $GITHUB_OUTPUT echo "nodejs_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT echo "python_version=$(grep "^nodejs" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT - echo "terraform_version=$(grep "^terraform" .tool-versions | cut -f2 -d' ')" >> $GITHUB_OUTPUT # TODO: Get the version, but it may not be the .version file as this should come from the CI/CD Pull Request Workflow echo "version=$(head -n 1 .version 2> /dev/null || echo unknown)" >> $GITHUB_OUTPUT echo "tag=${{ github.event.inputs.tag }}" >> $GITHUB_OUTPUT @@ -45,7 +43,6 @@ jobs: export BUILD_EPOCH="${{ steps.variables.outputs.build_epoch }}" export NODEJS_VERSION="${{ steps.variables.outputs.nodejs_version }}" export PYTHON_VERSION="${{ steps.variables.outputs.python_version }}" - export TERRAFORM_VERSION="${{ steps.variables.outputs.terraform_version }}" export VERSION="${{ steps.variables.outputs.version }}" export TAG="${{ steps.variables.outputs.tag }}" make list-variables diff --git a/.github/workflows/stage-1-commit.yaml b/.github/workflows/stage-1-commit.yaml index a516b786343..209efb0d25e 100644 --- a/.github/workflows/stage-1-commit.yaml +++ b/.github/workflows/stage-1-commit.yaml @@ -23,10 +23,6 @@ on: description: "Python version, set by the CI/CD pipeline workflow" required: true type: string - terraform_version: - description: "Terraform version, set by the CI/CD pipeline workflow" - required: true - type: string version: description: "Version of the software, set by the CI/CD pipeline workflow" required: true @@ -77,15 +73,6 @@ jobs: fetch-depth: 0 # Full history is needed to compare branches - name: "Check English usage" uses: ./.github/actions/check-english-usage - lint-terraform: - name: "Lint Terraform" - runs-on: ubuntu-latest - timeout-minutes: 2 - steps: - - name: "Checkout code" - uses: actions/checkout@v4 - - name: "Lint Terraform" - uses: ./.github/actions/lint-terraform count-lines-of-code: name: "Count lines of code" runs-on: ubuntu-latest diff --git a/.github/workflows/stage-2-test.yaml b/.github/workflows/stage-2-test.yaml index efcb2ac4671..8af66ad64ae 100644 --- a/.github/workflows/stage-2-test.yaml +++ b/.github/workflows/stage-2-test.yaml @@ -23,10 +23,6 @@ on: description: "Python version, set by the CI/CD pipeline workflow" required: true type: string - terraform_version: - description: "Terraform version, set by the CI/CD pipeline workflow" - required: true - type: string version: description: "Version of the software, set by the CI/CD pipeline workflow" required: true diff --git a/.github/workflows/stage-3-build.yaml b/.github/workflows/stage-3-build.yaml index 2a53a07a110..fab62915bdc 100644 --- a/.github/workflows/stage-3-build.yaml +++ b/.github/workflows/stage-3-build.yaml @@ -23,10 +23,6 @@ on: description: "Python version, set by the CI/CD pipeline workflow" required: true type: string - terraform_version: - description: "Terraform version, set by the CI/CD pipeline workflow" - required: true - type: string version: description: "Version of the software, set by the CI/CD pipeline workflow" required: true diff --git a/.github/workflows/stage-4-acceptance.yaml b/.github/workflows/stage-4-acceptance.yaml index d554f98af0a..d4e4155b628 100644 --- a/.github/workflows/stage-4-acceptance.yaml +++ b/.github/workflows/stage-4-acceptance.yaml @@ -23,10 +23,6 @@ on: description: "Python version, set by the CI/CD pipeline workflow" required: true type: string - terraform_version: - description: "Terraform version, set by the CI/CD pipeline workflow" - required: true - type: string version: description: "Version of the software, set by the CI/CD pipeline workflow" required: true diff --git a/.tool-versions b/.tool-versions index 4cf4d1041c0..c69b41f4660 100644 --- a/.tool-versions +++ b/.tool-versions @@ -13,7 +13,6 @@ editorconfig-checker 3.2.1 # docker/ghcr.io/make-ops-tools/gocloc latest@sha256:6888e62e9ae693c4ebcfed9f1d86c70fd083868acb8815fe44b561b9a73b5032 # SEE: https://github.com/make-ops-tools/gocloc/pkgs/container/gocloc # docker/ghcr.io/nhs-england-tools/github-runner-image 20230909-321fd1e-rt@sha256:ce4fd6035dc450a50d3cbafb4986d60e77cb49a71ab60a053bb1b9518139a646 # SEE: https://github.com/nhs-england-tools/github-runner-image/pkgs/container/github-runner-image # docker/hadolint/hadolint 2.12.0-alpine@sha256:7dba9a9f1a0350f6d021fb2f6f88900998a4fb0aaf8e4330aa8c38544f04db42 # SEE: https://hub.docker.com/r/hadolint/hadolint/tags -# docker/hashicorp/terraform 1.5.6@sha256:180a7efa983386a27b43657ed610e9deed9e6c3848d54f9ea9b6cb8a5c8c25f5 # SEE: https://hub.docker.com/r/hashicorp/terraform/tags # docker/jdkato/vale v2.29.7@sha256:5ccfac574231b006284513ac3e4e9f38833989d83f2a68db149932c09de85149 # SEE: https://hub.docker.com/r/jdkato/vale/tags # docker/koalaman/shellcheck latest@sha256:e40388688bae0fcffdddb7e4dea49b900c18933b452add0930654b2dea3e7d5c # SEE: https://hub.docker.com/r/koalaman/shellcheck/tags # docker/mstruebing/editorconfig-checker 2.7.1@sha256:dd3ca9ea50ef4518efe9be018d669ef9cf937f6bb5cfe2ef84ff2a620b5ddc24 # SEE: https://hub.docker.com/r/mstruebing/editorconfig-checker/tags diff --git a/docs/developer-guides/Bash_and_Make.md b/docs/developer-guides/Bash_and_Make.md index d4379910045..6d914f0a1fa 100644 --- a/docs/developer-guides/Bash_and_Make.md +++ b/docs/developer-guides/Bash_and_Make.md @@ -17,7 +17,7 @@ some-target: # Target description - mandatory: foo=[description]; optional: baz= # Recipe implementation... ``` -- `some-target`: This is the name of the target you would specify when you want to run this particular target. Use the kebab-case naming convention and prefix with an underscore `_` to mark it as a "private" target. The first part of the name is used for grouping, e.g. `docker-*` or `terraform-*`. +- `some-target`: This is the name of the target you would specify when you want to run this particular target. Use the kebab-case naming convention and prefix with an underscore `_` to mark it as a "private" target. The first part of the name is used for grouping, e.g. `docker-*`. - `Target Description`: Provided directly after the target name as a single line, so be concise. - `mandatory` parameters: Parameters that must be provided when invoking the target. Each parameter has its own description. Please follow the specified format as it is used by `make help`. - `optional` parameters: Parameters that are not required when invoking the target. They may have a default value. Each parameter has its own description. diff --git a/docs/developer-guides/Scripting_Terraform.md b/docs/developer-guides/Scripting_Terraform.md deleted file mode 100644 index 14b80ca1a68..00000000000 --- a/docs/developer-guides/Scripting_Terraform.md +++ /dev/null @@ -1,174 +0,0 @@ -# Developer Guide: Scripting Terraform - -- [Developer Guide: Scripting Terraform](#developer-guide-scripting-terraform) - - [Overview](#overview) - - [Features](#features) - - [Key files](#key-files) - - [Usage](#usage) - - [Quick start](#quick-start) - - [Your stack implementation](#your-stack-implementation) - - [Conventions](#conventions) - - [Secrets](#secrets) - - [Variables](#variables) - - [IaC directory](#iac-directory) - - [FAQ](#faq) - -## Overview - -Terraform is an open-source infrastructure as code (IaC) tool. It allows you to define, provision and manage infrastructure in a declarative way, using a configuration language called HCL. Terraform can manage a wide variety of resources, such as virtual machines, databases, networking components and many more, across multiple cloud providers like AWS and Azure. - -Some advantages of using Terraform are as outlined below: - -- **Declarative configuration**: Terraform enables the precise definition of the desired state of infrastructure, streamlining its creation through a readable and understandable codebase. -- **Version control**: The infrastructure code may be subject to version control, thereby providing an audit trail of environmental changes. -- **Modularisation and reusability**: Terraform facilitates the packaging of infrastructure into modular components, enhancing both reusability and ease of sharing across organisational teams. -- **State management**: Terraform's state management capabilities ensure an accurate representation of real-world resources, enabling features such as resource dependencies and idempotence. -- **Collaboration and workflow**: The platform supports collaboration through features like remote backends and state locking, thereby fostering collective work on infrastructure projects. -- **Community and ecosystem**: A robust community actively contributes to the Terraform ecosystem, providing a wealth of modules and examples that expedite infrastructure development. - -## Features - -Here are some key features built into this repository's Terraform module: - -- Provides Make targets for frequently-used Terraform commands for streamlined execution -- Offers code completion and command signature assistance via Make for enhanced CLI usability -- Supports named arguments with default values for an improved coding experience -- Allows the working directory to be controlled by either arguments or a predefined constant for flexible stack management -- Features a command wrapper to improve the onboarding experience and ensure environmental consistency -- Incorporates both a Git hook and a GitHub action to enforce code quality standards -- Comes with the CI/CD pipeline workflow integration -- Includes a file cleanup routine to efficiently remove temporary resources -- Incorporates a ready-to-run example to demonstrate the module's capabilities -- Integrates a code linting routine to ensure scripts are free from unintended side effects -- Includes a verbose mode for in-depth troubleshooting and debugging -- Incorporates a best practice guide - -## Key files - -- Scripts - - [`terraform.lib.sh`](../../scripts/terraform/terraform.lib.sh) A library code loaded by custom make targets and CLI scripts - - [`terraform.mk`](../../scripts/terraform/terraform.mk): Customised implementation of the Terraform routines loaded by the `scripts/init.mk` file - - [`terraform.sh`](../../scripts/terraform/terraform.sh): Terraform command wrapper -- Configuration - - [`.tool-versions`](../../.tool-versions): Stores Terraform version to be used -- Code quality gates - - [`lint-terraform/action.yaml`](../../.github/actions/lint-terraform/action.yaml): GitHub action - - [`check-terraform-format.sh`](../../scripts/githooks/check-terraform-format.sh): Git hook -- Usage example - - Declarative infrastructure definition example [`terraform-state-aws-s3`](../../scripts/terraform/examples/terraform-state-aws-s3) to store Terraform state - - A set of [make targets](https://github.com/nhs-england-tools/repository-template/blob/main/scripts/terraform/terraform.mk#L44) to run the example - -## Usage - -### Quick start - -Run the example: - -```shell -# AWS console access setup -export AWS_ACCESS_KEY_ID="..." -export AWS_SECRET_ACCESS_KEY="..." -export AWS_SESSION_TOKEN="..." -``` - -```shell -$ make terraform-example-provision-aws-infrastructure - -Initializing the backend.. -... -Plan: 5 to add, 0 to change, 0 to destroy. -Saved the plan to: terraform.tfplan -To perform exactly these actions, run the following command to apply: - terraform apply "terraform.tfplan" -... -Apply complete! Resources: 5 added, 0 changed, 0 destroyed. - -$ make terraform-example-destroy-aws-infrastructure - -... -Plan: 0 to add, 0 to change, 5 to destroy. -... -Apply complete! Resources: 0 added, 0 changed, 5 destroyed. -``` - -### Your stack implementation - -Always follow [best practices for using Terraform](https://cloud.google.com/docs/terraform/best-practices-for-terraform) while providing infrastructure as code (IaC) for your service. - -Directory structure: - -```shell -service-repository/ -├─ ... -└─ infrastructure/ - ├─ modules/ - │ ├─ service-module-name/ - │ │ ├─ main.tf - │ │ ├─ outputs.tf - │ │ ├─ variables.tf - │ │ ├─ versions.tf - │ │ └─ README.md - │ ... - ├─ environments/ - │ ├─ dev/ # This is where your ephemeral environments live - │ │ ├─ backend.tf - │ │ ├─ main.tf - │ │ ├─ provider.tf - │ │ └─ terraform.tfvars - │ ├─ nonprod/ - | │ ├─ ... - │ └─ prod/ - | ├─ ... - └─ .gitignore -``` - -At its core, the structure of the Terraform setup consists of two main parts. The `modules` section is designed to house the shared or common configurations for a service. Meanwhile, the individual folders for each environment, like `dev` (ephemeral environments), `nonprod`, `prod` and so on, invoke these shared modules while also defining their unique variables and parameters. By arranging resources in distinct Terraform directories for every component, we ensure clarity and promote cohesion. Each environment directory not only references shared code from the `modules` section but also represents a default Terraform workspace as a deployment of the service to the designated environment. - -Stack management: - -```shell -export STACK=infrastructure/environments/dev # or use 'dir' argument on each command -make terraform-init -make terraform-plan opts="-out=terraform.tfplan" -make terraform-apply opts="-auto-approve terraform.tfplan" -make terraform-destroy opts="-auto-approve" -``` - -Plugging it in to the CI/CD pipeline lifecycle: - -```shell -deploy: # Deploy the project artefact to the target environment - # The value assigned to this variable should be driven by the GitHub environments setup - STACK=infrastructure/environments/security-test \ - make environment-set-up - # Prepare datastore - # Deploy artefact - -environment-set-up: # Use for all environment types - STACK=[path to your stack] - make terraform-init - make terraform-plan opts="-out=terraform.tfplan" - make terraform-apply opts="-auto-approve terraform.tfplan" - -environment-tear-down: # Use only for ephemeral environments, e.g. dev and test automation - STACK=[path to your stack] - make terraform-destroy opts="-auto-approve" -``` - -## Conventions - -### Secrets - -GitHub secrets for Terraform must be granular to avoid appearing in logs. For example, use `arn:aws:iam::${{ secrets.AWS_ACCOUNT_ID }}:role/${{ secrets.AWS_ASSUME_ROLE_NAME }}`. It has been proven that if a role ARN is defined as `AWS_ROLE_ARN`, details such as the account number are not redacted from the output and are visible in plain text. While this information may not be considered sensitive on its own, it could contribute to a vector attack and therefore be used to exploit the service. - -### Variables - -To specify the location of your Terraform [root module](https://developer.hashicorp.com/terraform/language/modules#the-root-module) set the `terraform_stack` or `TERRAFORM_STACK` variable. Alternatively, you can use their shorthand versions, `stack` or `STACK`. To emphasize that it is a global variable, using the uppercase version is recommended, depending on your implementation. All environment stacks must be root modules and should be located in the `infrastructure/environments` directory. - -### IaC directory - -The `infrastructure` directory is used to store IaC, as it is the most descriptive and portable name. This approach enables the use of supporting technologies, CDKs and solutions specific to the cloud providers like AWS and Azure. - -## FAQ - -1. _What are the advantages of using this module over directly invoking Terraform commands?_ - - The primary purpose of this module is to integrate best practices for CI/CD pipeline workflows with infrastructure as code (IaC), offering a well-defined structural framework that encourages modularisation and reusability of components. Additionally, it enhances the onboarding experience and increases the portability of the provisioning process. diff --git a/docs/user-guides/Run_Git_hooks_on_commit.md b/docs/user-guides/Run_Git_hooks_on_commit.md index 5dd191f5e55..23910bee4f1 100644 --- a/docs/user-guides/Run_Git_hooks_on_commit.md +++ b/docs/user-guides/Run_Git_hooks_on_commit.md @@ -16,7 +16,6 @@ The [pre-commit](https://pre-commit.com/) framework is a powerful tool for manag - Scripts - [`check-file-format.sh`](../../scripts/githooks/check-file-format.sh) - [`check-markdown-format.sh`](../../scripts/githooks/check-markdown-format.sh) - - [`check-terraform-format.sh`](../../scripts/githooks/check-terraform-format.sh) - [`scan-secrets.sh`](../../scripts/githooks/scan-secrets.sh) - Configuration - [`pre-commit.yaml`](../../scripts/config/pre-commit.yaml) diff --git a/infrastructure/.gitignore b/infrastructure/.gitignore deleted file mode 100644 index 22ebdac3536..00000000000 --- a/infrastructure/.gitignore +++ /dev/null @@ -1,37 +0,0 @@ -# SEE: https://github.com/github/gitignore/blob/main/Terraform.gitignore - -# Local .terraform directories -**/.terraform/* - -# .tfstate files -*.tfstate -*.tfstate.* - -# Crash log files -crash.log -crash.*.log - -# Exclude all .tfvars files, which are likely to contain sensitive data, such as -# password, private keys, and other secrets. These should not be part of version -# control as they are data points which are potentially sensitive and subject -# to change depending on the environment. -*.tfvars -*.tfvars.json - -# Ignore override files as they are usually used to override resources locally and so -# are not checked in -override.tf -override.tf.json -*_override.tf -*_override.tf.json - -# Include override files you do wish to add to version control using negated pattern -# !example_override.tf - -# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan -# example: *tfplan* -*tfplan* - -# Ignore CLI configuration files -.terraformrc -terraform.rc diff --git a/infrastructure/environments/.gitkeep b/infrastructure/environments/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/infrastructure/images/.gitkeep b/infrastructure/images/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/infrastructure/modules/.gitkeep b/infrastructure/modules/.gitkeep deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/scripts/config/gitleaks.toml b/scripts/config/gitleaks.toml index af5f0bb7160..18860d6053c 100644 --- a/scripts/config/gitleaks.toml +++ b/scripts/config/gitleaks.toml @@ -16,4 +16,4 @@ regexes = [ ] [allowlist] -paths = ['''.terraform.lock.hcl''', '''poetry.lock''', '''yarn.lock'''] +paths = ['''poetry.lock''', '''yarn.lock'''] diff --git a/scripts/config/pre-commit.yaml b/scripts/config/pre-commit.yaml index 37ca6375044..3156979c680 100644 --- a/scripts/config/pre-commit.yaml +++ b/scripts/config/pre-commit.yaml @@ -31,10 +31,3 @@ repos: args: ["check=staged-changes"] language: script pass_filenames: false -- repo: local - hooks: - - id: lint-terraform - name: Lint Terraform - entry: ./scripts/githooks/check-terraform-format.sh - language: script - pass_filenames: false diff --git a/scripts/githooks/check-terraform-format.sh b/scripts/githooks/check-terraform-format.sh deleted file mode 100755 index 7255e512682..00000000000 --- a/scripts/githooks/check-terraform-format.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash - -# WARNING: Please DO NOT edit this file! It is maintained in the Repository Template (https://github.com/nhs-england-tools/repository-template). Raise a PR instead. - -set -euo pipefail - -# Pre-commit git hook to check format Terraform code. -# -# Usage: -# $ [options] ./check-terraform-format.sh -# -# Options: -# check_only=true # Do not format, run check only, default is 'false' -# FORCE_USE_DOCKER=true # If set to true the command is run in a Docker container, default is 'false' -# VERBOSE=true # Show all the executed commands, default is 'false' - -# ============================================================================== - -function main() { - - cd "$(git rev-parse --show-toplevel)" - - local check_only=${check_only:-false} - check_only=$check_only terraform-fmt -} - -# Format Terraform files. -# Arguments (provided as environment variables): -# check_only=[do not format, run check only] -function terraform-fmt() { - - local opts= - if is-arg-true "$check_only"; then - opts="-check" - fi - opts=$opts make terraform-fmt -} - -# ============================================================================== - -function is-arg-true() { - - if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then - return 0 - else - return 1 - fi -} - -# ============================================================================== - -is-arg-true "${VERBOSE:-false}" && set -x - -main "$@" - -exit 0 diff --git a/scripts/init.mk b/scripts/init.mk index 373f8a4f456..24887ff6239 100644 --- a/scripts/init.mk +++ b/scripts/init.mk @@ -2,7 +2,6 @@ include scripts/docker/docker.mk include scripts/tests/test.mk --include scripts/terraform/terraform.mk # ============================================================================== diff --git a/scripts/terraform/examples/terraform-state-aws-s3/.gitignore b/scripts/terraform/examples/terraform-state-aws-s3/.gitignore deleted file mode 100644 index c831140710d..00000000000 --- a/scripts/terraform/examples/terraform-state-aws-s3/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Ignore the lock file as this is just an example -.terraform.lock.hcl -# Ignore Terraform plan -*tfplan* - -# SEE: https://github.com/github/gitignore/blob/main/Terraform.gitignore - -# Local .terraform directories -**/.terraform/* - -# .tfstate files -*.tfstate -*.tfstate.* - -# Crash log files -crash.log -crash.*.log - -# Exclude all .tfvars files, which are likely to contain sensitive data, such as -# password, private keys, and other secrets. These should not be part of version -# control as they are data points which are potentially sensitive and subject -# to change depending on the environment. -*.tfvars -*.tfvars.json - -# Ignore override files as they are usually used to override resources locally and so -# are not checked in -override.tf -override.tf.json -*_override.tf -*_override.tf.json - -# Include override files you do wish to add to version control using negated pattern -# !example_override.tf - -# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan -# example: *tfplan* - -# Ignore CLI configuration files -.terraformrc -terraform.rc diff --git a/scripts/terraform/examples/terraform-state-aws-s3/main.tf b/scripts/terraform/examples/terraform-state-aws-s3/main.tf deleted file mode 100644 index a4ca5b0e5aa..00000000000 --- a/scripts/terraform/examples/terraform-state-aws-s3/main.tf +++ /dev/null @@ -1,46 +0,0 @@ -resource "aws_s3_bucket" "terraform_state_store" { - bucket = var.terraform_state_bucket_name - lifecycle { - prevent_destroy = false // FIXME: Normally, this should be 'true' - this is just an example - } -} - -resource "aws_s3_bucket_versioning" "enabled" { - bucket = aws_s3_bucket.terraform_state_store.id - versioning_configuration { - status = "Enabled" - } -} - -resource "aws_s3_bucket_server_side_encryption_configuration" "default" { - bucket = aws_s3_bucket.terraform_state_store.id - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "AES256" - } - } -} - -resource "aws_s3_bucket_public_access_block" "public_access" { - bucket = aws_s3_bucket.terraform_state_store.id - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -resource "aws_dynamodb_table" "dynamodb_terraform_state_lock" { - name = var.terraform_state_table_name - billing_mode = "PAY_PER_REQUEST" - hash_key = "LockID" - attribute { - name = "LockID" - type = "S" - } - server_side_encryption { - enabled = true - } - point_in_time_recovery { - enabled = true - } -} diff --git a/scripts/terraform/examples/terraform-state-aws-s3/provider.tf b/scripts/terraform/examples/terraform-state-aws-s3/provider.tf deleted file mode 100644 index b64be2afe0b..00000000000 --- a/scripts/terraform/examples/terraform-state-aws-s3/provider.tf +++ /dev/null @@ -1,3 +0,0 @@ -provider "aws" { - region = "eu-west-2" -} diff --git a/scripts/terraform/examples/terraform-state-aws-s3/variables.tf b/scripts/terraform/examples/terraform-state-aws-s3/variables.tf deleted file mode 100644 index 07f60cb1813..00000000000 --- a/scripts/terraform/examples/terraform-state-aws-s3/variables.tf +++ /dev/null @@ -1,9 +0,0 @@ -variable "terraform_state_bucket_name" { - description = "The S3 bucket name to store Terraform state" - default = "repository-template-example-terraform-state-store" -} - -variable "terraform_state_table_name" { - description = "The DynamoDB table name to acquire Terraform lock" - default = "repository-template-example-terraform-state-lock" -} diff --git a/scripts/terraform/examples/terraform-state-aws-s3/versions.tf b/scripts/terraform/examples/terraform-state-aws-s3/versions.tf deleted file mode 100644 index 18fd04af82a..00000000000 --- a/scripts/terraform/examples/terraform-state-aws-s3/versions.tf +++ /dev/null @@ -1,8 +0,0 @@ -terraform { - required_version = ">= 1.5.0" - required_providers { - aws = { - version = ">= 5.14.0" - } - } -} diff --git a/scripts/terraform/terraform.lib.sh b/scripts/terraform/terraform.lib.sh deleted file mode 100644 index 7793b9b0243..00000000000 --- a/scripts/terraform/terraform.lib.sh +++ /dev/null @@ -1,93 +0,0 @@ -#!/bin/bash - -# WARNING: Please DO NOT edit this file! It is maintained in the Repository Template (https://github.com/nhs-england-tools/repository-template). Raise a PR instead. - -set -euo pipefail - -# A set of Terraform functions written in Bash. -# -# Usage: -# $ source ./terraform.lib.sh - -# ============================================================================== -# Common Terraform functions. - -# Initialise Terraform. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform init command, default is none/empty] -function terraform-init() { - - _terraform init # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# Plan Terraform changes. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform plan command, default is none/empty] -function terraform-plan() { - - _terraform plan # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# Apply Terraform changes. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform apply command, default is none/empty] -function terraform-apply() { - - _terraform apply # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# Destroy Terraform resources. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform destroy command, default is none/empty] -function terraform-destroy() { - - _terraform apply -destroy # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# Format Terraform code. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform fmt command, default is '-recursive'] -function terraform-fmt() { - - _terraform fmt -recursive # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# Validate Terraform code. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -# opts=[options to pass to the Terraform validate command, default is none/empty] -function terraform-validate() { - - _terraform validate # 'dir' and 'opts' are passed to the function as environment variables, if set -} - -# shellcheck disable=SC2001,SC2155 -function _terraform() { - - local dir="$(echo "${dir:-$PWD}" | sed "s#$PWD#.#")" - local cmd="-chdir=$dir $* ${opts:-}" - local project_dir="$(git rev-parse --show-toplevel)" - - cmd="$cmd" "$project_dir/scripts/terraform/terraform.sh" -} - -# Remove Terraform files. -# Arguments (provided as environment variables): -# dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is '.'] -function terraform-clean() { - - ( - cd "${dir:-$PWD}" - rm -rf \ - .terraform \ - terraform.log \ - terraform.tfplan \ - terraform.tfstate \ - terraform.tfstate.backup - ) -} diff --git a/scripts/terraform/terraform.mk b/scripts/terraform/terraform.mk deleted file mode 100644 index 120a0591eab..00000000000 --- a/scripts/terraform/terraform.mk +++ /dev/null @@ -1,96 +0,0 @@ -# This file is for you! Edit it to implement your own Terraform make targets. - -# ============================================================================== -# Custom implementation - implementation of a make target should not exceed 5 lines of effective code. -# In most cases there should be no need to modify the existing make targets. - -terraform-init: # Initialise Terraform - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform init command, default is none/empty] @Development - make _terraform cmd="init" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-plan: # Plan Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform plan command, default is none/empty] @Development - make _terraform cmd="plan" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-apply: # Apply Terraform changes - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform apply command, default is none/empty] @Development - make _terraform cmd="apply" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-destroy: # Destroy Terraform resources - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform destroy command, default is none/empty] @Development - make _terraform \ - cmd="destroy" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-fmt: # Format Terraform files - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform fmt command, default is '-recursive'] @Quality - make _terraform cmd="fmt" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -terraform-validate: # Validate Terraform configuration - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], terraform_opts|opts=[options to pass to the Terraform validate command, default is none/empty] @Quality - make _terraform cmd="validate" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -clean:: # Remove Terraform files (terraform) - optional: terraform_dir|dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set] @Operations - make _terraform cmd="clean" \ - dir=$(or ${terraform_dir}, ${dir}) \ - opts=$(or ${terraform_opts}, ${opts}) - -_terraform: # Terraform command wrapper - mandatory: cmd=[command to execute]; optional: dir=[path to a directory where the command will be executed, relative to the project's top-level directory, default is one of the module variables or the example directory, if not set], opts=[options to pass to the Terraform command, default is none/empty] - # 'TERRAFORM_STACK' is passed to the functions as environment variable - TERRAFORM_STACK=$(or ${TERRAFORM_STACK}, $(or ${terraform_stack}, $(or ${STACK}, $(or ${stack}, scripts/terraform/examples/terraform-state-aws-s3)))) - dir=$(or ${dir}, ${TERRAFORM_STACK}) - source scripts/terraform/terraform.lib.sh - terraform-${cmd} # 'dir' and 'opts' are accessible by the function as environment variables, if set - -# ============================================================================== -# Quality checks - please DO NOT edit this section! - -terraform-shellscript-lint: # Lint all Terraform module shell scripts @Quality - for file in $$(find scripts/terraform -type f -name "*.sh"); do - file=$${file} scripts/shellscript-linter.sh - done - -# ============================================================================== -# Module tests and examples - please DO NOT edit this section! - -terraform-example-provision-aws-infrastructure: # Provision example of AWS infrastructure @ExamplesAndTests - make terraform-init - make terraform-plan opts="-out=terraform.tfplan" - make terraform-apply opts="-auto-approve terraform.tfplan" - -terraform-example-destroy-aws-infrastructure: # Destroy example of AWS infrastructure @ExamplesAndTests - make terraform-destroy opts="-auto-approve" - -terraform-example-clean: # Remove Terraform example files @ExamplesAndTests - dir=$(or ${dir}, ${TERRAFORM_STACK}) - source scripts/terraform/terraform.lib.sh - terraform-clean - rm -f ${TERRAFORM_STACK}/.terraform.lock.hcl - -# ============================================================================== -# Configuration - please DO NOT edit this section! - -terraform-install: # Install Terraform @Installation - make _install-dependency name="terraform" - -# ============================================================================== - -${VERBOSE}.SILENT: \ - _terraform \ - clean \ - terraform-apply \ - terraform-destroy \ - terraform-example-clean \ - terraform-example-destroy-aws-infrastructure \ - terraform-example-provision-aws-infrastructure \ - terraform-fmt \ - terraform-init \ - terraform-install \ - terraform-plan \ - terraform-shellscript-lint \ - terraform-validate \ diff --git a/scripts/terraform/terraform.sh b/scripts/terraform/terraform.sh deleted file mode 100755 index 73f37c1aff8..00000000000 --- a/scripts/terraform/terraform.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/bash - -# WARNING: Please DO NOT edit this file! It is maintained in the Repository Template (https://github.com/nhs-england-tools/repository-template). Raise a PR instead. - -set -euo pipefail - -# Terraform command wrapper. It will run the command natively if Terraform is -# installed, otherwise it will run it in a Docker container. -# -# Usage: -# $ [options] ./terraform.sh -# -# Options: -# cmd=command # Terraform command to execute -# FORCE_USE_DOCKER=true # If set to true the command is run in a Docker container, default is 'false' -# VERBOSE=true # Show all the executed commands, default is 'false' - -# ============================================================================== - -function main() { - - cd "$(git rev-parse --show-toplevel)" - - if command -v terraform > /dev/null 2>&1 && ! is-arg-true "${FORCE_USE_DOCKER:-false}"; then - # shellcheck disable=SC2154 - cmd=$cmd run-terraform-natively - else - cmd=$cmd run-terraform-in-docker - fi -} - -# Run Terraform natively. -# Arguments (provided as environment variables): -# cmd=[Terraform command to execute] -function run-terraform-natively() { - - # shellcheck disable=SC2086 - terraform $cmd -} - -# Run Terraform in a Docker container. -# Arguments (provided as environment variables): -# cmd=[Terraform command to execute] -function run-terraform-in-docker() { - - # shellcheck disable=SC1091 - source ./scripts/docker/docker.lib.sh - - # shellcheck disable=SC2155 - local image=$(name=hashicorp/terraform docker-get-image-version-and-pull) - # shellcheck disable=SC2086 - docker run --rm --platform linux/amd64 \ - --volume "$PWD":/workdir \ - --workdir /workdir \ - "$image" \ - $cmd -} - -# ============================================================================== - -function is-arg-true() { - - if [[ "$1" =~ ^(true|yes|y|on|1|TRUE|YES|Y|ON)$ ]]; then - return 0 - else - return 1 - fi -} - -# ============================================================================== - -is-arg-true "${VERBOSE:-false}" && set -x - -main "$@" - -exit 0