Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Currently, I am using mod_proxy_ajp to load balance requests to multiple Tomcat servers. Callers are authenticated using client certificates and an ACL. This has been working fine, callers are routed to either server at an even rate. Now I want to pre-fetch and cache data per user, so each Tomcat server will serve a known set of users. So I'm thinking it would be fine to split caller's alphabetically; user's with a names (CN or DN) starting with A-M go to server 1, users with names starting with [N-Z] go to server 2. But I don't know how to make this work.

Currently I have:

<Proxy balancer://lb-service>
   BalancerMember ajp://svr1:8009 loadfactor=1 
   BalancerMember ajp://svr2:8009 loadfactor=1 
</Proxy>

<Location /lookup>
   ProxyPass balancer://lb-service/lookup
</Location>

I'm considering using mod_rewite to change the URL to include the user's CN but I can't seem to make that work.

I'm pretty much stuck using apache mod_proxy_ajp and Tomcat for load balancing. I can change the services running the Tomcat to accept different requests.

Anyone have a good way to do this?

share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

Interesting idea for caching! Let's see if we can get it working..

I've got a couple of options: one that would be more efficient but I really have no idea whether it will work, and one that's less efficient but I'm reasonably sure will work just fine.

The issue with the more efficient option (and, more generally, using something like the client cert to determine load balancer assignment) is that as far as I know there's no way to change mod_proxy_balancer's mind on node assignment after the request has come in - there's probably some creative hackery that could make it happen, but I'm not coming up with any better ideas off the top of my head. The crux of this is that it's doing a redirect to the same location that it's at, in order to have the cookie in place for the first request that gets proxied, to get the right route - and I'm not sure if that will work. Worth a shot:

RewriteEngine On

RewriteCond %{ENV:BALANCER_ROUTE_CHANGED} 1
RewriteCond %{SSL:SSL_CLIENT_S_DN} ^[a-m] [NC]
RewriteRule ^(.*)$ /.$1 [R,CO=ROUTEID:route.1:.yourdomain.com]

RewriteCond %{ENV:BALANCER_ROUTE_CHANGED} 1
RewriteCond %{SSL:SSL_CLIENT_S_DN} ^[n-z] [NC]
RewriteRule ^(.*)$ /.$1 [R,CO=ROUTEID:route.2:.yourdomain.com]

<Proxy balancer://lb-service>
    BalancerMember ajp://svr1:8009 loadfactor=1 route=1
    BalancerMember ajp://svr2:8009 loadfactor=1 route=2
    ProxySet stickysession=ROUTEID
</Proxy>

<Location /lookup>
   ProxyPass balancer://lb-service/lookup
</Location>

If that doesn't work, then here's plan B; just match the client certificate's DN every time. Adding extra overhead to each request, but it shouldn't be too bad of a performance impact overall.

<Proxy */lookup>
    RewriteEngine On

    RewriteCond %{SSL:SSL_CLIENT_S_DN} ^[a-m] [NC]
    RewriteRule ^/lookup((?:/.*|))$ ajp://svr1:8009/lookup$1 [P,L]

    RewriteCond %{SSL:SSL_CLIENT_S_DN} ^[n-z] [NC]
    RewriteRule ^/lookup((?:/.*|))$ ajp://svr2:8009/lookup$1 [P,L]

    # This will take care of any other orphan requests (say, those with no client
    # cert) - we'll just lump those on server 1; if there's a lot then we can do
    # something else to balance randomly (like just leave the current config there)
    RewriteRule ^/lookup((?:/.*|))$ ajp://svr1:8009/lookup$1 [P,L]
</Proxy>

I've got this matching for a trailing slash after /lookup to avoid a nasty security vulnerability where an attacker could get to your internal network - if that won't work for your application then we can work around it.

share|improve this answer
    
I'm trying to make option #2 work but so far I keep getting a Not_Found (404) when I try to access /lookup. I've turned on some logging (RewriteLog) and it seems like the RewriteCond is not matching. It's like the SSL_CLIENT_S_DN variable is not set, yet I'm sure the client cert is being passed because I check it in the Tomcat app. –  John in MD Jan 3 '12 at 20:40
    
@JohninMD Do you access just /lookup or is there anything after it? I've got the rules in option 2 set up to look for /lookup/* instead of /lookup, to avoid a security vulnerability. But if you do need /lookup working, I can adjust the rules. –  Shane Madden Jan 3 '12 at 20:46
    
just /lookup. One change I've made is to use SSL_CLIENT_S_DN_CN to get just the common name and not the entire DN. –  John in MD Jan 3 '12 at 21:01
    
In my error_log, I'm seeing the message "File /data/www/html/lookup does not exist" in the error log. Seems to be the source of the 404 but I don't understand why it's looking there. –  John in MD Jan 3 '12 at 21:29
    
@JohninMD Just needed an uglier regex to allow for that path. Edited, try it now. –  Shane Madden Jan 3 '12 at 21:45
show 4 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.