Skip to content
Open
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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ No modules.
| [aws_cloudfront_monitoring_subscription.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_monitoring_subscription) | resource |
| [aws_cloudfront_origin_access_control.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_control) | resource |
| [aws_cloudfront_origin_access_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_identity) | resource |
| [aws_cloudfront_response_headers_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_response_headers_policy) | resource |
| [aws_cloudfront_vpc_origin.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_vpc_origin) | resource |
| [aws_cloudfront_cache_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |
| [aws_cloudfront_origin_request_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_origin_request_policy) | data source |
Expand All @@ -143,6 +144,7 @@ No modules.
| <a name="input_create_monitoring_subscription"></a> [create\_monitoring\_subscription](#input\_create\_monitoring\_subscription) | If enabled, the resource for monitoring subscription will created. | `bool` | `false` | no |
| <a name="input_create_origin_access_control"></a> [create\_origin\_access\_control](#input\_create\_origin\_access\_control) | Controls if CloudFront origin access control should be created | `bool` | `false` | no |
| <a name="input_create_origin_access_identity"></a> [create\_origin\_access\_identity](#input\_create\_origin\_access\_identity) | Controls if CloudFront origin access identity should be created | `bool` | `false` | no |
| <a name="input_create_response_headers_policy"></a> [create\_response\_headers\_policy](#input\_create\_response\_headers\_policy) | Controls if CloudFront response headers policies should be created | `bool` | `false` | no |
| <a name="input_create_vpc_origin"></a> [create\_vpc\_origin](#input\_create\_vpc\_origin) | If enabled, the resource for VPC origin will be created. | `bool` | `false` | no |
| <a name="input_custom_error_response"></a> [custom\_error\_response](#input\_custom\_error\_response) | One or more custom error response elements | `any` | `{}` | no |
| <a name="input_default_cache_behavior"></a> [default\_cache\_behavior](#input\_default\_cache\_behavior) | The default cache behavior for this distribution | `any` | `null` | no |
Expand All @@ -159,6 +161,7 @@ No modules.
| <a name="input_origin_group"></a> [origin\_group](#input\_origin\_group) | One or more origin\_group for this distribution (multiples allowed). | `any` | `{}` | no |
| <a name="input_price_class"></a> [price\_class](#input\_price\_class) | The price class for this distribution. One of PriceClass\_All, PriceClass\_200, PriceClass\_100 | `string` | `null` | no |
| <a name="input_realtime_metrics_subscription_status"></a> [realtime\_metrics\_subscription\_status](#input\_realtime\_metrics\_subscription\_status) | A flag that indicates whether additional CloudWatch metrics are enabled for a given CloudFront distribution. Valid values are `Enabled` and `Disabled`. | `string` | `"Enabled"` | no |
| <a name="input_response_headers_policy"></a> [response\_headers\_policy](#input\_response\_headers\_policy) | Map of CloudFront response headers policies with their configurations | <pre>map(object({<br/> name = optional(string)<br/> comment = optional(string)<br/><br/> cors_config = optional(object({<br/> access_control_allow_credentials = bool<br/> origin_override = bool<br/> access_control_allow_headers = object({<br/> items = list(string)<br/> })<br/> access_control_allow_methods = object({<br/> items = list(string)<br/> })<br/> access_control_allow_origins = object({<br/> items = list(string)<br/> })<br/> access_control_expose_headers = optional(object({<br/> items = list(string)<br/> }))<br/> access_control_max_age_sec = optional(number)<br/> }))<br/><br/> custom_headers_config = optional(object({<br/> items = list(object({<br/> header = string<br/> override = bool<br/> value = string<br/> }))<br/> }))<br/><br/> remove_headers_config = optional(object({<br/> items = list(object({<br/> header = string<br/> }))<br/> }))<br/><br/> security_headers_config = optional(object({<br/> content_security_policy = optional(object({<br/> content_security_policy = string<br/> override = bool<br/> }))<br/> content_type_options = optional(object({<br/> override = bool<br/> }))<br/> frame_options = optional(object({<br/> frame_option = string<br/> override = bool<br/> }))<br/> referrer_policy = optional(object({<br/> referrer_policy = string<br/> override = bool<br/> }))<br/> strict_transport_security = optional(object({<br/> access_control_max_age_sec = number<br/> override = bool<br/> include_subdomains = optional(bool)<br/> preload = optional(bool)<br/> }))<br/> xss_protection = optional(object({<br/> mode_block = bool<br/> override = bool<br/> protection = bool<br/> report_uri = optional(string)<br/> }))<br/> }))<br/><br/> server_timing_headers_config = optional(object({<br/> enabled = bool<br/> sampling_rate = number<br/> }))<br/> }))</pre> | `{}` | no |
| <a name="input_retain_on_delete"></a> [retain\_on\_delete](#input\_retain\_on\_delete) | Disables the distribution instead of deleting it when destroying the resource through Terraform. If this is set, the distribution needs to be deleted manually afterwards. | `bool` | `false` | no |
| <a name="input_staging"></a> [staging](#input\_staging) | Whether the distribution is a staging distribution. | `bool` | `false` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | A map of tags to assign to the resource. | `map(string)` | `null` | no |
Expand Down Expand Up @@ -189,6 +192,9 @@ No modules.
| <a name="output_cloudfront_origin_access_identities"></a> [cloudfront\_origin\_access\_identities](#output\_cloudfront\_origin\_access\_identities) | The origin access identities created |
| <a name="output_cloudfront_origin_access_identity_iam_arns"></a> [cloudfront\_origin\_access\_identity\_iam\_arns](#output\_cloudfront\_origin\_access\_identity\_iam\_arns) | The IAM arns of the origin access identities created |
| <a name="output_cloudfront_origin_access_identity_ids"></a> [cloudfront\_origin\_access\_identity\_ids](#output\_cloudfront\_origin\_access\_identity\_ids) | The IDS of the origin access identities created |
| <a name="output_cloudfront_response_headers_policies"></a> [cloudfront\_response\_headers\_policies](#output\_cloudfront\_response\_headers\_policies) | The response headers policies created |
| <a name="output_cloudfront_response_headers_policy_etags"></a> [cloudfront\_response\_headers\_policy\_etags](#output\_cloudfront\_response\_headers\_policy\_etags) | The ETags of the response headers policies created |
| <a name="output_cloudfront_response_headers_policy_ids"></a> [cloudfront\_response\_headers\_policy\_ids](#output\_cloudfront\_response\_headers\_policy\_ids) | The IDs of the response headers policies created |
| <a name="output_cloudfront_vpc_origin_ids"></a> [cloudfront\_vpc\_origin\_ids](#output\_cloudfront\_vpc\_origin\_ids) | The IDS of the VPC origin created |
<!-- END_TF_DOCS -->

Expand Down
75 changes: 75 additions & 0 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ module "cloudfront" {
cache_policy_name = "Managed-CachingOptimized"
origin_request_policy_name = "Managed-UserAgentRefererHeaders"
response_headers_policy_name = "Managed-SimpleCORS"
# using a response header policy you're dynamically creating below
# response_header_policy: "cors_policy"

function_association = {
# Valid keys: viewer-request, viewer-response
Expand Down Expand Up @@ -231,6 +233,79 @@ module "cloudfront" {
locations = ["NO", "UA", "US", "GB"]
}

create_response_headers_policy = true
response_headers_policy = {
cors_policy = {
name = "CORSPolicy"
comment = "CORS configuration for API"

cors_config = {
access_control_allow_credentials = true
origin_override = true

access_control_allow_headers = {
items = ["*"]
}

access_control_allow_methods = {
items = ["GET", "POST", "PUT", "DELETE", "OPTIONS"]
}

access_control_allow_origins = {
items = ["https://example.com", "https://app.example.com"]
}

access_control_expose_headers = {
items = ["X-Custom-Header", "X-Request-Id"]
}

access_control_max_age_sec = 3600
}
}
custom_headers = {
name = "CustomHeadersPolicy"
comment = "Add custom response headers"

custom_headers_config = {
items = [
{
header = "X-Powered-By"
override = true
value = "MyApp/1.0"
},
{
header = "X-API-Version"
override = false
value = "v2"
},
{
header = "Cache-Control"
override = true
value = "public, max-age=3600"
}
]
}
}
remove_headers = {
name = "RemoveHeadersPolicy"
comment = "Remove unwanted headers from origin"

remove_headers_config = {
items = [
{
header = "x-robots-tag"
},
{
header = "server"
},
{
header = "x-powered-by"
}
]
}
}
}

}

######
Expand Down
147 changes: 144 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,9 +1,150 @@
locals {
create_origin_access_identity = var.create_origin_access_identity && length(keys(var.origin_access_identities)) > 0
create_origin_access_control = var.create_origin_access_control && length(keys(var.origin_access_control)) > 0
create_vpc_origin = var.create_vpc_origin && length(keys(var.vpc_origin)) > 0
create_origin_access_identity = var.create_origin_access_identity && length(keys(var.origin_access_identities)) > 0
create_origin_access_control = var.create_origin_access_control && length(keys(var.origin_access_control)) > 0
create_vpc_origin = var.create_vpc_origin && length(keys(var.vpc_origin)) > 0
create_response_headers_policy = var.create_response_headers_policy && length(keys(var.response_headers_policy)) > 0
}

resource "aws_cloudfront_response_headers_policy" "this" {
for_each = local.create_response_headers_policy ? var.response_headers_policy : {}

name = each.value.name != null ? each.value.name : each.key
comment = each.value.comment

dynamic "cors_config" {
for_each = each.value.cors_config != null ? [each.value.cors_config] : []

content {
access_control_allow_credentials = cors_config.value.access_control_allow_credentials
origin_override = cors_config.value.origin_override
access_control_max_age_sec = cors_config.value.access_control_max_age_sec != null ? cors_config.value.access_control_max_age_sec : null

access_control_allow_headers {
items = cors_config.value.access_control_allow_headers.items
}

access_control_allow_methods {
items = cors_config.value.access_control_allow_methods.items
}

access_control_allow_origins {
items = cors_config.value.access_control_allow_origins.items
}

dynamic "access_control_expose_headers" {
for_each = cors_config.value.access_control_expose_headers != null ? [cors_config.value.access_control_expose_headers] : []

content {
items = access_control_expose_headers.value.items
}
}
}
}

dynamic "custom_headers_config" {
for_each = each.value.custom_headers_config != null ? [each.value.custom_headers_config] : []

content {
dynamic "items" {
for_each = custom_headers_config.value.items

content {
header = items.value.header
override = items.value.override
value = items.value.value
}
}
}
}

dynamic "remove_headers_config" {
for_each = each.value.remove_headers_config != null ? [each.value.remove_headers_config] : []

content {
dynamic "items" {
for_each = remove_headers_config.value.items

content {
header = items.value.header
}
}
}
}

dynamic "security_headers_config" {
for_each = each.value.security_headers_config != null ? [each.value.security_headers_config] : []

content {
dynamic "content_security_policy" {
for_each = security_headers_config.value.content_security_policy != null ? [security_headers_config.value.content_security_policy] : []

content {
content_security_policy = content_security_policy.value.content_security_policy
override = content_security_policy.value.override
}
}

dynamic "content_type_options" {
for_each = security_headers_config.value.content_type_options != null ? [security_headers_config.value.content_type_options] : []

content {
override = content_type_options.value.override
}
}

dynamic "frame_options" {
for_each = security_headers_config.value.frame_options != null ? [security_headers_config.value.frame_options] : []

content {
frame_option = frame_options.value.frame_option
override = frame_options.value.override
}
}

dynamic "referrer_policy" {
for_each = security_headers_config.value.referrer_policy != null ? [security_headers_config.value.referrer_policy] : []

content {
referrer_policy = referrer_policy.value.referrer_policy
override = referrer_policy.value.override
}
}

dynamic "strict_transport_security" {
for_each = security_headers_config.value.strict_transport_security != null ? [security_headers_config.value.strict_transport_security] : []

content {
access_control_max_age_sec = strict_transport_security.value.access_control_max_age_sec
override = strict_transport_security.value.override
include_subdomains = strict_transport_security.value.include_subdomains
preload = strict_transport_security.value.preload
}
}

dynamic "xss_protection" {
for_each = security_headers_config.value.xss_protection != null ? [security_headers_config.value.xss_protection] : []

content {
mode_block = xss_protection.value.mode_block
override = xss_protection.value.override
protection = xss_protection.value.protection
report_uri = xss_protection.value.report_uri
}
}
}
}

dynamic "server_timing_headers_config" {
for_each = each.value.server_timing_headers_config != null ? [each.value.server_timing_headers_config] : []

content {
enabled = server_timing_headers_config.value.enabled
sampling_rate = server_timing_headers_config.value.sampling_rate
}
}
}


resource "aws_cloudfront_origin_access_identity" "this" {
for_each = local.create_origin_access_identity ? var.origin_access_identities : {}

Expand Down
15 changes: 15 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,18 @@ output "cloudfront_vpc_origin_ids" {
description = "The IDS of the VPC origin created"
value = local.create_vpc_origin ? [for v in aws_cloudfront_vpc_origin.this : v.id] : []
}

output "cloudfront_response_headers_policies" {
description = "The response headers policies created"
value = local.create_response_headers_policy ? { for k, v in aws_cloudfront_response_headers_policy.this : k => v } : {}
}

output "cloudfront_response_headers_policy_ids" {
description = "The IDs of the response headers policies created"
value = local.create_response_headers_policy ? { for k, v in aws_cloudfront_response_headers_policy.this : k => v.id } : {}
}

output "cloudfront_response_headers_policy_etags" {
description = "The ETags of the response headers policies created"
value = local.create_response_headers_policy ? { for k, v in aws_cloudfront_response_headers_policy.this : k => v.etag } : {}
}
82 changes: 82 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,85 @@ variable "vpc_origin_timeouts" {
type = map(string)
default = {}
}

variable "create_response_headers_policy" {
description = "Controls if CloudFront response headers policies should be created"
type = bool
default = false
}

variable "response_headers_policy" {
description = "Map of CloudFront response headers policies with their configurations"
type = map(object({
name = optional(string)
comment = optional(string)

cors_config = optional(object({
access_control_allow_credentials = bool
origin_override = bool
access_control_allow_headers = object({
items = list(string)
})
access_control_allow_methods = object({
items = list(string)
})
access_control_allow_origins = object({
items = list(string)
})
access_control_expose_headers = optional(object({
items = list(string)
}))
access_control_max_age_sec = optional(number)
}))

custom_headers_config = optional(object({
items = list(object({
header = string
override = bool
value = string
}))
}))

remove_headers_config = optional(object({
items = list(object({
header = string
}))
}))

security_headers_config = optional(object({
content_security_policy = optional(object({
content_security_policy = string
override = bool
}))
content_type_options = optional(object({
override = bool
}))
frame_options = optional(object({
frame_option = string
override = bool
}))
referrer_policy = optional(object({
referrer_policy = string
override = bool
}))
strict_transport_security = optional(object({
access_control_max_age_sec = number
override = bool
include_subdomains = optional(bool)
preload = optional(bool)
}))
xss_protection = optional(object({
mode_block = bool
override = bool
protection = bool
report_uri = optional(string)
}))
}))

server_timing_headers_config = optional(object({
enabled = bool
sampling_rate = number
}))
}))
default = {}
}
Loading
Loading