Learn F5 Technologies, Get Answers & Share Community Solutions Join DevCentral

Filter by:
  • Solution
  • Technology
Answers

serverssl, SNI, vHosts

Hi,

I wonder how to solve such issue:

  • Target server is using vHost and HTTPS
  • Each vHost has separate certificate for FQDN (no Wildcard or SAN)
  • Traffic is passed to target servers via one VS with Local Traffic Policy switching Pools based on Host header
  • VS is of course doing decrypting - so multiple clientssl profiles with SNI enabled assigned

I wonder how to configure serverssl profiles. Serverssl profiles are assigned at VS not Pool so how it can be done? Multiple serverssl profiles - each with FQDN of target vHost? If so how VS will know which serverssl use to present correct FQDN to target vHost during SSL handshake?

For me it seems not possible - or there is some way?

Example:

VS IP has two entries in DNS:

I have two clientssl profiles assigned to VS with Server Name field values:

I have two serverssl profiles assigned to VS with Server Name field values:

  • serverssl_host1 - host.host1.com
  • serverssl_host2 - host.host2.com

VS has no default Pool, just Local Traffic Policy choosing:

  • Pool host1_pl if Host header is www.host1.com. First of course it's doing SSL handshake using clientssl_host1 based on SNI value from client. This Pool points to Pool Member 192.168.1.1:443 (this is necessary to assign monitor sending correct value in Host header - in this case Host: host.host1.com)
  • Pool host2_pl if Host header is www.host2.com. This Pool is as well pointing to Pool Member 192.168.1.1:443 (this is necessary to assign monitor sending correct value in Host header - in this case Host: host.host2.com)

Let's say target node is 192.168.1.1. On this node we have to vHosts using certificates for FQDN:

  • host.host1.com
  • host.host2.com

So how VS can know that when pool host1_pl is chosen serverssl_host1 profile should be used to send SNI value host.host1.com to target vHost? Both Pool Members are using same IP:port, so even if reverse DNS query would be performed it will return both host.host1.com and host.host2.com no matter which Pool will be used (same defined IP:port for Pool Members in both Pools).

Probably it could be solved in 11.6+ using FQDN for Nodes? So we can define two separate nodes:

  • host.host1.com
  • host.host2.com

and then use them when creating Pool Members for each Pool, so:

  • Pool host1_pl - host.host1.com:443
  • Pool host2_pl - host.host2.com:443

but I am not sure if it will work? Piotr

0
Rate this Question

Answers to this Question

placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi Piotr,

It is very likely you will need iRules to achieve this, as I don't think the ServerSSL profile supports SNI. We basically read the SSL extension in CLIENTSSL_HANDSHAKE and keep it in the session table with the SSL::sessionid as the key (value is SSL::extensions -type 0), and then inserting it in SERVERSSL_CLIENTHELLO_SEND.

This is only a problem of course if your servers also serve different SSL certs using SNI so this solution is more for a niche problem. If your servers don't actually run SNI themselves, then sending the SNI value in the CLIENTHELLO is a moot point.

Radu

1
Comments on this Answer
Comment made 02-Mar-2016 by Piotr Lewandowski 1162
Hi, I am sure that serverssl profile supports SNI - of course as a client, so it means it can send SNI in client hello when starting SSL Handshake - then target server supporting SNI can choose correct certificate for SSL Handshake. Problem here is how correct serverssl profile can be slected when connecting with target server. Piotr
0
Comment made 02-Mar-2016 by raduioncu 64
Hi Piotr, You don't need multiple ServerSSL profiles - just the default one. You then use the iRule to manually insert the SNI value in the client hello when establishing the serverside connection.
0
Comment made 02-Mar-2016 by Piotr Lewandowski 1162
Hi, Well, with iRule for sure everything is possible :-). I was just curious if this is possible as well using just GUI and ssl profiles - like it's possible with clientssl. As far as I understand your answer it's not really possible this way? Piotr
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi Piotr, Radu,

continued to play with the SNI-Relay and implemented a server side "CN" and/or "SAN" verification code. Seems that this technique could be securely used to relay SNI values between client/server side and use the provided SNI value to verify the serverside CN or SAN values.

when CLIENTSSL_HANDSHAKE {
    if { [SSL::extensions exists -type 0] } then {
        set tls_sni_extension [SSL::extensions -type 0]
    } else {
        set tls_sni_extension ""
    }
}
when SERVERSSL_CLIENTHELLO_SEND {
    if { $tls_sni_extension ne "" } then {
        SSL::extensions insert $tls_sni_extension
    }
}
when SERVERSSL_HANDSHAKE {
    set cname_valid 0
    if { [SSL::cert count] > 0 } then {
        set cnames [string tolower [string map { "*" "" } [findstr [X509::subject [SSL::cert 0]] "CN=" 3 ","]]]
        set cnames [lsort -unique "$cnames [string tolower [string map { ", DNS:*" " " ", DNS:" " " ",DNS:*" " " ",DNS:" " " "*" "" ", " " " "," " " } [findstr [X509::extensions [SSL::cert 0]] "DNS:" 4 "\n"]]]"]
    }
    foreach cname $cnames {
        if { $cname starts_with "." } then {
            if { [llength [split $tls_sni_extension "."]] == [llength [split $cname "."]] } then {
                if { [findstr $tls_sni_extension "\." 0 end] ends_with $cname } then {
                    set cname_valid 1
                    return
                }
            }
        } else {
            if { $tls_sni_extension equals $cname } then {
                set cname_valid 1
                return
            }
        }       
    }
}
when HTTP_REQUEST_SEND {
    clientside {
        HTTP::respond 200 content "Client/Server SSL SNI = [string range $tls_sni_extension 9 end], Server SSL CNAMES = $cnames, Verification Result = $cname_valid" Content-Type "text/txt"
    }
}

Note: This is a PROOF OF CONCEPT code. DON'T use it in production environments without further testings. And by any means implement OneConnect to reduce the overhead of the iRule... ;-)

Cheers, Kai

1
Comments on this Answer
Comment made 03-Mar-2016 by Piotr Lewandowski 1162
I really appreciate your work to create this I rule. Probably not useful for this project (but you never know) but it's great to have it in my library. That is as well good base to play around with SSL in iRules - I am far from being experienced in this area. Piotr
0
Comment made 04-Mar-2016 by raduioncu 64
Very neat code - I hadn't considered the security part until now as for my specific case it wasn't a requirement.
0
Comment made 06-Mar-2016 by Kai Wilke 7392
@Piotr: The iRule can be used in your scenario to use SNI on the backend systems by using just a single Server SSL Profile with a custom or even the default CA-Bundle. It will reduce the Server Side configuration to a minimum. @Radu: You're welcome. The security should be garanteed now, but unfortunately its kind of a dirty hack to parse the SAN information out of the [X509::extensions] command. The performance is not ideal and future updates may require tweakes to the parsing code. A build in SAN field command analog to [X509::subject] would be really helpful in this specific case.. Cheers, Kai
1
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hi Piotr,

you have to use iRule to select different SNI enabled Server SSL Profiles (with appropiate "Server Name" fields) to support SNI on the web server level, or simply use a unified Server SSL Profile that would be valid for every website (e.g. using a fixed internal SSL certificate for every internal site).

You could also try to automate the SNI-enabled Server SSL profile selection by parsing the SNI value submitted by your client and then apply a custom logic to select the right SNI enabled Server SSL Profile on the fly within the SERVER_CONNECTED event. It should be somehow possible to do so, but I haven't digged into such a code yet... ;-)

Cheers, Kai

0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

Hey Radu,

your mentioned SNI-Relay logic is indeed a cool method to support Piotrs requirement without switching between multiple different Server_SSL_Profiles. Great hint and Kudo +1...;-)

when CLIENTSSL_HANDSHAKE {
    if { [SSL::extensions exists -type 0] } then {
        set tls_sni_extension [SSL::extensions -type 0]
    }
}
when SERVERSSL_CLIENTHELLO_SEND {
    if { [info exists tls_sni_extension] } then {
        SSL::extensions insert $tls_sni_extension
    }
}

Cheers, Kai

0
Comments on this Answer
Comment made 02-Mar-2016 by Kai Wilke 7392
Hmm... but how do we tell the Server SSL Profile the allowed CNAME values for the server side channel? I guess some added scripting would be required to make it secure.... :-(
0
Comment made 02-Mar-2016 by Piotr Lewandowski 1162
Hmm, but you mentioned that it's possible to switch serversssl profiles based on extracted SNI from client request, maybe it's easier? Piotr
0
Comment made 02-Mar-2016 by Kai Wilke 7392
Switching the Server_SSL_Profiles is indeed the "build-in" method to specify the server side SNI string, the CA-Combo and also the mandatory X509 CNAME/SAN value for each backend certificate. But after some experiments with Radu's approach it seesm that switching profiles is just one-of-different ways to relay SNI to the backend system... I'm currently just somewhat curious to see where the limits of this technique are... ;-) Note: I'm actually not sure if matching Server_SSL_Profiles based on SNI information is usefull for you. You've already told us in a different post, that you're going to use a dedicated pool for each backend application based on hostheader values. So parsing the selected pool name or hostheader should be much more stable to auto-select the right Server_SSL_Profile, isn't it?
0
Comment made 02-Mar-2016 by Piotr Lewandowski 1162
Hi, That's true, I was thinking about using pool names as a parameter to choose correct serverssl. If I rule is used for that do I have to have all serverssl profiles attached to VS or just configured? Anyway, my original question here was about if choosing correct profile is possible without iRule (like it is for clientssl and SNI) :-) obviously it is not possible :-(. Piotr
0
Comment made 03-Mar-2016 by Kai Wilke 7392
Hi Piotr, using the pool names or even an additional $variable of your choice would be a good approach, since those information are already set based on the received HOST-Header/URI and are therefor somewhat "trusted" (aka. provided by you). And yes you have to use iRules to switch between SSL Profiles, since LTM Policies don't support SSL Profile selection. In addition I doubt it will work to attach all of the Server SSL Profiles to your virtual server. It will most likely cause LTM to always negotiate just the Server SSL Profile with the highest priority (aka. using always the same SNI string). Cheers, Kai
0
Comment made 03-Mar-2016 by Piotr Lewandowski 1162
Hi, I wonder then why when you configure SNI for serverssl there is as well field Default SSL Profile for SNI? If the same profile is used every time then why this kind of fallback is available? In case of clientssl there is good reason - when SNI send by client do not match any Server Name in attached profiles use fallback one. So what about serverssl - help explanation is not really helpful - Specifies the default SSL profile to use for connecting to the back-end server. Client Hello sends Server Name configured in the default server profile to the back-end server. The same in description of Server Name in serverssl :-( Piotr
0
Comment made 03-Mar-2016 by Kai Wilke 7392
Hi Piotr, the "Default SSL Profile" is used for client SSL negotiation in the case the submited SNI does not match to any of your attached Client SSL Profiles (either by comparing the fixed "Server Name" value or by enumerating the attached SSL certificate CNAME/SAN values). For server SSL negotiation you have to configure the "Server Name" field, to send a fixed SNI value to your backend. If you leave the value empty, then no SNI value will be send to your backend systems. (Note: The description of the client/server profiles is slightly different. But indeed not that crystal clear...) Cheers, Kai
0
Comment made 03-Mar-2016 by Piotr Lewandowski 1162
Maybe I am nit picking but you have Default SSL Profile for SNI in serverssl - check it :-) Should I understand that it is there for no reason - so setting it changes nothing? Piotr
0
Comment made 03-Mar-2016 by Kai Wilke 7392
I guess, the setting is prefering the SNI value of the "Default Profile", when connecting to the backend system (in case you have more than one Server SSL Profile attached to your VS). Cheers, Kai
0
Comment made 04-Mar-2016 by Piotr Lewandowski 1162
Hi, I checked that it's possible to attach more than one serverssl profile only if one has at least checked Default SSL Profile for SNI (Server Name can be empty). In other case there is an error when updating VS. If LTM can't select serverssl profile to be used then what is the point of assigning more than one? This ability suggests that there is some mechanizm that is trying to choose appropriate serverssl for selected pool member - or I am missing something? Piotr
0
Comment made 06-Mar-2016 by Kai Wilke 7392
Yes its possible to attach more than one Server SSL Profile. But only god knows when this configuration would be required... at least it can't be used to magically decide which profile should be used for SNI. Honestly, I'm not aware of a single scenario that requires more than one Server SSL profile attached at the same time.. ;-) Cheers, Kai
0
placeholder+image
USER ACCEPTED ANSWER & F5 ACCEPTED ANSWER

To finish it up :-)

This question is quite clear explaining that without iRule correct serverssl is not selected by VS How can I configure Server SSL Profiles....

I am not sure but it seems that assigning multiple serverssl profiles allow iRule to select correct from assigned - so iRule can only select profile that is attached to VS - or it's not necessary?

Here is iRule:

when HTTP_REQUEST {
    set hostname [getfield [HTTP::host] ":" 1]
}

when SERVER_CONNECTED {
    switch -glob [string tolower [hostname]] {
        "site1.domain.uk" { SSL::profile site1.domain.uk-server }
        "site2.domain.uk" { SSL::profile site2.domain.uk-server }
    }
}

Piotr

0