Having spent the past few months working in ops I have learned a wide range of new skills in server and network infrastructure. I found that my skills as a developed augmented what my then competent ops skills. Coming back to full-time development now I was expecting to find that my infrastructure skills would improve my development. What I wasn't expecting was such an early and staggering example. A year ago, I solved a problem that I was then experiencing - querying ActiveDirectory with python-ldap under Debian. There was an incompatibility between GnuTLS and AD that made this impossible, due to AD missing TLS 1.1 support and no fallback from TLS 1.1 to TLS 1.0. This would happen:


$ gnutls-cli -p 636 ad.example.com

Resolving 'ad.example.com'...

Connecting to 'ad.example.com:636'...

*** Fatal error: A TLS packet with unexpected length was received.

*** Handshake has failed

GNUTLS ERROR: A TLS packet with unexpected length was received.

This worked when disabling TLS 1.1 in GnuTLS, but libldap does not expose a way to set GnuTLS options, and so nor does python-ldap.

My developer solution

My 2010 workaround was to recompile libldap against OpenSSL (which tested to work with AD). This is how it is done: Build instructions for libldap
  1. check that source repos are available in /etc/apt/sources.list
  2. $ apt-get source openldap
  3. # apt-get build-dep openldap
  4. # apt-get install libssl-dev
  5. cd to the openldap-* directory
  6. $ CPPFLAGS=-D_GNU_SOURCE ./configure --prefix=<where> --with-tls=openssl See http://www.openldap.org/its/index.cgi/Build?id=5464 for reasons behind the _GNU_SOURCE flag.
  7. $ make -j <number_of_cpus> depend
  8. $ cd libraries
  9. $ make -j <number_of_cpus>
  10. $ make install
  11. $ cd ../include
  12. $ make install
Build instructions for python-ldap libldap may provide the same binary interface (ABI) whether it's compiled with GnuTLS or OpenSSL, but there is a chance that it may differ, so recompiling python-ldap against the new libldap is recommended.
  1. # apt-get install python-dev
  2. Obtain source for stable python-ldap from http://pypi.python.org/pypi/python-ldap/
  3. Extract archive and enter extracted directory
  4. Edit setup.cfg: add <where>/lib after library_dirs = add <where>/include after include_dirs = add extra_link_args = -L<where>/lib -rpath <where>/lib somewhere in the [_ldap] section.
  5. $ mkdir -p <where>/lib/python<version>/site-packages (where <version> is eg. 2.5, 2.6)
  6. $ PYTHONPATH=<where>/lib/python<version>/site-packages/ python setup.py install --prefix=<where>
Running Python To use the recompiled version of the libraries

$ PYTHONPATH=/lib/python/site-packages/ python example.py

My DevOps Solution

Using stunnel it is possible to "unwrap" the SSL layer and provide unencrypted access to python-ldap. stunnel is compiled against OpenSSL and thus doesn't suffer from the GnuTLS bug.

$ sudo stunnel -c -d 127.0.0.1:389 -r ad.example.com:636

As a developer there's a certain hesitance to introduce another independent service into the system. It feels like weakening the chain, going from one point of failure to many points of failure - potentially bugs or misconfigurations in the adapting component itself or misconfigurations of the server that is supposed to be hosting that component. As a DevOp, given the tools and experience to maintain infrastructure systems that involve vastly more components than this, it seems robust - no non-standard components, just an easy-to-configure off-the-shelf tool doing what it is intended for.