Skip to content

Commit 2542a36

Browse files
authored
feat: Add "deny unencrypted object uploads" and "incorrect encryption headers" bucket policies (#238)
Co-authored-by: magreenbaum <magreenbaum>
1 parent 227888a commit 2542a36

File tree

5 files changed

+83
-5
lines changed

5 files changed

+83
-5
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,9 @@ No modules.
165165
| [aws_canonical_user_id.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/canonical_user_id) | data source |
166166
| [aws_iam_policy_document.access_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
167167
| [aws_iam_policy_document.combined](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
168+
| [aws_iam_policy_document.deny_incorrect_encryption_headers](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
168169
| [aws_iam_policy_document.deny_insecure_transport](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
170+
| [aws_iam_policy_document.deny_unencrypted_object_uploads](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
169171
| [aws_iam_policy_document.elb_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
170172
| [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 |
171173
| [aws_iam_policy_document.lb_log_delivery](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
@@ -187,7 +189,9 @@ No modules.
187189
| <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 |
188190
| <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 |
189191
| <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 |
192+
| <a name="input_attach_deny_incorrect_encryption_headers"></a> [attach\_deny\_incorrect\_encryption\_headers](#input\_attach\_deny\_incorrect\_encryption\_headers) | Controls if S3 bucket should deny incorrect encryption headers policy attached. | `bool` | `false` | no |
190193
| <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 |
194+
| <a name="input_attach_deny_unencrypted_object_uploads"></a> [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 |
191195
| <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 |
192196
| <a name="input_attach_inventory_destination_policy"></a> [attach\_inventory\_destination\_policy](#input\_attach\_inventory\_destination\_policy) | Controls if S3 bucket should have bucket inventory destination policy attached. | `bool` | `false` | no |
193197
| <a name="input_attach_lb_log_delivery_policy"></a> [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 |

examples/complete/main.tf

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,10 +132,12 @@ module "s3_bucket" {
132132
}
133133

134134
# Bucket policies
135-
attach_policy = true
136-
policy = data.aws_iam_policy_document.bucket_policy.json
137-
attach_deny_insecure_transport_policy = true
138-
attach_require_latest_tls_policy = true
135+
attach_policy = true
136+
policy = data.aws_iam_policy_document.bucket_policy.json
137+
attach_deny_insecure_transport_policy = true
138+
attach_require_latest_tls_policy = true
139+
attach_deny_incorrect_encryption_headers = true
140+
attach_deny_unencrypted_object_uploads = true
139141

140142
# S3 bucket-level Public Access Block configuration (by default now AWS has made this default as true for S3 bucket-level block public access)
141143
# block_public_acls = true

main.tf

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ data "aws_partition" "current" {}
88
locals {
99
create_bucket = var.create_bucket && var.putin_khuylo
1010

11-
attach_policy = var.attach_require_latest_tls_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_policy
11+
attach_policy = var.attach_require_latest_tls_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_unencrypted_object_uploads || var.attach_policy
1212

1313
# Variables with type `any` should be jsonencode()'d when value is coming from Terragrunt
1414
grants = try(jsondecode(var.grant), var.grant)
@@ -533,6 +533,8 @@ data "aws_iam_policy_document" "combined" {
533533
var.attach_access_log_delivery_policy ? data.aws_iam_policy_document.access_log_delivery[0].json : "",
534534
var.attach_require_latest_tls_policy ? data.aws_iam_policy_document.require_latest_tls[0].json : "",
535535
var.attach_deny_insecure_transport_policy ? data.aws_iam_policy_document.deny_insecure_transport[0].json : "",
536+
var.attach_deny_unencrypted_object_uploads ? data.aws_iam_policy_document.deny_unencrypted_object_uploads[0].json : "",
537+
var.attach_deny_incorrect_encryption_headers ? data.aws_iam_policy_document.deny_incorrect_encryption_headers[0].json : "",
536538
var.attach_inventory_destination_policy || var.attach_analytics_destination_policy ? data.aws_iam_policy_document.inventory_and_analytics_destination_policy[0].json : "",
537539
var.attach_policy ? var.policy : ""
538540
])
@@ -794,6 +796,62 @@ data "aws_iam_policy_document" "require_latest_tls" {
794796
}
795797
}
796798

799+
data "aws_iam_policy_document" "deny_incorrect_encryption_headers" {
800+
count = local.create_bucket && var.attach_deny_incorrect_encryption_headers ? 1 : 0
801+
802+
statement {
803+
sid = "denyIncorrectEncryptionHeaders"
804+
effect = "Deny"
805+
806+
actions = [
807+
"s3:PutObject"
808+
]
809+
810+
resources = [
811+
"${aws_s3_bucket.this[0].arn}/*"
812+
]
813+
814+
principals {
815+
identifiers = ["*"]
816+
type = "*"
817+
}
818+
819+
condition {
820+
test = "StringNotEquals"
821+
variable = "s3:x-amz-server-side-encryption"
822+
values = try(var.server_side_encryption_configuration.rule.apply_server_side_encryption_by_default.sse_algorithm, null) == "aws:kms" ? ["aws:kms"] : ["AES256"]
823+
}
824+
}
825+
}
826+
827+
data "aws_iam_policy_document" "deny_unencrypted_object_uploads" {
828+
count = local.create_bucket && var.attach_deny_unencrypted_object_uploads ? 1 : 0
829+
830+
statement {
831+
sid = "denyUnencryptedObjectUploads"
832+
effect = "Deny"
833+
834+
actions = [
835+
"s3:PutObject"
836+
]
837+
838+
resources = [
839+
"${aws_s3_bucket.this[0].arn}/*"
840+
]
841+
842+
principals {
843+
identifiers = ["*"]
844+
type = "*"
845+
}
846+
847+
condition {
848+
test = "Null"
849+
variable = "s3:x-amz-server-side-encryption"
850+
values = [true]
851+
}
852+
}
853+
}
854+
797855
resource "aws_s3_bucket_public_access_block" "this" {
798856
count = local.create_bucket && var.attach_public_policy ? 1 : 0
799857

variables.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@ variable "attach_analytics_destination_policy" {
5858
default = false
5959
}
6060

61+
variable "attach_deny_incorrect_encryption_headers" {
62+
description = "Controls if S3 bucket should deny incorrect encryption headers policy attached."
63+
type = bool
64+
default = false
65+
}
66+
67+
variable "attach_deny_unencrypted_object_uploads" {
68+
description = "Controls if S3 bucket should deny unencrypted object uploads policy attached."
69+
type = bool
70+
default = false
71+
}
72+
6173
variable "bucket" {
6274
description = "(Optional, Forces new resource) The name of the bucket. If omitted, Terraform will assign a random, unique name."
6375
type = string

wrappers/main.tf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ module "wrapper" {
1313
attach_public_policy = try(each.value.attach_public_policy, var.defaults.attach_public_policy, true)
1414
attach_inventory_destination_policy = try(each.value.attach_inventory_destination_policy, var.defaults.attach_inventory_destination_policy, false)
1515
attach_analytics_destination_policy = try(each.value.attach_analytics_destination_policy, var.defaults.attach_analytics_destination_policy, false)
16+
attach_deny_incorrect_encryption_headers = try(each.value.attach_deny_incorrect_encryption_headers, var.defaults.attach_deny_incorrect_encryption_headers, false)
17+
attach_deny_unencrypted_object_uploads = try(each.value.attach_deny_unencrypted_object_uploads, var.defaults.attach_deny_unencrypted_object_uploads, false)
1618
bucket = try(each.value.bucket, var.defaults.bucket, null)
1719
bucket_prefix = try(each.value.bucket_prefix, var.defaults.bucket_prefix, null)
1820
acl = try(each.value.acl, var.defaults.acl, null)

0 commit comments

Comments
 (0)