December 17, 2017

IIS AWS Elastic Beanstalk End to End SSL Encryption

How to enable end to end SSL encryption for IIS Elastic Beanstalk environments. This process will provide port 443 passthrough on the ELB. During the deployment of the Windows Beanstalk servers we will copy the certificate and bind it on the IIS server.  To perform this process we will use a certificate, s3 bucket, and .ebexentions (.ebextenstions documentation).

Requirements:

  1. A certificate which has been uploaded to a s3 bucket in .pfx format (typically requires a password)
  2. Use EC2 role to allow access to the s3 bucket where you have stored the .pfx file.  Here is the additional policy  which would need to be added to the ec2 elastic beanstalk role.  Replace “my-bucket” below with the bucket name where you are storing the .pfx.
    {
      "Version": "2012-10-17",
      "Statement":[{
        "Effect": "Allow",
        "Action": [
          "s3:GetObject",
          "s3:ListBucket"
        ],
        "Resource": ["arn:aws:s3:::my-bucket",
                     "arn:aws:s3:::my-bucket/*"]
        }
      ]
    }

Instructions:

In your .ebextensions folder we will be adding 3 files.  If you wanted you could combine some of these files but I wanted to split them to show each of the steps needed.

  1. 00-commands.config
  2. https-instance-securitygroup.config
  3. https-lb-passthrough.config

Next I will show the contents of each files above and describe what each is attempting to accomplish.  Please be aware the format of these files need to be YAML format so the tabs and spaces of the file is very important.  If you run into issues please be sure to verify the format is correct.  You can use something like http://www.yamllint.com/ to validate the format of each file.

00-commands.config:

The following file 00-commands.config is the only file which needs to be modified for your environment.    You will need to update the following variables $bucket, $key, $file,  and $pwd to match your environment.  You keep the “s and replace < name > including the < & >.

files:
  "c:/ssl.ps1":
    content: |
      # Settings
      $bucket = "<S3 Bucket Name>" #S3 bucket name
      $key = "<PFX filename>.pfx" #S3 object key
      $file = "C:\<PFX filename>.pfx" #local file path
      $pwd = ConvertTo-SecureString -String  "<PFX File password>" -Force -AsPlainText  #pfx password (should store this more securely)

      # Get certificate from S3
      Read-S3Object -BucketName $bucket -Key $key -File $file

      Import-Module WebAdministration
      Import-PfxCertificate -FilePath $file -CertStoreLocation cert:\localmachine\my -Password $pwd
      $Cert = dir cert:\localmachine\my | Where-Object {$_.Subject -like "*<CERTNAME>*" }
      $Thumb = $Cert.Thumbprint.ToString()
      Push-Location IIS:\SslBindings
      New-WebBinding -Name "Default Web Site" -IP "*" -Port 443 -Protocol https
      Get-Item cert:\localmachine\my\$Thumb | new-item 0.0.0.0!443
      Pop-Location
commands:
  install_ssl:
    command: PowerShell -ExecutionPolicy Bypass -File "c:/ssl.ps1"
    waitAfterCompletion: 0

Now let me explain what’s going on with this file.  On the first line you see “files:”, this tells the instance to create a file with the name and location on the next line “c:/ssl.ps1”:.  The next set of lines all the way to the “commands:’ line is the contents of file it’s creating.   Basically this is creating a powershell script (c:\ssl.ps1) which when executed will copy the .pfx file from an s3 bucket locally, import this .pfx into the certificate store, then  bind it to all ip’s on port 443 in IIS.

The commands: line is telling the instance to run a command or set of commands.  The next line names the command “install_ssl:” and the next line is the actual command it will runs.  The command which gets executed is after the “command:”.  So this command is executing the powershell script we just wrote locally:

PowerShell -ExecutionPolicy Bypass -File "c:/ssl.ps1"

The next line “waitAfterCompletion: 0” is stating to wait till this command completes before moving on to the next command or config file.  If you do not supply this value the default is 60 seconds.  0 means it will wait forever for it to complete.

https-instance-securitygroup.config:

This file is used to modify the security group which gets associated to the instance during the beanstalk deployment.  This process was taken from the following set of instructions on the AWS site:

http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-tcp-passthrough.html

Resources:
  443inboundfromloadbalancer:
    Type: AWS::EC2::SecurityGroupIngress
    Properties:
      GroupId: {"Fn::GetAtt" : ["AWSEBSecurityGroup", "GroupId"]}
      IpProtocol: tcp
      ToPort: 443
      FromPort: 443
      SourceSecurityGroupName: { "Fn::GetAtt": ["AWSEBLoadBalancer", "SourceSecurityGroup.GroupName"] }

This file is in the same format as Cloud Formation template, for more info on Cloud Formation please see the public documentation.  The first line tells you we are working with “Resources:”.  Then next line is just a name I have defined in this file, it is not seen anywhere else than in this file and could be used as a variable later in the file if needed.  The Type: line is telling us we will be working with, EC2 Security Group Ingress rules.  The next set of line is referring to the properties we will be adding to an existing rule which gets created during the beanstalk launch.  It’s adding tcp port 443 access from the ELB security group, so the ELB security group has access to talk to port 443 on instances with this security group associated.  This means web traffic would have to flow through the ELB to access port 443 on the backend instances and this would be the only way to gain access to the backend instances on this port.

https-lb-passthrough.config:

This file is used to allow tcp port 443 to be forwarded through the ELB to the backend instances.  This process was also taken from the following set of instructions on the AWS site:

http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/https-tcp-passthrough.html

option_settings:
  aws:elb:listener:443:
    ListenerProtocol: TCP
    InstancePort: 443
    InstanceProtocol: TCP

This is modifying an option_settings: on the ELB which gets launched during the Beanstalk deployment.  It is adding a listener on tcp port 443 and sending it to the backend instances on tcp port 443.

By default this would allow both ports 80 and 443 open on the ELB and the instance.  Your application would need to perform a redirect to https when it a client connects to port 80.

I was originally working with the following additional config file, but it does not work 100% anymore.  It will create a new security group and associate it with an ELB but does not remove the existing security group, which allows port 80 and 443.

https-lb-sg.config:

This creates a new security group which only allows port 443 access to the ELB.   You could include this in your .ebextensions and just remove the default security group and only allow this security group after Beanstalk deployment.

Resources:
    ELBSecurityGroup:
        Type: AWS::EC2::SecurityGroup
        Properties:
            GroupDescription: ELB SecurityGroup for ElasticBeanstalk environment.
            SecurityGroupIngress:
                - FromPort: 443
                  ToPort: 443
                  IpProtocol: tcp
                  CidrIp : 0.0.0.0/0
    AWSEBLoadBalancer:
        Type: "AWS::ElasticLoadBalancing::LoadBalancer"
        Properties:
            SecurityGroups:
                - Fn::GetAtt:
                    - ELBSecurityGroup
                    - GroupId


Please feel free to track any updates I do in my github account https://github.com/dagint/win-bs-ssl.

Related Posts:

DaGint Computer Support