Skip to content

Commit 2caacc7

Browse files
committed
fix(s3): Harden S3 bucket security to resolve SonarQube findings
1 parent 6b598bf commit 2caacc7

File tree

1 file changed

+69
-12
lines changed
  • Terraform/modules/01-Network

1 file changed

+69
-12
lines changed

Terraform/modules/01-Network/main.tf

Lines changed: 69 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,19 @@ resource "aws_route_table_association" "private" {
138138

139139
# S3 Bucket for ALB Access Logs
140140

141+
# This data source gets the AWS Account ID for the ELB service in the current region.
142+
data "aws_elb_service_account" "current" {}
143+
144+
# This data source gets the current AWS Account ID for policy construction.
145+
data "aws_caller_identity" "current" {}
146+
147+
# This is the primary bucket where the ALB will store its access logs.
141148
resource "aws_s3_bucket" "alb_access_logs" {
142149
# Only create this bucket if logging is enabled
143150
count = var.enable_alb_access_logs ? 1 : 0
144151

145152
# If a specific name is provided, use it. Otherwise, generate a unique name.
146-
bucket = var.alb_access_logs_bucket_name != "" ? var.alb_access_logs_bucket_name : "${var.project_prefix}-${var.environment}-alb-access-logs-${random_id.this.hex}"
153+
bucket = var.alb_access_logs_bucket_name != "" ? var.alb_access_logs_bucket_name : "${var.project_prefix}-${var.environment}-alb-access-logs-${data.aws_caller_identity.current.account_id}"
147154

148155
tags = merge(
149156
var.tags,
@@ -153,33 +160,83 @@ resource "aws_s3_bucket" "alb_access_logs" {
153160
)
154161
}
155162

156-
# This resource is needed to grant the ALB service permission to write to my S3 bucket.
157-
resource "aws_s3_bucket_policy" "alb_access_logs" {
163+
resource "aws_s3_bucket_public_access_block" "alb_access_logs" {
158164
count = var.enable_alb_access_logs ? 1 : 0
159165
bucket = aws_s3_bucket.alb_access_logs[0].id
160-
policy = data.aws_iam_policy_document.alb_access_logs[0].json
166+
167+
block_public_acls = true
168+
block_public_policy = true
169+
ignore_public_acls = true
170+
restrict_public_buckets = true
161171
}
162172

163-
# This data source constructs the required IAM policy document.
173+
# This is a SECOND bucket, used to store the access logs FOR the first bucket.
174+
resource "aws_s3_bucket" "s3_server_access_logs" {
175+
count = var.enable_alb_access_logs ? 1 : 0
176+
177+
bucket = "${var.project_prefix}-${var.environment}-s3-access-logs-${data.aws_caller_identity.current.account_id}"
178+
179+
tags = merge(
180+
var.tags,
181+
{
182+
Name = "${var.project_prefix}-${var.environment}-s3-server-access-logs"
183+
}
184+
)
185+
}
186+
resource "aws_s3_bucket_logging" "alb_access_logs" {
187+
count = var.enable_alb_access_logs ? 1 : 0
188+
189+
bucket = aws_s3_bucket.alb_access_logs[0].id
190+
191+
target_bucket = aws_s3_bucket.s3_server_access_logs[0].id
192+
target_prefix = "log/"
193+
}
194+
195+
196+
# This data source constructs the required IAM policy document for the ALB log bucket.
164197
data "aws_iam_policy_document" "alb_access_logs" {
165198
count = var.enable_alb_access_logs ? 1 : 0
166199

200+
# This statement allows the ALB service to write logs to the bucket.
167201
statement {
168-
effect = "Allow"
202+
effect = "AllowALBToWriteLogs"
169203
actions = ["s3:PutObject"]
170-
resources = ["${aws_s3_bucket.alb_access_logs[0].arn}/AWSLogs/AWS-ACCOUNT-ID/*"] # AWS-ACCOUNT-ID will be interpolated by AWS
204+
resources = ["${aws_s3_bucket.alb_access_logs[0].arn}/*"]
205+
171206
principals {
172207
type = "AWS"
173-
identifiers = ["elb-account-id.amazonaws.com"] # This is a placeholder for the regional ELB service account ID
208+
identifiers = [data.aws_elb_service_account.current.arn]
209+
}
210+
}
211+
212+
# This statement denies any access to the bucket over insecure HTTP.
213+
statement {
214+
sid = "DenyInsecureTransport"
215+
effect = "Deny"
216+
actions = ["s3:*"]
217+
resources = ["${aws_s3_bucket.alb_access_logs[0].arn}/*"]
218+
219+
principals {
220+
type = "*"
221+
identifiers = ["*"]
222+
}
223+
224+
condition {
225+
test = "Bool"
226+
variable = "aws:SecureTransport"
227+
values = ["false"]
174228
}
175229
}
176230
}
177231

178-
# Need a random_id to ensure the S3 bucket name is unique if not provided
179-
resource "random_id" "this" {
180-
byte_length = 4
232+
# This resource is needed to grant the ALB service permission to write to my S3 bucket.
233+
resource "aws_s3_bucket_policy" "alb_access_logs" {
234+
count = var.enable_alb_access_logs ? 1 : 0
235+
bucket = aws_s3_bucket.alb_access_logs[0].id
236+
policy = data.aws_iam_policy_document.alb_access_logs[0].json
181237
}
182238

239+
183240
# Application Load Balancer
184241

185242
resource "aws_security_group" "alb" {
@@ -234,7 +291,7 @@ resource "aws_lb" "main" {
234291
access_logs {
235292
bucket = var.enable_alb_access_logs ? aws_s3_bucket.alb_access_logs[0].bucket : null
236293
enabled = var.enable_alb_access_logs
237-
prefix = "alb"
294+
prefix = "alb-logs"
238295
}
239296

240297
tags = merge(

0 commit comments

Comments
 (0)