Edit: AWS now have a certificate service which may be more useful to you, depending on your setup.
The fundamental difference in setting up https on Elastic Beanstalk is that your certificate is installed on the load balancer/environment itself, *not* the individual instances. This actually makes life a lot easier: you don’t need to worry about doing anything to the instances themselves as the SSL terminates at the load balancer. This assumes you’re using multiple availability zones, not a single zoned instance.
Also, remember this won’t ever work on myenvironment.beanstalk.com, only on a CNAME entry for yourdomain.com which you’ve aliased to the beanstalk environment URL, as obviously, AWS don’t hand out certs for beanstalk.com 🙂
Get your certificates and ensure they’re in the right format.
I used sslmate.com, which I found very easy to use for a simple DV (Domain validated) certificate – you don’t actually need *more* than DV unless you want to do things like have “yourcompany” in the URL bar alongside the padlock sign. Wildcards are only really cost effective if you want more than 8-9 subdomains certified.
So once sslmate is installed locally, do:
$ sslmate buy www.example.com
and follow the prompts. Note, I didn’t add any of the ‘optional’ fields as I remember that can cause problems (unfortunately I can’t remember exactly *where* I read that).
Once you’ve successfully made the purchase, you should now have a bunch of files in the directory you ran the command. The good part is these certificates are in the correct format, and also are signed. The PEM format (as opposed to DER) is actually not necessarily to do with the file extension: i.e, .crt can be in PEM format, so don’t feel you need to convert these certificates just because they haven’t got a .pem extension. I only mention formats as this is the ‘other’ format which AWS uses for S3 key pair URL signing, so if you’re only exposure to that sort of thing is S3, this is the other one.
You should have:
mydomain.com.key mydomain.com.crt mydomain.com.chain.crt mydomain.com.chained.crt
Make sure you’ve got AWS command line tools installed. This isn’t the Elastic Beanstalk CLI tools – this is in addition to those. You can get them here: http://aws.amazon.com/cli/ – although as I had pip installed from installed the EB CLI, I just did
$ pip install awscli
After which, setup using:
$ aws configure AWS Access Key ID [None]: AKIAIOSFODNN7EXAMPLE AWS Secret Access Key [None]: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY Default region name [None]: us-west-1 Default output format [None]: json
Time to upload our certs to a AWS IAM profile:
$ aws iam upload-server-certificate --server-certificate-name certificate_object_name --certificate-body file://public_key_certificate_file --private-key file://privatekey.pem --certificate-chain file://certificate_chain_file
So this should equate to something like:
$ aws iam upload-server-certificate --server-certificate-name myDomainSSL --certificate-body file://mydomain.com.crt --private-key file://mydomain.com.key --certificate-chain file://mydomain.com.chain.crt
The Chain file is important for browser acceptance.
If successful, you should get something like:
returned at the prompt.
Attach cert to the load balancer:
Login to the web GUI at aws.amazon.com, select Elastic Beanstalk and click on the configuration section for the environment you want to apply the certificate to. Under Network Tier > Load Balancing, click on the cog to configure.
You should be able to see “myDomainSSL” as a dropdown under SSL Certificate ID – if you don’t, the certificate isn’t in IAM or something so you need to go back a few steps and check.
So at this point, you need to do something like:
Listener Port: 80 Protocol: HTTP Secure Listener Port: 443 Protocol: HTTPS
and ensure your certificate is selected.
Saving will restart your instance, and all going well, https://www.mydomain.com should work. Except if you’re using VPC, you need to do one last step, which is open up 443 on the security group; (Go to EC -> Security Groups, select Load Balancer Security Group, add an inbound rule for HTTPS/TCP/443 on 0.0.0.0/0)
Read something like This for some nice pointers/reminders about running an app over https.