This was a particular problem for me with my ASP.NET MVC project with various OAuth providers. Basically anything that should use https was broken under Elastic Beanstalk. I tried coding around it by looking for the X-Forwarded-Proto HTTP header, but it was pretty nasty. So I really wanted SSL straight through to my EC2 instances.
It probably took me 3h to figure out how to do this without using an AMI, so hopefully this helps someone.
I've previously tried the custom AMI approach and, though it works, it presents two problems:
- I have to patch and maintain my own AMI which is time consuming. If I use a standard image, I can just rebuild the environment when a newer image is available.
- I can't source-control my configuration settings - they are just embedded in an opaque AMI somewhere in the cloud.
I adapted this from this post.
First of all, you need to add a directory to the root of your visual studio web project called: .ebextensions
.
Inside it, create a text file called environment.config
- we're going to use YAML here, so don't edit it in Visual Studio in case it thinks it's an Application Config file and adds tabs - YAML is whitespace sensitive. The syntax for the file is documented on Amazon.
My file has a bunch of other settings for tuning IIS, but the relevant bit looks like this:
container_commands:
site_add_ssl_binding:
command: PowerShell -ExecutionPolicy Bypass -File "C:\\inetpub\\wwwroot\\.ebextensions\\ssl.ps1"
This will execute a custom PowerShell script called ssl.ps1
. So let's create that inside the .ebextensions
directory:
# If there is no existing SSL binding
if ( -not(Get-WebBinding "Default Web Site" -Port 443) ) {
# Import the .pfx file into the certificate store
$securepwd = ConvertTo-SecureString -String "YOUR_PFX_PASSWORD_HERE" -Force -AsPlainText
$cert = Import-PfxCertificate -FilePath C:\inetpub\wwwroot\.ebextensions\my-certificate.pfx cert:\localMachine\my -Password $securepwd
# Create site binding in IIS
New-WebBinding -Name "Default Web Site" -IP "*" -Port 443 -Protocol https
New-Item IIS:SslBindings\0.0.0.0!443 -value $cert
}
When executed, this command will import a .pfx file into the certificate store, and then create the SSL binding on port 443 of your website.
With the original code that I referenced, I had all kinds of issues with dodgy character encodings. So if you copy/paste this sample and it doesn't work, you can test it by remoting into your EC2 instance, opening a command prompt and executing the command directly: PowerShell -ExecutionPolicy Bypass -File "C:\inetpub\wwwroot\.ebextensions\ssl.ps1"
You'll need to add your .pfx file to the .ebextensions
directory too. In Visual Studio, make sure that all of the files are included in the project, and have a Build Action of Content (tip select the file in the Solution Explorer and press F4). The solution explorer should look like:
- web-project.csproj
- .ebextensions
- environment.config
- my-certificate.pfx
- ssl.ps1
- ...
Then using the AWS Toolkit for Visual Studio, right-click on your project and select Publish to AWS
and follow the prompts. This will upload your deployment package to your Elastic Beanstalk environment, and install it. Your customisations will be executed during a deployment, or whenever a new EC2 instance is provisioned.
Following a successful execution, the .ebextensions
directory gets deleted.
If you don't want to include the .pfx file inside your Visual Studio project, the original example uses PowerShell to download the .pfx file from an S3 instance. You can also avoid embedding the password in the .ps1 by referencing an Elastic Beanstalk environment variable.
To get this working end-to-end you'll also need to:
- Configure your load-balancer to forward 443 traffic to port 443 on your EC2 instances - the default switches to port 80.
- Configure the security group out of the load-balancer to allow 443 traffic.
- Configure the security group into the EC2 instances to allow 443 traffic.