├── .gitignore ├── README.md ├── minimal_alb.tf ├── provider.tf ├── ssl_cert.tf ├── vars.tf └── vpc.tf /.gitignore: -------------------------------------------------------------------------------- 1 | terraform.tf* 2 | .terraform 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # How to use: 2 | 3 | terraform init 4 | 5 | 1. Set your demo_dns_zone and demo_dns_name variables: (terraform.tfvars) 6 | 2. Setup your providers 7 | 8 | terraform plan 9 | terraform apply 10 | 11 | # Requirements: 12 | 13 | - existing route53 zone in AWS 14 | - terraform v0.13.1 or newer 15 | - AWS provider 3.4.x 16 | -------------------------------------------------------------------------------- /minimal_alb.tf: -------------------------------------------------------------------------------- 1 | resource "aws_alb" "mylb" { 2 | # Normal ALB content, options removed for BLOG 3 | subnets = module.vpc.public_subnets 4 | security_groups = [aws_security_group.myapp.id] 5 | } 6 | 7 | # Basic https lisener to demo HTTPS certiciate 8 | resource "aws_alb_listener" "mylb_https" { 9 | load_balancer_arn = aws_alb.mylb.arn 10 | certificate_arn = aws_acm_certificate_validation.cert.certificate_arn 11 | port = "443" 12 | protocol = "HTTPS" 13 | # Default action, and other paramters removed for BLOG 14 | default_action { 15 | type = "fixed-response" 16 | 17 | fixed_response { 18 | content_type = "text/html" 19 | message_body = "

Hello World!

This would usually be to a target group of web servers.. but this is just a demo to returning a fixed response\n\n

" 20 | status_code = "200" 21 | } 22 | } 23 | } 24 | 25 | # Always good practice to redirect http to https 26 | resource "aws_alb_listener" "mylb_http" { 27 | load_balancer_arn = aws_alb.mylb.arn 28 | port = "80" 29 | protocol = "HTTP" 30 | default_action { 31 | type = "redirect" 32 | redirect { 33 | port = "443" 34 | protocol = "HTTPS" 35 | status_code = "HTTP_301" 36 | } 37 | } 38 | } 39 | 40 | # Open Security Group for demo 41 | resource "aws_security_group" "myapp" { 42 | vpc_id = module.vpc.vpc_id 43 | 44 | ingress { 45 | from_port = 80 46 | to_port = 80 47 | protocol = "tcp" 48 | cidr_blocks = ["0.0.0.0/0"] 49 | } 50 | 51 | ingress { 52 | from_port = 443 53 | to_port = 443 54 | protocol = "tcp" 55 | cidr_blocks = ["0.0.0.0/0"] 56 | } 57 | 58 | egress { 59 | from_port = "0" 60 | to_port = "0" 61 | protocol = "-1" 62 | cidr_blocks = ["0.0.0.0/0"] 63 | } 64 | } -------------------------------------------------------------------------------- /provider.tf: -------------------------------------------------------------------------------- 1 | # AWS account that contains the route53 domain 2 | provider "aws" { 3 | alias = "account_route53" # Specific to your setup 4 | version = ">= 3.4.0" 5 | } 6 | 7 | # your normal provider 8 | provider "aws" { 9 | version = ">= 3.4.0" 10 | } 11 | 12 | terraform { 13 | required_version = ">= 0.13.1" 14 | } 15 | -------------------------------------------------------------------------------- /ssl_cert.tf: -------------------------------------------------------------------------------- 1 | # This data source looks up the public DNS zone 2 | data "aws_route53_zone" "public" { 3 | name = var.demo_dns_zone 4 | private_zone = false 5 | provider = aws.account_route53 6 | } 7 | 8 | # This creates an SSL certificate 9 | resource "aws_acm_certificate" "myapp" { 10 | domain_name = aws_route53_record.myapp.fqdn 11 | validation_method = "DNS" 12 | lifecycle { 13 | create_before_destroy = true 14 | } 15 | } 16 | 17 | # This is a DNS record for the ACM certificate validation to prove we own the domain 18 | # 19 | # This example, we make an assumption that the certificate is for a single domain name so can just use the first value of the 20 | # domain_validation_options. It allows the terraform to apply without having to be targeted. 21 | # This is somewhat less complex than the example at https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation 22 | # - that above example, won't apply without targeting 23 | 24 | resource "aws_route53_record" "cert_validation" { 25 | allow_overwrite = true 26 | name = tolist(aws_acm_certificate.myapp.domain_validation_options)[0].resource_record_name 27 | records = [ tolist(aws_acm_certificate.myapp.domain_validation_options)[0].resource_record_value ] 28 | type = tolist(aws_acm_certificate.myapp.domain_validation_options)[0].resource_record_type 29 | zone_id = data.aws_route53_zone.public.id 30 | ttl = 60 31 | provider = aws.account_route53 32 | } 33 | 34 | # This tells terraform to cause the route53 validation to happen 35 | resource "aws_acm_certificate_validation" "cert" { 36 | certificate_arn = aws_acm_certificate.myapp.arn 37 | validation_record_fqdns = [ aws_route53_record.cert_validation.fqdn ] 38 | } 39 | 40 | # Standard route53 DNS record for "myapp" pointing to an ALB 41 | resource "aws_route53_record" "myapp" { 42 | zone_id = data.aws_route53_zone.public.zone_id 43 | name = "${var.demo_dns_name}.${data.aws_route53_zone.public.name}" 44 | type = "A" 45 | alias { 46 | name = aws_alb.mylb.dns_name 47 | zone_id = aws_alb.mylb.zone_id 48 | evaluate_target_health = false 49 | } 50 | provider = aws.account_route53 51 | } 52 | 53 | output "testing" { 54 | value = "Test this demo code by going to https://${aws_route53_record.myapp.fqdn} and checking your have a valid SSL cert" 55 | } 56 | output "testing_sclient" { 57 | value = "Test this SSL by using openssl s_client -host ${aws_route53_record.myapp.fqdn} -port 443 and looking at the certs" 58 | } -------------------------------------------------------------------------------- /vars.tf: -------------------------------------------------------------------------------- 1 | variable "demo_dns_zone" { 2 | description = "Specific to your setup, pick a domain you have in route53" 3 | } 4 | 5 | 6 | variable "demo_dns_name" { 7 | description = "Just a demo domain name" 8 | default = "ssldemo" 9 | } 10 | -------------------------------------------------------------------------------- /vpc.tf: -------------------------------------------------------------------------------- 1 | # AZ lookup 2 | data "aws_availability_zones" "available" { 3 | state = "available" 4 | } 5 | 6 | # Minimal VPC config for demo 7 | module "vpc" { 8 | source = "terraform-aws-modules/vpc/aws" 9 | cidr = "10.211.0.0/16" 10 | public_subnets = ["10.211.214.0/27", "10.211.213.0/27"] 11 | azs = data.aws_availability_zones.available.names 12 | } --------------------------------------------------------------------------------