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
54 changes: 54 additions & 0 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,60 @@ usage: |2-
Then you can use this method for supressing the superfluous errors.
`TF_WARN_OUTPUT_ERRORS=1 terraform destroy`

### Custom Domain Names with IAM Server Certificates

CloudFront supports IAM Server Certificates as an alternative to ACM certificates for custom domains.
IAM certificates work in all AWS regions and are particularly important for specific use cases.

#### When to Use IAM Certificates:

- **Required**: AWS China regions (cn-north-1, cn-northwest-1) where ACM is not available
- **Optional**: Any region for legacy certificates, external CAs, or organizational certificate management policies

#### How to Use IAM Certificates:

1. **Upload your SSL certificate to IAM**:

```bash
aws iam upload-server-certificate \
--server-certificate-name my-cloudfront-cert \
--certificate-body file://certificate.crt \
--private-key file://private.key \
--certificate-chain file://chain.crt \
--path /cloudfront/
```

2. **Get the certificate ID from the output** (format: `ASCAI...`)

3. **Use the IAM certificate ID in the module:**

```hcl
module "cdn" {
source = "cloudposse/cloudfront-s3-cdn/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"

namespace = "eg"
stage = "prod"
name = "app"

# Use IAM certificate instead of ACM
iam_certificate_id = "ASCAI1234567890EXAMPLE"
aliases = ["abc.example.com"]

dns_alias_enabled = true
parent_zone_name = "example.com"

# ... other configuration
}
```

**Important Notes:**
- The certificate MUST be uploaded to IAM with the path `/cloudfront/` to work with CloudFront
- You cannot specify both `acm_certificate_arn` and `iam_certificate_id` - choose one based on your requirements
- **ACM certificates** (recommended): Use for standard AWS regions when ACM is available
- **IAM certificates**: Use when ACM is unavailable (China regions) or when required by organizational policies

#### Lambda@Edge

This module also features a Lambda@Edge submodule. Its `lambda_function_association` output is meant to feed directly into the variable of the same name in the parent module.
Expand Down
26 changes: 20 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,21 @@ locals {
local.lookup_cf_log_bucket ? data.aws_s3_bucket.cf_logs[0].bucket_domain_name : module.logs.bucket_domain_name
) : ""

use_default_acm_certificate = var.acm_certificate_arn == ""
minimum_protocol_version = var.minimum_protocol_version == "" ? (local.use_default_acm_certificate ? "TLSv1" : "TLSv1.2_2021") : var.minimum_protocol_version
# Certificate type detection - three states: default, ACM, or IAM
use_iam_certificate = var.iam_certificate_id != ""
use_acm_certificate = var.acm_certificate_arn != "" && !local.use_iam_certificate
use_default_certificate = !local.use_acm_certificate && !local.use_iam_certificate

# Auto-select protocol version based on certificate type
# Default cert: TLSv1 (required by CloudFront)
# ACM cert: TLSv1.2_2021 (CloudFront best practice for custom domains)
# IAM cert: TLSv1 (standard for China regions)
# User override: Always respected if var.minimum_protocol_version is set
minimum_protocol_version = var.minimum_protocol_version == "" ? (
local.use_default_certificate ? "TLSv1" :
local.use_acm_certificate ? "TLSv1.2_2021" :
"TLSv1" # IAM certificate (China regions)
) : var.minimum_protocol_version

website_config = {
redirect_all = [
Expand Down Expand Up @@ -486,7 +499,7 @@ resource "aws_cloudfront_distribution" "default" {
}
}

aliases = var.acm_certificate_arn != "" ? concat(var.aliases, var.external_aliases) : []
aliases = (var.acm_certificate_arn != "" || var.iam_certificate_id != "") ? concat(var.aliases, var.external_aliases) : []

dynamic "origin_group" {
for_each = var.origin_groups
Expand Down Expand Up @@ -623,10 +636,11 @@ resource "aws_cloudfront_distribution" "default" {
}

viewer_certificate {
acm_certificate_arn = var.acm_certificate_arn
ssl_support_method = local.use_default_acm_certificate ? null : "sni-only"
acm_certificate_arn = local.use_acm_certificate ? var.acm_certificate_arn : null
iam_certificate_id = local.use_iam_certificate ? var.iam_certificate_id : null
ssl_support_method = local.use_default_certificate ? null : "sni-only"
minimum_protocol_version = local.minimum_protocol_version
cloudfront_default_certificate = local.use_default_acm_certificate
cloudfront_default_certificate = local.use_default_certificate
}

default_cache_behavior {
Expand Down
16 changes: 14 additions & 2 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,25 @@ variable "acm_certificate_arn" {
default = ""
}

variable "iam_certificate_id" {
type = string
default = ""
description = "IAM certificate ID for CloudFront viewer certificate. Alternative to ACM certificates, required for AWS China regions where ACM is unavailable. The certificate must be uploaded to IAM with path `/cloudfront/`. Format: ASCAI... (example: ASCAI1234567890EXAMPLE)"

validation {
condition = !(var.acm_certificate_arn != "" && var.iam_certificate_id != "")
error_message = "Cannot specify both acm_certificate_arn and iam_certificate_id. Choose one based on your certificate management requirements."
}
}

variable "minimum_protocol_version" {
type = string
description = <<-EOT
Cloudfront TLS minimum protocol version.
If `var.acm_certificate_arn` is unset, only "TLSv1" can be specified. See: [AWS Cloudfront create-distribution documentation](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-distribution.html)
If using the default CloudFront certificate (neither `var.acm_certificate_arn` nor `var.iam_certificate_id` set), only "TLSv1" can be specified.
See: [AWS Cloudfront create-distribution documentation](https://docs.aws.amazon.com/cli/latest/reference/cloudfront/create-distribution.html)
and [Supported protocols and ciphers between viewers and CloudFront](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html#secure-connections-supported-ciphers) for more information.
Defaults to "TLSv1.2_2021" unless `var.acm_certificate_arn` is unset, in which case it defaults to `TLSv1`
Defaults to "TLSv1.2_2021" for ACM certificates, "TLSv1" for IAM certificates or default certificate.
EOT
default = ""
}
Expand Down