[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
01/02: cdn: Move service configs into individual files.
From: |
Chris Marusich |
Subject: |
01/02: cdn: Move service configs into individual files. |
Date: |
Sat, 5 Jan 2019 22:34:30 -0500 (EST) |
marusich pushed a commit to branch master
in repository maintenance.
commit 1540978fda67e06766b21bcee09f4e3dcbb2ca66
Author: Chris Marusich <address@hidden>
Date: Sat Jan 5 15:53:02 2019 -0800
cdn: Move service configs into individual files.
* cdn/terraform/main.tf: Remove all service-specific configuration.
* cdn/terraform/acm.tf: New file.
* cdn/terraform/cloudfront.tf: New file.
* cdn/terraform/cloudwatch.tf: New file.
* cdn/terraform/dynamodb.tf: New file.
* cdn/terraform/iam.tf: New file.
* cdn/terraform/s3.tf: New file.
---
cdn/terraform/acm.tf | 47 +++++
cdn/terraform/cloudfront.tf | 94 ++++++++++
cdn/terraform/cloudwatch.tf | 69 ++++++++
cdn/terraform/dynamodb.tf | 21 +++
cdn/terraform/iam.tf | 131 ++++++++++++++
cdn/terraform/main.tf | 421 +-------------------------------------------
cdn/terraform/s3.tf | 48 +++++
7 files changed, 415 insertions(+), 416 deletions(-)
diff --git a/cdn/terraform/acm.tf b/cdn/terraform/acm.tf
new file mode 100644
index 0000000..19b6e74
--- /dev/null
+++ b/cdn/terraform/acm.tf
@@ -0,0 +1,47 @@
+# ACM
+
+# Terraform will create this certificate automatically. However, to
+# validate it requires one-time manual action outside of Terraform.
+# This is because there don't seem to be any Terraform providers that
+# are compatible with our DNS registrar. To create and validate the
+# certificate, you must do the following in order:
+#
+# - Run "terraform apply" to create the certificate.
+# - Run "terraform show" to view the CNAME record ACM needs you to
+# create in order to prove domain ownership.
+# - Manually create the CNAME record.
+# - Run "terraform apply" or "terraform plan" again to ensure the
+# resources are in their final, correct state.
+# - Run "terraform show" to verify that the certificate is now
+# listed as "validated".
+# - Repeat the last two steps until the validation succeeds.
+#
+# This only has to be done once. For more information, see:
+# https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html
+#
+# Finally, since we intend to use this certificate with our CloudFront
+# distribution, we must create it in the us-east-1 region. See:
+# https://docs.aws.amazon.com/acm/latest/userguide/acm-services.html
+#
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-requirements.html
+resource "aws_acm_certificate" "berlin-mirror-certificate" {
+ domain_name = "ci.guix.info"
+ validation_method = "DNS"
+ # The AWS provider documentation recommends setting
+ # create_before_destroy to true in a lifecycle block. We probably
+ # won't need this, since we don't currently plan to replace the
+ # existing certificate using Terraform (ACM will just rotate it for
+ # us automatically), but it doesn't hurt to include this here.
+ lifecycle {
+ create_before_destroy = true
+ }
+}
+
+# SNS
+
+# Email subscriptions cannot be managed via Terraform. Therefore, any
+# email subscriptions must be configured manually. See:
+# https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html
+#
https://docs.aws.amazon.com/sns/latest/dg/sns-getting-started.html#SubscribeTopic
+resource "aws_sns_topic" "guix-billing-alarms" {
+ name = "guix-billing-alarms"
+}
diff --git a/cdn/terraform/cloudfront.tf b/cdn/terraform/cloudfront.tf
new file mode 100644
index 0000000..018b803
--- /dev/null
+++ b/cdn/terraform/cloudfront.tf
@@ -0,0 +1,94 @@
+# CloudFront
+
+resource "aws_cloudfront_distribution" "berlin-mirror" {
+ enabled = true
+ comment = "Distributed caching proxy for berlin.guixsd.org"
+ origin {
+ domain_name = "berlin.guixsd.org"
+ origin_id = "berlin.guixsd.org"
+ custom_origin_config {
+ http_port = 80 # Required, but not used.
+ https_port = 443
+ # Always use TLS when forwarding requests to the origin.
+ origin_protocol_policy = "https-only"
+ origin_ssl_protocols = ["TLSv1.2"]
+ origin_keepalive_timeout = 60
+ origin_read_timeout = 60
+ }
+ }
+ # The CNAME that will point to this CloudFront distribution.
+ aliases = ["ci.guix.info"]
+ is_ipv6_enabled = true
+ # This is actually the_maximum HTTP version to support. See:
+ #
https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#http_version
+ http_version = "http2"
+ # Serve requests from all edge locations.
+ price_class = "PriceClass_All"
+ # Do not restrict access.
+ restrictions { geo_restriction { restriction_type = "none" }}
+ # When deleting the distribution, actually delete it. See:
+ #
https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#retain_on_delete
+ retain_on_delete = false
+ default_cache_behavior {
+ # Only allow "read" verbs.
+ allowed_methods = ["GET", "HEAD"]
+ cached_methods = ["GET", "HEAD"]
+ # The origin will compress data when necessary.
+ compress = false
+ # Cache responses that lack a Cache-Control header.
+ default_ttl = 86400 # 1 day
+ # When deciding whether or not to cache a response, ignore any
+ # cookies, headers, or query strings that the client included in
+ # their request. This should increase the cache hit rate. In
+ # addition, this also causes CloudFront to omit these values
+ # when forwarding the request to the custom origin. See:
+ #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ConfiguringCaching.html
+ forwarded_values {
+ cookies { forward = "none" }
+ query_string = false
+ }
+ # Generally speaking, respect any Cache-Control or Expires
+ # headers that the origin includes in its responses. The
+ # exception is that if a Cache-Control or Expires header says to
+ # cache the result for more than 1 year, we ignore that and only
+ # cache the result for 1 year at most. Honestly, though, it
+ # seems unrealistic to expect CloudFront to actually keep the
+ # cached response for an entire year in that case. See:
+ #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
+ max_ttl = 31536000 # 365 days
+ min_ttl = 0
+ target_origin_id = "berlin.guixsd.org"
+ # Before ci.guix.info pointed to this distribution, it allowed
+ # both HTTP and HTTPS. We choose to maintain that policy here.
+ # In the future, we should consider changing this to "https-only".
+ viewer_protocol_policy = "allow-all"
+ }
+ # TODO: Maybe add more behaviors for specific paths/prefixes.
+ # ordered_cache_behavior {}
+ # TODO: Maybe set a caching behavior for error responses.
+ # custom_error_response {}
+ viewer_certificate {
+ # Note that "terraform apply" will fail until this certificate is
+ # valid. See the comment in the definition of
+ # berlin-mirror-certificate for more information.
+ acm_certificate_arn =
"${aws_acm_certificate.berlin-mirror-certificate.arn}"
+ # This is the recommended value as of 2018-12-28. See:
+ #
https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ViewerCertificate.html
+ #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html#secure-connections-supported-ciphers
+ minimum_protocol_version = "TLSv1.1_2016"
+ # Use SNI. Don't use the "vip" (i.e., dedicated IP address)
+ # method, since it's expensive and unnecessary. See:
+ #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-https-dedicated-ip-or-sni.html
+ ssl_support_method = "sni-only"
+ }
+}
+
+output "berlin-mirror-id" {
+ value = "${aws_cloudfront_distribution.berlin-mirror.id}"
+}
+output "berlin-mirror-status" {
+ value = "${aws_cloudfront_distribution.berlin-mirror.status}"
+}
+output "berlin-mirror-domain-name" {
+ value = "${aws_cloudfront_distribution.berlin-mirror.domain_name}"
+}
diff --git a/cdn/terraform/cloudwatch.tf b/cdn/terraform/cloudwatch.tf
new file mode 100644
index 0000000..5f790d1
--- /dev/null
+++ b/cdn/terraform/cloudwatch.tf
@@ -0,0 +1,69 @@
+# CloudWatch
+
+resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-150-usd" {
+ alarm_name = "alarm-estimated-charges-150-usd"
+ alarm_description = "Estimated charges have exceeded 150 USD"
+ namespace = "AWS/Billing"
+ metric_name = "EstimatedCharges"
+ statistic = "Maximum"
+ period = "21600" # 6 hours
+ evaluation_periods = "1"
+ comparison_operator = "GreaterThanThreshold"
+ threshold = "150"
+ actions_enabled = true
+ alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
+ dimensions {
+ Currency = "USD"
+ }
+}
+
+resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-140-usd" {
+ alarm_name = "alarm-estimated-charges-140-usd"
+ alarm_description = "Estimated charges have exceeded 140 USD"
+ namespace = "AWS/Billing"
+ metric_name = "EstimatedCharges"
+ statistic = "Maximum"
+ period = "21600" # 6 hours
+ evaluation_periods = "1"
+ comparison_operator = "GreaterThanThreshold"
+ threshold = "140"
+ actions_enabled = true
+ alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
+ dimensions {
+ Currency = "USD"
+ }
+}
+
+resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-100-usd" {
+ alarm_name = "alarm-estimated-charges-100-usd"
+ alarm_description = "Estimated charges have exceeded 100 USD"
+ namespace = "AWS/Billing"
+ metric_name = "EstimatedCharges"
+ statistic = "Maximum"
+ period = "21600" # 6 hours
+ evaluation_periods = "1"
+ comparison_operator = "GreaterThanThreshold"
+ threshold = "100"
+ actions_enabled = true
+ alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
+ dimensions {
+ Currency = "USD"
+ }
+}
+
+resource "aws_cloudwatch_metric_alarm" "alarm-free-tier-exceeded" {
+ alarm_name = "alarm-free-tier-exceeded"
+ alarm_description = "Free tier exceeded - further usage will cost money"
+ namespace = "AWS/Billing"
+ metric_name = "EstimatedCharges"
+ statistic = "Maximum"
+ period = "21600" # 6 hours
+ evaluation_periods = "1"
+ comparison_operator = "GreaterThanThreshold"
+ threshold = "0"
+ actions_enabled = true
+ alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
+ dimensions {
+ Currency = "USD"
+ }
+}
diff --git a/cdn/terraform/dynamodb.tf b/cdn/terraform/dynamodb.tf
new file mode 100644
index 0000000..4f5f17f
--- /dev/null
+++ b/cdn/terraform/dynamodb.tf
@@ -0,0 +1,21 @@
+# DynamoDB
+
+# DO NOT DELETE THIS TABLE! It contains the Terraform locking state,
+# shared by all Terraform users in the Guix project. In addition, the
+# s3 backend's locking feature will not function without it.
+resource "aws_dynamodb_table" "terraform-locking" {
+ name = "terraform-locking"
+ # This table will not receive a steady, predictable rate of
+ # requests. In addition, the absolute number of requests will be
+ # low. Therefore, pay-per-request will be the most cost-effective.
+ billing_mode = "PAY_PER_REQUEST"
+ hash_key = "LockID"
+ attribute {
+ name = "LockID"
+ type = "S"
+ }
+ # Always encrypt data at rest.
+ server_side_encryption {
+ enabled = true
+ }
+}
diff --git a/cdn/terraform/iam.tf b/cdn/terraform/iam.tf
new file mode 100644
index 0000000..28eb463
--- /dev/null
+++ b/cdn/terraform/iam.tf
@@ -0,0 +1,131 @@
+# IAM
+
+# A friendly name for our account. This is displayed in various
+# places, such as the AWS Management Console.
+
+resource "aws_iam_account_alias" "alias" {
+ account_alias = "guix"
+}
+
+# Encourage good password hygiene.
+
+resource "aws_iam_account_password_policy" "strict" {
+ minimum_password_length = 20
+ require_lowercase_characters = true
+ require_numbers = true
+ require_uppercase_characters = true
+ require_symbols = true
+ allow_users_to_change_password = true
+ password_reuse_prevention = 1
+}
+
+# The administrators group.
+
+resource "aws_iam_group" "administrators" {
+ name = "administrators"
+}
+resource "aws_iam_group_policy_attachment" "administrators-policy-attachment" {
+ group = "${aws_iam_group.administrators.name}"
+ # This is a "managed policy". See:
+ #
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html#jf_administrator
+ policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
+}
+resource "aws_iam_group_membership" "administrators-membership" {
+ name = "administrators-membership"
+ users = [
+ "${aws_iam_user.marusich.name}",
+ "${aws_iam_user.civodul.name}",
+ "${aws_iam_user.rekado.name}",
+ ]
+ group = "${aws_iam_group.administrators.name}"
+}
+
+# The administrators themselves.
+
+# Note that if we don't set force_destroy to true, then Terraform
+# might fail to delete the user when we remove it: See:
+# https://github.com/hashicorp/terraform/issues/8621
+
+# Chris Marusich <address@hidden>
+
+resource "aws_iam_user" "marusich" {
+ name = "marusich"
+ force_destroy = true
+}
+resource "aws_iam_access_key" "marusich-access-key-1" {
+ user = "${aws_iam_user.marusich.name}"
+ pgp_key = "${var.pgp_key_marusich}"
+}
+resource "aws_iam_user_login_profile" "marusich-login-profile" {
+ user = "${aws_iam_user.marusich.name}"
+ pgp_key = "${var.pgp_key_marusich}"
+}
+
+output "marusich-name" {
+ value = "${aws_iam_user.marusich.name}"
+}
+output "marusich-password" {
+ value =
"${aws_iam_user_login_profile.marusich-login-profile.encrypted_password}"
+}
+output "marusich-access-key-1-id" {
+ value = "${aws_iam_access_key.marusich-access-key-1.id}"
+}
+output "marusich-access-key-1-secret" {
+ value = "${aws_iam_access_key.marusich-access-key-1.encrypted_secret}"
+}
+
+# Ludovic Courtès <address@hidden>
+
+resource "aws_iam_user" "civodul" {
+ name = "civodul"
+ force_destroy = true
+}
+resource "aws_iam_access_key" "civodul-access-key-1" {
+ user = "${aws_iam_user.civodul.name}"
+ pgp_key = "${var.pgp_key_civodul}"
+}
+resource "aws_iam_user_login_profile" "civodul-login-profile" {
+ user = "${aws_iam_user.civodul.name}"
+ pgp_key = "${var.pgp_key_civodul}"
+}
+
+output "civodul-name" {
+ value = "${aws_iam_user.civodul.name}"
+}
+output "civodul-password" {
+ value =
"${aws_iam_user_login_profile.civodul-login-profile.encrypted_password}"
+}
+output "civodul-access-key-1-id" {
+ value = "${aws_iam_access_key.civodul-access-key-1.id}"
+}
+output "civodul-access-key-1-secret" {
+ value = "${aws_iam_access_key.civodul-access-key-1.encrypted_secret}"
+}
+
+# Ricardo Wurmus <address@hidden>
+
+resource "aws_iam_user" "rekado" {
+ name = "rekado"
+ force_destroy = true
+}
+resource "aws_iam_access_key" "rekado-access-key-1" {
+ user = "${aws_iam_user.rekado.name}"
+ pgp_key = "${var.pgp_key_rekado}"
+}
+resource "aws_iam_user_login_profile" "rekado-login-profile" {
+ user = "${aws_iam_user.rekado.name}"
+ pgp_key = "${var.pgp_key_rekado}"
+}
+
+output "rekado-name" {
+ value = "${aws_iam_user.rekado.name}"
+}
+output "rekado-password" {
+ value =
"${aws_iam_user_login_profile.rekado-login-profile.encrypted_password}"
+}
+output "rekado-access-key-1-id" {
+ value = "${aws_iam_access_key.rekado-access-key-1.id}"
+}
+output "rekado-access-key-1-secret" {
+ value = "${aws_iam_access_key.rekado-access-key-1.encrypted_secret}"
+}
diff --git a/cdn/terraform/main.tf b/cdn/terraform/main.tf
index d61d2b7..f680d9e 100644
--- a/cdn/terraform/main.tf
+++ b/cdn/terraform/main.tf
@@ -1,3 +1,8 @@
+# This file defines our backend and provider. The remaining resources
+# are defined in separate *.tf files in this directory. Terraform
+# merges them all together when it runs, and the order doesn't matter.
+# See: https://www.terraform.io/docs/configuration/index.html
+
# Backend documentation:
# https://www.terraform.io/docs/backends/types/s3.html
terraform {
@@ -42,419 +47,3 @@ provider "aws" {
# berlin-mirror-certificate for details.
region = "us-east-1"
}
-
-# IAM
-
-# A friendly name for our account. This is displayed in various
-# places, such as the AWS Management Console.
-
-resource "aws_iam_account_alias" "alias" {
- account_alias = "guix"
-}
-
-# Encourage good password hygiene.
-
-resource "aws_iam_account_password_policy" "strict" {
- minimum_password_length = 20
- require_lowercase_characters = true
- require_numbers = true
- require_uppercase_characters = true
- require_symbols = true
- allow_users_to_change_password = true
- password_reuse_prevention = 1
-}
-
-# The administrators group.
-
-resource "aws_iam_group" "administrators" {
- name = "administrators"
-}
-resource "aws_iam_group_policy_attachment" "administrators-policy-attachment" {
- group = "${aws_iam_group.administrators.name}"
- # This is a "managed policy". See:
- #
https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_job-functions.html#jf_administrator
- policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"
-}
-resource "aws_iam_group_membership" "administrators-membership" {
- name = "administrators-membership"
- users = [
- "${aws_iam_user.marusich.name}",
- "${aws_iam_user.civodul.name}",
- "${aws_iam_user.rekado.name}",
- ]
- group = "${aws_iam_group.administrators.name}"
-}
-
-# The administrators themselves.
-
-# Note that if we don't set force_destroy to true, then Terraform
-# might fail to delete the user when we remove it: See:
-# https://github.com/hashicorp/terraform/issues/8621
-
-# Chris Marusich <address@hidden>
-
-resource "aws_iam_user" "marusich" {
- name = "marusich"
- force_destroy = true
-}
-resource "aws_iam_access_key" "marusich-access-key-1" {
- user = "${aws_iam_user.marusich.name}"
- pgp_key = "${var.pgp_key_marusich}"
-}
-resource "aws_iam_user_login_profile" "marusich-login-profile" {
- user = "${aws_iam_user.marusich.name}"
- pgp_key = "${var.pgp_key_marusich}"
-}
-
-output "marusich-name" {
- value = "${aws_iam_user.marusich.name}"
-}
-output "marusich-password" {
- value =
"${aws_iam_user_login_profile.marusich-login-profile.encrypted_password}"
-}
-output "marusich-access-key-1-id" {
- value = "${aws_iam_access_key.marusich-access-key-1.id}"
-}
-output "marusich-access-key-1-secret" {
- value = "${aws_iam_access_key.marusich-access-key-1.encrypted_secret}"
-}
-
-# Ludovic Courtès <address@hidden>
-
-resource "aws_iam_user" "civodul" {
- name = "civodul"
- force_destroy = true
-}
-resource "aws_iam_access_key" "civodul-access-key-1" {
- user = "${aws_iam_user.civodul.name}"
- pgp_key = "${var.pgp_key_civodul}"
-}
-resource "aws_iam_user_login_profile" "civodul-login-profile" {
- user = "${aws_iam_user.civodul.name}"
- pgp_key = "${var.pgp_key_civodul}"
-}
-
-output "civodul-name" {
- value = "${aws_iam_user.civodul.name}"
-}
-output "civodul-password" {
- value =
"${aws_iam_user_login_profile.civodul-login-profile.encrypted_password}"
-}
-output "civodul-access-key-1-id" {
- value = "${aws_iam_access_key.civodul-access-key-1.id}"
-}
-output "civodul-access-key-1-secret" {
- value = "${aws_iam_access_key.civodul-access-key-1.encrypted_secret}"
-}
-
-# Ricardo Wurmus <address@hidden>
-
-resource "aws_iam_user" "rekado" {
- name = "rekado"
- force_destroy = true
-}
-resource "aws_iam_access_key" "rekado-access-key-1" {
- user = "${aws_iam_user.rekado.name}"
- pgp_key = "${var.pgp_key_rekado}"
-}
-resource "aws_iam_user_login_profile" "rekado-login-profile" {
- user = "${aws_iam_user.rekado.name}"
- pgp_key = "${var.pgp_key_rekado}"
-}
-
-output "rekado-name" {
- value = "${aws_iam_user.rekado.name}"
-}
-output "rekado-password" {
- value =
"${aws_iam_user_login_profile.rekado-login-profile.encrypted_password}"
-}
-output "rekado-access-key-1-id" {
- value = "${aws_iam_access_key.rekado-access-key-1.id}"
-}
-output "rekado-access-key-1-secret" {
- value = "${aws_iam_access_key.rekado-access-key-1.encrypted_secret}"
-}
-
-# CloudFront
-
-resource "aws_cloudfront_distribution" "berlin-mirror" {
- enabled = true
- comment = "Distributed caching proxy for berlin.guixsd.org"
- origin {
- domain_name = "berlin.guixsd.org"
- origin_id = "berlin.guixsd.org"
- custom_origin_config {
- http_port = 80 # Required, but not used.
- https_port = 443
- # Always use TLS when forwarding requests to the origin.
- origin_protocol_policy = "https-only"
- origin_ssl_protocols = ["TLSv1.2"]
- origin_keepalive_timeout = 60
- origin_read_timeout = 60
- }
- }
- # The CNAME that will point to this CloudFront distribution.
- aliases = ["ci.guix.info"]
- is_ipv6_enabled = true
- # This is actually the_maximum HTTP version to support. See:
- #
https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#http_version
- http_version = "http2"
- # Serve requests from all edge locations.
- price_class = "PriceClass_All"
- # Do not restrict access.
- restrictions { geo_restriction { restriction_type = "none" }}
- # When deleting the distribution, actually delete it. See:
- #
https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#retain_on_delete
- retain_on_delete = false
- default_cache_behavior {
- # Only allow "read" verbs.
- allowed_methods = ["GET", "HEAD"]
- cached_methods = ["GET", "HEAD"]
- # The origin will compress data when necessary.
- compress = false
- # Cache responses that lack a Cache-Control header.
- default_ttl = 86400 # 1 day
- # When deciding whether or not to cache a response, ignore any
- # cookies, headers, or query strings that the client included in
- # their request. This should increase the cache hit rate. In
- # addition, this also causes CloudFront to omit these values
- # when forwarding the request to the custom origin. See:
- #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/ConfiguringCaching.html
- forwarded_values {
- cookies { forward = "none" }
- query_string = false
- }
- # Generally speaking, respect any Cache-Control or Expires
- # headers that the origin includes in its responses. The
- # exception is that if a Cache-Control or Expires header says to
- # cache the result for more than 1 year, we ignore that and only
- # cache the result for 1 year at most. Honestly, though, it
- # seems unrealistic to expect CloudFront to actually keep the
- # cached response for an entire year in that case. See:
- #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/Expiration.html
- max_ttl = 31536000 # 365 days
- min_ttl = 0
- target_origin_id = "berlin.guixsd.org"
- # Before ci.guix.info pointed to this distribution, it allowed
- # both HTTP and HTTPS. We choose to maintain that policy here.
- # In the future, we should consider changing this to "https-only".
- viewer_protocol_policy = "allow-all"
- }
- # TODO: Maybe add more behaviors for specific paths/prefixes.
- # ordered_cache_behavior {}
- # TODO: Maybe set a caching behavior for error responses.
- # custom_error_response {}
- viewer_certificate {
- # Note that "terraform apply" will fail until this certificate is
- # valid. See the comment in the definition of
- # berlin-mirror-certificate for more information.
- acm_certificate_arn =
"${aws_acm_certificate.berlin-mirror-certificate.arn}"
- # This is the recommended value as of 2018-12-28. See:
- #
https://docs.aws.amazon.com/cloudfront/latest/APIReference/API_ViewerCertificate.html
- #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/secure-connections-supported-viewer-protocols-ciphers.html#secure-connections-supported-ciphers
- minimum_protocol_version = "TLSv1.1_2016"
- # Use SNI. Don't use the "vip" (i.e., dedicated IP address)
- # method, since it's expensive and unnecessary. See:
- #
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-https-dedicated-ip-or-sni.html
- ssl_support_method = "sni-only"
- }
-}
-
-output "berlin-mirror-id" {
- value = "${aws_cloudfront_distribution.berlin-mirror.id}"
-}
-output "berlin-mirror-status" {
- value = "${aws_cloudfront_distribution.berlin-mirror.status}"
-}
-output "berlin-mirror-domain-name" {
- value = "${aws_cloudfront_distribution.berlin-mirror.domain_name}"
-}
-
-# S3
-
-# DO NOT DELETE THIS BUCKET! This bucket contains the Terraform
-# state, shared by all Terraform users in the Guix project. In
-# addition, the s3 backend will not function without it.
-resource "aws_s3_bucket" "guix-terraform-state" {
- bucket = "guix-terraform-state"
- # Access should be granted via IAM policies.
- acl = "private"
- # This allows us to recover state if something ever goes wrong - as
- # long as we do so within the time period specified by our lifecycle
- # policy (see below). For details, see:
- # https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingObjectVersions.html
- versioning {
- enabled = true
- }
- # When we destroy the bucket, destroy all objects first so that the
- # bucket deletion succeeds. Of course, you should think twice
- # before deleting this bucket!
- force_destroy = true
- # Encrypt data at rest using S3's server side encryption. See:
- # https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html
- server_side_encryption_configuration {
- rule {
- apply_server_side_encryption_by_default {
- sse_algorithm = "AES256"
- }
- }
- }
- # The intent of this rule is to retain the current version and zero
- # or more recent non-current versions, while preventing the size of
- # the bucket from growing out of hand.
- lifecycle_rule {
- id = "clean-up"
- enabled = true
- # It seems unlikely that Terraform would use multi-part uploads to
- # upload the state, since the state is small, but just in case,
- # let's automatically abort any stuck multi-part uploads.
- abort_incomplete_multipart_upload_days = 7
- # Clean up old non-current versions.
- noncurrent_version_expiration {
- days = 14
- }
- }
- lifecycle {
- prevent_destroy = true
- }
-}
-
-# ACM
-
-# Terraform will create this certificate automatically. However, to
-# validate it requires one-time manual action outside of Terraform.
-# This is because there don't seem to be any Terraform providers that
-# are compatible with our DNS registrar. To create and validate the
-# certificate, you must do the following in order:
-#
-# - Run "terraform apply" to create the certificate.
-# - Run "terraform show" to view the CNAME record ACM needs you to
-# create in order to prove domain ownership.
-# - Manually create the CNAME record.
-# - Run "terraform apply" or "terraform plan" again to ensure the
-# resources are in their final, correct state.
-# - Run "terraform show" to verify that the certificate is now
-# listed as "validated".
-# - Repeat the last two steps until the validation succeeds.
-#
-# This only has to be done once. For more information, see:
-# https://docs.aws.amazon.com/acm/latest/userguide/gs-acm-validate-dns.html
-#
-# Finally, since we intend to use this certificate with our CloudFront
-# distribution, we must create it in the us-east-1 region. See:
-# https://docs.aws.amazon.com/acm/latest/userguide/acm-services.html
-#
https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cnames-and-https-requirements.html
-resource "aws_acm_certificate" "berlin-mirror-certificate" {
- domain_name = "ci.guix.info"
- validation_method = "DNS"
- # The AWS provider documentation recommends setting
- # create_before_destroy to true in a lifecycle block. We probably
- # won't need this, since we don't currently plan to replace the
- # existing certificate using Terraform (ACM will just rotate it for
- # us automatically), but it doesn't hurt to include this here.
- lifecycle {
- create_before_destroy = true
- }
-}
-
-# SNS
-
-# Email subscriptions cannot be managed via Terraform. Therefore, any
-# email subscriptions must be configured manually. See:
-# https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html
-#
https://docs.aws.amazon.com/sns/latest/dg/sns-getting-started.html#SubscribeTopic
-resource "aws_sns_topic" "guix-billing-alarms" {
- name = "guix-billing-alarms"
-}
-
-# CloudWatch
-
-resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-150-usd" {
- alarm_name = "alarm-estimated-charges-150-usd"
- alarm_description = "Estimated charges have exceeded 150 USD"
- namespace = "AWS/Billing"
- metric_name = "EstimatedCharges"
- statistic = "Maximum"
- period = "21600" # 6 hours
- evaluation_periods = "1"
- comparison_operator = "GreaterThanThreshold"
- threshold = "150"
- actions_enabled = true
- alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
- dimensions {
- Currency = "USD"
- }
-}
-
-resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-140-usd" {
- alarm_name = "alarm-estimated-charges-140-usd"
- alarm_description = "Estimated charges have exceeded 140 USD"
- namespace = "AWS/Billing"
- metric_name = "EstimatedCharges"
- statistic = "Maximum"
- period = "21600" # 6 hours
- evaluation_periods = "1"
- comparison_operator = "GreaterThanThreshold"
- threshold = "140"
- actions_enabled = true
- alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
- dimensions {
- Currency = "USD"
- }
-}
-
-resource "aws_cloudwatch_metric_alarm" "alarm-estimated-charges-100-usd" {
- alarm_name = "alarm-estimated-charges-100-usd"
- alarm_description = "Estimated charges have exceeded 100 USD"
- namespace = "AWS/Billing"
- metric_name = "EstimatedCharges"
- statistic = "Maximum"
- period = "21600" # 6 hours
- evaluation_periods = "1"
- comparison_operator = "GreaterThanThreshold"
- threshold = "100"
- actions_enabled = true
- alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
- dimensions {
- Currency = "USD"
- }
-}
-
-resource "aws_cloudwatch_metric_alarm" "alarm-free-tier-exceeded" {
- alarm_name = "alarm-free-tier-exceeded"
- alarm_description = "Free tier exceeded - further usage will cost money"
- namespace = "AWS/Billing"
- metric_name = "EstimatedCharges"
- statistic = "Maximum"
- period = "21600" # 6 hours
- evaluation_periods = "1"
- comparison_operator = "GreaterThanThreshold"
- threshold = "0"
- actions_enabled = true
- alarm_actions = ["${aws_sns_topic.guix-billing-alarms.arn}"]
- dimensions {
- Currency = "USD"
- }
-}
-
-# DynamoDB
-
-# DO NOT DELETE THIS TABLE! It contains the Terraform locking state,
-# shared by all Terraform users in the Guix project. In addition, the
-# s3 backend's locking feature will not function without it.
-resource "aws_dynamodb_table" "terraform-locking" {
- name = "terraform-locking"
- # This table will not receive a steady, predictable rate of
- # requests. In addition, the absolute number of requests will be
- # low. Therefore, pay-per-request will be the most cost-effective.
- billing_mode = "PAY_PER_REQUEST"
- hash_key = "LockID"
- attribute {
- name = "LockID"
- type = "S"
- }
- # Always encrypt data at rest.
- server_side_encryption {
- enabled = true
- }
-}
diff --git a/cdn/terraform/s3.tf b/cdn/terraform/s3.tf
new file mode 100644
index 0000000..caf6cbf
--- /dev/null
+++ b/cdn/terraform/s3.tf
@@ -0,0 +1,48 @@
+# S3
+
+# DO NOT DELETE THIS BUCKET! This bucket contains the Terraform
+# state, shared by all Terraform users in the Guix project. In
+# addition, the s3 backend will not function without it.
+resource "aws_s3_bucket" "guix-terraform-state" {
+ bucket = "guix-terraform-state"
+ # Access should be granted via IAM policies.
+ acl = "private"
+ # This allows us to recover state if something ever goes wrong - as
+ # long as we do so within the time period specified by our lifecycle
+ # policy (see below). For details, see:
+ # https://docs.aws.amazon.com/AmazonS3/latest/dev/DeletingObjectVersions.html
+ versioning {
+ enabled = true
+ }
+ # When we destroy the bucket, destroy all objects first so that the
+ # bucket deletion succeeds. Of course, you should think twice
+ # before deleting this bucket!
+ force_destroy = true
+ # Encrypt data at rest using S3's server side encryption. See:
+ # https://docs.aws.amazon.com/AmazonS3/latest/dev/serv-side-encryption.html
+ server_side_encryption_configuration {
+ rule {
+ apply_server_side_encryption_by_default {
+ sse_algorithm = "AES256"
+ }
+ }
+ }
+ # The intent of this rule is to retain the current version and zero
+ # or more recent non-current versions, while preventing the size of
+ # the bucket from growing out of hand.
+ lifecycle_rule {
+ id = "clean-up"
+ enabled = true
+ # It seems unlikely that Terraform would use multi-part uploads to
+ # upload the state, since the state is small, but just in case,
+ # let's automatically abort any stuck multi-part uploads.
+ abort_incomplete_multipart_upload_days = 7
+ # Clean up old non-current versions.
+ noncurrent_version_expiration {
+ days = 14
+ }
+ }
+ lifecycle {
+ prevent_destroy = true
+ }
+}