Adding SSL to our little AWS service
Earlier today I wrote a bit about separating the ELB and instance(s) into separate subnets and how we might make that useful. Potentially we could dive deeper into ACLs and/or routing tables and the bastion pattern. We could start looking at Terraform modules, Instead though, I want to press on towards getting something deployed.
These days, serving anything insecurely over the web is not acceptable. We need an SSL certificate and be configured to serve over https.
As we are on AWS it makes sense to use the AWS Certificate Manager to obtain and manage the certificate. This part is manual:
- Log on to the AWS console (as in the web interface)
- Click the blue “Request a certificate” button, towards the top and left of the main page
- Choose “Request a public certficiate”
- Enter your chosen domain name and click “Next”. (I used beta.correcthorsebatterystaple.com)
- Choose DNS Validation.
- Optionally tag your certificate with whatever, and “Review”
- “Confirm and request”
- Expand the domain. You’ll be given a name and value to add to your DNS as a CNAME. If you happen to use Amazon’s Route 53 you’re golden. I don’t and headed over to DNSimple an d added the record.
- Hit “continue”
- Keep refreshing and waiting. Hopefully validation will come your way.
Ok, back to the Terraform. We’ll keep on using the Two Tier example. First we need to be able to refer to the certificate:
data "aws_acm_certificate" "mycert" {
domain = "beta.correcthorsebatterystaple.com"
statuses = ["ISSUED"]
}
I love that you can find the certificate via the domain name. Arguably I should have used a variable for the domain, though.
We need to add ELB to support https over 443, with the certificate. We do this by adding a listener to resource "aws_elb" "web"
listener {
instance_port = 80
instance_protocol = "http"
lb_port = 443
lb_protocol = "https"
ssl_certificate_id = data.aws_acm_certificate.mycert.arn
}
A few things to note
- the communication with the instance is still
http
on port 80 - use
arn
to get thessl_certificate_id
notid
Don’t forget to open ope 443 in the security group for the ELB, resource "aws_security_group" "elb"
in our case:
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
Run terraform apply
and we can now serve our default ngninx
page securely.
I pulled this example code into its own repo, if you want to inspect it more fully.