Am I being overly repetitive?
Hey folks,
I've been asked to put together an iRule to support a multi-tenancy initiative. This iRule is intended to sit on a public facing VS which can handle connections for multiple customers which are separated by the subdomain of a wildcard FQDN.
The premise of the rule is that we should check that it's a valid customer and if they are, then make sure the request is being sourced from a permitted IP, and finally select an appropriate pool for the requested URI. The permitted IPs are customer specific as are the pools.
The rule should also requires no logic changes as customers, IPs and pool mappings are added/removed/changed over time.
Finally if any condition fails or there is something missing (e.g. a pool, or DGL etc.) then the connection must be closed and an appropriate log made.
I've messed with iRules for a number of years but I'm not a particularly clever coder. I get by as needed by scraping things together from DevCentral and other places. This is by far the longest rule I've stitched together (below) which seems to work okay with the testing I've done so far.
So I'm not really asking for anyone to check the rule in terms of its functionality (but any pointers on that front welcome), however I just can't shake the feeling that I'm being overly repetitive with the deny/error handling parts of the code. Any suggestions here would be appreciated.
Thanks in advance.
Leo
when RULE_INIT {
Set environment domain
set static::DOMAIN_ID ".mydomain"
Set debug logging on/off (0 for none, 1 for deny/error and 2 for all logging)
set static::DEBUG 2
}
when HTTP_REQUEST {
Check if our customer exists
if { [class match [string tolower [HTTP::host]] equals CUSTOMER_DGL] }{
Use the first string that comes before the environment domain to set our customer ID variable
set CUSTOMER_ID [getfield [HTTP::host] $static::DOMAIN_ID 1]
Debug Logging
if {$static::DEBUG==2}{log local0. "[virtual name] - Allow - Source IP [IP::client_addr] - The requested subdomain customer ID is:$CUSTOMER_ID"}
Our customer doesn't exist
} else {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Deny - Source IP [IP::client_addr] - Blocked accessing HTTP host:[HTTP::host] - client does not exist"}
Stop processing iRule event
return
}
Set a variable to check for the customer ID resource DGL
append CUSTOMER_CLASS [string toupper $CUSTOMER_ID] "_RESOURCE_DGL"
Set a variable to check for the customer ID allowed source IP
append WHITELIST_CLASS [string toupper $CUSTOMER_ID] "_WHITELIST_DGL"
Determine if the whitelist DGL exists
if { [class exists $WHITELIST_CLASS] }{
Check if connection is from an allowed Source IP
if { [class match [IP::client_addr] equals $WHITELIST_CLASS] } {
Debug Logging
if {$static::DEBUG==2}{log local0. "[virtual name] - Allow - Source IP [IP::client_addr] - Is a permitted IP for customer $CUSTOMER_ID"}
Determine if the resource DGL exists
if { [class exists $CUSTOMER_CLASS] }{
If the resource DGL exists, check if we have a valid resource pool
if { [class match [string tolower [HTTP::uri]] starts_with $CUSTOMER_CLASS] } {
Set our pool selection variable
set POOLSELECTION [class match -value [string tolower [HTTP::uri]] starts_with $CUSTOMER_CLASS]
A valid resource exists but the pool it references doesn't exist
if [ catch { pool $POOLSELECTION } ] {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Error - Source IP [IP::client_addr] - A pool named $POOLSELECTION doesn't exist for customer ID $CUSTOMER_ID and the resource [HTTP::uri]"}
Stop processing iRule event
return
The pool exists
} else {
Debug Logging
if {$static::DEBUG==2}{log local0. "[virtual name] - Allow - Source IP [IP::client_addr] - The pool selected was [LB::server]"}
}
A valid resource and it's associated pool doesn't exist
} else {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Deny - Source IP [IP::client_addr] - No pool was found for customer ID $CUSTOMER_ID and the resource [HTTP::uri]"}
Stop processing iRule event
return
}
The resource DGL doesn't exist
} else {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Error - Source IP [IP::client_addr] - A DGL named $CUSTOMER_CLASS does not exist"}
Stop processing iRule event
return
}
Request is not coming from an allowed source IP
} else {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Deny - Source IP [IP::client_addr] - This IP isn't permitted for customer $CUSTOMER_ID"}
Stop processing iRule event
return
}
The whitelist DGL doesn't exist
} else {
Issue 403 response
HTTP::respond 403 -version auto content "Forbidden" noserver
Gracefully close the connection here
TCP::close
Debug Logging
if {$static::DEBUG>=1}{log local0. "[virtual name] - Error - Source IP [IP::client_addr] - A DGL named $WHITELIST_CLASS does not exist"}
Stop processing iRule event
return
}
}