Shibboleth IDP 2.4 amb Debian Wheezy (amb SSL offloading via nginx)

Objectiu:

L’objectiu d’aquesta entrada és disposar d’una màquina que executi el servei de proveïdor d’identitat (en endavant idp) Shibboleth versió 2.4 fent l’SSL offloading des d’un servei nginx. Aquesta màquina serà l’encarregada d’autenticar els usuaris dels diferents serveis web de la nostra organització tot proporcionant un entorn d’entrada única (Single Sign On) a la vegada que subministrarà els atributs que aquestes aplicacions web requereixin. L’autenticació i l’obtenció dels atributs es duran a terme mitjançant un directori LDAP.

En una entrada anterior es va configurar l’idp darrere un apache2 que utilitzava AJP. En aquesta entrada, bàsicament, substituirem apache2 per nginx fins on sigui possible.

Requeriments previs:

El sistema operatiu que utilitzarem és Debian Wheezy versió 7. La instal·lació del sistema operatiu no es detallarà. Existeix una guia per a Debian Lenny 5.0 en aquest bloc que es pot utilitzar sense massa complicacions, ja que el procés d’instal·lació és gairebé calcat.

Per allotjar l’idp utilitzarem tomcat6 disponible als repositoris de Debian. S’utilitzarà nginx com a proveïdor de seguretat SSL.

A la vegada serà necessari disposar d’algun sistema de resolució de noms, ja sigui mitjançant un servidor DNS (com ara bind, unbound o similar) o bé mitjançant l’arxiu /etc/hosts en cada màquina on treballem. Tal i com s’indica en aquesta entrada el nom de la màquina on s’allotjarà l’idp serà idp.domain.org, alhora, el nom d’un proveïdor de serveis serà sp.domain.org.

Instal·lació del programari bàsic:

Partirem doncs d’un Debian Wheezy 7 net on treballarem amb l’usuari root.

Instal·larem els següents paquets dels repositoris oficials:

$ apt-get install unzip ntp curl ccze ca-certificates
$ apt-get install default-jre-headless
$ apt-get install nginx tomcat6

NOTA: El paquet default-jre-headless no instal·la els requeriments d’X11 que tampoc fan falta.

Configuració del servei tomcat6:

Un cop instal·lat el programari bàsic aturem el servei tomcat6 i en modifiquem les propietats d’arrencada:

$ service tomcat6 stop
$ pico /etc/default/tomcat6
...
JAVA_OPTS="-Djava.awt.headless=true -Xmx512M -XX:MaxPermSize=128M -Dcom.sun.security.enableCRLDP=true"
...

NOTA: Substituïm la línia que hi ha configurada.

A continuació modifiquem les propietats per defecte de tomcat6 adaptant el connector del port 8080 a les nostres necessitats i afegint un connector al port 8443 per a les peticions SOAP dels proveïdors de serveis:

$ pico /etc/tomcat6/server.xml
...
    <Connector port="8080" 
           protocol="HTTP/1.1" 
           connectionTimeout="20000" 
           URIEncoding="UTF-8" 
           scheme="https" 
           proxyPort="443" />

    <Connector port="8443" 
           protocol="org.apache.coyote.http11.Http11Protocol"
           SSLImplementation="edu.internet2.middleware.security.tomcat6.DelegateToApplicationJSSEImplementation"
           scheme="https"
           ciphers="TLS_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,SSL_RSA_WITH_3DES_EDE_CBC_SHA,SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"
           SSLEnabled="true"
           clientAuth="want"
           keystoreFile="/opt/shibboleth-idp/credentials/idp.jks"
           keystorePass="password" />
...
    <!-- Define the default virtual host
         Note: XML Schema validation will not work with Xerces 2.2.
    -->
    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="false" xmlValidation="false" xmlNamespaceAware="false">
...

NOTA: Com es pot apreciar em definit unes credencials que encara no existeixen. Les crearem a continuació.

Instal·lació de l’idp:

Per fer la instal·lació és necessari que el sistema conegui la ubicació del jre de java. Això ho podem fer amb un export o en l’arxiu .profile d’entrada en sessió:

$ pico ~/.profile
...
IdPCertLifetime=20
JAVA_HOME=/usr/lib/jvm/default-java
export IdPCertLifetime
export JAVA_HOME
...

A continuació obtenim el programari de l’idp i l’instal·lem al tomcat6:

$ cd /usr/local/src
$ curl -O http://shibboleth.net/downloads/identity-provider/2.4.0/shibboleth-identityprovider-2.4.0-bin.zip
$ unzip shibboleth-identityprovider-2.4.0-bin.zip
$ cd shibboleth-identityprovider-2.4.0
$ chmod u+x install.sh

OPCIONAL: Eliminem les restriccions respecte a les credencials (necessari si volem autenticar serveis imap, per exemple). També, opcionalment, afegim el rang d’adreces IP de la xarxa que estem usant per tal d’accedir a les pàgines d’estatus de l’idp. Això ens anirà bé a l’hora de fer el debug. Un cop tot estigui funcionant correctament es pot tornar a limitar l’accés:

$ pico src/main/webapp/WEB-INF/web.xml
...
    <!-- Authentication Engine Entry Point -->
    <servlet>
        <servlet-name>AuthenticationEngine</servlet-name>
        <servlet-class>edu.internet2.middleware.shibboleth.idp.authn.AuthenticationEngine</servlet-class>

        <!-- Whether public credentials returned by a login handler are retained in the subject. -->
        <init-param> <param-name>retainSubjectsPublicCredentials</param-name> <param-value>true</param-value> </init-param>

        <!-- Whether private credentials returned by a login handler are retained in the subject. -->
        <init-param> <param-name>retainSubjectsPrivateCredentials</param-name> <param-value>true</param-value> </init-param>

        <load-on-startup>2</load-on-startup>

    </servlet>
...
    <!-- Space separated list of CIDR blocks allowed to access the status page -->
    <init-param>
        <param-name>AllowedIPs</param-name>
        <param-value>127.0.0.1/32 ::1/128 {EL_NOSTRE_RANG}</param-value>
    </init-param>
...

Copiem unes llibreries necessàries:

$ mkdir /usr/share/tomcat6/endorsed/
$ cp ./endorsed/*.jar /usr/share/tomcat6/endorsed/
$ wget https://build.shibboleth.net/nexus/content/repositories/releases/edu/internet2/middleware/security/tomcat6/tomcat6-dta-ssl/1.0.0/tomcat6-dta-ssl-1.0.0.jar
$ mv tomcat6-dta-ssl-1.0.0.jar /usr/share/tomcat6/lib
$ ./install.sh

NOTA: Per tornar a tancar l’accés a les pàgines d’estat és necessari disposar del codi font de l’aplicació, és a dir la carpeta que s’ha descarregat i on s’estan duent a terme les modificacions, desfer l’edició i tornar a executar la comanda ./install.sh.

La instal·lació ens demanarà on volem instal·lar el programari, el lloc predeterminat és /opt/shibboleth-idp. Aquesta ubicació és correcta i recomanable. A continuació, i per tal de crear la configuració adaptada i els certificats adients ens demanarà el nom del servei on s’allotjarà l’idp. Aquest punt és important ja que afectarà als certificats que crearem més tard així com les configuracions que haurem de fer en la resta de proveïdors de serveis que desitgin contactar amb l’idp. Així doncs escollim un nom DNS que s’adapti a la nostra organització. Utilitzarem el nom idp.domain.org.

Durant la instal·lació se’ns demanarà una contrasenya pel Keystore. Aquesta contrasenya és la que hem posat en el Connector pel port 8443.

Deixem que es dugui a terme la instal·lació i procedim a afegir l’arxiu .war a la configuració de tomcat6:

$ pico /etc/tomcat6/Catalina/localhost/idp.xml
<Context
    docBase="/opt/shibboleth-idp/war/idp.war"
    privileged="true"
    antiResourceLocking="false"
    antiJARLocking="false"
    unpackWAR="false"
    swallowOutput="true"
    cookies="false" />

Apliquem la seguretat necessària al directori de l’idp:

$ cd /opt/shibboleth-idp
$ chown root credentials/idp.key
$ chgrp tomcat6 credentials/idp.{key,crt}
$ chmod 440 credentials/idp.key
$ chmod 644 credentials/idp.crt
$ chmod 440 credentials/idp.jks
$ chown -R tomcat6 logs metadata
$ chgrp -R tomcat6 conf credentials logs metadata war lib
$ chown tomcat6 conf/attribute-filter.xml
$ chmod 664 conf/attribute-filter.xml
$ chmod 750 lib war
$ chmod 750 conf credentials
$ chmod 775 logs metadata

Permetem que l’idp autentiqui mitjançant nom d’usuari i contrasenya i comentem l’opció d’autenticació mitjançant usuari remot:

$ pico conf/handler.xml
...
    <!--
    <ph:LoginHandler xsi:type="ph:RemoteUser">
        <ph:AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</ph:AuthenticationMethod>
    </ph:LoginHandler>
    -->
...
    <!--  Username/password login handler -->
    <ph:LoginHandler xsi:type="ph:UsernamePassword" jaasConfigurationLocation="file:///opt/shibboleth-idp/conf/login.config">
        <ph:AuthenticationMethod>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</ph:AuthenticationMethod>
    </ph:LoginHandler>
...

Per l’autenticació dels usuaris mitjançant LDAP modifiquem l’arxiu d’autenticació de l’idp:

$ pico conf/login.config
ShibUserPassAuth {
   edu.vt.middleware.ldap.jaas.LdapLoginModule required
      ldapUrl="ldap://ldap.domain.org"
      baseDn="dc=domain,dc=org"
      bindDn="cn=binduser,dc=domain,dc=org"
      bindCredential="password"
      searchScope="SUBTREE"
      userFilter="uid={0}";
};

ALTERNATIVA: Si s’utilitza Active Directory és millor accedir pel port 3268 i el filtre d’usuari s’hauria de modificar també:

ShibUserPassAuth {
   edu.vt.middleware.ldap.jaas.LdapLoginModule required
      ldapUrl="ldap://ad.domain.org:3268"
      baseDn="dc=domain,dc=org"
      bindDn="cn=binduser,dc=domain,dc=org"
      bindCredential="password"
      searchScope="SUBTREE"
      userFilter="samaccountname={0}";
};

Creació dels certificats SSL de seguretat per l’nginx:

A continuació crearem els certificats SSL que incorporarem en la configuració d’nginx per tal que la comunicació amb els usuaris finals sigui segura. No s’entra en detall del que es fa en cada comanda. Existeix un tutorial d’openssl en aquest blog si es desitja més informació.

$ pico /usr/lib/ssl/openssl.cnf

Canviem les següents línies:

dir             = .
certificate	= $dir/ca.crt
private_key	= $dir/private/ca.key

Creem una CA de desenvolupament i els certificats necessaris:

$ cd
$ mkdir -p CA/{certs,private,newcerts}
$ cd CA
$ openssl req -x509 -days 3650 -newkey rsa:2048 -keyout ca.key -out ca.crt
$ chmod g-rwx,o-rwx private
$ echo '01' > serial
$ touch index.txt
$ mv ca.key private/
$ chmod 0600 private/ca.key
$ openssl req -nodes -newkey rsa:2048 -keyout idp.domain.org.key -out idp.domain.org.req
$ openssl ca -in idp.domain.org.req -out idp.domain.org.crt
$ rm idp.domain.org.req
$ openssl req -nodes -newkey rsa:2048 -keyout sp.domain.org.key -out sp.domain.org.req
$ openssl ca -in sp.domain.org.req -out sp.domain.org.crt
$ rm sp.domain.org.req

NOTA: Com es pot apreciar, s’ha creat un certificat per a idp.domain.org i un pel proveïdor de serveis sp.domain.org que ens farà falta en la configuració del service provider (sp).

Un cop creats els certificats afegim la CA al grup de certificats arrel vàlids pel sistema:

$ mkdir /usr/share/ca-certificates/domain.org
$ cp ca.crt /usr/share/ca-certificates/domain.org
$ dpkg-reconfigure ca-certificates

Configuració de l’nginx:

Modifiquem la configuració d’nginx per adaptar-la als nostres requeriments:

$ mkdir /etc/nginx/ssl
$ cp idp.domain.org* /etc/nginx/ssl
$ chmod 0600 /etc/nginx/ssl/idp.domain.org.key

A continuació afegim una configuració nova per a l’idp:

$ pico /etc/nginx/conf.d/default.conf
upstream idp { server 127.0.0.1:8080; }

server {
    listen 443 ssl;

    server_name  idp.domain.org;

    ssl on;
    ssl_certificate      /etc/nginx/ssl/idp.domain.org.crt;
    ssl_certificate_key  /etc/nginx/ssl/idp.domain.org.key;

    location / {
     proxy_pass http://idp;
     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
     proxy_redirect off;
     proxy_buffering off;
     proxy_set_header        Host            $host;
     proxy_set_header        X-Real-IP       $remote_addr;
     proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Accés a SOAP per part dels proveïdors de serveis:

Els sp fan peticions a l’idp indepentdentment de la comunicació per navegador amb l’usuari. A més, aquesta comunicació segura es realitza mitjançat certificats de client, de manera que no podem fer SSL offloading d’aquesta part de la configuració amb nginx. La comunicació per part dels sp fins l’idp en peticions SOAP ha de ser directa. En aquest exemple que estem configurant no hi haurà problema ja que tot succeeix en un entorn força tancat.
En altres situacions més complexes ens hem d’assegurar que els sp arribin a l’idp sense problemes. Així, per exemple si nginx s’executa en una altra màquina que gestiona l’SSL offloading de tota l’organització podríem afegir les línies següents a /etc/rc.local del servidor nginx:

...
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A PREROUTING -p tcp --dport 8443 -j DNAT --to-destination ip_servidor_idp:8443
iptables -t nat -A POSTROUTING -p tcp -d ip_servidor_idp --dport 8443 -j SNAT --to-source ip_servidor_nginx
...

Arrencada de l’idp:

Finalment reiniciem el servei nginx i iniciem el servei tomcat6:

$ service nginx restart
$ service tomcat6 start

La següent comanda ens mostrarà els registres d’arrencada per poder verificar que l’idp ha arrencat sense incidències:

$ tail -f /var/log/tomcat6/catalina.out /opt/shibboleth-idp/logs/idp-process.log | ccze

Comprovació final:

Per comprovar que el servei funciona podem accedir a la pàgina següent des d’un navegador:

https://idp.domain.org/idp/status

La pàgina, en text clar, ens mostrarà l’estat del nostre idp.

En aquest punt la instal·lació de l’idp es pot donar per completada tot i que actualment no és capaç d’autenticar cap proveïdor de serveis o subministrar atributs ja que aquestes opcions encara no s’han configurat. En una altra entrada es mostra com dur a terme la configuració bàsica d’un proveïdor de serveis i com subministrar atributs.

Documentació:

Bona sort amb la documentació de Shibboleth. Ells ja hi posen bona fe, ja, però és força complexa de seguir. Us deixo l’enllaç a la wiki: https://wiki.shibboleth.net/confluence/display/SHIB2/Home