Skip to content

Commit 99453cc

Browse files
authored
Always require TLS connection to S3 bucket (#139)
* Always deny unencrypted HTTP connections * tflint fixes
1 parent 1d48b08 commit 99453cc

File tree

7 files changed

+66
-60
lines changed

7 files changed

+66
-60
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ Available targets:
286286
| [aws_s3_bucket_server_side_encryption_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
287287
| [aws_s3_bucket_versioning.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |
288288
| [local_file.terraform_backend_config](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
289-
| [aws_iam_policy_document.prevent_unencrypted_uploads](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
289+
| [aws_iam_policy_document.bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
290290
| [aws_iam_policy_document.replication](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
291291
| [aws_iam_policy_document.replication_sts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
292292
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |

docs/terraform.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
| [aws_s3_bucket_server_side_encryption_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource |
4242
| [aws_s3_bucket_versioning.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource |
4343
| [local_file.terraform_backend_config](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
44-
| [aws_iam_policy_document.prevent_unencrypted_uploads](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
44+
| [aws_iam_policy_document.bucket_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
4545
| [aws_iam_policy_document.replication](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
4646
| [aws_iam_policy_document.replication_sts](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
4747
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |

examples/complete/versions.tf

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ terraform {
44
required_providers {
55
aws = {
66
source = "hashicorp/aws"
7-
version = ">= 2.0"
7+
version = ">= 4.9.0"
88
}
99
local = {
1010
source = "hashicorp/local"

main.tf

+57-52
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,7 @@ locals {
88

99
prevent_unencrypted_uploads = local.enabled && var.prevent_unencrypted_uploads
1010

11-
policy = local.prevent_unencrypted_uploads ? join(
12-
"",
13-
data.aws_iam_policy_document.prevent_unencrypted_uploads.*.json
14-
) : ""
11+
policy = one(data.aws_iam_policy_document.bucket_policy[*].json)
1512

1613
terraform_backend_config_file = format(
1714
"%s/%s",
@@ -56,63 +53,71 @@ module "bucket_label" {
5653

5754
data "aws_region" "current" {}
5855

59-
data "aws_iam_policy_document" "prevent_unencrypted_uploads" {
60-
count = local.prevent_unencrypted_uploads ? 1 : 0
56+
data "aws_iam_policy_document" "bucket_policy" {
57+
count = local.enabled ? 1 : 0
6158

62-
statement {
63-
sid = "DenyIncorrectEncryptionHeader"
59+
dynamic "statement" {
60+
for_each = local.prevent_unencrypted_uploads ? ["true"] : []
6461

65-
effect = "Deny"
62+
content {
63+
sid = "DenyIncorrectEncryptionHeader"
6664

67-
principals {
68-
identifiers = ["*"]
69-
type = "AWS"
70-
}
65+
effect = "Deny"
7166

72-
actions = [
73-
"s3:PutObject"
74-
]
67+
principals {
68+
identifiers = ["*"]
69+
type = "AWS"
70+
}
7571

76-
resources = [
77-
"${var.arn_format}:s3:::${local.bucket_name}/*",
78-
]
79-
80-
condition {
81-
test = "StringNotEquals"
82-
variable = "s3:x-amz-server-side-encryption"
72+
actions = [
73+
"s3:PutObject"
74+
]
8375

84-
values = [
85-
"AES256",
86-
"aws:kms"
76+
resources = [
77+
"${var.arn_format}:s3:::${local.bucket_name}/*",
8778
]
79+
80+
condition {
81+
test = "StringNotEquals"
82+
variable = "s3:x-amz-server-side-encryption"
83+
84+
values = [
85+
"AES256",
86+
"aws:kms"
87+
]
88+
}
8889
}
8990
}
9091

91-
statement {
92-
sid = "DenyUnEncryptedObjectUploads"
92+
dynamic "statement" {
93+
for_each = local.prevent_unencrypted_uploads ? ["true"] : []
9394

94-
effect = "Deny"
95+
content {
96+
sid = "DenyUnEncryptedObjectUploads"
9597

96-
principals {
97-
identifiers = ["*"]
98-
type = "AWS"
99-
}
98+
effect = "Deny"
10099

101-
actions = [
102-
"s3:PutObject"
103-
]
100+
principals {
101+
identifiers = ["*"]
102+
type = "AWS"
103+
}
104104

105-
resources = [
106-
"${var.arn_format}:s3:::${local.bucket_name}/*",
107-
]
108-
109-
condition {
110-
test = "Null"
111-
variable = "s3:x-amz-server-side-encryption"
105+
actions = [
106+
"s3:PutObject"
107+
]
112108

113-
values = [
114-
"true"
109+
resources = [
110+
"${var.arn_format}:s3:::${local.bucket_name}/*",
115111
]
112+
113+
condition {
114+
test = "Null"
115+
variable = "s3:x-amz-server-side-encryption"
116+
117+
values = [
118+
"true"
119+
]
120+
}
116121
}
117122
}
118123

@@ -157,14 +162,14 @@ resource "aws_s3_bucket" "default" {
157162
resource "aws_s3_bucket_policy" "default" {
158163
count = local.bucket_enabled ? 1 : 0
159164

160-
bucket = one(aws_s3_bucket.default.*.id)
165+
bucket = one(aws_s3_bucket.default[*].id)
161166
policy = local.policy
162167
}
163168

164169
resource "aws_s3_bucket_acl" "default" {
165170
count = local.bucket_enabled && !var.bucket_ownership_enforced_enabled ? 1 : 0
166171

167-
bucket = one(aws_s3_bucket.default.*.id)
172+
bucket = one(aws_s3_bucket.default[*].id)
168173
acl = var.acl
169174

170175
# Default "bucket ownership controls" for new S3 buckets is "BucketOwnerEnforced", which disables ACLs.
@@ -175,7 +180,7 @@ resource "aws_s3_bucket_acl" "default" {
175180
resource "aws_s3_bucket_versioning" "default" {
176181
count = local.bucket_enabled ? 1 : 0
177182

178-
bucket = one(aws_s3_bucket.default.*.id)
183+
bucket = one(aws_s3_bucket.default[*].id)
179184

180185
versioning_configuration {
181186
status = "Enabled"
@@ -186,7 +191,7 @@ resource "aws_s3_bucket_versioning" "default" {
186191
resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
187192
count = local.bucket_enabled ? 1 : 0
188193

189-
bucket = one(aws_s3_bucket.default.*.id)
194+
bucket = one(aws_s3_bucket.default[*].id)
190195

191196
rule {
192197
apply_server_side_encryption_by_default {
@@ -198,7 +203,7 @@ resource "aws_s3_bucket_server_side_encryption_configuration" "default" {
198203
resource "aws_s3_bucket_logging" "default" {
199204
count = local.bucket_enabled && length(var.logging) > 0 ? 1 : 0
200205

201-
bucket = one(aws_s3_bucket.default.*.id)
206+
bucket = one(aws_s3_bucket.default[*].id)
202207

203208
target_bucket = var.logging[0].target_bucket
204209
target_prefix = var.logging[0].target_prefix
@@ -207,7 +212,7 @@ resource "aws_s3_bucket_logging" "default" {
207212
resource "aws_s3_bucket_public_access_block" "default" {
208213
count = local.bucket_enabled && var.enable_public_access_block ? 1 : 0
209214

210-
bucket = one(aws_s3_bucket.default.*.id)
215+
bucket = one(aws_s3_bucket.default[*].id)
211216
block_public_acls = var.block_public_acls
212217
ignore_public_acls = var.ignore_public_acls
213218
block_public_policy = var.block_public_policy
@@ -218,7 +223,7 @@ resource "aws_s3_bucket_public_access_block" "default" {
218223
# See https://docs.aws.amazon.com/AmazonS3/latest/userguide/about-object-ownership.html
219224
resource "aws_s3_bucket_ownership_controls" "default" {
220225
count = local.bucket_enabled ? 1 : 0
221-
bucket = one(aws_s3_bucket.default.*.id)
226+
bucket = one(aws_s3_bucket.default[*].id)
222227

223228
rule {
224229
object_ownership = var.bucket_ownership_enforced_enabled ? "BucketOwnerEnforced" : "BucketOwnerPreferred"

outputs.tf

+3-3
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,17 @@ output "s3_replication_role_arn" {
1919
}
2020

2121
output "dynamodb_table_name" {
22-
value = one(aws_dynamodb_table.with_server_side_encryption.*.name)
22+
value = one(aws_dynamodb_table.with_server_side_encryption[*].name)
2323
description = "DynamoDB table name"
2424
}
2525

2626
output "dynamodb_table_id" {
27-
value = one(aws_dynamodb_table.with_server_side_encryption.*.id)
27+
value = one(aws_dynamodb_table.with_server_side_encryption[*].id)
2828
description = "DynamoDB table ID"
2929
}
3030

3131
output "dynamodb_table_arn" {
32-
value = one(aws_dynamodb_table.with_server_side_encryption.*.arn)
32+
value = one(aws_dynamodb_table.with_server_side_encryption[*].arn)
3333
description = "DynamoDB table ARN"
3434
}
3535

replication.tf

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ data "aws_iam_policy_document" "replication" {
7171
"s3:ListBucket"
7272
]
7373
resources = [
74-
join("", aws_s3_bucket.default.*.arn),
75-
"${join("", aws_s3_bucket.default.*.arn)}/*"
74+
join("", aws_s3_bucket.default[*].arn),
75+
"${join("", aws_s3_bucket.default[*].arn)}/*"
7676
]
7777
}
7878

variables.tf

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ variable "ignore_public_acls" {
7171
}
7272

7373
variable "block_public_policy" {
74+
type = bool
7475
description = "Whether Amazon S3 should block public bucket policies for this bucket"
7576
default = true
7677
}

0 commit comments

Comments
 (0)