diff --git a/.gitignore b/.gitignore index c73ac15..59dd80a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties + +aws/cloudfront/response-headers.zip diff --git a/aws/cloudfront/-input.tf b/aws/cloudfront/-input.tf index 83b73fd..a0e3e32 100644 --- a/aws/cloudfront/-input.tf +++ b/aws/cloudfront/-input.tf @@ -26,6 +26,11 @@ variable "custom_error_responses" { type = any } +variable "custom_response_headers" { + default = {} + type = map(string) +} + variable "default_root_object" { default = "index.html" type = string diff --git a/aws/cloudfront/config.tf b/aws/cloudfront/config.tf index a8ef91e..f042881 100644 --- a/aws/cloudfront/config.tf +++ b/aws/cloudfront/config.tf @@ -39,6 +39,13 @@ resource "aws_cloudfront_distribution" "distribution" { event_type = "origin-request" lambda_arn = aws_lambda_function.redirector.qualified_arn } + dynamic "lambda_function_association" { + for_each = length(var.custom_response_headers) == 0 ? [] : [1] + content { + event_type = "origin-response" + lambda_arn = aws_lambda_function.response_headers[0].qualified_arn + } + } max_ttl = 86400 min_ttl = 0 target_origin_id = var.distribution_name @@ -48,9 +55,6 @@ resource "aws_cloudfront_distribution" "distribution" { depends_on = [aws_lambda_permission.redirector] enabled = var.enabled is_ipv6_enabled = true - lifecycle { - ignore_changes = [default_cache_behavior] - } logging_config { bucket = data.aws_s3_bucket.log_bucket.bucket_domain_name include_cookies = false diff --git a/aws/cloudfront/response-headers.js b/aws/cloudfront/response-headers.js new file mode 100644 index 0000000..3cceb95 --- /dev/null +++ b/aws/cloudfront/response-headers.js @@ -0,0 +1,17 @@ +'use strict'; +const cfg = require('./config.json'); +exports.handler = (event, context, callback) => { + //Get contents of response + const response = event.Records[0].cf.response; + const headers = response.headers; + + //Set new headers + Object.entries(cfg).forEach(([key,value]) => { + headers[key] = [ + {key: key, value: value} + ]; + }); + + //Return modified response + callback(null, response); +}; diff --git a/aws/cloudfront/response-headers.tf b/aws/cloudfront/response-headers.tf new file mode 100644 index 0000000..e6a9614 --- /dev/null +++ b/aws/cloudfront/response-headers.tf @@ -0,0 +1,93 @@ +data "aws_iam_policy_document" "response_headers_assume_role" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + statement { + actions = [ + "sts:AssumeRole" + ] + principals { + identifiers = [ + "lambda.amazonaws.com", + "edgelambda.amazonaws.com", + ] + type = "Service" + } + } +} + +data "aws_iam_policy_document" "response_headers" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + statement { + actions = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + ] + resources = [ + "arn:aws:logs:*:*:*" + ] + sid = "AllowLogCreation" + } +} + +resource "aws_iam_role" "response_headers" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + assume_role_policy = data.aws_iam_policy_document.response_headers_assume_role[0].json + name = "${var.distribution_name}-response-headers" +} + +resource "aws_iam_role_policy" "response_headers" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + name = "${var.distribution_name}-response-headers" + policy = data.aws_iam_policy_document.response_headers[0].json + role = aws_iam_role.response_headers[0].id +} + +data "archive_file" "response_headers_zip" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + type = "zip" + output_path = "${path.module}/response-headers.zip" + output_file_mode = "0644" + + source { + content = jsonencode(var.custom_response_headers) + filename = "config.json" + } + + source { + content = file("${path.module}/response-headers.js") + filename = "function.js" + } +} + +resource "aws_lambda_function" "response_headers" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + filename = "${path.module}/response-headers.zip" + function_name = "${var.distribution_name}-response-headers" + handler = "function.handler" + publish = true + role = aws_iam_role.response_headers[0].arn + runtime = "nodejs12.x" + source_code_hash = data.archive_file.response_headers_zip[0].output_base64sha256 + tags = local.tags + + lifecycle { + ignore_changes = [ + filename, + ] + } +} + +resource "aws_lambda_permission" "response_headers" { + count = length(var.custom_response_headers) == 0 ? 0 : 1 + + action = "lambda:GetFunction" + function_name = aws_lambda_function.response_headers[0].function_name + principal = "edgelambda.amazonaws.com" + statement_id = "AllowExecutionFromCloudFront" +}