HTTP To HTTPS Cookie Persistence
Problem this snippet solves:
Problem
Customer has pretty standard eCommerce site - end-users are browsing the shop using HTTP and while they are ready to purchase, they go to checkout using HTTPS. HTTPS is offloaded to the BigIP, so catch-all cannot be used. Decrypted HTTPS traffic is sent to backend servers on different port (e.g. 81). Also, customer is not happy to use source IP based persistence because of inconsistencies in load distribution across the servers. The real problem here is that BigIP does not allow you to maintain persistence when using cookies and transitioning between two virtual servers (from HTTP to HTTPS).
Solution
While BigIP does offer "Match across services" option in some of the persistence profiles like sourceip, there is no such option for cookie persistence. The solution is to use universal persistence profile accompanied by custom-made iRule. Instead of creating persistence records based on node's IP and port, custom iRule will use just IP address. This will allow you to stick to the same server regardless of which port you use.
Take the following steps to get this configured
Code :
# iRule v11 option rule cookie_persist_http_plus_s { # Check if there is a cookie and use persistence table # if the entry does not exist, loadbalance and create record when HTTP_REQUEST { if { [HTTP::cookie value "bIPs"] ne "" } { persist uie [HTTP::cookie value "bIPs"] set need_cookie 0 } else { set need_cookie 1 } } when PERSIST_DOWN { # This event will only work in 11.0+. # Ask F5 Support for details on BZ225436 for details. # Server that UIE peristence pointed to was down set need_cookie 1 } # Calculate CRC32 checksum of the server's IP # and store it as a cookie and create persistence record when HTTP_RESPONSE { if { $need_cookie } { HTTP::cookie insert name "bIPs" value [crc32 [IP::server_addr]] path "/" persist add uie [HTTP::cookie value "bIPs"] } } } # iRule v10.x option rule cookie_persist_http_plus_s { # Check if there is a cookie and use persistence table # if the entry does not exist, loadbalance and create record when HTTP_REQUEST { if { [HTTP::cookie value "bIPs"] ne "" } { persist uie [HTTP::cookie value "bIPs"] } } # Calculate CRC32 checksum of the server's IP # and store it as a cookie and create persistence record when HTTP_RESPONSE { HTTP::cookie insert name "bIPs" value [crc32 [IP::server_addr]] path "/" persist add uie [HTTP::cookie value "bIPs"] } } # Once you have the iRule created, it's time to associate it with persistence profile: ltm persistence universal persist-https_plus_s { defaults-from universal match-across-pools disabled match-across-services enabled match-across-virtuals disabled mirror disabled override-connection-limit disabled rule cookie_persist_http_plus_s timeout 3600 } # And finally you can create virtual servers and pools, for example: ltm pool POOL-HTTP { members { 192.168.117.51:http { state up } 192.168.117.52:http { state up } } monitor http } ltm pool POOL-HTTPS-81 { members { 192.168.117.51:hosts2-ns { state up } 192.168.117.52:hosts2-ns { state up } } monitor http } ltm virtual VS-192.168.113.101-80 { destination 192.168.113.101:http ip-protocol tcp mask 255.255.255.255 persist { persist-https_plus_s { default yes } } pool POOL-HTTP profiles { http { } tcp { } } } ltm virtual VS-192.168.113.101-SSL { destination 192.168.113.101:https ip-protocol tcp mask 255.255.255.255 persist { persist-https_plus_s { default yes } } pool POOL-HTTPS-81 profiles { clientssl { context clientside } http { } tcp { } } }