Forum Discussion
bernie_9326
Nimbostratus
Feb 24, 2010in layer 7 routing, how to direct request under SSL
Hi
Wondering if you can help. We are trying to use layer 7 routing to send web requests to three different pools.
Our questions are - is there a way to set up Layer 7 routing such that
a. if the requests come in as HTTPS, we can interpret the URI and the redirected request goes up as HTTPS (see issues in Test 2 below)
b. if the requests come in as HTTP, we simply redirect along as HTTP.
Our test iRule is:
when HTTP_REQUEST {
log local0. "uri=[HTTP::uri]"
set uri [HTTP::uri]
if {$uri starts_with "/acme"} {
log local0. " going to pool-acme"
pool pool-acme
} elseif {$uri starts_with "/onlyssl"} {
pool pool-onlyssl
} else {
pool pool-bob
}
}
Test 1
When we send in the request as HTTP (e.g., http://vip/acme), the iRule works. The request comes in and goes to pool-acme.
Test 2
if we send in the request as httpS://vip/onlyssl (because the servers in pool-onlyssl only serves requests coming in as HTTPS), the HTTP::uri returns what appears to be encrypted string. Specifically, it is not /onlyssl but is instead something like "uri=~G?}?~_?X??\R".
Our suspicion is that the request is still under SSL hence the URI is still encrypted.
Test 3
If we set up the virtual server to break the SSL. We could be wrong but we added "clientssl" to Virtual Server > Configuration > SSL Profile (client). When we did that, the logging now shows "uri=/onlyssl". However, the request going to the onlyssl servers are in HTTP. We needed them to be in SSL.
Test 4
We then also added "serverssl" to SSL Profile (server). Now the requests goes all the way to the onlyssl servers as HTTPS and we get a clean response.
Test 5
But now the problem is that the original request in Test 1 fails.
8 Replies
- The_Bhattman
Nimbostratus
Hi Bernie,
Are you running 2 virtual address, one running on http and other on https
In that case you could use the following on HTTPwhen HTTP_REQUEST { log local0. "uri=[HTTP::uri]" if {[HTTP::uri] starts_with "/acme"} { log local0. " going to pool-acme" pool pool-acme } }
The other can be applied to HTTPSwhen HTTP_REQUEST { log local0. "uri=[HTTP::uri]" switch -glob [string tolower [HTTP::uri]] { "/onlyssl*" { pool pool-onlyssl } default { pool pool-bob } } }
I hope this helps
Bhattman - bernie_9326
Nimbostratus
Bhattman
Thanks for your reply. Unfortunately, we are running under one virtual address (vip). The reason is for cross-domain communication. The containing (parent) HTML from /acme needs to be able to grab data from iFrames that get data from /onlyssl and /bob. We are using the single vip to make all requests appear to be coming from the same URL domain.
Our root issue is HTTP::uri returning the encrypted URI under HTTPS. I believe our problem would be solved if HTTP::uri could return the actual uri so we can route even when the request comes up as HTTPS.
Thanks again.
Bernie - The_Bhattman
Nimbostratus
Hi Bernie
Hoolio created an excellent irule to run http and https on the same virtual address (Click here)
Here is the the same code that has your specifics (Of course it's untested so there might be some fine tunning)when RULE_INIT { Requests to ports not defined in either the https or http ports list will be reset Set this option to 1 to redirect client requests from HTTP to HTTPS. Set to 0 to not redirect clients from HTTP to HTTPS. set ::redirect_http_to_https 0 Set this option to 1 to rewrite the requested URI to lower case. Set to 0 to not rewrite the URI. set ::rewrite_uri_to_lower_case 1 Set this option to 1 to log debug messages (to /var/log/ltm by default) set ::single_vs_debug 1 } when CLIENT_ACCEPTED { Save the VIP name, client IP:port as a log prefix to make the log lines shorter set log_prefix "[IP::client_addr]:[TCP::client_port]" if { [matchclass [TCP::local_port] equals "443" }{ Request was to an HTTPS port, so do nothing for the clientside connection. The defined client and/or server SSL profiles will be applied as normal if {$::single_vs_debug}{log local0. "$log_prefix: HTTPS request to [IP::local_addr]:[TCP::local_port]"} log an error if the virtual server doesn't have a client SSL profile, but receives an SSL request if {[PROFILE::exists clientssl] == 0}{ if {$::single_vs_debug}{log local0. "$log_prefix:\ Client connection received on port [TCP::local_port], but no client SSL profile is enabled on [IP::local_addr]"} reject } log local0. "uri=[HTTP::uri]" switch -glob [string tolower [HTTP::uri]] { "/onlyssl*" { pool pool-onlyssl } default { pool pool-bob } } } elseif {([matchclass [TCP::local_port] equals "80"]) }{ Request was to an HTTP port, not an HTTPS port, so disable client SSL profile if one is enabled on the VIP set vip_http_port 1 if {$::single_vs_debug}{log local0. "$log_prefix: HTTP request to [IP::local_addr]:[TCP::local_port]"} Check to see if there is a client SSL profile and if so, disable it if { [PROFILE::exists clientssl] == 1} { if {$::single_vs_debug}{log local0. "$log_prefix: Client SSL profile enabled on VIP. Disabling SSL."} set disable_cmd "SSL::disable" eval $disable_cmd if {[HTTP::uri] starts_with "/acme"} { log local0. " going to pool-acme" pool pool-acme } } } else { Request wasn't to a defined port, so reset the TCP connection. if {$::single_vs_debug}{log local0. "$log_prefix:\ Dropping request to undefined port [IP::local_addr]:[TCP::local_port]"} reject } } when HTTP_REQUEST { If redirect_http_to_https is enabled and the request was made to an HTTP port, redirect the client to the same host/URI over HTTPS if { ($::redirect_http_to_https == 1 or ([info exists redirect_http_to_https] && $redirect_http_to_https)) && \ ([info exists vip_http_port] && $vip_http_port==1)}{ HTTP::redirect https://[getfield [HTTP::host] ":" 1][HTTP::uri] if {$::single_vs_debug}{log local0. "$log_prefix:\ Redirecting client [IP::client_addr] to https://[getfield [HTTP::host] \":\" 1][HTTP::uri]"} } else { Rewrite the HTTP::path to lower case if the option is enabled globally or in a separate rule if {$::rewrite_uri_to_lower_case or ([info exists rewrite_uri_to_lower_case] and $rewrite_uri_to_lower_case)}{ HTTP::path [string tolower [HTTP::path]] } } }
I hope this helps - bernie_9326
Nimbostratus
Hey Bhattman
Wow - thanks for that sample. I am thinking that my problem is a little bit simpler. I apologize if I didn't explain the problem clearer.
Here is the description of what we would like to do
1. all traffic (both HTTP and HTTPS) go to a single virtual address (vip).
2. we want to route requests based on URI (layer 7 routing) to one of three different load-balancing pools (call them pool-acme, pool-bob and pool-onlyssl).
3. F5 when routing preserves the protocol - if requests comes in as HTTP, it is sent to the pool as HTTP
We have the following iRule that seems to do the trickwhen HTTP_REQUEST { log local0. "uri=[HTTP::uri]" set uri [HTTP::uri] if {$uri starts_with "/acme"} { log local0. " going to pool-acme" pool pool-acme } elseif {$uri starts_with "/onlyssl"} { pool pool-onlyssl } else { pool pool-bob } }
EXCEPT when the request comes in as HTTPS. When in HTTPS, the value of HTTP::uri appears to be the encrypted uri which breaks our Layer 7 routing decision.
Question 1 - is there a way we could get the value of HTTP::uri when the request comes in HTTPS
Alternatively, we could set up the F5 to be the SSL break. In that case, when requests comes in as
1. HTTP: look at and route based on uri - leave protocol as HTTP
2. HTTPS: then break SSL, route based on uri, then send to pool as HTTPS
Bernie - The_Bhattman
Nimbostratus
Hi Bernie,
Looking back at your earlier posts, you mentioned that you couldn't use 2 Virtual addresses. After re-reading that statement I think I wasn't clear in explaining. You can create 2 Virtual address using the same IP address but different ports on them. This way your domains will always point to the same address and be able to separately handle the SSL termination on the F5 for HTTPS and HTTP separately.
Bhattman - hoolio
Cirrostratus
Hi Bernie,
In order to inspect or modify the HTTP headers or payload for HTTPS traffic, you need to import the cert/key to LTM and configure them in a client SSL profile. You can then use an iRule like the one you've posted to inspect the HTTP and select a pool based on the URI.
Also, you can use a switch statement to evaluate the URI. It's a bit more efficient and easier to organize.when HTTP_REQUEST { log local0. "uri=[HTTP::uri]" Check the requested URI switch -glob [HTTP::uri] { "/acme*" { log local0. " going to pool-acme" pool pool-acme } "/onlyssl*"} { pool pool-onlyssl log local0. " going to onlyssl" } default { pool pool-bob log local0. " going to pool-bob" } } }
Aaron - bernie_9326
Nimbostratus
Posted By Bhattman on 02/25/2010 4:34 AM
Hi Bernie,
Looking back at your earlier posts, you mentioned that you couldn't use 2 Virtual addresses. After re-reading that statement I think I wasn't clear in explaining. You can create 2 Virtual address using the same IP address but different ports on them. This way your domains will always point to the same address and be able to separately handle the SSL termination on the F5 for HTTPS and HTTP separately.
Bhattman
Bhattman, you are right!!!! It worked. Thanks!!!! - bernie_9326
Nimbostratus
Aaron
Thanks for those two suggestions. We will definitely try it out.
Bernie
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects