How to implement HTTP Strict Transport Security (HSTS) on AWS Elastic Load Balancer?

I asked the AWS Support and the answer was that at the moment ELB cannot add HSTS headers on the requests from the clients. So, I decided to find a workaround using my Apache server. Here is the solution I found:

The HSTS RFC states that

An HSTS Host MUST NOT include the STS header field in HTTP responses conveyed over non-secure transport.

What I did then was to set the header AFTER the http=>https redirection in Apache. Since this redirection has the flag [L], that means that the 301 redirection will not include the header, but any https request will. My apache config looks like this:

<VirtualHost *:80>
...
    #http=>https
    RewriteCond %{HTTP:X-Forwarded-Proto} =http
    RewriteRule . https://%{HTTP:Host}%{REQUEST_URI} [L,R=permanent]

    #hsts
    Header set Strict-Transport-Security "max-age=31536000"

If you're working with Apache 2.4+, you may be familiar with expressions and the directives <If>, <ElseIf>, and <Else>.

I have a complex configuration between dev, staging, and production environments, so relying on the [L] flag with the RewriteRule just wouldn't cut it for me.

This brought me to the following solution, which I placed in my .htaccess:

<IfModule mod_headers.c>
    <If "%{REQUEST_SCHEME} == 'https' || %{HTTP:X-Forwarded-Proto} == 'https'">
        Header set Strict-Transport-Security "max-age=31536000"
    </If>
</IfModule>

It works better in my environment and I feel that it is more reliable for meeting the RFC.

You could drop the "%{REQUEST_SCHEME} == 'https' part if you never hit your instances directly, but that's part of my debug process in my dev environments.

Much thanks to Pedreiro for pointing me in the right direction for the actual specifications on the HSTS RFC.