Skip to content

Commit bafac30

Browse files
authored
feat: Add default Access Log Delivery Policy (same as ALB/NLB) to work since April 2023 (#230)
1 parent d73535b commit bafac30

File tree

5 files changed

+141
-48
lines changed

5 files changed

+141
-48
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ No modules.
163163
| [aws_s3_bucket_website_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_website_configuration) | resource |
164164
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
165165
| [aws_canonical_user_id.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id) | data source |
166+
| [aws_iam_policy_document.access_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
166167
| [aws_iam_policy_document.combined](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
167168
| [aws_iam_policy_document.deny_insecure_transport](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
168169
| [aws_iam_policy_document.elb_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
@@ -177,11 +178,14 @@ No modules.
177178
| Name | Description | Type | Default | Required |
178179
|------|-------------|------|---------|:--------:|
179180
| <a name="input_acceleration_status"></a> [acceleration\_status](#input\_acceleration\_status) | (Optional) Sets the accelerate configuration of an existing bucket. Can be Enabled or Suspended. | `string` | `null` | no |
181+
| <a name="input_access_log_delivery_policy_source_accounts"></a> [access\_log\_delivery\_policy\_source\_accounts](#input\_access\_log\_delivery\_policy\_source\_accounts) | (Optional) List of AWS Account IDs should be allowed to deliver access logs to this bucket. | `list(string)` | `[]` | no |
182+
| <a name="input_access_log_delivery_policy_source_buckets"></a> [access\_log\_delivery\_policy\_source\_buckets](#input\_access\_log\_delivery\_policy\_source\_buckets) | (Optional) List of S3 bucket ARNs wich should be allowed to deliver access logs to this bucket. | `list(string)` | `[]` | no |
180183
| <a name="input_acl"></a> [acl](#input\_acl) | (Optional) The canned ACL to apply. Conflicts with `grant` | `string` | `null` | no |
181184
| <a name="input_analytics_configuration"></a> [analytics\_configuration](#input\_analytics\_configuration) | Map containing bucket analytics configuration. | `any` | `{}` | no |
182185
| <a name="input_analytics_self_source_destination"></a> [analytics\_self\_source\_destination](#input\_analytics\_self\_source\_destination) | Whether or not the analytics source bucket is also the destination bucket. | `bool` | `false` | no |
183186
| <a name="input_analytics_source_account_id"></a> [analytics\_source\_account\_id](#input\_analytics\_source\_account\_id) | The analytics source account id. | `string` | `null` | no |
184187
| <a name="input_analytics_source_bucket_arn"></a> [analytics\_source\_bucket\_arn](#input\_analytics\_source\_bucket\_arn) | The analytics source bucket ARN. | `string` | `null` | no |
188+
| <a name="input_attach_access_log_delivery_policy"></a> [attach\_access\_log\_delivery\_policy](#input\_attach\_access\_log\_delivery\_policy) | Controls if S3 bucket should have S3 access log delivery policy attached | `bool` | `false` | no |
185189
| <a name="input_attach_analytics_destination_policy"></a> [attach\_analytics\_destination\_policy](#input\_attach\_analytics\_destination\_policy) | Controls if S3 bucket should have bucket analytics destination policy attached. | `bool` | `false` | no |
186190
| <a name="input_attach_deny_insecure_transport_policy"></a> [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 |
187191
| <a name="input_attach_elb_log_delivery_policy"></a> [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 |

examples/complete/main.tf

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,18 @@ module "log_bucket" {
6767
source = "../../"
6868

6969
bucket = "logs-${random_pet.this.id}"
70-
acl = "log-delivery-write"
7170
force_destroy = true
7271

7372
control_object_ownership = true
74-
object_ownership = "ObjectWriter"
7573

7674
attach_elb_log_delivery_policy = true
7775
attach_lb_log_delivery_policy = true
76+
attach_access_log_delivery_policy = true
7877
attach_deny_insecure_transport_policy = true
7978
attach_require_latest_tls_policy = true
79+
80+
access_log_delivery_policy_source_accounts = [data.aws_caller_identity.current.account_id]
81+
access_log_delivery_policy_source_buckets = ["arn:aws:s3:::${local.bucket_name}"]
8082
}
8183

8284
module "cloudfront_log_bucket" {

main.tf

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ data "aws_iam_policy_document" "combined" {
522522
source_policy_documents = compact([
523523
var.attach_elb_log_delivery_policy ? data.aws_iam_policy_document.elb_log_delivery[0].json : "",
524524
var.attach_lb_log_delivery_policy ? data.aws_iam_policy_document.lb_log_delivery[0].json : "",
525+
var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
525526
var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
526527
var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
527528
var.attach_inventory_destination_policy || var.attach_analytics_destination_policy ? data.aws_iam_policy_document.inventory_and_analytics_destination_policy[0].json : "",
@@ -658,6 +659,71 @@ data "aws_iam_policy_document" "lb_log_delivery" {
658659
}
659660
}
660661

662+
# Grant access to S3 log delivery group for server access logging
663+
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-ownership-migrating-acls-prerequisites.html#object-ownership-server-access-logs
664+
# https://docs.aws.amazon.com/AmazonS3/latest/userguide/enable-server-access-logging.html#grant-log-delivery-permissions-general
665+
data "aws_iam_policy_document" "access_log_delivery" {
666+
count = local.create_bucket && var.attach_access_log_delivery_policy ? 1 : 0
667+
668+
statement {
669+
sid = "AWSAccessLogDeliveryWrite"
670+
671+
principals {
672+
type = "Service"
673+
identifiers = ["logging.s3.amazonaws.com"]
674+
}
675+
676+
effect = "Allow"
677+
678+
actions = [
679+
"s3:PutObject",
680+
]
681+
682+
resources = [
683+
"${aws_s3_bucket.this[0].arn}/*",
684+
]
685+
686+
dynamic "condition" {
687+
for_each = length(var.access_log_delivery_policy_source_buckets) != 0 ? [true] : []
688+
content {
689+
test = "ForAnyValue:ArnLike"
690+
variable = "aws:SourceArn"
691+
values = var.access_log_delivery_policy_source_buckets
692+
}
693+
}
694+
695+
dynamic "condition" {
696+
for_each = length(var.access_log_delivery_policy_source_accounts) != 0 ? [true] : []
697+
content {
698+
test = "ForAnyValue:StringEquals"
699+
variable = "aws:SourceAccount"
700+
values = var.access_log_delivery_policy_source_accounts
701+
}
702+
}
703+
704+
}
705+
706+
statement {
707+
sid = "AWSAccessLogDeliveryAclCheck"
708+
709+
effect = "Allow"
710+
711+
principals {
712+
type = "Service"
713+
identifiers = ["logging.s3.amazonaws.com"]
714+
}
715+
716+
actions = [
717+
"s3:GetBucketAcl",
718+
]
719+
720+
resources = [
721+
aws_s3_bucket.this[0].arn,
722+
]
723+
724+
}
725+
}
726+
661727
data "aws_iam_policy_document" "deny_insecure_transport" {
662728
count = local.create_bucket && var.attach_deny_insecure_transport_policy ? 1 : 0
663729

variables.tf

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ variable "attach_lb_log_delivery_policy" {
1616
default = false
1717
}
1818

19+
variable "attach_access_log_delivery_policy" {
20+
description = "Controls if S3 bucket should have S3 access log delivery policy attached"
21+
type = bool
22+
default = false
23+
}
24+
1925
variable "attach_deny_insecure_transport_policy" {
2026
description = "Controls if S3 bucket should have deny non-SSL transport policy attached"
2127
type = bool
@@ -124,6 +130,18 @@ variable "logging" {
124130
default = {}
125131
}
126132

133+
variable "access_log_delivery_policy_source_buckets" {
134+
description = "(Optional) List of S3 bucket ARNs wich should be allowed to deliver access logs to this bucket."
135+
type = list(string)
136+
default = []
137+
}
138+
139+
variable "access_log_delivery_policy_source_accounts" {
140+
description = "(Optional) List of AWS Account IDs should be allowed to deliver access logs to this bucket."
141+
type = list(string)
142+
default = []
143+
}
144+
127145
variable "grant" {
128146
description = "An ACL policy grant. Conflicts with `acl`"
129147
type = any

wrappers/main.tf

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,53 @@ module "wrapper" {
33

44
for_each = var.items
55

6-
create_bucket = try(each.value.create_bucket, var.defaults.create_bucket, true)
7-
attach_elb_log_delivery_policy = try(each.value.attach_elb_log_delivery_policy, var.defaults.attach_elb_log_delivery_policy, false)
8-
attach_lb_log_delivery_policy = try(each.value.attach_lb_log_delivery_policy, var.defaults.attach_lb_log_delivery_policy, false)
9-
attach_deny_insecure_transport_policy = try(each.value.attach_deny_insecure_transport_policy, var.defaults.attach_deny_insecure_transport_policy, false)
10-
attach_require_latest_tls_policy = try(each.value.attach_require_latest_tls_policy, var.defaults.attach_require_latest_tls_policy, false)
11-
attach_policy = try(each.value.attach_policy, var.defaults.attach_policy, false)
12-
attach_public_policy = try(each.value.attach_public_policy, var.defaults.attach_public_policy, true)
13-
attach_inventory_destination_policy = try(each.value.attach_inventory_destination_policy, var.defaults.attach_inventory_destination_policy, false)
14-
attach_analytics_destination_policy = try(each.value.attach_analytics_destination_policy, var.defaults.attach_analytics_destination_policy, false)
15-
bucket = try(each.value.bucket, var.defaults.bucket, null)
16-
bucket_prefix = try(each.value.bucket_prefix, var.defaults.bucket_prefix, null)
17-
acl = try(each.value.acl, var.defaults.acl, null)
18-
policy = try(each.value.policy, var.defaults.policy, null)
19-
tags = try(each.value.tags, var.defaults.tags, {})
20-
force_destroy = try(each.value.force_destroy, var.defaults.force_destroy, false)
21-
acceleration_status = try(each.value.acceleration_status, var.defaults.acceleration_status, null)
22-
request_payer = try(each.value.request_payer, var.defaults.request_payer, null)
23-
website = try(each.value.website, var.defaults.website, {})
24-
cors_rule = try(each.value.cors_rule, var.defaults.cors_rule, [])
25-
versioning = try(each.value.versioning, var.defaults.versioning, {})
26-
logging = try(each.value.logging, var.defaults.logging, {})
27-
grant = try(each.value.grant, var.defaults.grant, [])
28-
owner = try(each.value.owner, var.defaults.owner, {})
29-
expected_bucket_owner = try(each.value.expected_bucket_owner, var.defaults.expected_bucket_owner, null)
30-
lifecycle_rule = try(each.value.lifecycle_rule, var.defaults.lifecycle_rule, [])
31-
replication_configuration = try(each.value.replication_configuration, var.defaults.replication_configuration, {})
32-
server_side_encryption_configuration = try(each.value.server_side_encryption_configuration, var.defaults.server_side_encryption_configuration, {})
33-
intelligent_tiering = try(each.value.intelligent_tiering, var.defaults.intelligent_tiering, {})
34-
object_lock_configuration = try(each.value.object_lock_configuration, var.defaults.object_lock_configuration, {})
35-
metric_configuration = try(each.value.metric_configuration, var.defaults.metric_configuration, [])
36-
inventory_configuration = try(each.value.inventory_configuration, var.defaults.inventory_configuration, {})
37-
inventory_source_account_id = try(each.value.inventory_source_account_id, var.defaults.inventory_source_account_id, null)
38-
inventory_source_bucket_arn = try(each.value.inventory_source_bucket_arn, var.defaults.inventory_source_bucket_arn, null)
39-
inventory_self_source_destination = try(each.value.inventory_self_source_destination, var.defaults.inventory_self_source_destination, false)
40-
analytics_configuration = try(each.value.analytics_configuration, var.defaults.analytics_configuration, {})
41-
analytics_source_account_id = try(each.value.analytics_source_account_id, var.defaults.analytics_source_account_id, null)
42-
analytics_source_bucket_arn = try(each.value.analytics_source_bucket_arn, var.defaults.analytics_source_bucket_arn, null)
43-
analytics_self_source_destination = try(each.value.analytics_self_source_destination, var.defaults.analytics_self_source_destination, false)
44-
object_lock_enabled = try(each.value.object_lock_enabled, var.defaults.object_lock_enabled, false)
45-
block_public_acls = try(each.value.block_public_acls, var.defaults.block_public_acls, true)
46-
block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, true)
47-
ignore_public_acls = try(each.value.ignore_public_acls, var.defaults.ignore_public_acls, true)
48-
restrict_public_buckets = try(each.value.restrict_public_buckets, var.defaults.restrict_public_buckets, true)
49-
control_object_ownership = try(each.value.control_object_ownership, var.defaults.control_object_ownership, false)
50-
object_ownership = try(each.value.object_ownership, var.defaults.object_ownership, "BucketOwnerEnforced")
51-
putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true)
6+
create_bucket = try(each.value.create_bucket, var.defaults.create_bucket, true)
7+
attach_elb_log_delivery_policy = try(each.value.attach_elb_log_delivery_policy, var.defaults.attach_elb_log_delivery_policy, false)
8+
attach_lb_log_delivery_policy = try(each.value.attach_lb_log_delivery_policy, var.defaults.attach_lb_log_delivery_policy, false)
9+
attach_access_log_delivery_policy = try(each.value.attach_access_log_delivery_policy, var.defaults.attach_access_log_delivery_policy, false)
10+
attach_deny_insecure_transport_policy = try(each.value.attach_deny_insecure_transport_policy, var.defaults.attach_deny_insecure_transport_policy, false)
11+
attach_require_latest_tls_policy = try(each.value.attach_require_latest_tls_policy, var.defaults.attach_require_latest_tls_policy, false)
12+
attach_policy = try(each.value.attach_policy, var.defaults.attach_policy, false)
13+
attach_public_policy = try(each.value.attach_public_policy, var.defaults.attach_public_policy, true)
14+
attach_inventory_destination_policy = try(each.value.attach_inventory_destination_policy, var.defaults.attach_inventory_destination_policy, false)
15+
attach_analytics_destination_policy = try(each.value.attach_analytics_destination_policy, var.defaults.attach_analytics_destination_policy, false)
16+
bucket = try(each.value.bucket, var.defaults.bucket, null)
17+
bucket_prefix = try(each.value.bucket_prefix, var.defaults.bucket_prefix, null)
18+
acl = try(each.value.acl, var.defaults.acl, null)
19+
policy = try(each.value.policy, var.defaults.policy, null)
20+
tags = try(each.value.tags, var.defaults.tags, {})
21+
force_destroy = try(each.value.force_destroy, var.defaults.force_destroy, false)
22+
acceleration_status = try(each.value.acceleration_status, var.defaults.acceleration_status, null)
23+
request_payer = try(each.value.request_payer, var.defaults.request_payer, null)
24+
website = try(each.value.website, var.defaults.website, {})
25+
cors_rule = try(each.value.cors_rule, var.defaults.cors_rule, [])
26+
versioning = try(each.value.versioning, var.defaults.versioning, {})
27+
logging = try(each.value.logging, var.defaults.logging, {})
28+
access_log_delivery_policy_source_buckets = try(each.value.access_log_delivery_policy_source_buckets, var.defaults.access_log_delivery_policy_source_buckets, [])
29+
access_log_delivery_policy_source_accounts = try(each.value.access_log_delivery_policy_source_accounts, var.defaults.access_log_delivery_policy_source_accounts, [])
30+
grant = try(each.value.grant, var.defaults.grant, [])
31+
owner = try(each.value.owner, var.defaults.owner, {})
32+
expected_bucket_owner = try(each.value.expected_bucket_owner, var.defaults.expected_bucket_owner, null)
33+
lifecycle_rule = try(each.value.lifecycle_rule, var.defaults.lifecycle_rule, [])
34+
replication_configuration = try(each.value.replication_configuration, var.defaults.replication_configuration, {})
35+
server_side_encryption_configuration = try(each.value.server_side_encryption_configuration, var.defaults.server_side_encryption_configuration, {})
36+
intelligent_tiering = try(each.value.intelligent_tiering, var.defaults.intelligent_tiering, {})
37+
object_lock_configuration = try(each.value.object_lock_configuration, var.defaults.object_lock_configuration, {})
38+
metric_configuration = try(each.value.metric_configuration, var.defaults.metric_configuration, [])
39+
inventory_configuration = try(each.value.inventory_configuration, var.defaults.inventory_configuration, {})
40+
inventory_source_account_id = try(each.value.inventory_source_account_id, var.defaults.inventory_source_account_id, null)
41+
inventory_source_bucket_arn = try(each.value.inventory_source_bucket_arn, var.defaults.inventory_source_bucket_arn, null)
42+
inventory_self_source_destination = try(each.value.inventory_self_source_destination, var.defaults.inventory_self_source_destination, false)
43+
analytics_configuration = try(each.value.analytics_configuration, var.defaults.analytics_configuration, {})
44+
analytics_source_account_id = try(each.value.analytics_source_account_id, var.defaults.analytics_source_account_id, null)
45+
analytics_source_bucket_arn = try(each.value.analytics_source_bucket_arn, var.defaults.analytics_source_bucket_arn, null)
46+
analytics_self_source_destination = try(each.value.analytics_self_source_destination, var.defaults.analytics_self_source_destination, false)
47+
object_lock_enabled = try(each.value.object_lock_enabled, var.defaults.object_lock_enabled, false)
48+
block_public_acls = try(each.value.block_public_acls, var.defaults.block_public_acls, true)
49+
block_public_policy = try(each.value.block_public_policy, var.defaults.block_public_policy, true)
50+
ignore_public_acls = try(each.value.ignore_public_acls, var.defaults.ignore_public_acls, true)
51+
restrict_public_buckets = try(each.value.restrict_public_buckets, var.defaults.restrict_public_buckets, true)
52+
control_object_ownership = try(each.value.control_object_ownership, var.defaults.control_object_ownership, false)
53+
object_ownership = try(each.value.object_ownership, var.defaults.object_ownership, "BucketOwnerEnforced")
54+
putin_khuylo = try(each.value.putin_khuylo, var.defaults.putin_khuylo, true)
5255
}

0 commit comments

Comments
 (0)