DEV Community

Kamil Kujawiński
Kamil Kujawiński

Posted on

Using Cloudflare SSL with Elastic Beanstalk instances

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 and server.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 role aws-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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode
  • .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

Enter fullscreen mode Exit fullscreen mode
  • .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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)