SSL Orchestrator Use Case: Inbound SNI Switching

Introduction

SSLO will generate a single set of SSL profiles for use in a topology. It may be useful, especially in an inbound gateway mode, to process traffic to multiple sites, requiring different server certificates. The use case is to employ native BIG-IP SNI switching in SSLO, such that an SSLO topology can select a correct client SSL profile and server certificate based on the incoming SNI.

In this example we have a single web server with multiple IP addresses hosting different web site domains:

en.appserverone.com resides on 10.1.10.90

en.appservertwo.com resides on 10.1.10.91

When an external client requests https://en.appserverone.com we want the SSL Orchestrator to use a specific keypair for the sessions and direct the traffic to 10.1.10.90. When an external client requests https://en.appservertwo.com we want the SSL Orchestrator to use a different keypair for the sessions and direct the traffic to 10.1.10.91.

Configuration Steps

Import Private Keys and Certificates

Create Client SSL Profiles

Create a String Data Group*

Import iRules

Attach iRule to existing Topology

Attach iRule to Existing Application Topology

Attach iRule to existing Topology Interception Rule (alternative)

*Note: You can either use an iRule and Data Group to match SNI to a Profile, or a static SNI-to-profile mapping in an iRule. The advantage of using a Data Group is all management is done at the Data Group.

Import the Private Key and Certificate for the different web site domains

From the BIG-IP Configuration Utility go to SSL Orchestrator > Certificates Management > Certificates and Keys.

Click Import on the right.

For the Import Type select Key.

Give it a name, en.appserverone.com in this example. For the Key Source you can upload a file or paste in the text. We’ll use the Paste option which you can see below. Click Import when done.

Click on the Key Name created in the previous step.

Click Import.

For the Certificate Source you can upload a file or paste in the text. We’ll use the Paste option which you can see below. Click Import when done.

Repeat these steps for other web site domains. In this example we will add one more, en.appservertwo.com as you can see below.

Create a Client SSL Profile for each certificate/key pair

From the BIG-IP Configuration Utility go to SSL Orchestrator > Components > Profiles > Client SSL.

Click Create on the right.

Give it a name, en.appserverone.com in this example. Select the Custom box on the far right then click Add for the Certificate Key Chain.

Select the Certificate and Key created previously and click Add. A Passphrase and Chain can be specified if needed. Click Add when done.

Select the Advanced option next to Configuration.

Scroll down and find the Server Name field. Enter the FQDN that external clients will request, en.appserverone.com in this example.

Note: when an external client requests https://en.appserverone.com their TLS Client Hello will contain an extension value for ‘server_name’ field with a value of ‘en.appserverone.com’. We’re instructing SSL Orchestrator to use this Client SSL Profile when it receives this type of request from a client.

Scroll to the bottom and click Finished when done. 

Repeat these steps for other web site domains. In this example we will add one more, en.appservertwo.com as you can see below.

Create a String Data Group that maps the SNI to the Client SSL Profile. 

This step is only required if using the ‘in-t-rule-datagroup’ iRule.

From the BIG-IP Configuration Utility go to Local Traffic > iRules > Data Group List.

Click Create over on the right.

Give it a name, SNI_switcher in this example and select String next to Type.

Create a String that maps the SNI to the Client SSL Profile name created previously. Click Add.

Note: If creating these profiles in other partitions, or if the VIP runs in another partition, it’s useful to prepend the partition name to avoid confusion. So, in this case, the client SSL profile would be:

/Common/en.appserverone.com

Repeat this step for as many mappings as you require. We’re doing two in this example and it should look like the following. Click Finished when done.

Import iRules

We will create two iRules from the following

1.    library-rule: This rule is required. The next two iRules will make calls to the Library iRule to check the TCP payload for the ‘server_name’ field in the TLS Client Hello.

2.    in-t-rule-datagroup: This iRule depends upon a ‘Data Group’ to map the SNI to the Client SSL Profile

3.    in-t-rule-static: This is a static iRule does not depend upon a ‘Data Group’. This iRule contains the mapping of theSNI(s) to the Client SSL Profile(s)

Note: Rules 2 and 3 perform the same function in a slightly different manner. We will cover both options but you can pick whichever one you want to use.

Note: Using a data group or static iRule to switch the client SSL profile, requires a binary-scanning TCP iRule that may have an impact on performance

Click Create over on the Right.

Give it the name library-rule

Copy and paste the following into the Definition field:

proc getSNI { payload } {
    set detect_handshake 1

    binary scan ${payload} H* orig
    if { [binary scan [TCP::payload] cSS tls_xacttype tls_version tls_recordlen] < 3 } {
        reject
        return
    }

    ## 768 SSLv3.0
    ## 769 TLSv1.0
    ## 770 TLSv1.1
    ## 771 TLSv1.2
    switch $tls_version {
        "769" -
        "770" -
        "771" {
            if { ($tls_xacttype == 22) } {
                binary scan ${payload} @5c tls_action
                if { not (($tls_action == 1) && ([string length ${payload}] > $tls_recordlen)) } {
                    set detect_handshake 0
                }
            }
        }
        "768" {
            set detect_handshake 0
        }
        default {
            set detect_handshake 0
        }
    }

    if { ($detect_handshake) } {
        ## skip past the session id
        set record_offset 43
        binary scan ${payload} @${record_offset}c tls_sessidlen
        set record_offset [expr {$record_offset + 1 + $tls_sessidlen}]

        ## skip past the cipher list
        binary scan ${payload} @${record_offset}S tls_ciphlen
        set record_offset [expr {$record_offset + 2 + $tls_ciphlen}]

        ## skip past the compression list
        binary scan ${payload} @${record_offset}c tls_complen
        set record_offset [expr {$record_offset + 1 + $tls_complen}]

        ## check for the existence of ssl extensions
        if { ([string length ${payload}] > $record_offset) } {
            ## skip to the start of the first extension
            binary scan ${payload} @${record_offset}S tls_extenlen
            set record_offset [expr {$record_offset + 2}]
            ## read all the extensions into a variable
            binary scan ${payload} @${record_offset}a* tls_extensions

            ## for each extension
            for { set ext_offset 0 } { $ext_offset < $tls_extenlen } { incr ext_offset 4 } {
                binary scan $tls_extensions @${ext_offset}SS etype elen
                if { ($etype == 0) } {
                    ## if it's a servername extension read the servername
                    set grabstart [expr {$ext_offset + 9}]
                    set grabend [expr {$elen - 5}]
                    binary scan $tls_extensions @${grabstart}A${grabend} tls_servername_orig
                    set tls_servername [string tolower ${tls_servername_orig}]
                    set ext_offset [expr {$ext_offset + $elen}]
                    break
                } else {
                    ## skip over other extensions
                    set ext_offset [expr {$ext_offset + $elen}]
                }
            }
        }
    }

    if { ![info exists tls_servername] } {
        ## This isn't TLS so we can't decrypt it anyway
        return "null"
    } else {
        return ${tls_servername}
    }
    TCP::release
  }

Click Finished when Done

From the BIG-IP Configuration Utility go to Local Traffic > iRules > iRule List.

Click Create over on the Right.

Give it a name, in-t-rule-datagroup in this example. Copy and paste the following into the Definition field:

## SSLO SNI Switching Rule
## Date: July 2020
## Purpose: Useful in SSLO versions 8.x and below to switch the client SSL profile based on ClientHello SNI
##      in inbound SSLO topologies. This would be practical for L3 inbound gateway mode or L2 inbound topologies.
## Instructions:
##      - Import server certificates and private keys
##      - Create a separate client SSL profile for each cert/key pair
##      - Create a string data group that maps the SNI to the client SSL profile name (ex. test0.f5labs.com := test0-clientssl)
##      - Add the library-rule iRule to LTM (name "library-rule")
##      - Add the SNI-switching-rule to LTM (name is arbitrary)
##      - Create an L3 inbound gateway mode SSLO topology. Define a server cert/key to be used as the "default" (when no SNI matches)
##      - Edit the L3 inbound Interception Rule and add the SNI switching rule. Deploy and test.

when CLIENT_ACCEPTED priority 250 {
    TCP::collect
}
when CLIENT_DATA priority 250 {
    ## call the external procedure
    set sni [call library-rule::getSNI [TCP::payload]]

    ## lookup SSL profile in data group
    set sslprofile [class lookup ${sni} sni-switching-dg]

    if { ${sslprofile} ne "" } {
        set cmd "SSL::profile /Common/${sslprofile}" ; eval $cmd
    }
    TCP::release
}

Click Finished when done.

Click Create over on the Right.

Give it a name, in-t-rule-static in this example. Copy and paste the following into the Definition field:

when CLIENT_ACCEPTED priority 250 {
    TCP::collect
}
when CLIENT_DATA priority 250 {
    ## call the external procedure
    set sni [call library-rule::getSNI [TCP::payload]]   

    switch [string tolower ${sni}] {
        "en.appserverone.com" {
            set cmd1 "SSL::profile /Common/en.appserverone.com" ; eval $cmd1
        }
        "en.appservertwo.com" {
            set cmd2 "SSL::profile /Common/en.appservertwo.com" ; eval $cmd2
        }
    }
    TCP::release
}

Note: this iRule requires customization. The items in Blue are the Server Names that external clients will request. The items above in Red are the names of the Client SSL Profiles created previously.

Click Finished when done

Attach iRule to existing Inbound Topology

If you have an existing Topology you can attach the iRule to that Topology. To do this you will need to disable Strictness on the Topology. From the BIG-IP Configuration Utility select SSL Orchestrator > Configuration. Click the padlock on the right to Unprotect the Configuration.

Click OK when presented with the following message.

Note: Disabling Strictness on the Topology is needed to modify it and add multiple client-ssl profiles.

Select Local Traffic > Virtual Servers. Click the name of your Topology, sslo_Inbound_Topology in this example.

Scroll down to the SSL Profile (Client). Add the SSL Profiles created previously, 10.1.10.90 and 10.1.10.91 in this example. You also need a default SNI SSL Profile in case no SNI matches. We’re using clientssl in this example. Your screen should look similar to the following.

Click Update at the bottom when done.

Select Resources so we can attach the iRule.

In the iRule section select Manage.

Locate the iRule in the Available field. Select the one you want to use, in-t-rule-static in this example, then click the << to move it to Enabled. Click Finished when done.

The configuration is now complete. When external clients request en.appserverone.com or en.appservertwo.com the correct Client SSL profile will be used. 

Existing Application Topology

SSL Orchestrator manages the services and service policies for existing applications while an existing ADC application manages its own SSL settings and application delivery, consuming the SSL Orchestrator service policy information. The Existing Application topology is available for SSL Orchestrator addon licensed devices.

·     Traffic flows into the BIG-IP. (This is configured outside of this topology.)

·     Traffic is decrypted and sent to security devices.

·     Traffic is re-encrypted and sent out to the applications. (This is configured outside of this flow.) 

From the BIG-IP Configuration Utility select SSL Orchestrator > Configuration.

Scroll down and click Next.

Give it a name, Inbound in this example. Choose the Existing Application option and click Save & Next.

On the Services List screen you can Add Services now or do so later. In this example we’ll have a Generic L3 Inline Service. Click Save & Next.

On the Services Chain List screen you can Add or Edit a Service Chain. In this example it’s named ServiceChain. Click Save & Next.

On the Security Policy screen click the pencil icon on the right to edit the Rule.

Select the Service Chain and click OK.

Click Save & Next.

Review the configuration summary and make any changes as needed. Otherwise click Deploy.

Add iRule and SSL Profiles to the Virtual Server

From the BIG-IP Configuration Utility select Local Traffic > Virtual Servers. Click the name of the Virtual Server you want to configure, SNI in this example.

Scroll down to the SSL Profile (Client) section. Highlight the SSL Profiles created previously and click << to move them to Selected.

Scroll to the bottom and click Update.

Select Resources to attach the iRule.

Click Manage to the right of iRules.

Select the iRule you want to use, in-t-rule-static in this example. Click << to move it to Enabled. Click Finished.

The configuration is now complete.

Attach iRule to existing Topology Interception Rule (alternative)

Assign an iRule to the Interception Rule

·     This incurs a performance hit without the SSL profiles attached to a VIP, but doesn’t require default-for-sni to be configured and does not require Strictness to be disabled on the Topology.

From the BIG-IP Configuration Utility select SSL Orchestrator > Configuration.

Select Interception Rules then click on the name of your Interception Rule, sslo_Inbound_App in this example.

Click the pencil icon to edit the rule.

Scroll down until you get to the section on iRules. Select the iRule you want to use, in-t-rule-static in this example and click the arrow to move it to Selected.

Click Save & Next at the bottom.

Click Deploy to complete the configuration.

The configuration is now complete.

Published Feb 17, 2021
Version 1.0
  • Thanks for sharing.I found a lot of interesting information here. A really good post, very thankful and hopeful that you will write many more posts like this one.

     

  • Thanks for the update and quick reply. I'll be sure to keep an eye on this thread.  Looking for the same issue. Bumped into your thread. Thanks for creating it. Looking forward for solution.

     

     

  • thanks for the articel! Am I right that TLSv1.3 needs tls_version 772 in the library switch?

  • Yes, I believe that is correct. Give me a day or so and I'll have an updated iRule to share.

  • Hi Torti, I got an update on this from an expert and here's what he had to say:

    So as it turns out, the answer to Torti’s question is ‘no’. The ‘cSS’ binary scan flags are only looking at the outer layer of the TLS packet, and this is ALWAYS 1.0 (769). To get to the inner/actual TLS version you have to add a few more binary scan flags. But that’s not important for fetching the Server Name Indication extension. Plus, TLS 1.3 identifies itself in the TLS extensions, so a TLS 1.3 handshake will have 1.0 as the outer version (same as the others), and 1.2 as the inner version (for backward compatibility). 

     

    Otherwise, this iRule works natively for TLS 1.3 as long as encrypted client hello (ECH) isn’t enabled.