For more information regarding the security incident at F5, the actions we are taking to address it, and our ongoing efforts to protect our customers, click here.

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 ">"]

    }
}
Published Nov 23, 2017
Version 1.0

6 Comments

  • 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?

     

  • C_Ang's avatar
    C_Ang
    Icon for Nimbostratus rankNimbostratus

    @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.

     

  • @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.

     

  • 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?

     

  • 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.

     

  • C_Ang's avatar
    C_Ang
    Icon for Nimbostratus rankNimbostratus

    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