Elastic Beanstalk Security Certificates
Overview
Instructions on installing and maintaining SSL for AWS Elastic Beanstalk web apps.
Amazon offers its own security certificates for load balanced EC2 instances, but not for smaller stand-alone instances.
Let's Encrypt offers free security certificates.
Prerequisites
All these commands are issued after using ssh to get a command prompt on the EC2 instance.
- ssh access to the EC2 instance
- Git, virtualenv, pip
Open port 443 on the EC2 instance
- AWS Management Console > EC2 > instance > click for details > Security Group > click for details
- Inbound tab > Edit button
- Add Rule button
- Type: HTTPS
- Protocol: TCP
- Port Range: 443
- Source: 0.0.0.0/0, ::/0
Note that this can also be accomplished with a directive in an .ebextensiosns config file. See the bottom of Terminating HTTPS on EC2 Instances Running Python in the AWS documentation for an example.
Enable SSL on EC2 instance
The Amazon documentation instructs you to install mod_ssl with the following command which should create a file /etc/httpd/conf.d/ssl.conf when it completes.
$ sudo yum install mod_ssl
This did not work for me for dbarchowsky.com which was on a t1.micro instance, Amazon Linux AMI version 2018.03. What worked instead was:
$ sudo yum install mod24_ssl
Installing Let's Encrypt
Install Let's encrypt into /opt/letsencrypt with git
$ sudo git clone https://github.com/letsencrypt/letsencrypt /opt/letsencript
Preserving Let's Encrypt configuration
Create a configuration file at /etc/letsencrypt/config.ini.
$ echo "rsa-key-size = 4096" >> /etc/letsencrypt/config.ini $ echo "email = ________@____.com" >> /etc/letsencrypt/config.ini
Installing certificates
PHP
Use Let's Encrypt to install security certificates. [1] [2]
The source instructions gave this command:
$ /opt/letsencrypt/letsencrypt-auto --debug
But that returned the following error:
PluginError: Unable to find a virtual host listening on port 80 which is currently needed for Certbot to prove to the CA that you control your domain. Please add a virtual host for port 80.
This is cause by not having the typical VirtualHost running on port 80 in the Apache configuration, so Certbot needs an alternative method for authenticating the doamin. It's possible to manually specify the web root of the website: [3] (Set /var/www/webroot to a path appropriate to the environment.)
$ /opt/letsencrypt/letsencrypt-auto --debug --authenticator webroot --installer apache -w /var/www/webroot -d mydomain.com -d www.mydomain.com
Python
Set Up Let's Encrypt SSL Certificate With AWS Elastic Beanstalk Single Instance has good clear instructions on how to accomplish this. Also see Terminating HTTPS on EC2 Instances Running Python in the AWS documentation, which is the basis for that blog post.
Create a config file in .ebextensions for SSL and use eb deploy to update the environment (this should also work for PHP environments).
With this method the domain names and admin email address are specified with environment variables. This is nice because staging and production can have different secure domain names while sharing the same code base.
To set the values for these variables: AWS Management Console > Elastic Beanstalk > choose application > choose environment > Configuration > Software > Modify
LE_DOMAIN_ARGS- List of all domains to be included in the certificate. Each domain name should be preceded by the-dflag, e.g.-d mydomain.com -d www.mydomain.comLETSENCRYPT_DOMAIN- Primary domain for the purposes of creating a symlink between /etc/letsencrypt/live/ebcert/ and the directory where Let's Encrypt actually places the certificate files.LETSENCRYPT_EMAIL- Contact email
Reference the north-rose project for a working example of this configuration.
Troubleshooting
The AWS documentation assumes that you generate the certificates manually and insert the contents of the certificate in the .ebextensions config file. The alternative example above places the command to generate the certificates in the .ebextensions config file. There is a flag that is incompatible with production environments: --staging. This will cause the Let's Encrypt staging server to issue the certificates. The server address will also get stored in a local config file, so subsequent attempts to reissue the certificates without the --staging flag will still invoke that staging server. [4]
One symptom of this situation are testing the domain's SSL with digicert will result in a report stating that "Certificate Name matches domaininquestion.com", however the issuer will be listed as "Fake LE Intermediate X1". A valid production certificate will have "Let's Encrypt Authority X3" as the issuer.
Another symptom is that the browser will state that the domain's certificate is not from a trusted source, even though everything will look as expected in the ssl.conf file and in /etc/letsencrypt/live/ebcert/.
Renewing certificates
Cron job
Let's Encrypt certificates expire every 90 days. Create a cron job (in /etc/crontab) that will run once per day to check and renew the certificates as necessary.
Follow the renewal of the certificate with a restart of the Apache server in order to have the server recognize any renewed certificates.
# Renew SSL Certs 0 1 * * * ec2-user /opt/letsencrypt/letsencrypt-auto --no-bootstrap renew # Refresh Server 10 1 * * * root apachectl -k restart > /dev/null 2>&1
Manually
Certificates can be manually forced to renew with
$ /opt/letsencrypt/certbot-auto renew --force-renewal
Troubleshooting
URLs for evaluating a domain's SSL
systemctl command not found
The AWS documentation uses systemctl to restart the Apache server. If this command is not available use the service command instead.
Cannot find SSLCertificateFile directive
When running letsencrypt-auto or certbot-auto
Cannot find an SSLCertificateFile directive in /files/etc/httpd/conf/httpd-le-ssl.conf/IfModule/VirtualHost. VirtualHost was not modified Unable to find an SSLCertificateFile directive
This was fixed by successfully installing mod_ssl
ERR_CONNECTION_REFUSED in Chrome
Attempting to load the site using https protocol in Chrome results in ERR_CONNECTION_REFUSED error.
This was fixed after the certificate was installed (creating the httpd-le-ssl.conf file with correct SSL directives).
Reference
See also
Notes
- ↑ Tutorial: Configure Apache Web Server on Amazon Linux 2 to Use SSL/TLS - AWS documentation
- ↑ Deploying Let's Encrype on An Amazon Linux AMI EC2 Instance - Medium.com
- ↑ Error installing Let's Encrypt on AWS Linux - AWS forums
- ↑ CN=Fake LE Intermediate X1 - Let's Encrypt forums