diff --git a/infra/main.tf b/infra/main.tf index 606d7e5..17353cc 100644 --- a/infra/main.tf +++ b/infra/main.tf @@ -1,4 +1,6 @@ terraform { + required_version = ">= 0.12" + backend "s3" { region = "ca-central-1" bucket = "rekahsoft-terraform" @@ -8,102 +10,109 @@ terraform { } provider "aws" { - region = "${var.region}" - version = "~> 1.9" + region = var.region + version = "~> 2.15" - assume_role = [{ - role_arn = "${var.workspace_iam_roles[terraform.workspace]}" - }] + assume_role { + role_arn = var.workspace_iam_roles[terraform.workspace] + } } provider "aws" { alias = "us_east_1" region = "us-east-1" - version = "~> 1.9" + version = "~> 2.1" - assume_role = [{ - role_arn = "${var.workspace_iam_roles[terraform.workspace]}" - }] + assume_role { + role_arn = var.workspace_iam_roles[terraform.workspace] + } } provider "null" { - version = "~> 1.0" + version = "~> 2.1" } provider "random" { - version = "~> 1.3" + version = "~> 2.1" } provider "template" { - version = "~> 1.0" + version = "~> 2.1" } # # Local values to be re-used throughout this template locals { - common_tags = "${map( - "Project", "${var.project}", - "Environment", "${terraform.workspace}" - )}" - cdn_origin_id = "${terraform.workspace}-origin-cdn" - www = "${var.enable_naked_domain ? "" : "www."}" - subdomain = "${var.subdomain == "" ? "" : "${var.subdomain}."}" - naked_domain = "${local.subdomain}${var.dns_apex}" - domain = "${local.www}${local.naked_domain}" - project_env = "${var.project}-${terraform.workspace}" -} + common_tags = { + "Project" = var.project + "Environment" = terraform.workspace + } + cdn_origin_id = "${terraform.workspace}-origin-cdn" + www = var.enable_naked_domain ? "" : "www." + subdomain = var.subdomain == "" ? "" : "${var.subdomain}." + naked_domain = "${local.subdomain}${var.dns_apex}" + domain = "${local.www}${local.naked_domain}" + project_env = "${var.project}-${terraform.workspace}" +} # # Data Sources data "template_file" "s3_origin_policy" { - template = "${file("templates/s3_origin_policy.json")}" + template = file("templates/s3_origin_policy.json") - vars { - bucket_arn = "${aws_s3_bucket.static.arn}" - user_arn = "${aws_iam_user.app_deploy.arn}" - cloudfront_arn = "${aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn}" + vars = { + bucket_arn = aws_s3_bucket.static.arn + user_arn = aws_iam_user.app_deploy.arn + cloudfront_arn = aws_cloudfront_origin_access_identity.origin_access_identity.iam_arn } } data "aws_route53_zone" "external" { - name = "${var.dns_apex}." + name = "${var.dns_apex}." } - # # Resources resource "aws_acm_certificate" "cert" { - domain_name = "${local.domain}" - subject_alternative_names = "${compact(list("${var.enable_naked_domain}" ? "" : "${local.naked_domain}"))}" + domain_name = local.domain + subject_alternative_names = compact([var.enable_naked_domain ? "" : local.naked_domain]) validation_method = "DNS" - tags = "${local.common_tags}" + tags = local.common_tags - provider = "aws.us_east_1" + provider = aws.us_east_1 } resource "aws_route53_record" "cert_validation" { - count = "${1 + "${var.enable_naked_domain ? 0 : 1}"}" + count = 1 + (var.enable_naked_domain ? 0 : 1) - zone_id = "${data.aws_route53_zone.external.id}" - name = "${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_name")}" - type = "${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_type")}" + zone_id = data.aws_route53_zone.external.id + name = aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_name"] + type = aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_type"] ttl = 60 - records = ["${lookup(aws_acm_certificate.cert.domain_validation_options[count.index], "resource_record_value")}"] + # TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to + # force an interpolation expression to be interpreted as a list by wrapping it + # in an extra set of list brackets. That form was supported for compatibilty in + # v0.11, but is no longer supported in Terraform v0.12. + # + # If the expression in the following list itself returns a list, remove the + # brackets to avoid interpretation as a list of lists. If the expression + # returns a single list item then leave it as-is and remove this TODO comment. + records = [aws_acm_certificate.cert.domain_validation_options[count.index]["resource_record_value"]] } resource "aws_acm_certificate_validation" "cert" { - certificate_arn = "${aws_acm_certificate.cert.arn}" - validation_record_fqdns = ["${aws_route53_record.cert_validation.*.fqdn}"] + certificate_arn = aws_acm_certificate.cert.arn + validation_record_fqdns = aws_route53_record.cert_validation.*.fqdn - provider = "aws.us_east_1" + provider = aws.us_east_1 } resource "aws_s3_bucket" "static" { - bucket_prefix = "${local.project_env}" + bucket_prefix = local.project_env acl = "private" website { @@ -111,71 +120,71 @@ resource "aws_s3_bucket" "static" { error_document = "error.html" } - tags = "${local.common_tags}" + tags = local.common_tags } resource "aws_s3_bucket" "static_redirect" { - count = "${var.enable_naked_domain ? 0 : 1}" + count = var.enable_naked_domain ? 0 : 1 - bucket_prefix = "${local.project_env}" + bucket_prefix = local.project_env acl = "private" website { redirect_all_requests_to = "https://${local.domain}" } - tags = "${local.common_tags}" + tags = local.common_tags } resource "aws_s3_bucket" "static_logs" { - bucket_prefix = "${local.project_env}" + bucket_prefix = local.project_env acl = "private" } resource "random_string" "app_deploy_username" { - length = 16 - special = true + length = 16 + special = true override_special = "_+=,.@-" } resource "aws_iam_user" "app_deploy" { - name = "${random_string.app_deploy_username.result}" + name = random_string.app_deploy_username.result } resource "aws_iam_access_key" "app_deploy" { - user = "${aws_iam_user.app_deploy.name}" -# pgp_key = "keybase:some_person_that_exists" + user = aws_iam_user.app_deploy.name + # pgp_key = "keybase:some_person_that_exists" } resource "aws_route53_record" "static" { - zone_id = "${data.aws_route53_zone.external.zone_id}" + zone_id = data.aws_route53_zone.external.zone_id name = "${local.domain}." type = "A" alias { - name = "${aws_cloudfront_distribution.cdn.domain_name}" - zone_id = "${aws_cloudfront_distribution.cdn.hosted_zone_id}" + name = aws_cloudfront_distribution.cdn.domain_name + zone_id = aws_cloudfront_distribution.cdn.hosted_zone_id evaluate_target_health = true } } resource "aws_route53_record" "static_redirect" { - count = "${var.enable_naked_domain ? 0 : 1}" + count = var.enable_naked_domain ? 0 : 1 - zone_id = "${data.aws_route53_zone.external.zone_id}" + zone_id = data.aws_route53_zone.external.zone_id name = "${local.naked_domain}." type = "A" alias { - name = "${aws_cloudfront_distribution.cdn_redirect.domain_name}" - zone_id = "${aws_cloudfront_distribution.cdn_redirect.hosted_zone_id}" + name = aws_cloudfront_distribution.cdn_redirect[0].domain_name + zone_id = aws_cloudfront_distribution.cdn_redirect[0].hosted_zone_id evaluate_target_health = true } } resource "aws_s3_bucket_policy" "static_policy" { - bucket = "${aws_s3_bucket.static.id}" - policy = "${data.template_file.s3_origin_policy.rendered}" + bucket = aws_s3_bucket.static.id + policy = data.template_file.s3_origin_policy.rendered } resource "aws_cloudfront_origin_access_identity" "origin_access_identity" { @@ -185,11 +194,11 @@ resource "aws_cloudfront_origin_access_identity" "origin_access_identity" { resource "aws_cloudfront_distribution" "cdn" { # Static file origin origin { - domain_name = "${aws_s3_bucket.static.bucket_regional_domain_name}" - origin_id = "${local.cdn_origin_id}" + domain_name = aws_s3_bucket.static.bucket_regional_domain_name + origin_id = local.cdn_origin_id s3_origin_config { - origin_access_identity = "${aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path}" + origin_access_identity = aws_cloudfront_origin_access_identity.origin_access_identity.cloudfront_access_identity_path } } @@ -201,22 +210,30 @@ resource "aws_cloudfront_distribution" "cdn" { # Return index.html for any route that is not found custom_error_response { error_caching_min_ttl = 0 - error_code = 403 - response_code = 200 - response_page_path = "/index.html" + error_code = 403 + response_code = 200 + response_page_path = "/index.html" } logging_config { include_cookies = false - bucket = "${aws_s3_bucket.static_logs.bucket_domain_name}" + bucket = aws_s3_bucket.static_logs.bucket_domain_name } - aliases = ["${local.domain}"] + # TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to + # force an interpolation expression to be interpreted as a list by wrapping it + # in an extra set of list brackets. That form was supported for compatibilty in + # v0.11, but is no longer supported in Terraform v0.12. + # + # If the expression in the following list itself returns a list, remove the + # brackets to avoid interpretation as a list of lists. If the expression + # returns a single list item then leave it as-is and remove this TODO comment. + aliases = [local.domain] default_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] - target_origin_id = "${local.cdn_origin_id}" + target_origin_id = local.cdn_origin_id forwarded_values { query_string = false @@ -237,11 +254,11 @@ resource "aws_cloudfront_distribution" "cdn" { path_pattern = "index.html" allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] - target_origin_id = "${local.cdn_origin_id}" + target_origin_id = local.cdn_origin_id forwarded_values { query_string = false - headers = ["Origin"] + headers = ["Origin"] cookies { forward = "none" } @@ -262,25 +279,25 @@ resource "aws_cloudfront_distribution" "cdn" { } } - tags = "${local.common_tags}" + tags = local.common_tags viewer_certificate { - acm_certificate_arn = "${aws_acm_certificate_validation.cert.certificate_arn}" + acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.1_2016" } } resource "aws_cloudfront_distribution" "cdn_redirect" { - count = "${var.enable_naked_domain ? 0 : 1}" + count = var.enable_naked_domain ? 0 : 1 # Static file origin origin { - domain_name = "${aws_s3_bucket.static_redirect.id}.${aws_s3_bucket.static_redirect.website_domain}" - origin_id = "${local.cdn_origin_id}" + domain_name = "${aws_s3_bucket.static_redirect[0].id}.${aws_s3_bucket.static_redirect[0].website_domain}" + origin_id = local.cdn_origin_id custom_origin_config { - http_port = 80 + http_port = 80 https_port = 443 origin_ssl_protocols = ["TLSv1.1", "TLSv1.2"] @@ -288,21 +305,29 @@ resource "aws_cloudfront_distribution" "cdn_redirect" { } } - enabled = true - is_ipv6_enabled = true - comment = "CDN redirect for ${var.project} (environment ${terraform.workspace})" + enabled = true + is_ipv6_enabled = true + comment = "CDN redirect for ${var.project} (environment ${terraform.workspace})" logging_config { include_cookies = false - bucket = "${aws_s3_bucket.static_logs.bucket_domain_name}" + bucket = aws_s3_bucket.static_logs.bucket_domain_name } - aliases = ["${local.naked_domain}"] + # TF-UPGRADE-TODO: In Terraform v0.10 and earlier, it was sometimes necessary to + # force an interpolation expression to be interpreted as a list by wrapping it + # in an extra set of list brackets. That form was supported for compatibilty in + # v0.11, but is no longer supported in Terraform v0.12. + # + # If the expression in the following list itself returns a list, remove the + # brackets to avoid interpretation as a list of lists. If the expression + # returns a single list item then leave it as-is and remove this TODO comment. + aliases = [local.naked_domain] default_cache_behavior { allowed_methods = ["GET", "HEAD", "OPTIONS"] cached_methods = ["GET", "HEAD", "OPTIONS"] - target_origin_id = "${local.cdn_origin_id}" + target_origin_id = local.cdn_origin_id forwarded_values { query_string = false @@ -326,10 +351,10 @@ resource "aws_cloudfront_distribution" "cdn_redirect" { } } - tags = "${local.common_tags}" + tags = local.common_tags viewer_certificate { - acm_certificate_arn = "${aws_acm_certificate_validation.cert.certificate_arn}" + acm_certificate_arn = aws_acm_certificate_validation.cert.certificate_arn ssl_support_method = "sni-only" minimum_protocol_version = "TLSv1.1_2016" } @@ -338,7 +363,7 @@ resource "aws_cloudfront_distribution" "cdn_redirect" { resource "null_resource" "deploy_app" { provisioner "local-exec" { interpreter = ["bash", "-c"] - command = <