diff --git a/.tool-versions b/.tool-versions index b5b08159..13b6acde 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,11 +1,9 @@ -# This file is for you! Please, updated to the versions agreed by your team. - -terraform 1.9.1 -pre-commit 3.6.0 -nodejs 18.18.2 +act 0.2.64 gitleaks 8.18.4 -vale 3.6.0 +pre-commit 3.6.0 +terraform 1.9.2 tfsec 1.28.10 +vale 3.6.0 # ============================================================================== # The section below is reserved for Docker image versions. diff --git a/infrastructure/environments/dev/.gitkeep b/infrastructure/environments/dev/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/infrastructure/terraform/bin/terraform.sh b/infrastructure/terraform/bin/terraform.sh index 22143d1a..756b4ef8 100755 --- a/infrastructure/terraform/bin/terraform.sh +++ b/infrastructure/terraform/bin/terraform.sh @@ -8,7 +8,7 @@ ## # Set Script Version ## -readonly script_ver="1.8.0"; +readonly script_ver="1.8.1"; ## # Standardised failure function @@ -399,13 +399,16 @@ fi; pushd "${component_path}"; readonly component_name=$(basename ${component_path}); -# Check for presence of tfenv (https://github.com/kamatama41/tfenv) -# and a .terraform-version file. If both present, ensure required -# version of terraform for this component is installed automagically. -tfenv_bin="$(which tfenv 2>/dev/null)"; -if [[ -n "${tfenv_bin}" && -x "${tfenv_bin}" && -f .terraform-version ]]; then - ${tfenv_bin} install; -fi; +# install terraform +# verify terraform version matches .tool-versions +echo ${PWD} +tool_version=$(grep "terraform " .tool-versions | cut -d ' ' -f 2) +asdf plugin-add terraform && asdf install terraform "${tool_version}" +current_version=$(terraform --version | head -n 1 | cut -d 'v' -f 2) + +if [ -z "${current_version}" ] || [ "${current_version}" != "${tool_version}" ]; then + error_and_die "Terraform version mismatch. Expected: ${tool_version}, Actual: ${current_version}" +fi # Regardless of bootstrapping or not, we'll be using this string. # If bootstrapping, we will fill it with variables, diff --git a/infrastructure/terraform/bootstrap/.terraform-version b/infrastructure/terraform/bootstrap/.terraform-version deleted file mode 100644 index 80e78df6..00000000 --- a/infrastructure/terraform/bootstrap/.terraform-version +++ /dev/null @@ -1 +0,0 @@ -1.3.5 diff --git a/infrastructure/terraform/bootstrap/data_iam_policy_document_bucket.tf b/infrastructure/terraform/bootstrap/data_iam_policy_document_bucket.tf deleted file mode 100644 index dd231f57..00000000 --- a/infrastructure/terraform/bootstrap/data_iam_policy_document_bucket.tf +++ /dev/null @@ -1,68 +0,0 @@ -data "aws_iam_policy_document" "bucket" { - statement { - sid = "DontAllowNonSecureConnection" - effect = "Deny" - - actions = [ - "s3:*", - ] - - resources = [ - aws_s3_bucket.bucket.arn, - "${aws_s3_bucket.bucket.arn}/*", - ] - - principals { - type = "AWS" - - identifiers = [ - "*", - ] - } - - condition { - test = "Bool" - variable = "aws:SecureTransport" - - values = [ - "false", - ] - } - } - - statement { - sid = "AllowManagedAccountsToList" - effect = "Allow" - - actions = [ - "s3:ListBucket", - ] - - resources = [ - aws_s3_bucket.bucket.arn, - ] - - principals { - type = "AWS" - identifiers = local.ro_principals - } - } - - statement { - sid = "AllowManagedAccountsToGet" - effect = "Allow" - - actions = [ - "s3:GetObject", - ] - - resources = [ - "${aws_s3_bucket.bucket.arn}/*", - ] - - principals { - type = "AWS" - identifiers = local.ro_principals - } - } -} diff --git a/infrastructure/terraform/bootstrap/data_iam_policy_document_kms_key_s3.tf b/infrastructure/terraform/bootstrap/data_iam_policy_document_kms_key_s3.tf deleted file mode 100644 index 9741a087..00000000 --- a/infrastructure/terraform/bootstrap/data_iam_policy_document_kms_key_s3.tf +++ /dev/null @@ -1,46 +0,0 @@ -data "aws_iam_policy_document" "kms_key_s3" { - statement { - sid = "AllowLocalIAMAdministration" - effect = "Allow" - - actions = [ - "*", - ] - - resources = [ - "*", - ] - - principals { - type = "AWS" - identifiers = [ - "arn:aws:iam::${var.aws_account_id}:root", - ] - } - } - - statement { - sid = "AllowManagedAccountsToUse" - effect = "Allow" - - actions = [ - "kms:Decrypt", - "kms:DescribeKey", - "kms:Encrypt", - "kms:GenerateDataKey", - "kms:GenerateDataKeyPair", - "kms:GenerateDataKeyPairWithoutPlaintext", - "kms:GenerateDataKeyWithoutPlaintext", - "kms:ReEncrypt", - ] - - resources = [ - "*", - ] - - principals { - type = "AWS" - identifiers = local.ro_principals - } - } -} diff --git a/infrastructure/terraform/bootstrap/dynamodb_table.tf b/infrastructure/terraform/bootstrap/dynamodb_table.tf deleted file mode 100644 index a5510f84..00000000 --- a/infrastructure/terraform/bootstrap/dynamodb_table.tf +++ /dev/null @@ -1,26 +0,0 @@ -resource "aws_dynamodb_table" "tfscaffold" { - name = var.bucket_name - hash_key = "LockID" - billing_mode = "PAY_PER_REQUEST" - - attribute { - name = "LockID" - type = "S" - } - - point_in_time_recovery { - enabled = true - } - - server_side_encryption { - enabled = true - kms_key_arn = aws_kms_key.s3.arn - } - - tags = merge( - local.default_tags, - { - Name = var.bucket_name - }, - ) -} diff --git a/infrastructure/terraform/bootstrap/kms_key_s3.tf b/infrastructure/terraform/bootstrap/kms_key_s3.tf deleted file mode 100644 index d8a9ff42..00000000 --- a/infrastructure/terraform/bootstrap/kms_key_s3.tf +++ /dev/null @@ -1,16 +0,0 @@ -resource "aws_kms_key" "s3" { - description = "tfscaffold Bootstrap S3 Bucket" - deletion_window_in_days = 10 - enable_key_rotation = true - - policy = data.aws_iam_policy_document.kms_key_s3.json - - # This does not use default tag map merging because bootstrapping is special - # You should use default tag map merging elsewhere - tags = merge( - local.default_tags, - { - Name = "tfscaffold Bootstrap S3 Bucket" - } - ) -} diff --git a/infrastructure/terraform/bootstrap/locals.tf b/infrastructure/terraform/bootstrap/locals.tf deleted file mode 100644 index 1449f889..00000000 --- a/infrastructure/terraform/bootstrap/locals.tf +++ /dev/null @@ -1,13 +0,0 @@ -locals { - ro_principals = compact(distinct(flatten([ - var.tfscaffold_ro_principals, - "arn:aws:iam::${var.aws_account_id}:root", - ]))) - - default_tags = { - "tfscaffold:Environment" = var.environment - "tfscaffold:Project" = var.project - "tfscaffold:Component" = var.component - "tfscaffold:Account" = var.aws_account_id - } -} diff --git a/infrastructure/terraform/bootstrap/outputs.tf b/infrastructure/terraform/bootstrap/outputs.tf deleted file mode 100644 index 05b4902c..00000000 --- a/infrastructure/terraform/bootstrap/outputs.tf +++ /dev/null @@ -1,23 +0,0 @@ -output "bucket_name" { - value = aws_s3_bucket.bucket.id -} - -output "bucket_policy" { - value = data.aws_iam_policy_document.bucket.json -} - -output "bucket_arn" { - value = aws_s3_bucket.bucket.arn -} - -output "kms_key_arn" { - value = aws_kms_key.s3.arn -} - -output "kms_key_id" { - value = aws_kms_key.s3.id -} - -output "kms_key_policy" { - value = data.aws_iam_policy_document.kms_key_s3.json -} diff --git a/infrastructure/terraform/bootstrap/provider_aws.tf b/infrastructure/terraform/bootstrap/provider_aws.tf deleted file mode 100644 index 02a88588..00000000 --- a/infrastructure/terraform/bootstrap/provider_aws.tf +++ /dev/null @@ -1,12 +0,0 @@ -# The default AWS provider in the default region -provider "aws" { - region = var.region - - # For no reason other than redundant safety - # we only allow the use of the AWS Account - # specified in the environment variables. - # This helps to prevent accidents. - allowed_account_ids = [ - var.aws_account_id, - ] -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket.tf b/infrastructure/terraform/bootstrap/s3_bucket.tf deleted file mode 100644 index 5d5e092f..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket.tf +++ /dev/null @@ -1,14 +0,0 @@ -resource "aws_s3_bucket" "bucket" { - bucket = var.bucket_name - - force_destroy = false - - # This does not use default tag map merging because bootstrapping is special - # You should use default tag map merging elsewhere - tags = merge( - local.default_tags, - { - Name = "Terraform Scaffold State File Bucket for account ${var.aws_account_id} in region ${var.region}" - } - ) -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_lifecycle_configuration.tf b/infrastructure/terraform/bootstrap/s3_bucket_lifecycle_configuration.tf deleted file mode 100644 index 4e173b67..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_lifecycle_configuration.tf +++ /dev/null @@ -1,26 +0,0 @@ -resource "aws_s3_bucket_lifecycle_configuration" "bucket" { - bucket = aws_s3_bucket.bucket.id - - rule { - id = "bootstrap" - status = "Enabled" - - filter { - prefix = "" - } - - noncurrent_version_transition { - noncurrent_days = "30" - storage_class = "STANDARD_IA" - } - - noncurrent_version_transition { - noncurrent_days = "60" - storage_class = "GLACIER" - } - - noncurrent_version_expiration { - noncurrent_days = "90" - } - } -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_ownership_controls.tf b/infrastructure/terraform/bootstrap/s3_bucket_ownership_controls.tf deleted file mode 100644 index fc4a359c..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_ownership_controls.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_s3_bucket_ownership_controls" "bucket" { - bucket = aws_s3_bucket.bucket.id - - rule { - object_ownership = "BucketOwnerEnforced" - } -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_policy.tf b/infrastructure/terraform/bootstrap/s3_bucket_policy.tf deleted file mode 100644 index d12922ac..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_policy.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_s3_bucket_policy" "bucket" { - bucket = aws_s3_bucket.bucket.id - policy = data.aws_iam_policy_document.bucket.json - - depends_on = [ - aws_s3_bucket_public_access_block.bucket, - ] -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_public_access_block.tf b/infrastructure/terraform/bootstrap/s3_bucket_public_access_block.tf deleted file mode 100644 index d134b312..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_public_access_block.tf +++ /dev/null @@ -1,8 +0,0 @@ -resource "aws_s3_bucket_public_access_block" "bucket" { - bucket = aws_s3_bucket.bucket.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_server_side_encryption_configuration.tf b/infrastructure/terraform/bootstrap/s3_bucket_server_side_encryption_configuration.tf deleted file mode 100644 index 5733d983..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_server_side_encryption_configuration.tf +++ /dev/null @@ -1,12 +0,0 @@ -resource "aws_s3_bucket_server_side_encryption_configuration" "bucket" { - bucket = aws_s3_bucket.bucket.id - - rule { - apply_server_side_encryption_by_default { - kms_master_key_id = aws_kms_key.s3.arn - sse_algorithm = "aws:kms" - } - - bucket_key_enabled = true - } -} diff --git a/infrastructure/terraform/bootstrap/s3_bucket_versioning.tf b/infrastructure/terraform/bootstrap/s3_bucket_versioning.tf deleted file mode 100644 index 80c1ab95..00000000 --- a/infrastructure/terraform/bootstrap/s3_bucket_versioning.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_s3_bucket_versioning" "bucket" { - bucket = aws_s3_bucket.bucket.id - - versioning_configuration { - status = "Enabled" - } -} diff --git a/infrastructure/terraform/bootstrap/variables.tf b/infrastructure/terraform/bootstrap/variables.tf deleted file mode 100644 index d7b1f44b..00000000 --- a/infrastructure/terraform/bootstrap/variables.tf +++ /dev/null @@ -1,37 +0,0 @@ -variable "project" { - type = string - description = "The name of the Project we are bootstrapping tfscaffold for" -} - -variable "aws_account_id" { - type = string - description = "The AWS Account ID into which we are bootstrapping tfscaffold" -} - -variable "region" { - type = string - description = "The AWS Region into which we are bootstrapping tfscaffold" -} - -variable "environment" { - type = string - description = "The name of the environment for the bootstrapping process; which is always bootstrap" - default = "bootstrap" -} - -variable "component" { - type = string - description = "The name of the component for the bootstrapping process; which is always bootstrap" - default = "bootstrap" -} - -variable "bucket_name" { - type = string - description = "The name to use for the tfscaffold bucket. This should be provided from tfscaffold shell, not environment or group tfvars" -} - -variable "tfscaffold_ro_principals" { - type = list(string) - description = "A list of Principals permitted to ListBucket and GetObject for Remote State purposes. Normally the root principal of the account" - default = [] -} diff --git a/infrastructure/terraform/bootstrap/versions.tf b/infrastructure/terraform/bootstrap/versions.tf deleted file mode 100644 index 87dc6a9d..00000000 --- a/infrastructure/terraform/bootstrap/versions.tf +++ /dev/null @@ -1,10 +0,0 @@ -terraform { - required_providers { - aws = { - source = "hashicorp/aws" - version = "~> 4.61.0" - } - } - - required_version = ">= 0.14.7" -} diff --git a/infrastructure/terraform/components/acct/.terraform-version b/infrastructure/terraform/components/acct/.terraform-version deleted file mode 100644 index 631f7908..00000000 --- a/infrastructure/terraform/components/acct/.terraform-version +++ /dev/null @@ -1 +0,0 @@ -latest:^1\.8\. diff --git a/infrastructure/terraform/components/acct/.tool-versions b/infrastructure/terraform/components/acct/.tool-versions new file mode 100644 index 00000000..3874604d --- /dev/null +++ b/infrastructure/terraform/components/acct/.tool-versions @@ -0,0 +1 @@ +terraform 1.9.2 diff --git a/infrastructure/terraform/components/acct/README b/infrastructure/terraform/components/acct/README deleted file mode 100644 index d2148877..00000000 --- a/infrastructure/terraform/components/acct/README +++ /dev/null @@ -1,5 +0,0 @@ -README for 'acct' component - Account-level resources - -This component is intended to be run to set up things (such as a DNS subdomain) at the account level, and this should be run for each account belonging to the Notify Domain - i.e. there should be a nonprod and prod environment .tfvars - -Copy the `env_eu-west-2_example.tfvars` file in the `etc` directory and adjust as needed for nonprod and prod for your NHS Notify Domain. diff --git a/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf b/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf new file mode 100644 index 00000000..e30e2087 --- /dev/null +++ b/infrastructure/terraform/components/acct/cloudwatch_log_group_route53_query_log.tf @@ -0,0 +1,37 @@ +resource "aws_cloudwatch_log_group" "aws_route53_query_log" { + provider = aws.us-east-1 # Route53 query logging must be in us-east-1 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_query_log + + name = "/aws/route53/${local.csi}" + retention_in_days = var.log_retention_in_days +} + +resource "aws_cloudwatch_log_resource_policy" "route53_query_logging_policy" { + provider = aws.us-east-1 # Route53 query logging must be in us-east-1 https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_query_log + + policy_document = data.aws_iam_policy_document.route53_logs.json + policy_name = "${local.csi}-route53-query-logging-policy" +} + +data "aws_iam_policy_document" "route53_logs" { + statement { + effect = "Allow" + + principals { + type = "Service" + + identifiers = [ + "route53.amazonaws.com" + ] + } + + actions = [ + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + + resources = [ + aws_cloudwatch_log_group.aws_route53_query_log.arn, + "${aws_cloudwatch_log_group.aws_route53_query_log.arn}:*" + ] + } +} diff --git a/infrastructure/terraform/components/acct/locals_tfscaffold.tf b/infrastructure/terraform/components/acct/locals_tfscaffold.tf index e5084cdf..b7cf3217 100644 --- a/infrastructure/terraform/components/acct/locals_tfscaffold.tf +++ b/infrastructure/terraform/components/acct/locals_tfscaffold.tf @@ -34,12 +34,11 @@ locals { default_tags = merge( var.default_tags, { - Project = var.project - Environment = var.environment - Component = var.component - Group = var.group - NHSNotifyDomain = var.nhs_notify_domain - Name = local.csi + Project = var.project + Environment = var.environment + Component = var.component + Group = var.group + Name = local.csi }, ) } diff --git a/infrastructure/terraform/components/acct/outputs.tf b/infrastructure/terraform/components/acct/outputs.tf index 5bc34180..58f3fefd 100644 --- a/infrastructure/terraform/components/acct/outputs.tf +++ b/infrastructure/terraform/components/acct/outputs.tf @@ -1,19 +1,7 @@ -output "aws_account_id" { - value = var.aws_account_id -} - -output "r53_delegation_set_id" { - value = aws_route53_delegation_set.main.id -} - -output "r53_delegation_set_nameservers" { - value = aws_route53_delegation_set.main.name_servers -} - -output "r53_subdomain_name" { - value = var.subdomain_name -} - -output "r53_subdomain_id" { - value = one(aws_route53_zone.subdomain[*].id) +output "dns_zone" { + value = { + id = aws_route53_zone.main.id + name = aws_route53_zone.main.name + nameservers = aws_route53_zone.main.name_servers + } } diff --git a/infrastructure/terraform/components/acct/provider_aws.tf b/infrastructure/terraform/components/acct/provider_aws.tf index a8058431..d694811e 100644 --- a/infrastructure/terraform/components/acct/provider_aws.tf +++ b/infrastructure/terraform/components/acct/provider_aws.tf @@ -6,13 +6,19 @@ provider "aws" { ] default_tags { - tags = { - Project = var.project - Environment = var.environment - Component = var.component - Group = var.group - NHSNotifyDomain = var.nhs_notify_domain - Name = local.csi - } + tags = local.default_tags } } + +provider "aws" { + alias = "us-east-1" + region = "us-east-1" + + default_tags { + tags = local.default_tags + } + + allowed_account_ids = [ + var.aws_account_id, + ] +} diff --git a/infrastructure/terraform/components/acct/route53_delegation_set.tf b/infrastructure/terraform/components/acct/route53_delegation_set.tf new file mode 100644 index 00000000..d3d0896b --- /dev/null +++ b/infrastructure/terraform/components/acct/route53_delegation_set.tf @@ -0,0 +1,3 @@ +resource "aws_route53_delegation_set" "main" { + reference_name = "unset.${var.root_domain_name}" +} diff --git a/infrastructure/terraform/components/acct/route53_delegation_set_main.tf b/infrastructure/terraform/components/acct/route53_delegation_set_main.tf deleted file mode 100644 index 76ad88e0..00000000 --- a/infrastructure/terraform/components/acct/route53_delegation_set_main.tf +++ /dev/null @@ -1,3 +0,0 @@ -resource "aws_route53_delegation_set" "main" { - reference_name = "main" -} diff --git a/infrastructure/terraform/components/acct/route53_query_log.tf b/infrastructure/terraform/components/acct/route53_query_log.tf new file mode 100644 index 00000000..305ebb44 --- /dev/null +++ b/infrastructure/terraform/components/acct/route53_query_log.tf @@ -0,0 +1,9 @@ +resource "aws_route53_query_log" "main" { + zone_id = aws_route53_zone.main.zone_id + + cloudwatch_log_group_arn = aws_cloudwatch_log_group.aws_route53_query_log.arn + + depends_on = [ + aws_cloudwatch_log_resource_policy.route53_query_logging_policy + ] +} diff --git a/infrastructure/terraform/components/acct/route53_zone.tf b/infrastructure/terraform/components/acct/route53_zone.tf new file mode 100644 index 00000000..cfd7be29 --- /dev/null +++ b/infrastructure/terraform/components/acct/route53_zone.tf @@ -0,0 +1,5 @@ +resource "aws_route53_zone" "main" { + name = "unset.${var.root_domain_name}" + + delegation_set_id = aws_route53_delegation_set.main.id +} diff --git a/infrastructure/terraform/components/acct/route53_zone_subdomain.tf b/infrastructure/terraform/components/acct/route53_zone_subdomain.tf deleted file mode 100644 index cc52061b..00000000 --- a/infrastructure/terraform/components/acct/route53_zone_subdomain.tf +++ /dev/null @@ -1,7 +0,0 @@ -resource "aws_route53_zone" "subdomain" { - count = var.subdomain_name != "" ? 1 : 0 - - name = var.subdomain_name - - delegation_set_id = aws_route53_delegation_set.main.id -} diff --git a/infrastructure/terraform/components/acct/variables.tf b/infrastructure/terraform/components/acct/variables.tf index f625501d..14cf64df 100644 --- a/infrastructure/terraform/components/acct/variables.tf +++ b/infrastructure/terraform/components/acct/variables.tf @@ -41,24 +41,24 @@ variable "component" { default = "acct" } -variable "nhs_notify_domain" { - type = string - description = "The name of the NHS Notify Domain that this is deploying to" -} - variable "default_tags" { type = map(string) description = "A map of default tags to apply to all taggable resources within the component" default = {} } - ## -# Variables specific to the "acct" component +# Variables specific to the "dnsroot"component ## -variable "subdomain_name" { +variable "log_retention_in_days" { + type = number + description = "The retention period in days for the Cloudwatch Logs events to be retained, default of 0 is indefinite" + default = 0 +} + +variable "root_domain_name" { type = string - description = "The subdomain name to create a Route53 zone for" - default = "" + description = "The service's root DNS root nameespace, like nonprod.nhsnotify.national.nhs.uk" + default = "nonprod.nhsnotify.national.nhs.uk" } diff --git a/infrastructure/terraform/components/acct/versions.tf b/infrastructure/terraform/components/acct/versions.tf index ee15bad7..5fba18d2 100644 --- a/infrastructure/terraform/components/acct/versions.tf +++ b/infrastructure/terraform/components/acct/versions.tf @@ -6,5 +6,5 @@ terraform { } } - required_version = "~> 1.8.4" + required_version = ">= 1.9.0" } diff --git a/infrastructure/terraform/components/examplecomponent/.tool-versions b/infrastructure/terraform/components/examplecomponent/.tool-versions new file mode 100644 index 00000000..3874604d --- /dev/null +++ b/infrastructure/terraform/components/examplecomponent/.tool-versions @@ -0,0 +1 @@ +terraform 1.9.2 diff --git a/scripts/terraform/terraform.lib.sh b/scripts/terraform/terraform.lib.sh index 7793b9b0..d94213e8 100644 --- a/scripts/terraform/terraform.lib.sh +++ b/scripts/terraform/terraform.lib.sh @@ -53,8 +53,12 @@ function terraform-destroy() { # 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() { + for d in "${PWD}infrastructure/"*; do + if [ -d "$d" ]; then + terraform fmt --recursive "${d}" + fi + done - _terraform fmt -recursive # 'dir' and 'opts' are passed to the function as environment variables, if set } # Validate Terraform code. diff --git a/scripts/terraform/terraform.mk b/scripts/terraform/terraform.mk index 111acda9..4a2783a1 100644 --- a/scripts/terraform/terraform.mk +++ b/scripts/terraform/terraform.mk @@ -4,11 +4,6 @@ # 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. -TF_ENV ?= dev -STACK ?= ${stack} -TERRAFORM_STACK ?= $(or ${STACK}, infrastructure/environments/${TF_ENV}) -dir ?= ${TERRAFORM_STACK} - 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}) \ @@ -46,9 +41,11 @@ clean:: # Remove Terraform files (terraform) - optional: terraform_dir|dir=[path 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}, ${stack}))) dir=$(or ${dir}, ${TERRAFORM_STACK}) - . scripts/terraform/terraform.lib.sh && \ - terraform-${cmd} # 'dir' and 'opts' are accessible by the function as environment variables, if set + . "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! @@ -58,6 +55,31 @@ terraform-shellscript-lint: # Lint all Terraform module shell scripts @Quality file=$${file} scripts/shellscript-linter.sh done +terraform-sec: # TFSEC check against 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 + tfsec infrastructure/terraform \ + --force-all-dirs \ + --exclude-downloaded-modules \ + --tfvars-file infrastructure/terraform/etc/global.tfvars \ + --tfvars-file infrastructure/terraform/etc/env_eu-west-2_main.tfvars \ + --config-file scripts/config/tfsec.yml + +# ============================================================================== +# 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}) + . "scripts/terraform/terraform.lib.sh"; \ + terraform-clean + rm -f ${TERRAFORM_STACK}/.terraform.lock.hcl + # ============================================================================== # Configuration - please DO NOT edit this section! @@ -71,6 +93,9 @@ ${VERBOSE}.SILENT: \ clean \ terraform-apply \ terraform-destroy \ + terraform-example-clean \ + terraform-example-destroy-aws-infrastructure \ + terraform-example-provision-aws-infrastructure \ terraform-fmt \ terraform-init \ terraform-install \