Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions terraform/modules/platform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,10 @@ data "aws_s3_bucket" "access_logs" {
bucket = local.access_logs_bucket[local.parent_env]
}

data "aws_s3_bucket" "logs_to_splunk" {
bucket = "cms-cloud-${data.aws_caller_identity.this.account_id}-${data.aws_region.primary.name}"
}

data "aws_security_groups" "this" {
filter {
name = "vpc-id"
Expand Down
6 changes: 3 additions & 3 deletions terraform/modules/platform/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ output "ssm" {
value = { for named_root, data in data.aws_ssm_parameters_by_path.ssm : named_root => { for each in [for arn, value in zipmap(data.arns, data.values) : { "value" = value, "arn" = arn }] : reverse(split("/", each.arn))[0] => each } }
}

output "network_access_logs_bucket" {
description = "Standardized CMS Hybrid Cloud Providued Network Access Logs bucket Name"
value = "cms-cloud-${data.aws_caller_identity.this.account_id}-${data.aws_region.primary.name}"
output "splunk_logging_bucket" {
description = "Bucket created by the CMS Hybrid Cloud team where logs are ingested into Splunk"
value = data.aws_s3_bucket.logs_to_splunk
}
6 changes: 4 additions & 2 deletions terraform/modules/web/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# CDAP Web Module

This module creates a CloudFront distribution and origin access control intended for use with the AB2D, BCDA and DPC static websites. A sample usage is as follows:
This module creates a CloudFront distribution and origin access control intended for use with the AB2D, BCDA and DPC static websites.
This module assumes an S3 bucket as the origin has already been created. This module currently assumes a single domain with an already issued certificate.

A sample usage is as follows :

```
module "platform" {
Expand Down Expand Up @@ -56,7 +59,6 @@ module "web" {
source = "../modules/web"

certificate = aws_acm_certificate.cert
logging_bucket = module.logging_bucket
origin_bucket = module.origin_bucket
platform = module.platform
web_acl = module.web_acl
Expand Down
23 changes: 23 additions & 0 deletions terraform/modules/web/logs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
resource "aws_cloudwatch_log_delivery_source" "this" {
name = "${var.platform.app}-${var.platform.env}"
log_type = "ACCESS_LOGS"
resource_arn = aws_cloudfront_distribution.this.arn
}

resource "aws_cloudwatch_log_delivery_destination" "this" {
name = "${var.platform.app}-${var.platform.env}"
output_format = "parquet"

delivery_destination_configuration {
destination_resource_arn = var.platform.splunk_logging_bucket.arn
}
}

resource "aws_cloudwatch_log_delivery" "this" {
delivery_source_name = aws_cloudwatch_log_delivery_source.this.name
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.this.arn

s3_delivery_configuration {
suffix_path = "/AWSLogs/${data.aws_caller_identity.this.account_id}/Cloudfront/{DistributionId}/{yyyy}/{MM}/{dd}/{HH}"
Comment thread
mianava marked this conversation as resolved.
}
}
62 changes: 31 additions & 31 deletions terraform/modules/web/main.tf
Original file line number Diff line number Diff line change
@@ -1,26 +1,44 @@
data "aws_caller_identity" "this" {}

data "aws_acm_certificate" "issued" {
domain = var.domain_name
statuses = ["ISSUED"]
Comment thread
mianava marked this conversation as resolved.
}

resource "aws_cloudfront_function" "redirects" {
name = "redesign-redirects"
name = "${var.domain_name}-redirects"
runtime = "cloudfront-js-2.0"
comment = "Function that handles cool URIs and redirects."
code = templatefile("${path.module}/redirects-function.tftpl", { redirects = var.redirects })
}

resource "aws_cloudfront_origin_access_control" "this" {
name = var.origin_bucket.bucket_regional_domain_name
name = "${var.domain_name}-s3-origin"
description = "Manages an AWS CloudFront Origin Access Control, which is used by CloudFront Distributions with an Amazon S3 bucket as the origin."
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}

resource "aws_cloudfront_response_headers_policy" "this" {
name = "${var.platform.app}-${var.platform.env}-StsHeaderPolicy"

security_headers_config {
strict_transport_security {
access_control_max_age_sec = 31536000
override = false
include_subdomains = true
}
}
}

resource "aws_cloudfront_distribution" "this" {
aliases = var.certificate == null ? [] : [var.certificate.domain_name]
aliases = [var.domain_name]
comment = "Distribution for the ${var.platform.app}-${var.platform.env} website"
default_root_object = "index.html"
enabled = var.enabled
http_version = "http2and3"
is_ipv6_enabled = true
price_class = "PriceClass_100"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed because the assignment gets overwritten by institutionalized templates in the AWS accounts. Geographical restrictions are preferred to this setting.

web_acl_id = var.web_acl.arn

custom_error_response {
Expand All @@ -41,7 +59,7 @@ resource "aws_cloudfront_distribution" "this" {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
compress = true
target_origin_id = "s3_origin"
target_origin_id = var.s3_origin_id
viewer_protocol_policy = "redirect-to-https"

cache_policy_id = (
Expand All @@ -50,6 +68,8 @@ resource "aws_cloudfront_distribution" "this" {
"4135ea2d-6df8-44a3-9df3-4b5a84be39ad" # CachingDisabled managed policy
)

response_headers_policy_id = aws_cloudfront_response_headers_policy.this.id

function_association {
event_type = "viewer_request"
function_arn = aws_cloudfront_function.redirects.arn
Expand All @@ -59,7 +79,7 @@ resource "aws_cloudfront_distribution" "this" {
origin {
domain_name = var.origin_bucket.bucket_regional_domain_name
origin_access_control_id = aws_cloudfront_origin_access_control.this.id
origin_id = "s3_origin"
origin_id = var.s3_origin_id
}

restrictions {
Expand All @@ -70,29 +90,9 @@ resource "aws_cloudfront_distribution" "this" {
}

viewer_certificate {
cloudfront_default_certificate = var.certificate == null ? true : false
acm_certificate_arn = var.certificate == null ? null : var.certificate.arn
minimum_protocol_version = var.certificate == null ? null : "TLSv1.2_2021"
ssl_support_method = var.certificate == null ? null : "sni-only"
cloudfront_default_certificate = false
Comment on lines -73 to +93

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gsf this now assumes that a certificate is already issued - as there is no longer a certificate value, just domain.

acm_certificate_arn = data.aws_acm_certificate.issued.arn
minimum_protocol_version = "TLSv1.2_2021"
ssl_support_method = "sni-only"
}
}

resource "aws_cloudwatch_log_delivery_source" "this" {
name = "${var.platform.app}-${var.platform.env}"
log_type = "ACCESS_LOGS"
resource_arn = aws_cloudfront_distribution.this.arn
}

resource "aws_cloudwatch_log_delivery_destination" "this" {
name = "${var.platform.app}-${var.platform.env}"
output_format = "parquet"

delivery_destination_configuration {
destination_resource_arn = "${var.logging_bucket.arn}/${var.origin_bucket.bucket_regional_domain_name}"
}
}

resource "aws_cloudwatch_log_delivery" "this" {
delivery_source_name = aws_cloudwatch_log_delivery_source.this.name
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.this.arn
}
}
58 changes: 58 additions & 0 deletions terraform/modules/web/origin.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/* To reduce module nesting and adhere to current configurations, S3 buckets are managed outside of this module.
Permissions for Cloudfront, however, are managed here. */

resource "aws_s3_bucket_policy" "allow_cloudfront_access" {
bucket = var.origin_bucket.id
policy = data.aws_iam_policy_document.allow_cloudfront_access.json
}

# S3 static site host bucket policy document
data "aws_iam_policy_document" "allow_cloudfront_access" {
# There are no dev or test environments for the static site

statement {
sid = "AllowCloudfrontAccess"
effect = "Allow"

principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}

actions = [
"s3:GetObject",
"s3:ListBucket"
]

condition {
test = "StringEquals"
variable = "AWS:SourceArn"
values = [
aws_cloudfront_distribution.this.arn
]
}

resources = [
var.origin_bucket.arn
]
}
statement {
sid = "AllowSSLRequestsOnly"
effect = "Deny"
principals {
type = "AWS"
identifiers = ["*"]
}
actions = ["s3:*"]
resources = [
var.origin_bucket.arn,
"${var.origin_bucket.arn}/*",
]
condition {
test = "Bool"
variable = "aws:SecureTransport"
values = ["false"]
}
}
}

42 changes: 21 additions & 21 deletions terraform/modules/web/variables.tf
Original file line number Diff line number Diff line change
@@ -1,37 +1,25 @@
variable "certificate" {
default = null
description = "Object representing the website certificate."
type = object({
arn = string
domain_name = string
})
}

variable "enabled" {
default = true
description = "Whether the distribution is enabled to accept end user requests for content."
type = bool
}

variable "logging_bucket" {
description = "Object representing the logging S3 bucket."
type = object({
arn = string
})
variable "domain_name" {
description = "An externally managed domain that points to this distribution. A matching ACM certificate must already be issued."
type = string
}

variable "origin_bucket" {
description = "Object representing the origin S3 bucket."
type = object({
bucket_regional_domain_name = string,
arn = string,
id = string
})
}

variable "platform" {
description = "Object representing the CDAP plaform module."
type = object({
app = string,
env = string
env = string,
splunk_logging_bucket = object({
arn = string
})
})
}

Expand All @@ -46,3 +34,15 @@ variable "web_acl" {
arn = string
})
}

variable "enabled" {
default = true
description = "Whether the distribution is enabled to accept end user requests for content."
type = bool
}

variable "s3_origin_id" {
default = "s3_origin"
description = "Variable to manage existing s3 origins without recreation. All new instances of this module can leave the default."
type = string
}