LDAP Support in DHCP Original Author: Brian Masney Current Maintainer: David Cantrell Last updated 07-Jul-2009 This document describes setting up the DHCP server to read it's configuration from LDAP. This work is based on the IETF document draft-ietf-dhc-ldap-schema-01.txt included in the doc directory. For the latest version of this document, please see http://dcantrel.fedorapeople.org/dhcp/ldap-patch/ First question on most people's mind is "Why do I want to store my configuration in LDAP?" If you run a small DHCP server, and the configuration on it rarely changes, then you won't need to store your configuration in LDAP. But, if you have several DHCP servers, and you want an easy way to manage your configuration, this can be a solution. The first step will be to setup your LDAP server. I am using OpenLDAP from www.openldap.org. Building and installing OpenLDAP is beyond the scope of this document. There is plenty of documentation out there about this. Once you have OpenLDAP installed, you will have to edit your slapd.conf file. I added the following 2 lines to my configuration file: include /etc/ldap/schema/dhcp.schema index dhcpHWAddress eq index dhcpClassData eq The first line tells it to include the dhcp schema file. You will find this file under the contrib directory in this distribution. You will need to copy this file to where your other schema files are (maybe /etc/openldap/schema/). The second line sets up an index for the dhcpHWAddress parameter. The third parameter is for reading subclasses from LDAP every time a DHCP request comes in. Make sure you run the slapindex command and restart slapd to have these changes to into effect. Now that you have LDAP setup, you should be able to use gq (http://biot.com/gq/) to verify that the dhcp schema file is loaded into LDAP. Pull up gq, and click on the Schema tab. Go under objectClasses, and you should see at least the following object classes listed: dhcpClass, dhcpGroup, dhcpHost, dhcpOptions, dhcpPool, dhcpServer, dhcpService, dhcpSharedNetwork, dhcpSubClass, and dhcpSubnet. If you do not see these, you need to check over your LDAP configuration before you go any further. You should now be ready to build DHCP. If you would like to enable LDAP in dhcpd, you will need to perform the following steps: * Apply the patch here to the unpacked ISC dhcp source tree. * Regenerate the configure script (requires GNU autoconf and automake): aclocal libtoolize --copy --force autoconf autoheader automake --foreign --add-missing --copy * Run ./configure with the '--with-ldap' argument to enable OpenLDAP. If you want LDAP over SSL, also use the '--with-ldapcrypto' argument. * Run 'make' to build ISC dhcp. Once you have DHCP installed, you will need to setup your initial plaintext config file. In my /etc/dhcpd.conf file, I have: ldap-server "localhost"; ldap-port 389; ldap-username "cn=DHCP User, dc=ntelos, dc=net"; ldap-password "blah"; ldap-base-dn "dc=ntelos, dc=net"; ldap-method dynamic; ldap-debug-file "/var/log/dhcp-ldap-startup.log"; If SSL has been enabled at compile time, the dhcp server trys to use TLS if possible, but continues without TLS if not. You can modify this behaviour using following option in /etc/dhcp/dhcpd.conf: ldap-ssl off: disables TLS/LDAPS. ldaps: enables LDAPS -- don't forget to set ldap-port to 636. start_tls: enables TLS using START_TLS command on: enables LDAPS if ldap-port is set to 636 or TLS in other cases. See also "man 5 ldap.conf" for description the following TLS related options: ldap-tls-reqcert, ldap-tls-ca-file, ldap-tls-ca-dir, ldap-tls-cert ldap-tls-key, ldap-tls-crlcheck, ldap-tls-ciphers, ldap-tls-randfile The ldap-init-retry enables an optional ldap connect retry loop with the specified number of retries with a one second sleep between each try during the initial startup of the dhcp server. It allows to catch the condition, that the (remote) ldap server is not yet started at the start time of the dhcp server. All of these parameters should be self explanatory except for the ldap-method. You can set this to static or dynamic. If you set it to static, the configuration is read once on startup, and LDAP isn't used anymore. But, if you set this to dynamic, the configuration is read once on startup, and the hosts that are stored in LDAP are looked up every time a DHCP request comes in. When the optional statement ldap-debug-file is specified, on startup the DHCP server will write out the configuration that it generated from LDAP. If you are getting errors about your LDAP configuration, this is a good place to start looking. The next step is to set up your LDAP tree. Here is an example config that will give a 10.100.0.x address to machines that have a host entry in LDAP. Otherwise, it will give a 10.200.0.x address to them. (NOTE: replace dc=ntelos, dc=net with your base dn). If you would like to convert your existing dhcpd.conf file to LDIF format, there is a script dhcpd-conf-to-ldap that will convert it for you. Type dhcpd-conf-to-ldap --help to see the usage information for this script. # You must specify the server's host name in LDAP that you are going to run # DHCP on and point it to which config tree you want to use. Whenever DHCP # first starts up, it will do a search for this entry to find out which # config to use dn: cn=brian.ntelos.net, dc=ntelos, dc=net objectClass: top objectClass: dhcpServer cn: brian.ntelos.net dhcpServiceDN: cn=DHCP Service Config, dc=ntelos, dc=net # Here is the config tree that brian.ntelos.net points to. dn: cn=DHCP Service Config, dc=ntelos, dc=net cn: DHCP Service Config objectClass: top objectClass: dhcpService dhcpPrimaryDN: dc=ntelos, dc=net dhcpStatements: ddns-update-style none dhcpStatements: default-lease-time 600 dhcpStatements: max-lease-time 7200 # Set up a shared network segment dn: cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: WV objectClass: top objectClass: dhcpSharedNetwork # Set up a subnet declaration with a pool statement. Also note that we have # a dhcpOptions object with this entry dn: cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: 10.100.0.0 objectClass: top objectClass: dhcpSubnet objectClass: dhcpOptions dhcpOption: domain-name-servers 10.100.0.2 dhcpOption: routers 10.100.0.1 dhcpOption: subnet-mask 255.255.255.0 dhcpOption: broadcast-address 10.100.0.255 dhcpNetMask: 24 # Set up a pool for this subnet. Only known hosts will get these IPs dn: cn=Known Pool, cn=10.100.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: Known Pool objectClass: top objectClass: dhcpPool dhcpRange: 10.100.0.3 10.100.0.254 dhcpPermitList: deny unknown-clients # Set up another subnet declaration with a pool statement dn: cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: 10.200.0.0 objectClass: top objectClass: dhcpSubnet objectClass: dhcpOptions dhcpOption: domain-name-servers 10.200.0.2 dhcpOption: routers 10.200.0.1 dhcpOption: subnet-mask 255.255.255.0 dhcpOption: broadcast-address 10.200.0.255 dhcpNetMask: 24 # Set up a pool for this subnet. Only unknown hosts will get these IPs dn: cn=Known Pool, cn=10.200.0.0, cn=WV Test, cn=DHCP Service Config, dc=ntelos, dc=net cn: Known Pool objectClass: top objectClass: dhcpPool dhcpRange: 10.200.0.3 10.200.0.254 dhcpPermitList: deny known clients # Set aside a group for all of our known MAC addresses dn: cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net objectClass: top objectClass: dhcpGroup cn: Customers # Host entry for my laptop dn: cn=brianlaptop, cn=Customers, cn=DHCP Service Config, dc=ntelos, dc=net objectClass: top objectClass: dhcpHost cn: brianlaptop dhcpHWAddress: ethernet 00:00:00:00:00:00 You can use the command ldapadd to load all of these entries into your LDAP server. After you load this, you should be able to start up DHCP. If you run into problems reading the configuration, try running dhcpd with the -d flag. If you still have problems, edit the site.conf file in the DHCP source and add the line: COPTS= -DDEBUG_LDAP and recompile DHCP. (make sure you run make clean and rerun configure before you rebuild). DHCPv6 requires a separate instance of the dhcpd server from the DHCPv4 server. It is convenient to use distinct LDAP login DNs for the two servers, and setup LDAP access restrictions in the LDAP server, so that each DHCP server only has access to its own data. You will need to create a separate configuration file, call it /etc/dhcpd6.conf. For example: ldap-server "localhost"; ldap-port 389; ldap-username "cn=DHCPv6 User, dc=ntelos, dc=net"; ldap-password "blahblah"; ldap-base-dn "dc=ntelos, dc=net"; ldap-method dynamic; ldap-debug-file "/var/log/dhcp-ldap-startup.log"; And use these command line arguments to dhcpd: dhcpd eth... -6 -cf /etc/dhcpd6.conf -pf /var/run/dhcpd6.pid -lf /var/lib/dhcpd6/dhcpd.leases For DHCPv6, the client configuration is the same, but substitute the Client ID for the Ethernet hardware address. Here is an example of a host definition for a DHCPv6 client: dn: cn=examplehost,cn=XXXX:XXXX:XXXX:XXXX::/64,cn=Network-eth1,cn=DHCPv6,dc=example,dc=com objectClass: top objectClass: dhcpHost cn: examplehost dhcpClientId: XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX:XX dhcpStatements: fixed-address6 XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX option host-name "examplehost.ipv6.example.com" option domain-name "ipv6.example.com"