-
-
Notifications
You must be signed in to change notification settings - Fork 248
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Easily Deploy a CDN Backend by S3 (#1)
- Loading branch information
Showing
6 changed files
with
472 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Compiled files | ||
*.tfstate | ||
*.tfstate.backup | ||
*.terraform.tfstate* | ||
# Module directory | ||
.terraform/ | ||
|
||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,91 @@ | ||
# tf_cdn | ||
Terraform module to easily provision CloudFront CDN with an S3 or custom origin | ||
# tf_cdn_s3 | ||
|
||
Terraform module to easily provision CloudFront CDN with an S3 or custom origin. | ||
|
||
## Usage | ||
|
||
module "cdn_s3" { | ||
source = "git::https://github.com/cloudposse/tf_cdn_s3.git?ref=master" | ||
namespace = "${var.namespace}" | ||
stage = "${var.stage}" | ||
name = "${var.name}" | ||
aliases = "${var.hostname}" | ||
parent_zone_name = "${var.parent_zone_name}" | ||
} | ||
|
||
### Generating ACM Certificate | ||
|
||
Use the AWS cli to [request new ACM certifiates](http://docs.aws.amazon.com/acm/latest/userguide/gs-acm-request.html) (requires email validation) | ||
``` | ||
aws acm request-certificate --domain-name example.com --subject-alternative-names a.example.com b.example.com *.c.example.com | ||
``` | ||
|
||
|
||
## Variables | ||
|
||
| Name | Default | Description | Required | | ||
|:-------------------------------|:----------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:| | ||
| `namespace` | `` | Namespace (e.g. `cp` or `cloudposse`) | Yes | | ||
| `stage` | `` | Stage (e.g. `prod`, `dev`, `staging`) | Yes | | ||
| `name` | `` | Name (e.g. `bastion` or `db`) | Yes | | ||
| `attributes` | `[]` | Additional attributes (e.g. `policy` or `role`) | No | | ||
| `tags` | `{}` | Additional tags (e.g. `map("BusinessUnit","XYZ")` | No | | ||
| `acm_certificate_arn` | `` | Existing ACM Certificate ARN | No | | ||
| `aliases` | `[]` | List of aliases | Yes | | ||
| `allowed_methods` | `["*"]` | List of allowed methods (e.g. ` GET, PUT, POST, DELETE, HEAD`) for AWS CloudFront | No | | ||
| `cached_methods` | `["GET", "HEAD"]` | List of cached methods (e.g. ` GET, PUT, POST, DELETE, HEAD`) | No | | ||
| `comment` | `Managed by Terraform` | Comment for the origin access identity | No | | ||
| `compress` | `false` | Compress content for web requests that include Accept-Encoding: gzip in the request header | No | | ||
| `cors_allowed_headers` | `["*"]` | List of allowed headers for S3 bucket | No | | ||
| `cors_allowed_methods` | `["GET"]` | List of allowed methods (e.g. ` GET, PUT, POST, DELETE, HEAD`) for S3 bucket | No | | ||
| `cors_allowed_origins` | `["*"]` | List of allowed origins (e.g. ` example.com, test.com`) for S3 bucket | No | | ||
| `cors_max_age_seconds` | `3600` | Time in seconds that browser can cache the response for S3 bucket | No | | ||
| `cors_expose_headers` | `["ETag"]` | List of expose header in the response for S3 bucket | No | | ||
| `bucket_domain_format` | `%s.s3.amazonaws.com` | Format of bucket domain name | No | | ||
| `default_root_object` | `index.html` | Object that CloudFront return when requests the root URL | No | | ||
| `enabled` | `true` | State of CloudFront | No | | ||
| `forward_cookies` | `none` | Forward cookies to the origin that is associated with this cache behavior | No | | ||
| `forward_query_string` | `false` | Forward query strings to the origin that is associated with this cache behavior | No | | ||
| `geo_restriction_locations` | `[]` | List of country codes for which CloudFront either to distribute content (whitelist) or not distribute your content (blacklist) | No | | ||
| `geo_restriction_type` | `none` | Method that use to restrict distribution of your content by country: `none`, `whitelist`, or `blacklist` | No | | ||
| `is_ipv6_enabled` | `true` | State of CloudFront IPv6 | No | | ||
| `log_standard_transition_days` | `30` | Number of days to persist in the standard storage tier before moving to the glacier tier | No | | ||
| `log_glacier_transition_days` | `60` | Number of days to persist in the standard storage tier before moving to the infrequent access | No | | ||
| `log_expiration_days` | `90` | Number of days after which to expunge the objects | No | | ||
| `log_include_cookies` | `false` | Include cookies in access logs | No | | ||
| `log_prefix` | `` | Path of logs in S3 bucket | No | | ||
| `min_ttl` | `0` | Minimum amount of time that you want objects to stay in CloudFront caches | No | | ||
| `default_ttl` | `60` | Default amount of time (in seconds) that an object is in a CloudFront cache | No | | ||
| `max_ttl` | `31536000` | Maximum amount of time (in seconds) that an object is in a CloudFront cache | No | | ||
| `null` | `` | Empty string | No | | ||
| `price_class` | `PriceClass_100` | Price class for this distribution: `PriceClass_All`, `PriceClass_200`, `PriceClass_100` | No | | ||
| `viewer_protocol_policy` | `redirect-to-https` | Element to specify the protocol: `allow-all`, `https-only`, `redirect-to-https` | No | | ||
| `null` | `` | Empty string | No | | ||
| `origin_force_destroy` | `` | Delete all objects from the bucket so that the bucket can be destroyed without error (e.g. `true` or `false`) | No | | ||
| `origin_bucket` | `` | Name of S3 bucket | No | | ||
| `origin_path` | `` | Element that causes CloudFront to request your content from a directory in your Amazon S3 bucket. Begins with `/`. CAUTION! Do not use bare `/` as `origin_path`. | No | | ||
| `parent_zone_id` | `` | ID of the hosted zone to contain this record (or specify `parent_zone_name`) | Yes | | ||
| `parent_zone_name` | `` | Name of the hosted zone to contain this record (or specify `parent_zone_id`) | Yes | | ||
|
||
|
||
## Outputs | ||
|
||
| Name | Description | | ||
|:------------------------|:--------------------------------------------------| | ||
| `cf_arn` | ID of AWS CloudFront distribution | | ||
| `cf_domain_name` | Domain name corresponding to the distribution | | ||
| `cf_etag` | Current version of the distribution's information | | ||
| `cf_hosted_zone_id` | CloudFront Route 53 zone ID | | ||
| `cf_id` | ID of AWS CloudFront distribution | | ||
| `cf_status` | Current status of the distribution | | ||
| `s3_bucket` | Name of S3 bucket | | ||
| `s3_bucket_domain_name` | Domain of S3 bucket | | ||
|
||
|
||
## Known Issues | ||
|
||
If the bucket is created in a region other than `us-east-1`, it will take a while for the distribution to become fully operational. | ||
|
||
> All buckets have at least two REST endpoint hostnames. In eu-west-1, they are example-bucket.s3-eu-west-1.amazonaws.com and example-bucket.s3.amazonaws.com. The first one will be immediately valid when the bucket is created. The second one -- sometimes referred to as the "global endpoint" -- which is the one CloudFront uses -- will not, unless the bucket is in us-east-1. Over a period of seconds to minutes, variable by location and other factors, it becomes globally accessible as well. Before that, the 307 redirect is returned. Hence, the bucket was not ready. | ||
Via: https://stackoverflow.com/questions/38706424/aws-cloudfront-returns-http-307-when-origin-is-s3-bucket |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
module "origin_label" { | ||
source = "git::https://github.com/cloudposse/tf_label.git?ref=tags/0.2.0" | ||
namespace = "${var.namespace}" | ||
stage = "${var.stage}" | ||
name = "${var.name}" | ||
delimiter = "${var.delimiter}" | ||
attributes = ["origin"] | ||
tags = "${var.tags}" | ||
} | ||
|
||
resource "aws_cloudfront_origin_access_identity" "default" { | ||
comment = "${module.distribution_label.id}" | ||
} | ||
|
||
data "aws_iam_policy_document" "origin" { | ||
statement { | ||
actions = ["s3:GetObject"] | ||
resources = ["arn:aws:s3:::$${bucket_name}$${origin_path}*"] | ||
|
||
principals { | ||
type = "AWS" | ||
identifiers = ["${aws_cloudfront_origin_access_identity.default.iam_arn}"] | ||
} | ||
} | ||
|
||
statement { | ||
actions = ["s3:ListBucket"] | ||
resources = ["arn:aws:s3:::$${bucket_name}"] | ||
|
||
principals { | ||
type = "AWS" | ||
identifiers = ["${aws_cloudfront_origin_access_identity.default.iam_arn}"] | ||
} | ||
} | ||
} | ||
|
||
data "template_file" "default" { | ||
template = "${data.aws_iam_policy_document.origin.json}" | ||
|
||
vars { | ||
origin_path = "${coalesce(var.origin_path, "/")}" | ||
bucket_name = "${null_resource.default.triggers.bucket}" | ||
} | ||
} | ||
|
||
resource "aws_s3_bucket_policy" "default" { | ||
bucket = "${null_resource.default.triggers.bucket}" | ||
policy = "${data.template_file.default.rendered}" | ||
} | ||
|
||
resource "aws_s3_bucket" "origin" { | ||
count = "${signum(length(var.origin_bucket)) == 1 ? 0 : 1}" | ||
bucket = "${module.origin_label.id}" | ||
acl = "private" | ||
tags = "${module.origin_label.tags}" | ||
force_destroy = "${var.origin_force_destroy}" | ||
|
||
cors_rule { | ||
allowed_headers = "${var.cors_allowed_headers}" | ||
allowed_methods = "${var.cors_allowed_methods}" | ||
allowed_origins = "${sort(distinct(compact(concat(var.cors_allowed_origins, var.aliases))))}" | ||
expose_headers = "${var.cors_expose_headers}" | ||
max_age_seconds = "${var.cors_max_age_seconds}" | ||
} | ||
} | ||
|
||
module "logs" { | ||
source = "git::https://github.com/cloudposse/tf_log_storage.git?ref=tags/0.1.0" | ||
namespace = "${var.namespace}" | ||
stage = "${var.stage}" | ||
name = "${var.name}" | ||
delimiter = "${var.delimiter}" | ||
attributes = ["logs"] | ||
tags = "${var.tags}" | ||
prefix = "${var.log_prefix}" | ||
standard_transition_days = "${var.log_standard_transition_days}" | ||
glacier_transition_days = "${var.log_glacier_transition_days}" | ||
expiration_days = "${var.log_expiration_days}" | ||
} | ||
|
||
module "distribution_label" { | ||
source = "git::https://github.com/cloudposse/tf_label.git?ref=tags/0.2.0" | ||
namespace = "${var.namespace}" | ||
stage = "${var.stage}" | ||
name = "${var.name}" | ||
delimiter = "${var.delimiter}" | ||
tags = "${var.tags}" | ||
} | ||
|
||
resource "null_resource" "default" { | ||
triggers { | ||
bucket = "${element(compact(concat(list(var.origin_bucket), aws_s3_bucket.origin.*.bucket)), 0)}" | ||
bucket_domain_name = "${format(var.bucket_domain_format, element(compact(concat(list(var.origin_bucket), aws_s3_bucket.origin.*.bucket)), 0))}" | ||
} | ||
|
||
lifecycle { | ||
create_before_destroy = true | ||
} | ||
} | ||
|
||
resource "aws_cloudfront_distribution" "default" { | ||
enabled = "${var.enabled}" | ||
is_ipv6_enabled = "${var.is_ipv6_enabled}" | ||
comment = "${var.comment}" | ||
default_root_object = "${var.default_root_object}" | ||
price_class = "${var.price_class}" | ||
depends_on = ["aws_s3_bucket.origin"] | ||
|
||
logging_config = { | ||
include_cookies = "${var.log_include_cookies}" | ||
bucket = "${module.logs.bucket_domain_name}" | ||
prefix = "${var.log_prefix}" | ||
} | ||
|
||
aliases = ["${var.aliases}"] | ||
|
||
origin { | ||
domain_name = "${null_resource.default.triggers.bucket_domain_name}" | ||
origin_id = "${module.distribution_label.id}" | ||
origin_path = "${var.origin_path}" | ||
|
||
s3_origin_config { | ||
origin_access_identity = "${aws_cloudfront_origin_access_identity.default.cloudfront_access_identity_path}" | ||
} | ||
} | ||
|
||
viewer_certificate { | ||
acm_certificate_arn = "${var.acm_certificate_arn}" | ||
ssl_support_method = "sni-only" | ||
minimum_protocol_version = "TLSv1" | ||
cloudfront_default_certificate = true | ||
} | ||
|
||
default_cache_behavior { | ||
allowed_methods = "${var.allowed_methods}" | ||
cached_methods = "${var.cached_methods}" | ||
target_origin_id = "${module.distribution_label.id}" | ||
compress = "${var.compress}" | ||
|
||
forwarded_values { | ||
query_string = "${var.forward_query_string}" | ||
|
||
cookies { | ||
forward = "${var.forward_cookies}" | ||
} | ||
} | ||
|
||
viewer_protocol_policy = "${var.viewer_protocol_policy}" | ||
default_ttl = "${var.default_ttl}" | ||
min_ttl = "${var.min_ttl}" | ||
max_ttl = "${var.max_ttl}" | ||
} | ||
|
||
restrictions { | ||
geo_restriction { | ||
restriction_type = "${var.geo_restriction_type}" | ||
locations = "${var.geo_restriction_locations}" | ||
} | ||
} | ||
|
||
tags = "${module.distribution_label.tags}" | ||
} | ||
|
||
module "dns" { | ||
source = "git::https://github.com/cloudposse/tf_vanity.git?ref=tags/0.2.1" | ||
aliases = "${var.aliases}" | ||
parent_zone_id = "${var.parent_zone_id}" | ||
parent_zone_name = "${var.parent_zone_name}" | ||
target_dns_name = "${aws_cloudfront_distribution.default.domain_name}" | ||
target_zone_id = "${aws_cloudfront_distribution.default.hosted_zone_id}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
output "cf_id" { | ||
value = "${aws_cloudfront_distribution.default.id}" | ||
} | ||
|
||
output "cf_arn" { | ||
value = "${aws_cloudfront_distribution.default.arn}" | ||
} | ||
|
||
output "cf_status" { | ||
value = "${aws_cloudfront_distribution.default.status}" | ||
} | ||
|
||
output "cf_domain_name" { | ||
value = "${aws_cloudfront_distribution.default.domain_name}" | ||
} | ||
|
||
output "cf_etag" { | ||
value = "${aws_cloudfront_distribution.default.etag}" | ||
} | ||
|
||
output "cf_hosted_zone_id" { | ||
value = "${aws_cloudfront_distribution.default.hosted_zone_id}" | ||
} | ||
|
||
output "s3_bucket" { | ||
value = "${null_resource.default.bucket}" | ||
} | ||
|
||
output "s3_bucket_domain_name" { | ||
value = "${null_resource.default.bucket_domain_name}" | ||
} |
Oops, something went wrong.