Motivation:
To obtain a free SSL certificate (by Let's Encrypt) for your web application without the hassle of renewing it every three months, consider the following approach.
The simplest solution is to use a Load Balancer and attach an SSL certificate from AWS Certificate Manager (ACM) to it. However, relying on a Load Balancer solely for HTTPS may be costly. To address this, I’ve outlined a much more affordable alternative that requires a bit of configuration.
Additionally, in this post, I explain how to configure SSL for an Elastic Beanstalk instance, as I found the existing documentation and available resources to be somewhat outdated.
Keyword of the solution is Cloudflare.
Cloudflare offers a proxy feature that enables you to set up a free SSL certificate while securely proxying traffic to your host.
In Flexible mode, the communication between Cloudflare and AWS is not encrypted. If you prefer end-to-end encryption, you can opt for Full mode instead.
Steps
1. Add your domain to Cloudflare.
- In the DNS settings, configure your domain as proxied.
- In the SSL/TLS settings, select Full (strict) mode for end-to-end encryption.
2. Generate an Origin Certificate in Cloudflare
- Go to the SSL/TLS > Origin Server section in Cloudflare.
- Generate a certificate valid for up to 15 years.
- Use this certificate to configure SSL in AWS Elastic Beanstalk.
3. Store Certificates in AWS Secrets Manager:
- Save the
server.crt
andserver.key
files as secrets in AWS Secrets Manager. - Use the following secret names:
/app/ssl/server-crt
and/app/ssl/server-key
4. Grant IAM Role Access to Secrets:
- In AWS IAM add a new policy named
ReadSSLSecretKeys
for the roleaws-elasticbeanstalk-ec2-role
with the following permissions:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "ssm:GetParameter", "Resource": "arn:aws:ssm:region:account_id:parameter/app/ssl/server-crt" }, { "Effect": "Allow", "Action": "ssm:GetParameter", "Resource": "arn:aws:ssm:region:account_id:parameter/app/ssl/server-key" } ] }
5. Configure your Elastic Beanstalk deployment to listen on port 443
and use the Origin Certificate generated in Cloudflare (stored in AWS Secrets Manager) do changes in the following files:
-
.ebextensions/01_https-instance-securitygroup.config
Resources: sslSecurityGroupIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]} IpProtocol: tcp ToPort: 443 FromPort: 443 CidrIp: 0.0.0.0/0
-
.ebextensions/02_https-instance.config
files: /etc/pki/tls/certs/server.crt: mode: "000400" owner: root group: root content: | -----BEGIN CERTIFICATE----- certificate file contents -----END CERTIFICATE----- /etc/pki/tls/certs/server.key: mode: "000400" owner: root group: root content: | -----BEGIN RSA PRIVATE KEY----- private key contents # See note below. -----END RSA PRIVATE KEY----- container_commands: 01_fetch_server_crt: command: | aws ssm get-parameter --name "/app/ssl/server-crt" --with-decryption --query "Parameter.Value" --output text > /etc/pki/tls/certs/server.crt 02_fetch_server_key: command: | aws ssm get-parameter --name "/app/ssl/server-key" --with-decryption --query "Parameter.Value" --output text > /etc/pki/tls/certs/server.key
-
.platform/nginx/conf.d/https.conf
server { listen 443 ssl; ssl_certificate /etc/pki/tls/certs/server.crt; ssl_certificate_key /etc/pki/tls/certs/server.key; ssl_session_timeout 5m; ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_prefer_server_ciphers on; location / { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Connection ""; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto https; } }
Top comments (0)