A simple approach to handle sites that require SSL (HTTPS) encryption is to not allow plain-text HTTP, but that’s not very user-friendly and no one likes having to type extra characters into the browser to indicate HTTPS as the URI scheme. So the elegant solution for the client-side request is to allow HTTP, but then to redirect all such requests over to SSL. If you’re doing SSL Acceleration on your Cisco ACE load-balancer anyway, your configuration will become simpler in the long-run since you won’t have to maintain as much duplicate configuration to handle different load-balance policies for plain-text HTTP and SSL.
The solution is to create a generic redirect rserver and serverfarm that can be used for any SSL loadbalance policies. For web applications that may build absolute paths, the web server may need to know that the client protocol has switched over to SSL so you don’t have needless redirects. A HTTP Header can be sent in the request toward the web server to inform it of the protocol using the de facto standard header called X-Forwarded-Proto. Using the standard Via header is another alternative and will be shown in an example.
The ACE Module also has the ability to rewrite any HTTP redirects from the web server that should go to HTTPS using an action-list. Any plain-text redirects which show in the location header will be caught and rewritten to SSL.
Let’s get into the config. Complete config snippet here.
rserver redirect ssl-generic-redirect
webhost-redirection https://%h%p 302
Real server (rserver) of type redirect is created. This one is given a generic name of ssl-generic-redirect since it’s not tied to any particular VIPs (Virtual IPs). The webhost-redirection takes the hostname (%h) along with the full path (%p) and does a 302 (temporary) redirect. You could just as easily done a 301 (permanent) redirect. Using variables for the hostname and path is what allows the reuse of this generic rserver anywhere.
serverfarm redirect ssl-redirect
Now we simply tie the rserver to a serverfarm since the building blocks on the ACE require rservers into serverfarms into loadbalance policy-maps.
Now the interesting part is the action-list to set various request and response headers. This is also where the SSL location header rewrite occurs. The config below is a little overkill, but you’ll hopefully find some value in one or more of these actions.
action-list type modify http ssl-rewrite
header insert request X-Forwarded-Proto header-value “%pd”
header insert request Via header-value “1.1 web:%pd (ace10-8/a2)”
header insert response Via header-value “1.1 web:%ps (ace10-8/a2)”
ssl url rewrite location “.*”
ssl header-insert session Id
The header insert request X-Forwarded-Proto is where we set the client-side protocol (number) in the request toward the web server. Since by this time the client has already been redirected to SSL, the client will be making a request on port 443 which comes from the %pd (port destination) variable. The web app can look at this value in determining how to build absolute paths so that https:// is sent to the client instead of http://. An alternative is to use protocol-independent URL’s such as //www.example.com — notice the lack of the URI scheme HTTP or HTTPS — but some browsers may have trouble with this (we’re talking about you Mr. IE6). This header is added to the existing request headers and goes in the direction from the ACE to the web server since the request keyword appeared after header insert.
The Via header in the example is written in both directions with separate actions because the values are different. In fact, the ACE can do a header insert both to write the same header and value in both directions (i.e., added to both the request and response headers), but we don’t want to do that here. Following the RFC 2616 (HTTP/1.1) standard on the Via header, we identify our reverse proxy for the serverfarm in header insert request Via. We set the value to http protocol version to 1.1 followed by a pseudonym and comment. The pseudonym web:%pd in the example indicates the ACE context (web) plus the destination port (%pd) in the request. The comment added could indicate the ACE hardware and slot (ACE10-8) followed by the major version A2. The web server will see a value of “1.1 web:443 (ace10-8/a2)”.
For the response, we use header insert response Via which uses the source port (%ps) from the web server to show on the client-side that the web server handled the request in plain-text port 80. If you’re overly concerned with exposing the type of hardware and version you’re running, then modify the comment or eliminate it to your liking. The client will see a value of “1.1 web:80 (ace10-8/a2)”.
What wasn’t initially clear to me, and no amount of searching and documentation explained this, the header insert will append the value if the header already exists. I discovered this by accident by having two identical header insert response Via header-values in the config, and seeing in FireBug (for FireFox) — or Chrome or IE Developer Tools — that the second value was appended with a comma-delimeter.
The ssl url rewrite location “.*” uses the regex pattern “.*” to match any URL on the default clearport 80 so it can be rewritten to the default sslport 443. Additional parameters are required to change the clearport or sslport to non-standard ports. This handles any clear-text redirects being sent from the web server by modifying them to use the SSL port 443 to avoid unnecessary HTTP-to-HTTPS redirects on the ACE.
The ssl header-insert session Id shows how the SSL Session ID tied to the client session can be sent to the web server as another way in identifying that a SSL encryption with the client is in play. When SSL Acceleration is done on the ACE Module with a ssl-proxy, the web server receives all requests in plain-text http on port 80.
The last part of the config is the usual stuff where the class-maps identify the traffic for the policy-maps. Only key differences related to the HTTP-to-HTTPS redirection will be noted.
class-map match-all test.example.com
2 match virtual-address 10.4.64.38 tcp eq www
class-map match-all test.example.com-ssl
2 match virtual-address 10.4.64.38 tcp eq https
Here we have two class-maps to match on port 80 and 443 for the policy-maps below since the serverfarms are different.
policy-map type loadbalance first-match test.example.com-l7slb
policy-map type loadbalance first-match test.example.com-ssl-l7slb
The first policy-map takes the plaint-text http traffic and does the redirect to https (ssl). The second policy-map ties the action-list to it and spells out the serverfarm (a sticky-serverfarm in this case). The service-policy is not shown, but note that you need a parameter-map of type http with persistence-rebalance set in your policy-map multi-match (service policy) if you want the headers to be written on every request. The parameter-map is applied to the class in your service policy with your appl-parameter http advanced-options.
Complete config snippet here.
Now you can allow your secure sites to have a friendlier redirection of non-secure requests.
[This discussion highlights a recurring theme with learning how to configure the ACE Module. At first, the learning curve is high, but after seeing some examples and doing one of these yourself it is not so bad and exemplifies some of the power of the ACE.]