Heimdal Kerberos with LDAP backend: opening database: ldap_sasl_bind_s: Can't contact LDAP server

Setting up Heimdal Kerberos with LDAP backend i faced a weird problem. In kadmin i got following errors:

  • opening database: ldap_sasl_bind_s: Can't contact LDAP server
  • kadm5_get_principals: Wrong database version

Slapd was running and KDC had all permissions though. Despite such attempts, there were no activity in slapd logs.

The problem was simple: whereas slapd creates its socket as /var/run/slapd/ldapi, Kerberos(/libldap?) tries to open it as /var/run/ldapi. So ln -s /var/run/slapd/ldapi /var/run/ldapi has solved the problem.

Partial replication with syncrepl

I setup syncrepl replication and everything was fine untill i saw that the data on slave server was not complete. I was trying to restart server, rm -rf /var/lib/ldap and again it was incomplete. Every time it tried to get sync'ed, it stopped on the same record. I supposed it had something to do with size limitations, so i tried to set sizelimit -1, and this solved the problem.

LDAP replication setup using syncrepl

Once you installed LDAP server in your network and some of your mission critical services start using it, you probably will want to setup one or more of its replica to eliminate a single point of failure and to load balance.

Traditionally people use slurpd - Standalone LDAP Update Replication Daemon, but seems syncrepl is more advanced technology and have some advantages over slurpd. One thing i really like in syncrepl that you dont have to stop master server, copy content onto slave server(s) and so on - this is done automaticly with syncrepl. You dont have to run additional service (slurpd). In fact you even dont have to change anything on master server. syncrepl is a consumer-side replication engine. Syncrepl supports pull-based (RefreshOnly) and push-based (RefreshAndPersist) technics of synchronization.

Install slapd on your LDAP slave box. In Debian/Ubuntu it would be:

apt-get isntall slapd ldap-utils
Then edit /etc/ldap/slapd.conf and make it look similar to this:
include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/dnsdomain2.schema

#schemacheck     on
pidfile         /var/run/slapd/slapd.pid
argsfile        /var/run/slapd.args
loglevel        256
modulepath      /usr/lib/ldap
moduleload      back_bdb

backend         bdb
checkpoint      512 30

database      bdb
suffix             "dc=example,dc=com"
directory       "/var/lib/ldap"
rootdn          "cn=replica,dc=example,dc=com"
rootpw          secret
lastmod         on

index           default                          pres,eq
index           uid
index           cn,email                        pres,eq,sub
index           associatedDomain        pres,eq
index           objectClass,entryCSN,entryUUID eq

syncrepl   rid=1
                provider=ldap://10.1.1.1
                type=refreshOnly
                interval=00:00:05:00
                searchbase="dc=example,dc=com"
                filter="(objectClass=*)"
                attrs="*"
                scope=sub
                schemachecking=off
                updatedn="cn=replica,dc=example,dc=com"
                bindmethod=simple
                binddn="cn=replica,dc=example,dc=com"
                credentials="secret"

updateref       ldap://10.1.1.1

access to attrs=userPassword
        by dn="cn=admin,dc=example,dc=com" write
        by anonymous auth
        by self write
        by * none

access to dn.children="ou=dns,dc=example,dc=com"
        by dn="cn=dnsadmin,ou=people,dc=example,dc=com" write
        by * read

access to dn.base="" by * read

access to *
        by dn="cn=admin,dc=example,dc=com" write
        by * read
It almost identical to master's slapd.conf. The main difference is the following fragment:
syncrepl   rid=1
                provider=ldap://10.1.1.1
                type=refreshOnly
                interval=00:00:05:00
                searchbase="dc=example,dc=com"
                filter="(objectClass=*)"
                attrs="*"
                scope=sub
                schemachecking=off
                updatedn="cn=replica,dc=example,dc=com"
                bindmethod=simple
                binddn="cn=replica,dc=example,dc=com"
                credentials="secret"

updateref       ldap://10.1.1.1

You just need to make sure you can bind to master as "cn=replica,dc=example,dc=com" and are able read.

Note: You must have lastmod turned on on master in order to have entryCSN and entryUUID fields added. They're required for syncrepl to work. It should add them automaticly as it said in documentation:

The provider slapd (8) is not required to be restarted. contextCSN is 
automatically generated as needed: it might be originally contained in 
the LDIF file, generated by slapadd (8), generated upon changes in the
context, or generated when the first LDAP Sync search arrives at the provider.
But in my case (Debian 3.1, slapd 2.2.23-8) they appeared only after i had turned lastmod on

PowerDNS with LDAP backend setup

What I'm trying to do this days is to unite somehow all used services and have some centralized storage of all logins/passwords and other data. And then build a web based administration tool for this.

As centralized storage of all my data ive chosen LDAP. And a first service im trying to setup is DNS. I've had BIND9 setup with all info stored in plain text files. Now i wanna setup PowerDNS with LDAP backend and keep all my zones in LDAP.

I use debian, so installation procedure is straight-farward:

root@sun:~# apt-get install pdns-server pdns-recursor pdns-backend-ldap slapd
 ldap-utils

Now we need to setup slapd - Stand-alone LDAP daemon: Typical config would look like this:

include         /etc/ldap/schema/core.schema
include         /etc/ldap/schema/cosine.schema
include         /etc/ldap/schema/nis.schema
include         /etc/ldap/schema/inetorgperson.schema
include         /etc/ldap/schema/dnsdomain2.schema

schemacheck     on
pidfile         /var/run/slapd/slapd.pid
argsfile        /var/run/slapd.args
loglevel        0
modulepath      /usr/lib/ldap
moduleload      back_bdb

backend         bdb
checkpoint      512 30

database        bdb
suffix          "dc=example,dc=com"
directory       "/var/lib/ldap"
rootdn          "cn=admin,dc=example,dc=com"
rootpw          {SSHA}YxjoLOLbdXjLYlaKy6uws/Dbyix9AQVh

index           default     pres,eq
index           uid
index           cn,email    pres,eq,sub
index           associatedDomain    pres,eq
index           objectClass eq

lastmod         off

access to attrs=userPassword
        by dn="cn=admin,dc=example,dc=com" write
        by anonymous auth
        by self write
        by * none

access to dn.base="" by * read

access to *
        by dn="cn=admin,dc=example,dc=com" write
        by * read

The line include /etc/ldap/schema/dnsdomain2.schema is optinal - standard ldap schemas are sufficient to run PowerDNS unless you need to handle revers lookups. In this case you'll need to add PTR records into your ldap objects, though this attribute is not available in cosine.schema and you'll have to include another schema, bundled with powerdns-backend-ldap: /etc/ldap/schema/dnsdomain2.schema. It defines dNSDomain2 object, which has PTRRecord as well.

rootdn/rootpw lines are needed only for adding records into the db. Later you can add any account you like and give it access in your slapd.conf. Password can be either plain text or crypted (can be obtained with slappasswd) Alternatively, data can be added using slapadd command locally, though this tool does not perform schema checks and does not check if superior entries exist.

Now we can start slapd

invoke-rc.d slapd start
and add some dns stuff:
#dns.ldif:
dn: dc=example,dc=com
objectClass: dcObject
objectClass: organization
dc: example
o: example
description: http://example.com/

dn: ou=dns,dc=example,dc=com
objectClass: top
objectClass: organizationalUnit
ou: dns

dn: dc=com,ou=dns,dc=example,dc=com
objectClass: dNSDomain2
objectClass: domainRelatedObject
dc: com
associateddomain: com

dn: dc=example,dc=com,ou=dns,dc=example,dc=com
objectClass: dNSDomain2
objectClass: domainRelatedObject
dc: example
SOARecord: ns1.example.com sysadmin@example.com 1 1800 3600 86400 7200
NSRecord: ns1.example.com
NSRecord: ns2.example.com
MXRecord: 10 mail.example.com
ARecord: 10.1.1.1
associatedDomain: example.com

dn: dc=ns1,dc=example,dc=com,ou=dns,dc=example,dc=com
objectClass: dNSDomain2
objectClass: domainRelatedObject
dc: ns1
ARecord: 10.1.1.1
associatedDomain: ns1.example.com

dn: dc=ns2,dc=example,dc=com,ou=dns,dc=example,dc=com
objectClass: dNSDomain2
objectClass: domainRelatedObject
dc: ns2
ARecord: 10.1.1.2
associatedDomain: ns2.example.com

dn: dc=mail,dc=example,dc=com,ou=dns,dc=example,dc=com
objectClass: dNSDomain2
objectClass: domainRelatedObject
dc: mail
ARecord: 10.1.1.3
associatedDomain: mail.example.com

#End

ldapadd -f dns.ldif -x -D 'cn=admin,dc=example,dc=com'  -W
Enter LDAP Password: <rootpw_here>

Here we use 'tree style', that is powerdns looks for entries by translating domain name into ldap DN. E.g. query for mail.example.com domain would be translated into 'dn: dc=mail,dc=example,dc=com,ou=dns,dc=example,dc=com'. This method seems more logical/straightforward to me. Also it gives 7% perfomance advantage of other methods.

The only thing left to do is to tell our PowerDNS to use LDAP backend:

#/etc/powerdns/pdns.d/pdns.local

# host running slapd
ldap-host=127.0.0.1:389
ldap-basedn=ou=dns,dc=example,dc=com
#ldap-binddn=""
#ldap-secret=""
ldap-method="tree"
After this, edit /etc/powerdns/pdns.conf and make sure you have something similar in it:
#/etc/powerdns/pdns.conf

allow-recursion=127.0.0.1,10.1.1.0/24
launch=ldap
local-address=10.1.1.1,192.168.7.1
recursor=127.0.0.1

#/etc/powerdns/recursor.conf
local-address=127.0.0.1

You dont have to run recursor from PowerDNS. E.g. you cant do zone forwarding in pdns-recursor, but you can, for example, use dnscache from djbdns instead or any other server you like :)