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.

Minimalistic LDAP(S) proxy (via Simple-Bind) with Base-DN rewrite

Problem this snippet solves:

The outlined iRule can be used to access independent LDAP(S) instances behind a single Virtual Server using a single Base-DN.

The iRule, will forward LDAP(S) requests to an additional LDAP(S) pool, if the Simple-Bind user account name matches the

$static::other_domains
list.

The iRule would then translate the original Base-DN to the Base-DN matching the additional LDAP(S) instance.

Note1: The iRule doesn't adjust ASN.1/BER structures. So the original and changed Base-DN MUST have the same length. You may have to add SPACE paddings to allign the lenght of the Base-DNs.

Note2: The iRule wouldn't change the traffic for the default LDAP(S) instance. The traffic is passed through after the Simple-Bind request is completed.

Note3: The iRule would translates just the LDAP requests destined to the Base-DN of the additional LDAP(S) instance. The retrived results could then be accessed using their original DNs.

Cheers, Kai

How to use this snippet:

  • Setup a standard Virtual Server for TCP:636.
  • Apply SNAT and TCP profiles as needed.
  • Apply client and server side SSL profiles. The server side SSL profile has to support both instances.
  • Assign the default LDAP(S) instance as default_pool.
  • Tweak the RULE_INIT event to match your environment.

Code :

when RULE_INIT {

#
# Minimalistic LDAP(S) proxy (via Simple-Bind) with Base-DN rewrite
#

# Configuration of the other LDAP(S) instance username prefix/suffixes
set static::other_domains [list "itacs\\" "@itacs.de"];# List of lower case domain strings

# Configuration of the other LDAP(S) instance pool name
set static::other_ldaps_poolname OTHER_LDAPS_POOL_NAME;# Value of the other pool name

# Configuration of the Base-DN translation strings
#
# Important: The Base-DNs MUST have the same lenght.
#            You have to pad SPACES to match the length
#
binary scan "OU=xyz,DC=your-domain,DC=tld" H* temp(dn_default) ;# This is the default Base-DN
binary scan "OU=f5-team, DC=itacs,  DC=de" H* temp(dn_other);# This is the other Base-DN. Pad SPACES to match the length

set static::other_base_dn_map [list $temp(dn_default) $temp(dn_other)]
unset -nocomplain temp

}
when CLIENTSSL_HANDSHAKE {
# SSL session init
set session_binding_ldap 1
set session_other_active 0
# Collecting SSL data
SSL::collect
}
when CLIENTSSL_DATA {
if { $session_binding_ldap } then {
# Searching for simple Bind request to the other LDAP(S) instance 
set session_binding_ldap 0 
foreach temp(domain_string) $static::other_domains {
if { [string tolower [SSL::payload]] contains $temp(domain_string) } then {
# Forwarding the request to the other LDAP(S) instance 
set session_other_active 1
pool $static::other_ldaps_poolname
log -noname local0.debug "Bind request for other LDAP(S) instance detected. Forwarding the connection to pool [LB::server pool]"
break
}
}
if { $session_other_active == 0 } then {
# Forwarding the request to the default LDAP(S) instance
log -noname local0.debug "LDAPS request for default LDAP(S) instance detected. Forwarding the connection to pool [LB::server pool]"
# Releasing SSL data
SSL::release
unset -nocomplain temp
}
}
if { $session_other_active } then {
# Translating Base-DNs for the other LDAP(S) instance
binary scan [SSL::payload] H* temp(hex_ssl_payload)
set temp(new_ssl_payload) [binary format H* [string map $static::other_base_dn_map $temp(hex_ssl_payload)]]
SSL::payload replace 0 [string length [SSL::payload]] $temp(new_ssl_payload)
# Releasing SSL data
SSL::release
# Collecting further SSL data
SSL::collect
unset -nocomplain temp
}
}

Tested this on version:

12.0
Updated Jun 06, 2023
Version 2.0
No CommentsBe the first to comment