web sockets
11 TopicsMattermost, F5 LTM, and Websockets
I recently worked with a team that wanted to use the F5 Local Traffic Manager (LTM) feature to load balance connections to their new deployment of the Mattermost open source messaging platform within their on-premises datacenter. This application uses both HTTPS and Websockets connections for real-time chat. We ran into a few configuration issues but eventually found the right combination of “nerd knobs” to allow successful ingress traffic. This post is to consolidate these details and hopefully save time to other F5 engineers attempting to do the same. Business Requirements Ingress (client-side) connections TLS 1.1 or higher Support Websockets Only allow customized Mattermost mobile (iOS and Android) applications, provisioned from within the organization and using a custom header, to connect from the public Internet. The same VIP for the mobile traffic should be used by internal desktop or web browsers, which will not include this custom header Virtual Server Configuration The virtual server configuration was fairly straight forward: Protocol Profile (Client) = a mobile optimized TCP profile Protocol Profile (Server) = a LAN optimized TCP profile SSL Profile (Client) = profile with the Option No TLSv1 enabled SSL Profile (Server) = standard serverssl profile or custom one WebSocket Profile = WebSocket (or a custom one with this as the parent) SNAT = custom pool, but AutoMap would work OneConnect = standard oneconnect profile (or a custom one with this as the parent) Default Persistence = cookie Fallback Persistence = source address Pool = Mattermost server pool iRule = custom Mattermost iRule Mattermost iRule To meet some of the business requirements a custom iRule was created to handle some of the conditions outlined. Comments in-line, but this checks to see if the connection was outside of the organization and if so verifies the presence of the custom HTTP header and value. This also checks to see if the connection was requested to upgrade to Websockets, and if it is, change the HTTP filter from full parsing to passthrough mode. when HTTP_REQUEST { if { !(IP:addr [IP::client_addr] equals 192.168.0.0/255.255.255.0]) } { Request from IP outside of organization, check for customer HTTP header if { [HTTP::header x-the-custom-http-header-name] contains "customvalue" } { Custom HTTP header and matching value found if { [string tolower [HTTP::header Upgrade]] contains "websocket" }{ Connection is requesting WebSockets, stop HTTP parsing HTTP::disable } } elseif { [HTTP::cookie exists MMAUTHENTOKEN] && [HTTP::cookie exists MMUSERID] } { Since WebSocket connections do not have HTTP Header, check to see if connection has already authenticated and allow the connection return } else { Connection fails conditions, reject it reject } } else { if { [string tolower [HTTP::header Upgrade]] contains "websocket" }{ Connection is requesting WebSockets, stop HTTP parsing HTTP::disable } } }1.2KViews5likes2Comments