Forum Discussion
CREDCO_17916
Nimbostratus
Apr 07, 2008HTTPS 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
- hoolio
Cirrostratus
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 - CREDCO_17916
Nimbostratus
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 - CREDCO_17916
Nimbostratus
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_86682Historic F5 AccountI 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.
- CREDCO_17916
Nimbostratus
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_86682Historic F5 AccountSorry 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! - hoolio
Cirrostratus
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
Help guide the future of your DevCentral Community!
What tools do you use to collaborate? (1min - anonymous)Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects