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)