APM Clientless certificate authentication
Problem this snippet solves:
This code allow to configure certificate authentication with APM clientless-mode support.
The APM behavior when configuring following condition is to disable clientless-mode :
- APM clientless-mode in irule
- On-Demand Cert Auth in VPE
This code enable clientless mode if required based.
PS : this code use a list instead of a simple variable to be included in APM Sharepoint authentication code without changes.
How to use this snippet:
Edit the first HTTP_REQUEST event and add condition for enabling certificate authentication.
Code :
when HTTP_REQUEST {
set AUTHENTICATION_MODE {certificate}
#set AUTHENTICATION_MODE {none}
}
priority 900
when CLIENTSSL_CLIENTCERT {
if {[SSL::cert count] < 1}{
reject
} else {
HTTP::release
}
}
when HTTP_REQUEST {
if { ( [set apm_sessionid [HTTP::cookie value "MRHSession"]] ne "" ) and ( [ACCESS::session exists -state_allow $apm_sessionid] ) } then {
# Allow the successfully pre authenticated request to pass
return
}
# Check authentication mode selected in previous HTTP_REQUEST event
if {[lindex $AUTHENTICATION_MODE 0] equals "certificate"} {
if { [SSL::cert count] <= 0 } {
# if there is no client certificate hold the HTTP request till the SSL re-negotiation is done.
HTTP::header insert "clientless-mode" 1
HTTP::collect
SSL::session invalidate
SSL::authenticate always
SSL::authenticate depth 9
SSL::cert mode require
SSL::renegotiate
} elseif {[info exists sessionid]} {
# the previous HTTP request in the same TCP connection is already authenticated and session cookie is missing, Insert MRHSession
HTTP::cookie insert name MRHSession value $apm_sessionid
} else {
# SSL client is already authenticated, but Access session not evaluated. enable clientless mode
HTTP::header insert "clientless-mode" 1
}
}
}
when ACCESS_SESSION_STARTED {
# catch session ID for next requests in the same TCP connection
set apm_sessionid [ACCESS::session sid]
# extract CN from subject and set in session.logon.last.username variable
if {[lindex $AUTHENTICATION_MODE 0] equals "certificate"} {
# Allow comma and = to be included in subject. remove space at the end or beginning of strings.
set subject [ split [string map {"\\," "," " , " "|" ", " "|" " ," "|" "," "|" "\\=" "=" " = " "|" "= " "|" " =" "|" "=" "|"} [X509::subject [SSL::cert 0]]] "|"];
array set subject_list $subject
if {[info exists subject_list(CN)]} {
ACCESS::session data set session.logon.last.cn $subject_list(CN)
ACCESS::session data set session.logon.last.username $subject_list(CN)
ACCESS::session data set session.logon.last.logonname $subject_list(CN)
}
ACCESS::session data set session.logon.last.upn [findstr [ACCESS::session data get session.ssl.cert.x509extension] "othername:UPN<" 14 ">"]
}
}6 Comments
- C_Ang
Nimbostratus
Hi Stanislas,
I have a situation that might be able to use this, but we do have an On-Demand Certificate Authentication in our APM policy. We now have a requirement to connect to this VIP on a specific URL for a SOAP-based web service. Unfortunately, the POST method with the SOAP payload is encountering the 302 redirects to /my.policy. By the time it gets to back to the original SOAP endpoint, the request has become a GET and the payload is no longer being transmitted.
Also, we are trying to do this with mutual TLS, but because of the On-Demand Certificate Authentication, the client certificate is not requested until at least the 3rd redirect (the one with my.policy?nonce=?????). Is there no way around this?
Thanks in advance for any direction you might be able to point me towards,
Charlie
- Stanislas_Piro2
Cumulonimbus
This code usage is to not add a On-Demand Certificate Authentication box but only a Client Cert Inspection box. This irule manage the certificate request.
If you add a On-Demand Certificate Authentication box, it breaks the clientless mode.
- jkreyes_313300
Nimbostratus
Thanks. What if you just want to allow this for specific users? For example, allow a certain Common Name based on the client certificate supplied?
- Stanislas_Piro2
Cumulonimbus
@jkreyes : This code manage clientless authentication for APM and import CN in session.logon.last.cn variable.
you can filter in APM based on this variable.
- C_Ang
Nimbostratus
@stanislas. Thank you for the clarification. I am a little late getting back to you, but our F5 folks decided it was too clunky to squeeze both use-cases (requiring on-demand client cert and MTLS for web services) onto the same Virtual Server. So we are going with an HAProxy or a separate VIP.
- antec42
Altostratus
Picking up an old thread here maybe, but I have a use case for this but I also need to split the VIP into a layered VS.
I do the SSL stuff in the terminating LTM Vs and the APM part in the second Vs (to which I pass the traffic with the "virtual <apm_vs>" line in the LTM Vs. The reason for this is that I need to alter some responses that I do not see from APM if they are on the same Vs.
Anyway, when I'm doing this the SSL gets terminated on the LTM vs and I can not do the certificate checks in APM as I normally could. I'm trying a solution where I pass the client certificate on to APM by inserting it as a header into the HTTP traffic on the LTM vs, so that I could pick it up on the APM vs. It works to some extent (I can pass CN, Subject string etc properly) but when I try to pass the whole "[X509::whole [SSL::cert 0]]" and insert it with ACCESS::session data set session.ssl.cert.whole it fails. The set command seems to truncate the certificate or can not handle certain characters in the PEM cert. Does anyone has a clue to what I can do?