Hoppa till innehåll

Webbutveckling, systemförvaltning och design

Our take on web, social media and other tech stuff. From the people behind www.kth.se

Utnyttja redundans i Active Directory med Spring LDAP

Många har idag i sina system tillgång till en fullt redundant, multi-master LDAP-server i sina nätverk, i form av Active Directory. I det här inlägget tänkte jag dela med mig av mina erfarenheter att försöka utnyttja det för att göra tillgängligheten i en webbtjänst som använder Spring LDAP så god som möjligt.

Spring LDAP är en teknik för att göra LDAP-sökningar i Java. Man kan ha en del åsikter om Spring LDAP i sig, har man en tjänst som redan är uppbyggd med Spring-tekniker är det ett ganska naturligt val, annars kanske jag skulle fundera på att använda något annat.

I det här fallet handlade det om att modifiera ett system som är baserat på Spring att använda Kerberos mot Active Directory och LDAP-uppslagningar för att hämta meta-data. Dessutom gav det oss möjlighet att utnyttja den redundans våra multipla AD-kontrollanter har. Efter att ha arbetat ett tag med simulerade omstarter av AD-kontrollanter har jag landat i konfigurationen nedan för att få LDAP-funktionen att klara av det med så liten störning som möjligt.

<beans>
  <bean id="ldapContextSource"
        class=".ldap.core.support.LdapContextSource">
    <property name="urls"
              value="ldaps://dc1.ad.org,ldaps://dc2.ad.org"/>
    <property name="base" value="DC=ad,DC=org"/>
    <property name="userDn" value="minaduser"/>
    <property name="password" value="mittadpassword"/>
    <property name="pooled" value="false"/>
    <property name="baseEnvironmentProperties">
      <map>
        <entry key="com.sun.jndi.ldap.connect.timeout"
               value="30"/>
      </map>
    </property>
  </bean>

  <bean id="ldapDirContextValidator"
        class=".ldap.pool.validation.DefaultDirContextValidator"
  />

  <bean id="ldapPooledContextSource"
        class=".ldap.pool.factory.PoolingContextSource">
    <property name="contextSource"
              ref="ldapContextSource"/>
    <property name="dirContextValidator"
              ref="ldapDirContextValidator"/>
    <property name="testOnBorrow" value="true"/>
    <property name="testWhileIdle" value="true"/>
    <property name="timeBetweenEvictionRunsMillis"
              value="5000"/>
    <property name="numTestsPerEvictionRun"
              value="10"/>
    <property name="minEvictableIdleTimeMillis"
              value="5000"/>
    <property name="minIdle" value="2"/>
    <property name="maxIdle" value="10"/>
    <property name="maxActive" value="100"/>
    <property name="maxWait" value="10000"/>
  </bean>

  <bean id="ldapTemplate" class=".ldap.core.LdapTemplate">
    <constructor-arg ref="ldapPooledContextSource"/>
  </bean>
</beans>

Grunden i hela konfigurationen är att använda en connection pool. Det är frestande att göra det genom att sätta ”pooled” till true i sin context source, men då får man den inbyggda poolen i Java som inte har någon kunskap om Spring LDAP. Istället använder man en PoolingContextSource ifrån Spring LDAP som man får konfigurera upp.

Att sätta upp ett LDAP-koppel är dyrt och tar tid, i synnerhet om man dessutom ska förhandla upp en krypterad tunnel med TLS. Med en pool kan vi återanvända koppel i den mån det går, och genom att använda testWhileIdle kan vi se till att hålla den varm. Konfigurationen ovan är testad att fungera bra i ett system med måttlig last, men där kraven på respons  är relativt höga. Exakta tider är en justeringsfråga som man bara kan göra på ett bra sätt genom mätning med simulerad last. (Klassnamnen är trunkerade och startar med org.springframework i exemplet ovan för läsbarhet).

Som fotnot kan jag också lägga till att man behöver göra lite tweakar av sin krb5.conf om man vill att även Kerberos-autentisering ska bli mer effektiv och klara fail-over bättre. För det första behöver man ställa ner timeouten för kommunikation med KDC:n, den är som standard avsevärt lägre i andra kerberos-bibliotek. För det andra måste man peka ut ett krypto som AD:t stöder istället för des3 som är standard i Java för att undvika extra omförhandlingar med risk för störningar i varje request.

[libdefaults]
    kdc_timeout = 3
    default_tkt_enctypes = rc4-hmac
    default_tgs_enctypes = rc4-hmac
    permitted_enctypes = rc4-hmac

Ja, det här är en tråkig bloggpost, men kanske lite nyttig ändå. Var god cirkulera.

Bild: openclipart.org

 

Jag arbetar som chef över IT-arkitekturgruppen på IT-avdelningen på KTH.