iRules: Insert client certificate into HTTP Header

This iRule should be used when the back end server requires to see the client certificate presented to a VIP where SSL is being terminated and client authentication is being enforced. This iRule will do the following:

  • Check for existing HTTP Headers such as X-Forwarded-For and ssl.client_cert and remove them
  • Grab the client certificate and strip out any spaces or new lines
  • Insert the trimmed down client certificate into the HTTP Header ssl.client_cert
  • Insert the HTTP Header X-Forwarded-For with the client IP address
when HTTP_REQUEST {
	if { [HTTP::header exists "X-Forwarded-For"]} {
		HTTP::header remove X-Forwarded-For
		}
	if { [HTTP::header exists "ssl.client_cert"]} {
		HTTP::header remove ssl.client_cert
		}
	if { [SSL::cert count] > 0 } {
		set thecert [findstr [X509::whole [SSL::cert 0]] "-----BEGIN CERTIFICATE-----" 28 "-----END CERTIFICATE-----"]
		set certnospace [string map -nocase {" " "" \n "" \r ""} $thecert] 						  		
		HTTP::header insert ssl.client_cert $certnospace
		HTTP::header insert X-Forwarded-For [IP::client_addr]
	}
}

You may download a text version of the iRule here.

Regards,

BD

iRules: IP Reputation based on X-Forwarded-For HTTP Header

Recently I had a customer that wanted to use the IP Reputation Database on the F5 WAF however the client IP address was being proxied by an upstream device. Luckily for us, the client IP address was being sent in the X-Forwaded-For HTTP Header and we were able to hone in on that information and apply the IP Reputation logic via iRules.

The example below allows you to extract the client IP address from the X-Forwarded-For HTTP Header, check the IP Reputation Database, and either silently drop the traffic or respond with HTTP content.

when HTTP_REQUEST {
    # LOGGING OFF=0, LOGGING ON=1
    set DEBUG_LEVEL 1
    # SLIENT DROP BAD TRAFFIC=0, FRIENDLY DROP BAD TRAFFIC=1
    set BAD_ACTOR 1
    # Make sure XFF is present and the IP matches IPI
    if { ([HTTP::header exists "X-Forwarded-For"]) and not ( [IP::reputation [HTTP::header values "X-Forwarded-For"]] =="") } {
        set ip_reputation_categories [IP::reputation [HTTP::header values "X-Forwarded-For"]]
        set is_reject 0
        switch -glob $ip_reputation_categories {
            *Spam* { set is_reject 1  }
            *Proxy* { set is_reject 1 }
            *Denial* { set is_reject 1 }
            *Attacks* { set is_reject 1 }
            *Botnets* { set is_reject 1 }
            *Scanners* { set is_reject 1 }
            *Exploits* { set is_reject 1 }

        }
        if { ($is_reject)} {
            if { $BAD_ACTOR == "1"}{
                if { $DEBUG_LEVEL == 1} { log local0. "XFF:[HTTP::header values "X-Forwarded-For"] matched IPI Category:$ip_reputation_categories and was rejected with a page."}
                HTTP::respond 403 content "
                <HTML>
                <HEAD>
                <TITLE>Rejected Request</TITLE>
                </HEAD>
                <BODY>The request was rejected. <BR>Attempted access from malicious IP address</BODY>
                </HTML>"
                return
            }
            if { $BAD_ACTOR == "0"} {
                if { $DEBUG_LEVEL == 1} { log local0. "XFF:[HTTP::header values "X-Forwarded-For"] matched IPI Category:$ip_reputation_categories and was sliently dropped."}
                drop
                return
                }
            }
        }
        if { [HTTP::header exists "X-Forwarded-For"] } {
            if { $DEBUG_LEVEL == 1} {log local0. "XFF:[HTTP::header values "X-Forwarded-For"] and did not match any categories"}
            return
        }
    if { $DEBUG_LEVEL == 1} {log local0. "No XFF Sent and nothing was dropped"} 
}

You may also download a txt version of the iRule here.

Note: You can replace X-Forwarded-For to any HTTP Header that contains the client IP address, e.g, true-client-ip.

Regards,

BD

iRules: Dynamic load balancing via URI

The purpose of this iRule is to create a method of load balancing via the URI that is fully dynamic and never requires updating. Example: The URL https://briandeitch.com/gateway/ should be load balanced to the pool pool_gateway The URL https://briandeitch.com/pictures/ should be load balanced to the pool pool_pictures Here is the old iRule:

when HTTP_REQUEST {
      switch -glob [string tolower [HTTP::path]]
          */gateway/ { pool pool_gateway }
          */pictures/ { pool pool_gateway }
     }
}

In the past, every time I had a new URL, I would have to modify the iRule and create the new pool. If I need to add https://briandeitch.com/family/, I would have to modify the iRule:

when HTTP_REQUEST {
      switch -glob [string tolower [HTTP::path]]
          */gateway/* { pool pool_gateway }
          */pictures/* { pool pool_gateway }
          */family/* { pool pool_family }
     }
}

By using the iRule below, pool selection will happen automatically based on the URI.

when HTTP_REQUEST {
     # Grab the 1st folder after the hostname
     set lbfolder [string tolower [URI::path [HTTP::uri] 1 1]]
     # Strip out the "/"
     set lbfolder pool_[string trim $lbfolder "/"]
     # log local0. "testing01 $lbfolder"
if { [catch {pool $lbfolder} exc] } {
     # If a client sends a uri that does not match a pool, send to default pool or throw message
     #pool default
HTTP::respond 200 content "No matching pool for that URI"
persist cookie insert pr_cookie_insert
}
}

By using this iRule, I will never have to update the iRule again. Once I add the new pool, I’m done.

You may also download a txt version of the iRule here.

Regards,

BD