From 4aec0da347b8685c92066d2fc33c9096a6ff8351 Mon Sep 17 00:00:00 2001 From: AWS Date: Thu, 18 Jul 2024 17:13:11 +0000 Subject: [PATCH] Release: 1.13.0 --- README.md | 3 +- VERSION | 2 +- main.tf | 8 ++- modules/aft-backend/main.tf | 72 +++++++++++++++++++ ...aft_access_logs_primary_backend_bucket.tpl | 26 +++++++ modules/aft-backend/variables.tf | 8 +++ modules/aft-lambda-layer/lambda.tf | 1 - sources/aft-lambda-layer/pyproject.toml | 4 +- variables.tf | 14 +++- 9 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 modules/aft-backend/s3/bucket-policies/aft_access_logs_primary_backend_bucket.tpl diff --git a/README.md b/README.md index 1f38279c..2e4a4757 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ As of version 1.6.0, AFT collects anonymous operational metrics to help AWS impr | [account\_provisioning\_customizations\_repo\_name](#input\_account\_provisioning\_customizations\_repo\_name) | Repository name for the account provisioning customizations files. For non-CodeCommit repos, name should be in the format of Org/Repo | `string` | `"aft-account-provisioning-customizations"` | no | | [account\_request\_repo\_branch](#input\_account\_request\_repo\_branch) | Branch to source account request repo from | `string` | `"main"` | no | | [account\_request\_repo\_name](#input\_account\_request\_repo\_name) | Repository name for the account request files. For non-CodeCommit repos, name should be in the format of Org/Repo | `string` | `"aft-account-request"` | no | +| [aft\_backend\_bucket\_access\_logs\_object\_expiration\_days](#input\_aft\_backend\_bucket\_access\_logs\_object\_expiration\_days) | Amount of days to keep the objects stored in the access logs bucket for AFT backend buckets | `number` | `365` | no | | [aft\_enable\_vpc](#input\_aft\_enable\_vpc) | Flag turning use of VPC on/off for AFT | `bool` | `true` | no | | [aft\_feature\_cloudtrail\_data\_events](#input\_aft\_feature\_cloudtrail\_data\_events) | Feature flag toggling CloudTrail data events on/off | `bool` | `false` | no | | [aft\_feature\_delete\_default\_vpcs\_enabled](#input\_aft\_feature\_delete\_default\_vpcs\_enabled) | Feature flag toggling deletion of default VPCs on/off | `bool` | `false` | no | @@ -139,7 +140,7 @@ As of version 1.6.0, AFT collects anonymous operational metrics to help AWS impr | [terraform\_distribution](#input\_terraform\_distribution) | Terraform distribution being used for AFT - valid values are oss, tfc, or tfe | `string` | `"oss"` | no | | [terraform\_org\_name](#input\_terraform\_org\_name) | Organization name for Terraform Cloud or Enterprise | `string` | `"null"` | no | | [terraform\_token](#input\_terraform\_token) | Terraform token for Cloud or Enterprise | `string` | `"null"` | no | -| [terraform\_version](#input\_terraform\_version) | Terraform version being used for AFT | `string` | `"1.5.7"` | no | +| [terraform\_version](#input\_terraform\_version) | Terraform version being used for AFT | `string` | `"1.6.0"` | no | | [tf\_backend\_secondary\_region](#input\_tf\_backend\_secondary\_region) | AFT creates a backend for state tracking for its own state as well as OSS cases. The backend's primary region is the same as the AFT region, but this defines the secondary region to replicate to. | `string` | `""` | no | | [vcs\_provider](#input\_vcs\_provider) | Customer VCS Provider - valid inputs are codecommit, bitbucket, github, or githubenterprise | `string` | `"codecommit"` | no | diff --git a/VERSION b/VERSION index 6b89d58f..feaae22b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.12.2 +1.13.0 diff --git a/main.tf b/main.tf index cbdbdb04..0d2d7a67 100644 --- a/main.tf +++ b/main.tf @@ -65,9 +65,11 @@ module "aft_backend" { aws.primary_region = aws.aft_management aws.secondary_region = aws.tf_backend_secondary_region } - source = "./modules/aft-backend" - primary_region = var.ct_home_region - secondary_region = var.tf_backend_secondary_region + source = "./modules/aft-backend" + primary_region = var.ct_home_region + secondary_region = var.tf_backend_secondary_region + aft_management_account_id = var.aft_management_account_id + aft_backend_bucket_access_logs_object_expiration_days = var.aft_backend_bucket_access_logs_object_expiration_days } module "aft_code_repositories" { diff --git a/modules/aft-backend/main.tf b/modules/aft-backend/main.tf index 544799e4..f4aa32fb 100644 --- a/modules/aft-backend/main.tf +++ b/modules/aft-backend/main.tf @@ -16,6 +16,12 @@ resource "aws_s3_bucket" "primary-backend-bucket" { "Name" = "aft-backend-${data.aws_caller_identity.current.account_id}-primary-region" } } +resource "aws_s3_bucket_logging" "primary-backend-bucket-logging" { + provider = aws.primary_region + bucket = aws_s3_bucket.primary-backend-bucket.id + target_bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + target_prefix = "log/" +} #tfsec:ignore:aws-s3-enable-bucket-logging resource "aws_s3_bucket" "secondary-backend-bucket" { @@ -253,6 +259,72 @@ resource "aws_iam_role_policy_attachment" "replication" { policy_arn = aws_iam_policy.replication[0].arn } +#tfsec:ignore:aws-s3-enable-bucket-logging +resource "aws_s3_bucket" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = "aft-backend-${data.aws_caller_identity.current.account_id}-primary-region-access-logs" +} + +resource "aws_s3_bucket_policy" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + policy = templatefile("${path.module}/s3/bucket-policies/aft_access_logs_primary_backend_bucket.tpl", { + aws_s3_bucket_aft_access_logs_arn = aws_s3_bucket.aft_access_logs_primary_backend_bucket.arn + aws_s3_bucket_primary_backend_arn = aws_s3_bucket.primary-backend-bucket.arn + aft_management_account_id = var.aft_management_account_id + }) +} + +resource "aws_s3_bucket_versioning" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + versioning_configuration { + status = "Enabled" + } +} + +resource "aws_kms_key" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + enable_key_rotation = true +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + + rule { + apply_server_side_encryption_by_default { + kms_master_key_id = aws_kms_key.aft_access_logs_primary_backend_bucket.arn + sse_algorithm = "aws:kms" + } + } +} + +resource "aws_s3_bucket_lifecycle_configuration" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + rule { + status = "Enabled" + filter { + prefix = "log/" + } + id = "aft_primary_backend_bucket_access_logs_lifecycle_configuration_rule" + + noncurrent_version_expiration { + noncurrent_days = var.aft_backend_bucket_access_logs_object_expiration_days + } + } + +} + +resource "aws_s3_bucket_public_access_block" "aft_access_logs_primary_backend_bucket" { + provider = aws.primary_region + bucket = aws_s3_bucket.aft_access_logs_primary_backend_bucket.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} # DynamoDB Resources # TFSec incorrectly reports no DAX SSE encryption for a DDB table (SSE encryption is default-on) diff --git a/modules/aft-backend/s3/bucket-policies/aft_access_logs_primary_backend_bucket.tpl b/modules/aft-backend/s3/bucket-policies/aft_access_logs_primary_backend_bucket.tpl new file mode 100644 index 00000000..04e225c4 --- /dev/null +++ b/modules/aft-backend/s3/bucket-policies/aft_access_logs_primary_backend_bucket.tpl @@ -0,0 +1,26 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "Allow PutObject", + "Effect": "Allow", + "Principal": { + "Service": [ + "logging.s3.amazonaws.com" + ] + }, + "Action": "s3:PutObject", + "Resource": [ + "${aws_s3_bucket_aft_access_logs_arn}/*" + ], + "Condition": { + "ArnLike": { + "aws:SourceArn": "${aws_s3_bucket_primary_backend_arn}" + }, + "StringEquals": { + "aws:SourceAccount": "${aft_management_account_id}" + } + } + } + ] +} diff --git a/modules/aft-backend/variables.tf b/modules/aft-backend/variables.tf index 80b28895..3914b0d2 100644 --- a/modules/aft-backend/variables.tf +++ b/modules/aft-backend/variables.tf @@ -8,3 +8,11 @@ variable "primary_region" { variable "secondary_region" { type = string } + +variable "aft_management_account_id" { + type = string +} + +variable "aft_backend_bucket_access_logs_object_expiration_days" { + type = number +} diff --git a/modules/aft-lambda-layer/lambda.tf b/modules/aft-lambda-layer/lambda.tf index 2adf23ba..e5f3c8ef 100644 --- a/modules/aft-lambda-layer/lambda.tf +++ b/modules/aft-lambda-layer/lambda.tf @@ -13,7 +13,6 @@ resource "aws_lambda_function" "codebuild_trigger" { memory_size = 1024 runtime = var.lambda_runtime_python_version timeout = 900 - dynamic "vpc_config" { for_each = var.aft_enable_vpc ? [1] : [] content { diff --git a/sources/aft-lambda-layer/pyproject.toml b/sources/aft-lambda-layer/pyproject.toml index 15887c81..29f67a2e 100644 --- a/sources/aft-lambda-layer/pyproject.toml +++ b/sources/aft-lambda-layer/pyproject.toml @@ -24,8 +24,8 @@ classifiers=[ "Operating System :: OS Independent", ] dependencies = [ - "boto3 == 1.27.1", - "botocore == 1.30.1", + "boto3 == 1.28.17", + "botocore == 1.31.17", "requests == 2.31.0", "jsonschema == 4.3.2", ] diff --git a/variables.tf b/variables.tf index aa0473b4..eabf36d8 100644 --- a/variables.tf +++ b/variables.tf @@ -62,7 +62,7 @@ variable "ct_home_region" { description = "The region from which this module will be executed. This MUST be the same region as Control Tower is deployed." type = string validation { - condition = can(regex("(us(-gov)?|ap|ca|cn|eu|sa|me|af)-(central|(north|south)?(east|west)?)-\\d", var.ct_home_region)) + condition = can(regex("(us(-gov)?|ap|ca|cn|eu|sa|me|af|il)-(central|(north|south)?(east|west)?)-\\d", var.ct_home_region)) error_message = "Variable var: region is not valid." } } @@ -96,6 +96,16 @@ variable "log_archive_bucket_object_expiration_days" { } } +variable "aft_backend_bucket_access_logs_object_expiration_days" { + description = "Amount of days to keep the objects stored in the access logs bucket for AFT backend buckets" + type = number + default = 365 + validation { + condition = var.aft_backend_bucket_access_logs_object_expiration_days > 0 + error_message = "aft_backend_bucket_access_logs_object_expiration_days must be an integer greater than 0." + } +} + variable "maximum_concurrent_customizations" { description = "Maximum number of customizations/pipelines to run at once" type = number @@ -280,7 +290,7 @@ variable "account_provisioning_customizations_repo_branch" { variable "terraform_version" { description = "Terraform version being used for AFT" type = string - default = "1.5.7" + default = "1.6.0" validation { condition = can(regex("\\bv?\\d+(\\.\\d+)+[\\-\\w]*\\b", var.terraform_version)) error_message = "Invalid value for var: terraform_version."