Forum Discussion

CREDCO_17916's avatar
CREDCO_17916
Icon for Nimbostratus rankNimbostratus
Apr 07, 2008

HTTPS URI re-direct and client certs

Hi,

 

 

I'm trying to create an iRule that parses a URI and sends the request to 1 of 2 pools based on the URI. Very straight forward. The first URI listed below requires a Client Cert. The second one does not.

 

 

1. /cc/listener - Send to pool 1 ** Requires Client Cert

 

2. /cc/secondaryuse - Send to pool 2

 

 

Here is the iRule I'm using:

 

 

when HTTP_REQUEST {

 

if { [HTTP::uri] contains "secondaryuse"} {

 

pool CCJAVABETA_EM_TEST

 

} else {

 

pool CCJAVABETA_TEST

 

}

 

}

 

 

Without client certs enabled the iRule works as expected. As soon as I enforce Client Certs in IIS for URI 1 , I start getting 404's when I hit URI 1. I do not get a 403.7 "The Page Requires a Client Certificate" error page that I would expect to see.

 

 

Here are some options I have enabled on the Virtual Server:

 

- Http profile - "http" (the default http profile)

 

- SSL Profile (client) - "clientssl"

 

- SSL Profile (server) - "serverssl"

 

 

Do I need to use a separate iRule to handle the Client Certs? Is there a setting on the BigIP that I'm missing? This seems like a very simple and common configuration, so I'm sure I'm forgetting something stupid. Any help would be appreciated.

 

 

Thanks

 

 

7 Replies

  • Hello,

     

     

    Are you wanting the client to present a cert on the client - VIP connection? Or do you want the BIG-IP to use the same client cert regardless of what the client includes in it's request?

     

     

    If the former, you can use a client SSL profile with client cert set to request or require. You can use an iRule to parse the client cert and insert it into an HTTP header. You need to add an HTTP profile in order to insert an HTTP header using an iRule. The application would parse this HTTP header to determine whether the request is valid. There is an example of the iRule in the Codeshare (Click here). If you want to do validation of the client cert in a rule, you can start with this example (Click here).

     

     

    If you want to have the BIG-IP use a single client cert in all requests made to the pool, you can configure this in a server SSL profile. For details on this, check the LTM configuration guide for your version on AskF5.com.

     

     

    Aaron
  • Thanks for the info. Since only one of my URI's requires a CC, it seems like I'll need to:

     

    1. Check URI to see if its the one that requires a CC

     

    2. If it is the URI that requires a CC, pull the SSL info out of the cert and insert it into the HTTP header, and send it to POOLA

     

    3. If it's not a URI that requires a CC, send the request directly to POOLB without doing anything with SSL

     

     

    I'm a total iRule rookie, so please bear with me. Here's my first stab at combining the 2 examples you sent me:

     

     

    when CLIENTSSL_CLIENTCERT {

     

    set time to maintain session data (in seconds)

     

    set session_timeout 300

     

     

    set ssl_stuff [list anything1 anything2]

     

    set ssl_cert [SSL::cert 0]

     

    set ssl_errstr [X509::verify_cert_error_string [SSL::verify_result]]

     

    lset ssl_stuff 0 $ssl_cert

     

    lset ssl_stuff 1 $ssl_errstr

     

    session add ssl [SSL::sessionid] $ssl_stuff $session_timeout

     

    }

     

     

    when HTTP_REQUEST {

     

    if { [HTTP::uri] starts_with "/companyA" } {

     

    set ssl_stuff2 [session lookup ssl [SSL::sessionid]]

     

    set ssl_cert2 [lindex $ssl_stuff2 0]

     

    set ssl_errstr2 [lindex $ssl_stuff2 1]

     

    if { $ssl_errstr2 eq "ok" } {

     

    HTTP::header insert SSLClientCertStatus $ssl_errstr2

     

    HTTP::header insert SSLClientCertSN [X509::serial_number $ssl_cert2]

     

    pool POOLA

     

    } else {

     

    send HTTP 302 redirect to an error page

     

    HTTP::redirect "http://192.168.0.64/error.html"

     

    }

     

    } else {

     

    pool POOLB

     

    }

     

    }

     

     

    Am I even close?

     

     

    Thank you
  • Hi,

     

     

    This still isn't working for me. At this point all I'm trying to do is put the SSL information into the persistence table. However when I hit the VIP that this iRule is assigned to, I get this in the LTM log. I've imported my CA onto the BigIP, I assigned that CA to the ClientSSL profile that I configured for the Virtual Server, and from the logs below it looks like BigIP is decrypting the client cert and extracting the SSL ID. But it still doesn't like something about the last line in the iRule where I'm trying to enter the SSL info into the persistence table. It appears to me that it doesn't think the "when CLIENTSSL_CLIENTCERT" condition is true, at least that's how I interpret the error.

     

     

    Apr 10 16:41:46 tmm tmm[943]: Rule CC_2 : ===========================

     

    Apr 10 16:41:46 tmm tmm[943]: Rule CC_2 : <>

     

    Apr 10 16:41:46 tmm tmm[943]: Rule CC_2 : The timeout is set to: 300

     

    Apr 10 16:41:46 tmm tmm[943]: Rule CC_2 : SSL Error is: ok

     

    Apr 10 16:41:46 tmm tmm[943]: Rule CC_2 : SSL ID is: 55b2a9a2a30217fe6af49fdf555090099da4be966027c74a515c2b0fbee2dd68

     

    Apr 10 16:41:46 tmm tmm[943]: 01220001:3: TCL error: Rule CC_2 - Prerequisite operation not in progress (line 1) invoked from within "session add ssl [SSL::sessionid] $ssl_stuff $session_timeout"

     

     

    when CLIENTSSL_CLIENTCERT {

     

    log local0. "==========================="

     

    log local0. "<>"

     

    set time to maintain session data (in seconds)

     

    set session_timeout 300

     

    set ssl_stuff [list anything1 anything2]

     

    set ssl_cert [SSL::cert 0]

     

    set ssl_errstr [X509::verify_cert_error_string [SSL::verify_result]]

     

    set ssl_id [SSL::sessionid]

     

    log local0. "SSL Error is: $ssl_errstr"

     

    lset ssl_stuff 0 $ssl_cert

     

    lset ssl_stuff 1 $ssl_errstr

     

    log local0. "SSL ID is: $ssl_id"

     

    session add ssl [SSL::sessionid] $ssl_stuff $session_timeout

     

    }

     

     

    when HTTP_REQUEST {

     

    set ssl_stuff2 [session lookup ssl [SSL::sessionid]]

     

    set ssl_cert2 [lindex $ssl_stuff2 0]

     

    set ssl_errstr2 [lindex $ssl_stuff2 1]

     

     

    log local0. "HTTP_REQUEST: SSLStuff: $ssl_stuff2"

     

    log local0. "HTTP_REQUEST: SSLCert: $ssl_cert2"

     

    log local0. "HTTP_REQUEST: SSLErrStr: $ssl_errstr2"

     

    if { $ssl_errstr2 eq "ok" } {

     

    our stuff

     

    } else {

     

    log local0. "HTTP_REQUEST: SSLErrStr2 not OK: $ssl_errstr2"

     

    }

     

     

    }

     

     

    I know this iRule isn't very exciting, but I would definitely appreciate any help you could provide.

     

     

    thank you
  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    I realize that it's not intuitive, but the most common cause of the "Prerequisite operation not in progress" error from the session or persist commands is not having a default pool assigned to the VIP that this iRule is assigned to. Do you have a default pool assigned? If not, try adding it.
  • Thanks for the info.

     

     

    I did try naming a default pool, but still no luck. You think I need a default pool even though I'm parsing the URI and choosing a pool within my iRule? When I hit the Virtual in my browser, I don't get any error (404, 403.7 Client Cert required, etc), however in my IIS logs I do see 403.7 errors. As you can see I've added all sorts of logging, and all the variable values seem to be OK as I'm watching the LTM log. I wonder if I'm not inserting all the necessary data into the HTTP headers.

     

     

    when CLIENTSSL_CLIENTCERT {

     

    log local0. "==========================="

     

    log local0. "<>"

     

    set time to maintain session data (in seconds)

     

    set session_timeout 300

     

    set ssl_stuff [list anything1 anything2]

     

    set ssl_cert [SSL::cert 0]

     

    set ssl_errstr [X509::verify_cert_error_string [SSL::verify_result]]

     

    set ssl_id [SSL::sessionid]

     

    set subject_dn [X509::subject [SSL::cert 0]]

     

    log local0. "SSL Error is: $ssl_errstr"

     

    lset ssl_stuff 0 $ssl_cert

     

    lset ssl_stuff 1 $ssl_errstr

     

    log local0. "SSL ID is: $ssl_id"

     

    log local0. "The timeout is set to: $session_timeout"

     

    log local0. "Client cert received: $subject_dn"

     

    session add ssl $ssl_id $ssl_stuff $session_timeout

     

    log local0. "SSL Cert ID is $ssl_cert"

     

    log local0. "SSL Stuff is $ssl_stuff"

     

    log local0. "SSL errstr is $ssl_errstr"

     

    }

     

     

    when HTTP_REQUEST {

     

    Retrieve certificate information from the session

     

    set sslList [session lookup ssl [SSL::sessionid]]

     

    set issuer [lindex sslList 0]

     

    set subject [lindex sslList 1]

     

    set version [lindex sslList 2]

     

    log local0. "Value of ssllist is $sslList"

     

    if { [HTTP::uri] contains "listener" } {

     

    set ssl_stuff2 [session lookup ssl [SSL::sessionid]]

     

    set ssl_cert2 [lindex $ssl_stuff2 0]

     

    set ssl_errstr2 [lindex $ssl_stuff2 1]

     

    log local0. "URI value is [HTTP::uri]"

     

    log local0. "Value of ssl_errstr2 is $ssl_errstr2"

     

    log local0. "Value of SSL Cert2 is $ssl_cert2"

     

    HTTP::header insert SSLClientCertStatus $ssl_errstr2

     

    HTTP::header insert SSLClientCertSN [X509::serial_number $ssl_cert2]

     

    pool CCJAVABETA_TEST

     

    log local0. "HTTP headers have been inserted"

     

    } elseif { [HTTP::uri] contains "secondaryuse" } {

     

    pool CCJAVABETA_EM_TEST

     

    }

     

    }
  • spark_86682's avatar
    spark_86682
    Historic F5 Account
    Sorry for not getting back sooner.

     

     

    I didn't expect adding a default pool to completely solve your problem, no, but I did/do expect it to eliminate the "Prerequisite operation not in progress" error. I have no expertise in SSL or IIS, so I can't help you debug why your LTM<->server connection isn't functioning correctly; sorry. Note that there's no way for the LTM to actually use the client cert on the serverside connection (as that would require the client private key, which the LTM doesn't have), so if your IIS server is setup to require them then that may be why it's giving you a 403.7 error. My only recommendation would be to use ssldump and try to figure out what IIS really wants.

     

     

    Good luck!
  • I was suggesting that you can configure a server ssl profile to present a single client cert (one that you import into the BIG-IP configuration--not the one that the client for the specific client request presented). Ideally, the app could be changed to not require a client cert, but instead parse the client cert that the BIG-IP inserts in the HTTP header.

     

     

    Aaron