diff --git a/README.md b/README.md index 41ebb63..b74e21d 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,10 @@ module "s3_bucket_for_waf_logs" { } ``` +### Bucket with a custom policy attached + +When you need to attach a custom policy to the bucket, you can use the `policy` argument. To keep bucket policy with correct S3 bucket and AWS account properties, you can use the placeholders `_S3_BUCKET_ID_`, `_S3_BUCKET_ARN_`, and `_AWS_ACCOUNT_ID_` in the policy document. Those values will be replaced with the actual values during the policy attachment. This is especially useful when using bucket prefixes. + ## Conditional creation Sometimes you need to have a way to create S3 resources conditionally but Terraform does not allow to use `count` inside `module` block, so the solution is to specify argument `create_bucket`. diff --git a/examples/complete/main.tf b/examples/complete/main.tf index b033b99..407e1cb 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -60,6 +60,27 @@ data "aws_iam_policy_document" "bucket_policy" { "arn:aws:s3:::${local.bucket_name}", ] } + + statement { + principals { + type = "AWS" + identifiers = [aws_iam_role.this.arn] + } + + actions = [ + "s3:ListBucket", + ] + + resources = [ + "_S3_BUCKET_ARN_", + ] + + condition { + test = "StringNotEquals" + variable = "aws:PrincipalAccount" + values = ["_AWS_ACCOUNT_ID_"] + } + } } module "log_bucket" { diff --git a/main.tf b/main.tf index 56c5e4e..87fcc67 100644 --- a/main.tf +++ b/main.tf @@ -16,6 +16,24 @@ locals { attach_policy = var.attach_require_latest_tls_policy || var.attach_access_log_delivery_policy || var.attach_elb_log_delivery_policy || var.attach_lb_log_delivery_policy || var.attach_cloudtrail_log_delivery_policy || var.attach_deny_insecure_transport_policy || var.attach_inventory_destination_policy || var.attach_deny_incorrect_encryption_headers || var.attach_deny_incorrect_kms_key_sse || var.attach_deny_unencrypted_object_uploads || var.attach_deny_ssec_encrypted_object_uploads || var.attach_policy || var.attach_waf_log_delivery_policy + # Placeholders in the policy document to be replaced with the actual values + policy_placeholders = { + "_S3_BUCKET_ID_" = var.is_directory_bucket ? aws_s3_directory_bucket.this[0].bucket : aws_s3_bucket.this[0].id, + "_S3_BUCKET_ARN_" = var.is_directory_bucket ? aws_s3_directory_bucket.this[0].arn : aws_s3_bucket.this[0].arn, + "_AWS_ACCOUNT_ID_" = data.aws_caller_identity.current.account_id + } + + policy = local.create_bucket && local.attach_policy ? replace( + replace( + replace( + data.aws_iam_policy_document.combined[0].json, + "_S3_BUCKET_ID_", local.policy_placeholders["_S3_BUCKET_ID_"] + ), + "_S3_BUCKET_ARN_", local.policy_placeholders["_S3_BUCKET_ARN_"] + ), + "_AWS_ACCOUNT_ID_", local.policy_placeholders["_AWS_ACCOUNT_ID_"] + ) : "" + # Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt grants = try(jsondecode(var.grant), var.grant) cors_rules = try(jsondecode(var.cors_rule), var.cors_rule) @@ -591,7 +609,7 @@ resource "aws_s3_bucket_policy" "this" { # Ref: https://github.com/hashicorp/terraform-provider-aws/issues/7628 bucket = var.is_directory_bucket ? aws_s3_directory_bucket.this[0].bucket : aws_s3_bucket.this[0].id - policy = data.aws_iam_policy_document.combined[0].json + policy = local.policy depends_on = [ aws_s3_bucket_public_access_block.this