diff --git a/README.md b/README.md
index 131c44b9..61deeb23 100644
--- a/README.md
+++ b/README.md
@@ -14,8 +14,8 @@ These features of S3 bucket configurations are supported:
- server-side encryption
- object locking
- Cross-Region Replication (CRR)
-- ELB log delivery bucket policy
-- ALB/NLB log delivery bucket policy
+- ALB log delivery bucket policy
+- NLB and VPC flow logs delivery bucket policy
- WAF log delivery bucket policy
- Account-level Public Access Block
- S3 Directory Bucket
@@ -60,7 +60,7 @@ module "s3_bucket_for_logs" {
}
```
-### Bucket with ALB/NLB access log delivery policy attached
+### Bucket with ALB/NLB/VPC flow logs delivery policy attached
```hcl
module "s3_bucket_for_logs" {
@@ -75,7 +75,7 @@ module "s3_bucket_for_logs" {
object_ownership = "ObjectWriter"
attach_elb_log_delivery_policy = true # Required for ALB logs
- attach_lb_log_delivery_policy = true # Required for ALB/NLB logs
+ attach_lb_log_delivery_policy = true # Required for NLB/VPC flow logs logs
}
```
@@ -228,9 +228,9 @@ No modules.
| [attach\_deny\_insecure\_transport\_policy](#input\_attach\_deny\_insecure\_transport\_policy) | Controls if S3 bucket should have deny non-SSL transport policy attached | `bool` | `false` | no |
| [attach\_deny\_ssec\_encrypted\_object\_uploads](#input\_attach\_deny\_ssec\_encrypted\_object\_uploads) | Controls if S3 bucket should deny SSEC encrypted object uploads. | `bool` | `false` | no |
| [attach\_deny\_unencrypted\_object\_uploads](#input\_attach\_deny\_unencrypted\_object\_uploads) | Controls if S3 bucket should deny unencrypted object uploads policy attached. | `bool` | `false` | no |
-| [attach\_elb\_log\_delivery\_policy](#input\_attach\_elb\_log\_delivery\_policy) | Controls if S3 bucket should have ELB log delivery policy attached | `bool` | `false` | no |
+| [attach\_elb\_log\_delivery\_policy](#input\_attach\_elb\_log\_delivery\_policy) | Controls if S3 bucket should have ALB log delivery policy attached | `bool` | `false` | no |
| [attach\_inventory\_destination\_policy](#input\_attach\_inventory\_destination\_policy) | Controls if S3 bucket should have bucket inventory destination policy attached. | `bool` | `false` | no |
-| [attach\_lb\_log\_delivery\_policy](#input\_attach\_lb\_log\_delivery\_policy) | Controls if S3 bucket should have ALB/NLB log delivery policy attached | `bool` | `false` | no |
+| [attach\_lb\_log\_delivery\_policy](#input\_attach\_lb\_log\_delivery\_policy) | Controls if S3 bucket should have NLB and VPC flow logs delivery policy attached | `bool` | `false` | no |
| [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 |
| [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 |
| [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 |
@@ -244,6 +244,7 @@ No modules.
| [cors\_rule](#input\_cors\_rule) | List of maps containing rules for Cross-Origin Resource Sharing. | `any` | `[]` | no |
| [create\_bucket](#input\_create\_bucket) | Controls if S3 bucket should be created | `bool` | `true` | no |
| [data\_redundancy](#input\_data\_redundancy) | Data redundancy. Valid values: `SingleAvailabilityZone` | `string` | `null` | no |
+| [elb\_log\_delivery\_policy\_source\_organizations](#input\_elb\_log\_delivery\_policy\_source\_organizations) | (Optional) List of AWS Organization IDs should be allowed to deliver ALB logs to this bucket. | `list(string)` | `[]` | no |
| [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | The account ID of the expected bucket owner | `string` | `null` | no |
| [force\_destroy](#input\_force\_destroy) | (Optional, Default:false ) A boolean that indicates all objects should be deleted from the bucket so that the bucket can be destroyed without error. These objects are not recoverable. | `bool` | `false` | no |
| [grant](#input\_grant) | An ACL policy grant. Conflicts with `acl` | `any` | `[]` | no |
@@ -254,7 +255,7 @@ No modules.
| [inventory\_source\_account\_id](#input\_inventory\_source\_account\_id) | The inventory source account id. | `string` | `null` | no |
| [inventory\_source\_bucket\_arn](#input\_inventory\_source\_bucket\_arn) | The inventory source bucket ARN. | `string` | `null` | no |
| [is\_directory\_bucket](#input\_is\_directory\_bucket) | If the s3 bucket created is a directory bucket | `bool` | `false` | no |
-| [lb\_log\_delivery\_policy\_source\_organizations](#input\_lb\_log\_delivery\_policy\_source\_organizations) | (Optional) List of AWS Organization IDs should be allowed to deliver ALB/NLB logs to this bucket. | `list(string)` | `[]` | no |
+| [lb\_log\_delivery\_policy\_source\_organizations](#input\_lb\_log\_delivery\_policy\_source\_organizations) | (Optional) List of AWS Organization IDs should be allowed to deliver NLB and VPC flow logs to this bucket. | `list(string)` | `[]` | no |
| [lifecycle\_rule](#input\_lifecycle\_rule) | List of maps containing configuration of object lifecycle management. | `any` | `[]` | no |
| [location\_type](#input\_location\_type) | Location type. Valid values: `AvailabilityZone` or `LocalZone` | `string` | `null` | no |
| [logging](#input\_logging) | Map containing access bucket logging configuration. | `any` | `{}` | no |
diff --git a/examples/complete/README.md b/examples/complete/README.md
index cebfd965..cae13754 100644
--- a/examples/complete/README.md
+++ b/examples/complete/README.md
@@ -2,7 +2,7 @@
Configuration in this directory creates S3 bucket which demos such capabilities:
- static web-site hosting
-- access logging (for S3, ELB and ALB/NLB)
+- access logging (for S3 access, ALB, NLB and VPC flow logs)
- versioning
- CORS
- lifecycle rules
diff --git a/examples/complete/main.tf b/examples/complete/main.tf
index c6588782..2b1411ad 100644
--- a/examples/complete/main.tf
+++ b/examples/complete/main.tf
@@ -81,6 +81,7 @@ module "log_bucket" {
access_log_delivery_policy_source_accounts = [data.aws_caller_identity.current.account_id]
access_log_delivery_policy_source_buckets = ["arn:aws:s3:::${local.bucket_name}"]
access_log_delivery_policy_source_organizations = ["o-123456"]
+ elb_log_delivery_policy_source_organizations = ["o-123456"]
lb_log_delivery_policy_source_organizations = ["o-123456"]
}
diff --git a/main.tf b/main.tf
index 697aef1a..6dc1e3ea 100644
--- a/main.tf
+++ b/main.tf
@@ -610,7 +610,7 @@ data "aws_iam_policy_document" "combined" {
])
}
-# AWS Load Balancer access log delivery policy
+# ALB access and connection log delivery policy
locals {
# List of AWS regions where permissions should be granted to the specified Elastic Load Balancing account ID ( https://docs.aws.amazon.com/elasticloadbalancing/latest/application/enable-access-logging.html#attach-bucket-policy )
elb_service_accounts = {
@@ -651,7 +651,7 @@ data "aws_iam_policy_document" "elb_log_delivery" {
for_each = { for k, v in local.elb_service_accounts : k => v if k == data.aws_region.current.region }
content {
- sid = format("ELBRegion%s", title(statement.key))
+ sid = format("ALBRegion%s", title(statement.key))
principals {
type = "AWS"
@@ -667,6 +667,26 @@ data "aws_iam_policy_document" "elb_log_delivery" {
resources = [
"${aws_s3_bucket.this[0].arn}/*",
]
+
+ dynamic "condition" {
+ for_each = length(var.elb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "ArnLike"
+ variable = "aws:SourceArn"
+ values = ["arn:aws:elasticloadbalancing:*:${data.aws_caller_identity.current.id}:loadbalancer/*"]
+ }
+ }
+
+ dynamic "condition" {
+ for_each = length(var.elb_log_delivery_policy_source_organizations) > 0 ? [true] : []
+
+ content {
+ test = "StringEquals"
+ variable = "aws:SourceOrgId"
+ values = var.elb_log_delivery_policy_source_organizations
+ }
+ }
}
}
@@ -688,10 +708,30 @@ data "aws_iam_policy_document" "elb_log_delivery" {
resources = [
"${aws_s3_bucket.this[0].arn}/*",
]
+
+ dynamic "condition" {
+ for_each = length(var.elb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "ArnLike"
+ variable = "aws:SourceArn"
+ values = ["arn:aws:elasticloadbalancing:*:${data.aws_caller_identity.current.id}:loadbalancer/*"]
+ }
+ }
+
+ dynamic "condition" {
+ for_each = length(var.elb_log_delivery_policy_source_organizations) > 0 ? [true] : []
+
+ content {
+ test = "StringEquals"
+ variable = "aws:SourceOrgId"
+ values = var.elb_log_delivery_policy_source_organizations
+ }
+ }
}
}
-# ALB/NLB
+# NLB and VPC flow logs
data "aws_iam_policy_document" "lb_log_delivery" {
count = local.create_bucket && var.attach_lb_log_delivery_policy && !var.is_directory_bucket ? 1 : 0
@@ -719,6 +759,26 @@ data "aws_iam_policy_document" "lb_log_delivery" {
values = ["bucket-owner-full-control"]
}
+ dynamic "condition" {
+ for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "StringEquals"
+ variable = "aws:SourceAccount"
+ values = [data.aws_caller_identity.current.id]
+ }
+ }
+
+ dynamic "condition" {
+ for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "ArnLike"
+ variable = "aws:SourceArn"
+ values = ["arn:aws:logs:*:${data.aws_caller_identity.current.id}:*"]
+ }
+ }
+
dynamic "condition" {
for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [true] : []
@@ -749,6 +809,26 @@ data "aws_iam_policy_document" "lb_log_delivery" {
aws_s3_bucket.this[0].arn,
]
+ dynamic "condition" {
+ for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "StringEquals"
+ variable = "aws:SourceAccount"
+ values = [data.aws_caller_identity.current.id]
+ }
+ }
+
+ dynamic "condition" {
+ for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [] : [true]
+
+ content {
+ test = "ArnLike"
+ variable = "aws:SourceArn"
+ values = ["arn:aws:logs:*:${data.aws_caller_identity.current.id}:*"]
+ }
+ }
+
dynamic "condition" {
for_each = length(var.lb_log_delivery_policy_source_organizations) > 0 ? [true] : []
diff --git a/variables.tf b/variables.tf
index 9a97214e..a8d7ee72 100644
--- a/variables.tf
+++ b/variables.tf
@@ -5,13 +5,13 @@ variable "create_bucket" {
}
variable "attach_elb_log_delivery_policy" {
- description = "Controls if S3 bucket should have ELB log delivery policy attached"
+ description = "Controls if S3 bucket should have ALB log delivery policy attached"
type = bool
default = false
}
variable "attach_lb_log_delivery_policy" {
- description = "Controls if S3 bucket should have ALB/NLB log delivery policy attached"
+ description = "Controls if S3 bucket should have NLB and VPC flow logs delivery policy attached"
type = bool
default = false
}
@@ -196,8 +196,14 @@ variable "access_log_delivery_policy_source_organizations" {
default = []
}
+variable "elb_log_delivery_policy_source_organizations" {
+ description = "(Optional) List of AWS Organization IDs should be allowed to deliver ALB logs to this bucket."
+ type = list(string)
+ default = []
+}
+
variable "lb_log_delivery_policy_source_organizations" {
- description = "(Optional) List of AWS Organization IDs should be allowed to deliver ALB/NLB logs to this bucket."
+ description = "(Optional) List of AWS Organization IDs should be allowed to deliver NLB and VPC flow logs to this bucket."
type = list(string)
default = []
}
diff --git a/wrappers/main.tf b/wrappers/main.tf
index def69e27..660dd500 100644
--- a/wrappers/main.tf
+++ b/wrappers/main.tf
@@ -37,6 +37,7 @@ module "wrapper" {
cors_rule = try(each.value.cors_rule, var.defaults.cors_rule, [])
create_bucket = try(each.value.create_bucket, var.defaults.create_bucket, true)
data_redundancy = try(each.value.data_redundancy, var.defaults.data_redundancy, null)
+ elb_log_delivery_policy_source_organizations = try(each.value.elb_log_delivery_policy_source_organizations, var.defaults.elb_log_delivery_policy_source_organizations, [])
expected_bucket_owner = try(each.value.expected_bucket_owner, var.defaults.expected_bucket_owner, null)
force_destroy = try(each.value.force_destroy, var.defaults.force_destroy, false)
grant = try(each.value.grant, var.defaults.grant, [])