@aws/nx-plugin 1.0.0-rc.40 → 1.0.0-rc.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,18 @@ variable "website_file_path" {
23
23
  type = string
24
24
  }
25
25
 
26
+ variable "custom_domain_names" {
27
+ description = "Custom domain names (aliases) for the CloudFront distribution. Requires acm_certificate_arn."
28
+ type = list(string)
29
+ default = []
30
+ }
31
+
32
+ variable "acm_certificate_arn" {
33
+ description = "ARN of an ACM certificate (in us-east-1) for the custom domain names. When set, viewers are required to use TLS 1.2 or later."
34
+ type = string
35
+ default = null
36
+ }
37
+
26
38
  # Content-Security-Policy enforced on all responses. Restricts scripts and
27
39
  # framing to mitigate XSS and clickjacking, while permitting HTTPS/WSS calls
28
40
  # (connect-src) to AWS service endpoints such as API Gateway, Cognito and
@@ -30,6 +42,10 @@ variable "website_file_path" {
30
42
  # connect-src to your specific origins once they are known.
31
43
  locals {
32
44
  content_security_policy = "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:; connect-src 'self' https: wss:; object-src 'none'; base-uri 'self'; frame-ancestors 'none'"
45
+
46
+ # Delivery source/destination names have a 60 character maximum. Truncate the
47
+ # website name so the longest delivery name stays within the limit.
48
+ access_logs_name_prefix = substr(lower(var.website_name), 0, 16)
33
49
  }
34
50
 
35
51
 
@@ -68,6 +84,26 @@ resource "aws_kms_key" "website_key" {
68
84
  ]
69
85
  Resource = "*"
70
86
  },
87
+ {
88
+ Sid = "AllowCloudWatchLogs"
89
+ Effect = "Allow"
90
+ Principal = {
91
+ Service = "logs.${data.aws_region.current.region}.amazonaws.com"
92
+ }
93
+ Action = [
94
+ "kms:Encrypt",
95
+ "kms:Decrypt",
96
+ "kms:ReEncrypt*",
97
+ "kms:GenerateDataKey*",
98
+ "kms:DescribeKey"
99
+ ]
100
+ Resource = "*"
101
+ Condition = {
102
+ ArnLike = {
103
+ "kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:log-group:*"
104
+ }
105
+ }
106
+ },
71
107
  {
72
108
  Sid = "AllowCloudFrontServicePrincipalSSE-KMS"
73
109
  Effect = "Allow"
@@ -99,18 +135,12 @@ resource "aws_kms_alias" "website_key_alias" {
99
135
  target_key_id = aws_kms_key.website_key.key_id
100
136
  }
101
137
 
102
- # Access Logs Bucket
103
- resource "aws_s3_bucket" "access_logs" {
104
- #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for access logs bucket
105
- #checkov:skip=CKV_AWS_144:Cross-region replication not required for access logs
106
- #checkov:skip=CKV2_AWS_62:Event notifications not required for access logs bucket
107
- #checkov:skip=CKV_AWS_21:Versioning disabled for access logs to reduce storage costs
108
- bucket = "${lower(var.website_name)}-access-logs-${random_id.bucket_suffix.hex}"
109
- force_destroy = true
110
-
111
- tags = {
112
- Name = "${lower(var.website_name)}-access-logs"
113
- }
138
+ # CloudWatch log group receiving S3 server access logs for the website and
139
+ # distribution log buckets.
140
+ resource "aws_cloudwatch_log_group" "access_logs" {
141
+ name = "/aws/s3/${lower(var.website_name)}-access-logs-${random_id.bucket_suffix.hex}"
142
+ retention_in_days = 365
143
+ kms_key_id = aws_kms_key.website_key.arn
114
144
  }
115
145
 
116
146
  resource "random_id" "unique_suffix" {
@@ -121,63 +151,12 @@ resource "random_id" "bucket_suffix" {
121
151
  byte_length = 8
122
152
  }
123
153
 
124
- resource "aws_s3_bucket_versioning" "access_logs_versioning" {
125
- bucket = aws_s3_bucket.access_logs.id
126
- versioning_configuration {
127
- status = "Disabled"
128
- }
129
- }
130
-
131
- resource "aws_s3_bucket_server_side_encryption_configuration" "access_logs_encryption" {
132
- bucket = aws_s3_bucket.access_logs.id
133
-
134
- rule {
135
- apply_server_side_encryption_by_default {
136
- kms_master_key_id = aws_kms_key.website_key.arn
137
- sse_algorithm = "aws:kms"
138
- }
139
- }
140
- }
141
-
142
- resource "aws_s3_bucket_public_access_block" "access_logs_pab" {
143
- bucket = aws_s3_bucket.access_logs.id
144
-
145
- block_public_acls = true
146
- block_public_policy = true
147
- ignore_public_acls = true
148
- restrict_public_buckets = true
149
- }
150
-
151
- resource "aws_s3_bucket_policy" "access_logs_ssl_policy" {
152
- bucket = aws_s3_bucket.access_logs.id
153
-
154
- policy = jsonencode({
155
- Version = "2012-10-17"
156
- Statement = [
157
- {
158
- Sid = "DenyInsecureConnections"
159
- Effect = "Deny"
160
- Principal = "*"
161
- Action = "s3:*"
162
- Resource = [
163
- aws_s3_bucket.access_logs.arn,
164
- "${aws_s3_bucket.access_logs.arn}/*"
165
- ]
166
- Condition = {
167
- Bool = {
168
- "aws:SecureTransport" = "false"
169
- }
170
- }
171
- }
172
- ]
173
- })
174
- }
175
-
176
154
  # Website Bucket
177
155
  resource "aws_s3_bucket" "website" {
178
156
  #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for static website content
179
157
  #checkov:skip=CKV_AWS_144:Cross-region replication not required for static website
180
158
  #checkov:skip=CKV2_AWS_62:Event notifications not required for static website bucket
159
+ #checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.website)
181
160
  bucket = "${lower(var.website_name)}-website-${random_id.bucket_suffix.hex}"
182
161
  force_destroy = true
183
162
 
@@ -221,20 +200,35 @@ resource "aws_s3_bucket_ownership_controls" "website_ownership" {
221
200
  }
222
201
  }
223
202
 
224
- resource "aws_s3_bucket_logging" "website_logging" {
225
- bucket = aws_s3_bucket.website.id
203
+ # Deliver the website bucket's server access logs to CloudWatch Logs.
204
+ resource "aws_cloudwatch_log_delivery_source" "website" {
205
+ name = "${local.access_logs_name_prefix}-website-logs-${random_id.bucket_suffix.hex}"
206
+ log_type = "S3_SERVER_ACCESS_LOGS"
207
+ resource_arn = aws_s3_bucket.website.arn
208
+ }
226
209
 
227
- target_bucket = aws_s3_bucket.access_logs.id
228
- target_prefix = "website-access-logs/"
210
+ resource "aws_cloudwatch_log_delivery_destination" "access_logs" {
211
+ name = "${local.access_logs_name_prefix}-access-logs-${random_id.bucket_suffix.hex}"
212
+
213
+ delivery_destination_configuration {
214
+ destination_resource_arn = aws_cloudwatch_log_group.access_logs.arn
215
+ }
216
+ }
217
+
218
+ resource "aws_cloudwatch_log_delivery" "website" {
219
+ delivery_source_name = aws_cloudwatch_log_delivery_source.website.name
220
+ delivery_destination_arn = aws_cloudwatch_log_delivery_destination.access_logs.arn
229
221
  }
230
222
 
231
223
 
232
- # Distribution Log Bucket
224
+ # Distribution Log Bucket — holds CloudFront standard access logs (CloudFront
225
+ # delivers only to S3). Its own S3 server access logs go to CloudWatch Logs.
233
226
  resource "aws_s3_bucket" "distribution_logs" {
234
227
  #checkov:skip=CKV2_AWS_61:Lifecycle configuration not required for CloudFront logs
235
228
  #checkov:skip=CKV_AWS_144:Cross-region replication not required for CloudFront logs
236
229
  #checkov:skip=CKV2_AWS_62:Event notifications not required for CloudFront logs bucket
237
230
  #checkov:skip=CKV_AWS_21:Versioning not required for CloudFront access logs
231
+ #checkov:skip=CKV_AWS_18:Server access logs are delivered to CloudWatch Logs (see aws_cloudwatch_log_delivery.distribution_logs)
238
232
  bucket = "${lower(var.website_name)}-distribution-logs-${random_id.bucket_suffix.hex}"
239
233
  force_destroy = true
240
234
 
@@ -280,11 +274,16 @@ resource "aws_s3_bucket_acl" "distribution_logs_acl" {
280
274
  depends_on = [aws_s3_bucket_ownership_controls.distribution_logs_ownership]
281
275
  }
282
276
 
283
- resource "aws_s3_bucket_logging" "distribution_logs_logging" {
284
- bucket = aws_s3_bucket.distribution_logs.id
277
+ # Deliver the distribution log bucket's server access logs to CloudWatch Logs.
278
+ resource "aws_cloudwatch_log_delivery_source" "distribution_logs" {
279
+ name = "${local.access_logs_name_prefix}-distribution-logs-${random_id.bucket_suffix.hex}"
280
+ log_type = "S3_SERVER_ACCESS_LOGS"
281
+ resource_arn = aws_s3_bucket.distribution_logs.arn
282
+ }
285
283
 
286
- target_bucket = aws_s3_bucket.access_logs.id
287
- target_prefix = "distribution-access-logs/"
284
+ resource "aws_cloudwatch_log_delivery" "distribution_logs" {
285
+ delivery_source_name = aws_cloudwatch_log_delivery_source.distribution_logs.name
286
+ delivery_destination_arn = aws_cloudwatch_log_delivery_destination.access_logs.arn
288
287
  }
289
288
 
290
289
  resource "aws_s3_bucket_policy" "distribution_logs_ssl_policy" {
@@ -439,6 +438,7 @@ resource "aws_cloudfront_distribution" "website" {
439
438
  is_ipv6_enabled = true
440
439
  default_root_object = "index.html"
441
440
  web_acl_id = aws_wafv2_web_acl.cloudfront_waf.arn
441
+ aliases = var.custom_domain_names
442
442
 
443
443
  logging_config {
444
444
  include_cookies = false
@@ -485,7 +485,10 @@ resource "aws_cloudfront_distribution" "website" {
485
485
  }
486
486
 
487
487
  viewer_certificate {
488
- cloudfront_default_certificate = true
488
+ cloudfront_default_certificate = var.acm_certificate_arn == null
489
+ acm_certificate_arn = var.acm_certificate_arn
490
+ ssl_support_method = var.acm_certificate_arn == null ? null : "sni-only"
491
+ minimum_protocol_version = var.acm_certificate_arn == null ? "TLSv1" : "TLSv1.2_2021"
489
492
  }
490
493
 
491
494
  tags = {