Skip to content

Commit 98210a2

Browse files
authored
feat: Add WAF log delivery policy (#328)
1 parent 1eb6a57 commit 98210a2

File tree

5 files changed

+105
-2
lines changed

5 files changed

+105
-2
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ These features of S3 bucket configurations are supported:
1616
- Cross-Region Replication (CRR)
1717
- ELB log delivery bucket policy
1818
- ALB/NLB log delivery bucket policy
19+
- WAF log delivery bucket policy
1920
- Account-level Public Access Block
2021
- S3 Directory Bucket
2122
- S3 Table Bucket
@@ -78,6 +79,24 @@ module "s3_bucket_for_logs" {
7879
}
7980
```
8081

82+
### Bucket with WAF log delivery policy attached
83+
84+
```hcl
85+
module "s3_bucket_for_waf_logs" {
86+
source = "terraform-aws-modules/s3-bucket/aws"
87+
88+
bucket = "my-s3-bucket-for-waf-logs"
89+
90+
# Allow deletion of non-empty bucket
91+
force_destroy = true
92+
93+
control_object_ownership = true
94+
object_ownership = "ObjectWriter"
95+
96+
attach_waf_log_delivery_policy = true # Required for WAF logs
97+
}
98+
```
99+
81100
## Conditional creation
82101

83102
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`.
@@ -182,6 +201,7 @@ No modules.
182201
| [aws_iam_policy_document.inventory_and_analytics_destination_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
183202
| [aws_iam_policy_document.lb_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
184203
| [aws_iam_policy_document.require_latest_tls](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
204+
| [aws_iam_policy_document.waf_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
185205
| [aws_partition.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
186206
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
187207

@@ -212,6 +232,7 @@ No modules.
212232
| <a name="input_attach_policy"></a> [attach\_policy](#input\_attach\_policy) | Controls if S3 bucket should have bucket policy attached (set to `true` to use value of `policy` as bucket policy) | `bool` | `false` | no |
213233
| <a name="input_attach_public_policy"></a> [attach\_public\_policy](#input\_attach\_public\_policy) | Controls if a user defined public bucket policy will be attached (set to `false` to allow upstream to apply defaults to the bucket) | `bool` | `true` | no |
214234
| <a name="input_attach_require_latest_tls_policy"></a> [attach\_require\_latest\_tls\_policy](#input\_attach\_require\_latest\_tls\_policy) | Controls if S3 bucket should require the latest version of TLS | `bool` | `false` | no |
235+
| <a name="input_attach_waf_log_delivery_policy"></a> [attach\_waf\_log\_delivery\_policy](#input\_attach\_waf\_log\_delivery\_policy) | Controls if S3 bucket should have WAF log delivery policy attached | `bool` | `false` | no |
215236
| <a name="input_availability_zone_id"></a> [availability\_zone\_id](#input\_availability\_zone\_id) | Availability Zone ID or Local Zone ID | `string` | `null` | no |
216237
| <a name="input_block_public_acls"></a> [block\_public\_acls](#input\_block\_public\_acls) | Whether Amazon S3 should block public ACLs for this bucket. | `bool` | `true` | no |
217238
| <a name="input_block_public_policy"></a> [block\_public\_policy](#input\_block\_public\_policy) | Whether Amazon S3 should block public bucket policies for this bucket. | `bool` | `true` | no |

examples/complete/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ module "log_bucket" {
7575
attach_access_log_delivery_policy = true
7676
attach_deny_insecure_transport_policy = true
7777
attach_require_latest_tls_policy = true
78+
attach_waf_log_delivery_policy = true
7879

7980
access_log_delivery_policy_source_accounts = [data.aws_caller_identity.current.account_id]
8081
access_log_delivery_policy_source_buckets = ["arn:aws:s3:::${local.bucket_name}"]

main.tf

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ locals {
1212

1313
create_bucket_acl = (var.acl != null && var.acl != "null") || length(local.grants) > 0
1414

15-
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_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
15+
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_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
1616

1717
# Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt
1818
grants = try(jsondecode(var.grant), var.grant)
@@ -576,7 +576,8 @@ data "aws_iam_policy_document" "combined" {
576576
var.attach_deny_incorrect_kms_key_sse ? data.aws_iam_policy_document.deny_incorrect_kms_key_sse[0].json : "",
577577
var.attach_deny_incorrect_encryption_headers ? data.aws_iam_policy_document.deny_incorrect_encryption_headers[0].json : "",
578578
var.attach_inventory_destination_policy || var.attach_analytics_destination_policy ? data.aws_iam_policy_document.inventory_and_analytics_destination_policy[0].json : "",
579-
var.attach_policy ? var.policy : ""
579+
var.attach_policy ? var.policy : "",
580+
var.attach_waf_log_delivery_policy ? data.aws_iam_policy_document.waf_log_delivery[0].json : "",
580581
])
581582
}
582583

@@ -816,6 +817,79 @@ data "aws_iam_policy_document" "access_log_delivery" {
816817
}
817818
}
818819

820+
#WAF
821+
data "aws_iam_policy_document" "waf_log_delivery" {
822+
count = local.create_bucket && var.attach_waf_log_delivery_policy && !var.is_directory_bucket ? 1 : 0
823+
824+
statement {
825+
sid = "AWSLogDeliveryWrite"
826+
827+
effect = "Allow"
828+
829+
principals {
830+
type = "Service"
831+
identifiers = ["delivery.logs.amazonaws.com"]
832+
}
833+
834+
actions = [
835+
"s3:PutObject",
836+
]
837+
838+
resources = [
839+
"${aws_s3_bucket.this[0].arn}/AWSLogs/${data.aws_caller_identity.current.id}/*",
840+
]
841+
842+
condition {
843+
test = "StringEquals"
844+
values = ["bucket-owner-full-control"]
845+
variable = "s3:x-amz-acl"
846+
}
847+
848+
condition {
849+
test = "StringEquals"
850+
values = [data.aws_caller_identity.current.id]
851+
variable = "aws:SourceAccount"
852+
}
853+
854+
condition {
855+
test = "ArnLike"
856+
values = ["arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.id}:*"]
857+
variable = "aws:SourceArn"
858+
}
859+
}
860+
861+
statement {
862+
sid = "AWSLogDeliveryAclCheck"
863+
864+
effect = "Allow"
865+
866+
principals {
867+
type = "Service"
868+
identifiers = ["delivery.logs.amazonaws.com"]
869+
}
870+
871+
actions = [
872+
"s3:GetBucketAcl",
873+
]
874+
875+
resources = [
876+
aws_s3_bucket.this[0].arn,
877+
]
878+
879+
condition {
880+
test = "StringEquals"
881+
values = [data.aws_caller_identity.current.id]
882+
variable = "aws:SourceAccount"
883+
}
884+
885+
condition {
886+
test = "ArnLike"
887+
values = ["arn:aws:logs:${data.aws_region.current.name}:${data.aws_caller_identity.current.id}:*"]
888+
variable = "aws:SourceArn"
889+
}
890+
}
891+
}
892+
819893
data "aws_iam_policy_document" "deny_insecure_transport" {
820894
count = local.create_bucket && var.attach_deny_insecure_transport_policy && !var.is_directory_bucket ? 1 : 0
821895

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,12 @@ variable "attach_deny_ssec_encrypted_object_uploads" {
8888
default = false
8989
}
9090

91+
variable "attach_waf_log_delivery_policy" {
92+
description = "Controls if S3 bucket should have WAF log delivery policy attached"
93+
type = bool
94+
default = false
95+
}
96+
9197
variable "bucket" {
9298
description = "(Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name."
9399
type = string

wrappers/main.tf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ module "wrapper" {
2626
attach_policy = try(each.value.attach_policy, var.defaults.attach_policy, false)
2727
attach_public_policy = try(each.value.attach_public_policy, var.defaults.attach_public_policy, true)
2828
attach_require_latest_tls_policy = try(each.value.attach_require_latest_tls_policy, var.defaults.attach_require_latest_tls_policy, false)
29+
attach_waf_log_delivery_policy = try(each.value.attach_waf_log_delivery_policy, var.defaults.attach_waf_log_delivery_policy, false)
2930
availability_zone_id = try(each.value.availability_zone_id, var.defaults.availability_zone_id, null)
3031
block_public_acls = try(each.value.block_public_acls, var.defaults.block_public_acls, true)
3132
block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, true)

0 commit comments

Comments
 (0)