Skip to content

Instantly share code, notes, and snippets.

@nzoschke
Created May 26, 2015 18:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save nzoschke/5bebad3302fe7250abc8 to your computer and use it in GitHub Desktop.
Save nzoschke/5bebad3302fe7250abc8 to your computer and use it in GitHub Desktop.

Most web traffic should be available over HTTPS. AWS makes this easy with Elastic Load Balancers (ELBs). When configured with an SSL certificate, an ELB will perform SSL termination and forward the traffic onto our group of non-encrypted web server instances.

Using an ELB is advantageous to offload many responsibilities to Amazon:

Maintaining uptime for the primary service DNS name Balancing traffic to one or more instances Re-balancing traffic when instances are added, removed, or become unhealthy Storing and applying your mission-critical secret SSL certificate Configuring critical aspects of HTTP like what SSL protocols, cypher and options are available and permitted

Let’s create an HTTPS Load Balancer with a custom certificate.

Generate Self-Signed Certificate

# Generate an SSL key pair non-interactively

$ openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
......................+++
e is 65537 (0x10001)
$ openssl rsa -passin pass:x -in server.pass.key -out server.key
writing RSA key
$ rmserver.pass.key

# Generate certificate signing request. '.' leaves field blank

$ openssl req -new -key server.key -out server.csr \
  -subj "/C=US/ST=California/L=San Francisco/O=./OU=./CN=*.example.com"

# Generate a signed certificate

$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Signature ok
subject=/C=US/ST=California/L=San Francisco/O=./OU=./CN=*.example.com
Getting Private key

Upload Certificate to IAM

$ aws iam upload-server-certificate --server-certificate-name star-example-com \
  --certificate-body file://server.crt --private-key file://server.key
{
    "ServerCertificateMetadata": {
        "ServerCertificateId": "ASCAJLBBXDOA3ICOFAOS4", 
        "ServerCertificateName": "star-example-com", 
        "Expiration": "2016-05-25T16:30:10Z", 
        "Path": "/", 
        "Arn": "arn:aws:iam::901416387788:server-certificate/star-example-com", 
        "UploadDate": "2015-05-26T16:33:53.689Z"
    }
}

Create and Configure ELB

# Create a Security Group allowing TCP 80 and 443
$ aws ec2 create-security-group --group-name lb-group --description "for https load balancer"
{
    "GroupId": "sg-d97d44bd"
}
$ aws ec2 authorize-security-group-ingress --group-id sg-d97d44bd --protocol tcp --port 80 --cidr 0.0.0.0/0
$ aws ec2 authorize-security-group-ingress --group-id sg-d97d44bd --protocol tcp --port 443 --cidr 0.0.0.0/0

# Get all the default subnet ids
$ SUBNET_IDS=$(aws ec2 describe-subnets | jq -r '.Subnets[] | select(.DefaultForAz) | .SubnetId' | tr '\n' ' ')
$ echo $SUBNET_IDS
subnet-e47e0693 subnet-6cc35c35 subnet-1f870134 subnet-636d4659

# Create a Load Balancer in the security group and subnets, configured for HTTPS with our cert
$ aws elb create-load-balancer --load-balancer-name lb \
  --listeners Protocol=http,LoadBalancerPort=80,InstanceProtocol=http,InstancePort=80 Protocol=https,LoadBalancerPort=443,InstanceProtocol=http,InstancePort=80,SSLCertificateId=arn:aws:iam::901416387788:server-certificate/star-example-com \
  --security-groups sg-d97d44bd --subnets $SUBNET_IDS
{
    "DNSName": "lb-223575153.us-east-1.elb.amazonaws.com"
}

Run EC2 Instance and Register With ELB

# Launch a pre-configured Node.js server

$ aws ec2 run-instances --image-id ami-e0838588 --security-group-ids sg-d97d44bd
{
    ...
    "Instances": [
        {

            "InstanceId": "i-bc0e8043", 
            "ImageId": "ami-e0838588", 
            "PrivateDnsName": "ip-172-31-25-47.ec2.internal", 
            "SecurityGroups": [
                {
                    "GroupName": "lb-group", 
                    "GroupId": "sg-d97d44bd"
                }
            ], 
            ...
        }
    ]
}

# Register the instance with our ELB

$ aws elb register-instances-with-load-balancer --load-balancer-name lb --instances i-bc0e8043
{
    "Instances": [
        {
            "InstanceId": "i-bc0e8043"
        }
    ]
}

Test HTTP / HTTPS

We may need to wait a few minutes for the instance to boot and pass the health checks.

# HTTP

$ curl -s lb-223575153.us-east-1.elb.amazonaws.com | grep Congrat
          <h1>Congratulations!</h1>

# HTTPS

$ curl -ksv https://lb-223575153.us-east-1.elb.amazonaws.com | grep Congrat
* Rebuilt URL to: https://lb-223575153.us-east-1.elb.amazonaws.com/
* Hostname was NOT found in DNS cache
*   Trying 54.88.43.134...
* Connected to lb-223575153.us-east-1.elb.amazonaws.com (54.88.43.134) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
* Server certificate: *.example.com
...
* Connection #0 to host lb-223575153.us-east-1.elb.amazonaws.com left intact
          <h1>Congratulations!</h1>

As we can see, our service is available through our load balancer both over HTTP and HTTPS. Over HTTPS, the *.example.com certificate that we generated is served.

Future Improvements

Generate a trusted signed certificate Explore ELB SSL Security Policies Pass SSL Test with an A or A+ Pick a better base AMI to demo with

--

Please direct feedback and/or questions via Twitter to @nzoschke or email to noah@convox.io.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment