This blog post was driven by the need to make it easier to test Eucalyptus DNS in a lab environment. The goal was to have a scriptable way to add/delete fully delegated sub-domains without having to reload/restart DNS when Eucalyptus clouds were being deployed/destroyed. This was tested on an CentOS 6 instance running in a Eucalyptus 3.3 HA Cloud.
Prerequisites
This entry will not cover setting up Eucalyptus HA, creating a Eucalyptus user, using eustore to register the image, and/or opening up ports in security groups. Its assumed the reader understands these concepts. The focus will be configuring and deploying Bind9 and OpenLDAP.
In addition to using a CentOS 6.4 image, the following is needed:
- ports open for DNS (tcp and udp 53)
- port open for OpenLDAP (tcp 389)
- port open for SSH (tcp 22)
Now that the prereqs have been covered, lets jump into setting up the environment.
Base Software Installation
There are a series of packages needed to install OpenLDAP (since we are building from source), and Bind9. Once the instance is launched and running, SSH into the instance, and run the following commands:
# sudo yum -y upgrade # sudo yum install -y git cyrus-sasl gcc glibc-devel libtool-ltdl \ db4-devel openssl-devel unixODBC-devel libtool-ltdl-devel libtool \ cyrus-sasl-devel cyrus-sasl-gssapi cyrus-sasl-lib cyrus-sasl-md5 \ make bind-dyndb-ldap
All the packages except for bind-dyndb-ldap are needed to build OpenLDAP from source. The reason we are building OpenLDAP from source is to take advantage of their powerful backend – MDB. Check out my previous blogs on this topic from this listing.
The key package for Bind9 DNS to communicate to OpenLDAP as a backend is bind-dyndb-ldap. This plug-in is used by the FreeIPA Identity/Policy Management application to help leverage 389 Directory Servers (which is based off OpenLDAP) for storing domain name information.
OpenLDAP Installation and Configuration
Since all the base packages are installed, we can now grab and install the latest source version of OpenLDAP. While still being logged into the instance, run the following command:
# git clone git://git.openldap.org/openldap.git ~/openldap
Since we are working with an instance based on the CentOS 6 image on eustore, we will use the ephemeral store (which is mounted under /media/ephemeral0) for the location of our OpenLDAP installation. Create a directory for installing OpenLDAP on the ephemeral store by running the command below:
# mkdir /media/ephemeral0/openldap
Next, configure OpenLDAP:
# cd ~/openldap # ./configure --prefix=/media/ephemeral0/openldap --enable-debug=yes \ --enable-syslog --enable-dynamic --enable-slapd --enable-dynacl \ --enable-spasswd --enable-modules --enable-rlookups --enable-mdb \ --enable-monitor --enable-overlays --with-cyrus-sasl --with-threads \ --with-tls=openssl CC="gcc" LDFLAGS="-L/usr/lib64/sasl2" CPPFLAGS="-I/usr/include/sasl"
After thats completed successfully, compile and install OpenLDAP:
# make depend # make # sudo make install
After the installation is complete, create the openldap user that will be responsible for running OpenLDAP:
# sudo useradd -m -U -c "OpenLDAP User" -s /bin/bash openldap # sudo passwd -l openldap
Since the bind-dyndb-ldap package was installed earlier, copy the schema to where OpenLDAP stores its schemas, so that it can be added to the OpenLDAP configuration:
# sudo cp /usr/share/doc/bind-dyndb-ldap-2.3/schema \ /media/ephemeral0/openldap/etc/openldap/schema/bind-dyndb-ldap.schema
Next, create the LDAP password for the cn=admin,cn=config user. This user is responsible for managing the configuration of the OpenLDAP server using OLC:
# /media/ephemeral0/openldap/sbin/slappasswd -h {SSHA}
Modify the slapd.conf file located under /media/ephemeral0/openldap/etc/openldap/, to set up the base configuration structure (cn=config) for OpenLDAP. When completed, it should look like the following:
####################################################################### # Config database definitions ####################################################################### pidfile /media/ephemeral0/openldap/var/run/slapd.pid argsfile /media/ephemeral0/openldap/var/run/slapd.args database config rootdn cn=admin,cn=config rootpw {SSHA}xxxxxxxxxxxxxxxxxxxxxxxx - (password created for cn=admin,cn=config user) # Schemas, in order include /media/ephemeral0/openldap/etc/openldap/schema/core.schema include /media/ephemeral0/openldap/etc/openldap/schema/cosine.schema include /media/ephemeral0/openldap/etc/openldap/schema/inetorgperson.schema include /media/ephemeral0/openldap/etc/openldap/schema/collective.schema include /media/ephemeral0/openldap/etc/openldap/schema/corba.schema include /media/ephemeral0/openldap/etc/openldap/schema/duaconf.schema include /media/ephemeral0/openldap/etc/openldap/schema/dyngroup.schema include /media/ephemeral0/openldap/etc/openldap/schema/misc.schema include /media/ephemeral0/openldap/etc/openldap/schema/nis.schema include /media/ephemeral0/openldap/etc/openldap/schema/openldap.schema include /media/ephemeral0/openldap/etc/openldap/schema/ppolicy.schema include /media/ephemeral0/openldap/etc/openldap/schema/bind-dyndb-ldap.schema
Create the slapd.d directory under /media/ephemeral0/openldap/etc/openldap/. This will contain all the directory information:
# sudo chown -R openldap:openldap /media/ephemeral0/openldap/* # su - openldap -c "mkdir /media/ephemeral0/openldap/etc/openldap/slapd.d"
Populate the slapd.d directory with the base configuration by running the following command:
su - openldap -c "/media/ephemeral0/openldap/sbin/slaptest \ -f /media/ephemeral0/openldap/etc/openldap/slapd.conf \ -F /media/ephemeral0/openldap/etc/openldap/slapd.d" config file testing succeeded
For this example, we will be setting up the directory to use dc=eucalyptus,dc=com as the LDAP base. Create the cn=Directory Manager,dc=eucalyptus,dc=com LDAP password:
# /media/ephemeral0/openldap/sbin/slappasswd -h {SSHA}
Create an LDIF that will define the configuration of the DB associated with the information regarding the DNS entries. For this example, the LDIF will be called directory-layout.ldif. It should look like the following:
####################################################################### # MDB database definitions ####################################################################### # dn: olcDatabase=mdb,cn=config changetype: add objectClass: olcDatabaseConfig objectClass: olcMdbConfig olcDatabase: mdb olcSuffix: dc=eucalyptus,dc=com olcRootDN: cn=Directory Manager,dc=eucalyptus,dc=com olcRootPW: {SSHA}xxxx - (password of cn=Directory Manager,dc=eucalyptus,dc=com user) olcDbDirectory: /media/ephemeral0/openldap/var/openldap-data/dns olcDbIndex: objectClass eq olcAccess: to attrs=userPassword by dn="cn=Directory Manager,dc=eucalyptus,dc=com" write by anonymous auth by self write by * none olcAccess: to attrs=shadowLastChange by self write by * read olcAccess: to dn.base="" by * read olcAccess: to * by dn="cn=Directory Manager,dc=eucalyptus,dc=com" write by * read olcDbMaxReaders: 0 olcDbMode: 0600 olcDbSearchStack: 16 olcDbMaxSize: 4294967296 olcAddContentAcl: FALSE olcLastMod: TRUE olcMaxDerefDepth: 15 olcReadOnly: FALSE olcSyncUseSubentry: FALSE olcMonitoring: TRUE olcDbNoSync: FALSE olcDbEnvFlags: writemap olcDbEnvFlags: nometasync
Make sure and create the directory where the DB information will be stored:
# su - openldap -c "mkdir /media/ephemeral0/openldap/var/openldap-data/dns"
Start up the OpenLDAP directory:
# sudo /media/ephemeral0/openldap/libexec/slapd -h "ldap:/// ldapi:///" \ -u openldap -g openldap
After OpenLDAP has been started successfully, upload the directory-layout.ldif as the cn=admin,cn=config user:
# /media/ephemeral0/openldap/bin/ldapadd -D cn=admin,cn=config -W \ -f directory-layout.ldif Enter LDAP Password: adding new entry "olcDatabase=mdb,cn=config"
To allow search access to the directory, create an LDIF called frontend.ldif, that contains the following:
dn: olcDatabase={-1}frontend,cn=config changetype: modify replace: olcAccess olcAccess: to dn.base="" by * read olcAccess: to dn.base="cn=Subschema" by * read olcAccess: to * by self write by users read by anonymous auth
Upload the LDIF using the ldapmodify command:
# /media/ephemeral0/openldap/bin/ldapmodify -D cn=admin,cn=config -W -f frontend.ldif Enter LDAP Password: modifying entry "olcDatabase={-1}frontend,cn=config"
To check the results of these changes, use ldapsearch:
# /media/ephemeral0/openldap/bin/ldapsearch -D cn=admin,cn=config -W -b cn=config Enter LDAP Password: (ldapsearch results...)
After confirming that the base configurations have been stored, create an LDIF called dns-domain.ldif that lays out the directory structure for the database. As seen previously in the directory-layout.ldif, the base is dc=eucalyptus,dc=com. The dns-domain.ldif file should look like the following:
dn: dc=eucalyptus,dc=com objectClass: top objectClass: dcObject objectclass: organization o: Eucalyptus Systems Inc - QA DNS Domain dc: eucalyptus description: Test LDAP+DNS Setup dn: ou=dns,dc=eucalyptus,dc=com objectClass: organizationalUnit ou: dns
After creating the dns-domain.ldif file, upload the file using the cn=Directory Manager,dc=eucalyptus,dc=com user:
# /media/ephemeral0/openldap/bin/ldapadd -H ldap://localhost \ -D "cn=Directory Manager,dc=eucalyptus,dc=com" -W -f dns-domain.ldif Enter LDAP Password: adding new entry "dc=eucalyptus,dc=com" adding new entry "ou=dns,dc=eucalyptus,dc=com"
To allow the cn=Directory Manager,dc=eucalyptus,dc=com user to see what updates are being done to the Directory, enable the Access Log overlay. To enable this option, create an LDIF file called access-log.ldif. The contents should look like the following:
dn: olcDatabase={2}mdb,cn=config objectClass: olcDatabaseConfig objectClass: olcMdbConfig olcDatabase: {2}mdb olcDbDirectory: /media/ephemeral0/openldap/var/openldap-data/access olcSuffix: cn=log olcDbIndex: reqStart eq olcDbMaxSize: 1073741824 olcDbMode: 0600 olcAccess: {1}to * by dn="cn=Directory Manager,dc=eucalyptus,dc=com" read dn: olcOverlay={1}accesslog,olcDatabase={3}mdb,cn=config objectClass: olcOverlayConfig objectClass: olcAccessLogConfig olcOverlay: {1}accesslog olcAccessLogDB: cn=log olcAccessLogOps: all olcAccessLogPurge: 7+00:00 1+00:00 olcAccessLogSuccess: TRUE olcAccessLogOld: (objectclass=idnsRecord)
After creating the access-log.ldif, create the directory for storing the access database:
# su - openldap -c "mkdir /media/ephemeral0/openldap/var/openldap-data/access"
Upload the LDIF using the cn=admin,cn=config user:
# /media/ephemeral0/openldap/bin/ldapadd -D cn=admin,cn=config -W -f access-log.ldif
Now that OpenLDAP is ready to go, let’s work on configuring Bind9 DNS.
Bind9 DNS Configuration
Since bind-dyndb-ldap has a dependency package of bind, named has already been installed on the instance. The only thing left to do is edit /etc/named.conf so that we are able to use the dynamic ldap backend module. Edit /etc/named.conf so that it looks like the following:
options { listen-on port 53 { <private IP address of the instance>; }; listen-on-v6 port 53 { ::1; }; directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; recursion yes; dnssec-enable yes; dnssec-validation yes; dnssec-lookaside auto; /* Path to ISC DLV key */ bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; allow-recursion { any; }; }; dynamic-db "qa_dns_test" { library "ldap.so"; arg "uri ldap://localhost"; arg "base ou=dns,dc=eucalyptus, dc=com"; arg "auth_method none"; arg "cache_ttl 10"; arg "zone_refresh 1"; arg "dyn_update yes"; }; logging { channel default_debug { file "data/named.run"; severity debug; print-time yes; }; }; zone "." IN { type hint; file "named.ca"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key";
As seen above, the dynamic-db section is the configuration for connecting to the OpenLDAP server. For more advanced configurations, please reference the README in the bind-dyndb-ldap repository on git.fedorahosted.org.
Now we are ready to start named (the bind DNS server). Before starting the server, make sure and create the rndc key, then start named:
# rndc-confgen -a -r /dev/urandom # service named start
You have successfully created an Bind9 DNS + OpenLDAP deployment. Let’s run a quick test.
Test the Deployment
To test the deployment, I created an LDIF called test-cloud.ldif. The configuration sets up a domain called eucalyptus-systems.com. It also creates a sub-domain that will be forwarding requests for euca-hasp.eucalyptus-systems.com to the CLCs of the Eucalyptus HA deployment that has been set up. The contents of the file are as follows:
dn: idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: top objectClass: idnsZone objectClass: idnsRecord idnsName: eucalyptus-systems.com idnsUpdatePolicy: grant EUCALYPTUS-SYSTEMS.COM krb5-self * A; idnsZoneActive: TRUE idnsSOAmName: server.eucalyptus-systems.com idnsSOArName: root.server.eucalyptus-systems.com idnsAllowQuery: any; idnsAllowDynUpdate: TRUE idnsSOAserial: 1 idnsSOArefresh: 10800 idnsSOAretry: 900 idnsSOAexpire: 604800 idnsSOAminimum: 86400 NSRecord: ns ARecord: 192.168.55.103 - (the public IP of the instance) dn: idnsName=ns,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: ns aRecord: 192.168.55.103 dn: idnsName=server,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: server CNAMERecord: eucalyptus-systems.com. dn: idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com objectClass: idnszone objectClass: idnsrecord objectClass: top idnsName: 39.168.192.in-addr.arpa. idnsSOAmName: server.eucalyptus-systems.com idnsSOArName: root.server.eucalyptus-systems.com idnsSOAserial: 1350039556 idnsSOArefresh: 10800 idnsSOAretry: 900 idnsSOAexpire: 604800 idnsSOAminimum: 86400 idnsZoneActive: TRUE idnsAllowDynUpdate: TRUE idnsAllowQuery: any; idnsAllowTransfer: none; idnsUpdatePolicy: grant EUCALYPTUS-SYSTEMS.COM krb5-subdomain 39.168.192.in-addr.arpa. PTR; nSRecord: server.eucalyptus-systems.com. dn: idnsName=_ldap._tcp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: _ldap._tcp SRVRecord: 0 100 389 server dn: idnsName=_ntp._udp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: _ntp._udp SRVRecord: 0 100 123 server # The DNS entries for the CLCs of the cloud - viking-01 and viking-02 dn: idnsName=viking-02,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: viking-02 aRecord: 192.168.39.102 dn: idnsname=102,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com objectClass: idnsrecord objectClass: top idnsName: 102 pTRRecord: viking-02.eucalyptus-systems.com. dn: idnsName=viking-01,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: idnsRecord objectClass: top idnsName: viking-01 aRecord: 192.168.39.101 dn: idnsname=101,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com objectClass: idnsrecord objectClass: top idnsName: 101 pTRRecord: viking-01.eucalyptus-systems.com. # The delegated zone - euca-hasp.eucalyptus-systems.com dn: idnsName=euca-hasp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com objectClass: top objectClass: idnsRecord objectClass: idnsZone idnsForwardPolicy: first idnsAllowDynUpdate: FALSE idnsZoneActive: TRUE idnsAllowQuery: any; idnsForwarders: 192.168.39.101 idnsForwarders: 192.168.39.102 idnsName: euca-hasp idnsSOAmName: server.eucalyptus-systems.com idnsSOArName: root.server.eucalyptus-systems.com idnsSOAretry: 15 idnsSOAserial: 1 idnsSOArefresh: 80 idnsSOAexpire: 120 idnsSOAminimum: 30 nSRecord: viking-01.eucalyptus-systems.com nSRecord: viking-02.eucalyptus-systems.com
Since this was intended for a lab environment where sub-domains (and possibly domains) would be added/deleted on a regular basis, the SOA records were not set to the RFC 1912 standards defined for production DNS use.
After creating this LDIF, it was uploaded to the LDAP server as the cn=Directory Manager,dc=eucalyptus,dc=com user:
# /media/ephemeral0/openldap/bin/ldapadd -H ldap://localhost \ -D "cn=Directory Manager,dc=eucalyptus,dc=com" -W -f test-cloud.ldif Enter LDAP Password: adding new entry "idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=ns,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=server,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=_ldap._tcp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=_ntp._udp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=viking-02,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsname=102,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=viking-01,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsname=101,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" adding new entry "idnsName=euca-hasp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com"
To test out the setup, tests were ran against the public IP address of the instance to resolve for the various configurations:
# nslookup viking-01.eucalyptus-systems.com 192.168.55.103 Server: 192.168.55.103 Address: 192.168.55.103#53 Name: viking-01.eucalyptus-systems.com Address: 192.168.39.101 # nslookup 192.168.39.101 192.168.55.103 Server: 192.168.55.103 Address: 192.168.55.103#53 101.39.168.192.in-addr.arpa name = viking-01.eucalyptus-systems.com. # nslookup eucalyptus.euca-hasp.eucalyptus-systems.com 192.168.55.103 Server: 192.168.55.103 Address: 192.168.55.103#53 Non-authoritative answer: Name: eucalyptus.euca-hasp.eucalyptus-systems.com Address: 192.168.39.102 # nslookup walrus.euca-hasp.eucalyptus-systems.com 192.168.55.103 Server: 192.168.55.103 Address: 192.168.55.103#53 Non-authoritative answer: Name: walrus.euca-hasp.eucalyptus-systems.com Address: 192.168.39.101
As see above, not only did the resolution come back correct for the machines under the eucalyptus-systems.com domain, but it also forwarded the requests for the hosts under euca-hasp.eucalyptus-systems.com correctly, and returned the correct response.
To delete the set up, an LDIF called delete-test-cloud.ldif from the test-cloud.ldif as follows:
# tac test-cloud.ldif | grep dn: > delete-test-cloud.ldif
Open up the delete-test-cloud.ldif and add the following lines between each dn:
changetype: delete (empty line)
Now, use ldapmodify as the cn=Directory Manager,dc=eucalyptus,dc=com user to delete the entries:
# /media/ephemeral0/openldap/bin/ldapmodify -H ldap://localhost -D "cn=Directory Manager,dc=eucalyptus,dc=com" -W -f delete-test-cloud.ldif Enter LDAP Password: deleting entry "idnsName=euca-hasp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsname=101,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=viking-01,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsname=102,idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=viking-02,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=_ntp._udp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=_ldap._tcp,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsname=39.168.192.in-addr.arpa.,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=server,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=ns,idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com" deleting entry "idnsName=eucalyptus-systems.com,ou=dns,dc=eucalyptus,dc=com"
To confirm, do a lookup against one of the entries to see if it still exists:
# nslookup viking-01.eucalyptus-systems.com 192.168.55.103 Server: 192.168.55.103 Address: 192.168.55.103#53 ** server can't find viking-01.eucalyptus-systems.com: NXDOMAIN
There you have it! A successful Bind9 DNS + OpenLDAP deployment is ready to be used.
Enjoy! And as always, questions/suggestions/comments are always welcome.
Nice work buddy. We will put this into production in the coming month for the QA environment.
Sweet. Just let me know.
Why did you opt to add LDAP into the mix instead of just using nsupdate? You mentioned creating and destroying zones on the fly, but your use case doesn’t require that since you’re only messing with subdomains of your initial zones.
Great question. If you look at my LDIF, I add in a domain, and subdomain. From what I have read regarding using nsupdate, this is something that can’t be done currently. Therefore, this is a solution that I looked at to help test Eucalyptus DNS in a QA environment where you have many clouds being created/destroyed.
Since nsupdate doesn’t handle anding of subdomains and adding forwarding for those subdomains, the goal here was to be able to add/delete those on the fly without having to do an “service named reload”.
Does that help?
You don’t need to create a new zone for a subdomain when you aren’t delegating it — its records can use the authority of the parent zone.
Ah, ok. Thanks for the feedback. I was referencing the instructions found here – http://www.eucalyptus.com/docs/3.2/ig/setting_up_dns.html#setting_up_dns_del, where subdomains are being delegated – therefore a new zone is created. I do understand your point however – if I was just creating a subdomain and I am wasn’t delegating, then there would be no need for a new zone.
I think I understand the confusion here. The title is misleading, so therefore I changed it. There are two types of sub-domains (virtual and fully delegated). This blog post was primarily focused on deploying fully delegated sub-domains dynamically. Virtual sub-domains (which I think you are referring to) don’t require the need for another zone entry for the sub-domain in named.conf. Let me know if this helps clear up everything. Thanks again for the interaction. I really appreciate it.