ldap
As of PowerDNS Authoritative Server 4.0.0, the LDAP backend is fully supported.
The original author for this module is Norbert Sendetzky. This page is based on the content from his LDAPbackend wiki section as copied in February 2016, and edited from there.
Warning
Host names and the MNAME of a SOA records are NEVER terminated with a ‘.’ in PowerDNS storage! If a trailing ‘.’ is present it will inevitably cause problems, problems that may be hard to debug.
The LDAP backend enables PowerDNS to retrieve DNS information from any standard compliant LDAP server. This is extremely handy if information about hosts is already stored in an LDAP tree.
The schema is based on the ‘uninett’ dnszone schema, with a few types added by number as designed in that schema:
# A schema for storing DNS zones in LDAP
#
# ORDERING is not necessary, and some servers don't support
# integerOrderingMatch. Omit or change if you like
attributetype ( 1.3.6.1.4.1.2428.20.0.0 NAME 'dNSTTL'
DESC 'An integer denoting time to live'
EQUALITY integerMatch
ORDERING integerOrderingMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )
attributetype ( 1.3.6.1.4.1.2428.20.0.1 NAME 'dNSClass'
DESC 'The class of a resource record'
EQUALITY caseIgnoreIA5Match
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.11 NAME 'wKSRecord'
DESC 'a well known service description, RFC 1035'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.12 NAME 'pTRRecord'
DESC 'domain name pointer, RFC 1035'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.13 NAME 'hInfoRecord'
DESC 'host information, RFC 1035'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.14 NAME 'mInfoRecord'
DESC 'mailbox or mail list information, RFC 1035'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.16 NAME 'tXTRecord'
DESC 'text string, RFC 1035'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.17 NAME 'rPRecord'
DESC 'for Responsible Person, RFC 1183'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.18 NAME 'aFSDBRecord'
DESC 'for AFS Data Base location, RFC 1183'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.24 NAME 'SigRecord'
DESC 'Signature, RFC 2535'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.25 NAME 'KeyRecord'
DESC 'Key, RFC 2535'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.27 NAME 'gPosRecord'
DESC 'Geographical Position, RFC 1712'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.28 NAME 'aAAARecord'
DESC 'IPv6 address, RFC 1886'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.29 NAME 'LocRecord'
DESC 'Location, RFC 1876'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.30 NAME 'nXTRecord'
DESC 'non-existant, RFC 2535'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.33 NAME 'sRVRecord'
DESC 'service location, RFC 2782'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.35 NAME 'nAPTRRecord'
DESC 'Naming Authority Pointer, RFC 2915'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.36 NAME 'kXRecord'
DESC 'Key Exchange Delegation, RFC 2230'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.37 NAME 'certRecord'
DESC 'certificate, RFC 2538'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.38 NAME 'a6Record'
DESC 'A6 Record Type, RFC 2874'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.39 NAME 'dNameRecord'
DESC 'Non-Terminal DNS Name Redirection, RFC 2672'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.42 NAME 'aPLRecord'
DESC 'Lists of Address Prefixes, RFC 3123'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.43 NAME 'dSRecord'
DESC 'Delegation Signer, RFC 3658'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.44 NAME 'sSHFPRecord'
DESC 'SSH Key Fingerprint, RFC 4255'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.45 NAME 'iPSecKeyRecord'
DESC 'SSH Key Fingerprint, RFC 4025'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.46 NAME 'rRSIGRecord'
DESC 'RRSIG, RFC 3755'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.47 NAME 'nSECRecord'
DESC 'NSEC, RFC 3755'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.48 NAME 'dNSKeyRecord'
DESC 'DNSKEY, RFC 3755'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.49 NAME 'dHCIDRecord'
DESC 'DHCID, RFC 4701'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.50 NAME 'nSEC3Record'
DESC 'NSEC record version 3, RFC 5155'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.51 NAME 'nSEC3PARAMRecord'
DESC 'NSEC3 parameters, RFC 5155'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.52 NAME 'tLSARecord'
DESC 'TLSA certificate association, RFC 6698'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.59 NAME 'cDSRecord'
DESC 'Child DS, RFC7344'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.60 NAME 'cDNSKeyRecord'
DESC 'DNSKEY(s) the Child wants reflected in DS, RFC7344'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.61 NAME 'openPGPKeyRecord'
DESC 'OpenPGP Key, RFC7929'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.64 NAME 'SVCBRecord'
DESC 'Service binding, draft-ietf-dnsop-svcb-https-01'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.65 NAME 'HTTPSRecord'
DESC 'HTTPS service binding, draft-ietf-dnsop-svcb-https-01'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.99 NAME 'sPFRecord'
DESC 'Sender Policy Framework, RFC 4408'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.108 NAME 'EUI48Record'
DESC 'EUI-48 address, RFC7043'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.109 NAME 'EUI64Record'
DESC 'EUI-64 address, RFC7043'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.249 NAME 'tKeyRecord'
DESC 'Transaction Key, RFC2930'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.256 NAME 'uRIRecord'
DESC 'URI, RFC7553'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.257 NAME 'cAARecord'
DESC 'Certification Authority Restriction, RFC6844'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.32769 NAME 'dLVRecord'
DESC 'DNSSEC Lookaside Validation, RFC4431'
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.65226 NAME 'TYPE65226Record'
DESC ''
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
attributetype ( 1.3.6.1.4.1.2428.20.1.65534 NAME 'TYPE65534Record'
DESC ''
EQUALITY caseIgnoreIA5Match
SUBSTR caseIgnoreIA5SubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
objectclass ( 1.3.6.1.4.1.2428.20.2 NAME 'dNSDomain2'
SUP 'dNSDomain' STRUCTURAL
MAY ( DNSTTL $ DNSClass $ WKSRecord $ PTRRecord $
HINFORecord $ MINFORecord $ TXTRecord $ RPRecord $
AFSDBRecord $ SIGRecord $ KEYRecord $ GPOSRecord $
AAAARecord $ LOCRecord $ NXTRecord $ SRVRecord $
NAPTRRecord $ KXRecord $ CERTRecord $ A6Record $
DNAMERecord $ APLRecord $ DSRecord $ SSHFPRecord $
IPSECKEYRecord $ RRSIGRecord $ NSECRecord $
DNSKEYRecord $ DHCIDRecord $ NSEC3Record $ NSEC3PARAMRecord $
TLSARecord $ CDSRecord $ CDNSKEYRecord $ OPENPGPKEYRecord $
SVCBRecord $ HTTPSRecord $
SPFRecord $ EUI48Record $ EUI64Record $ TKEYRecord $
URIRecord $ CAARecord $ DLVRecord $ TYPE65226Record $
TYPE65534Record
) )
The LDAP dnsdomain2 schema contains the additional object descriptions which are required by the LDAP server to check the validity of entries when they are added. Please consult the documentation of the LDAP server to find out how to add this schema to the server.
The LDAP backend can be compiled by adding ldap
to either the
--with-modules
or --with-dynmodules
configure
options.
When using packages, the pdns-backend-ldap
package should be
installed.
There are a few options through the LDAP DNS backend can be configured.
Add them to the pdns.conf
file.
To launch the ldap backend:
launch=ldap
ldap-host
¶(default “ldap://127.0.0.1:389/
”) : The values assigned to this
parameter can be LDAP URIs (e.g. ldap://127.0.0.1/
or
ldaps://127.0.0.1/
) describing the connection to the LDAP server.
There can be multiple LDAP URIs specified for load balancing and high
availability if they are separated by spaces. In case the used LDAP
client library doesn’t support LDAP URIs as connection parameter, use
plain host names or IP addresses instead (both may optionally be
followed by a colon and the port).
ldap-starttls
¶(default “no”) : Use TLS encrypted connections to the LDAP server. This
is only allowed if ldap-host is an ldap://
URI or a host name / IP
address.
ldap-timeout
¶(default: “5”) : The number of seconds to wait for LDAP operations to complete.
ldap-reconnect-attempts
¶(default: “5”) : The number of attempts to make to re-establish a lost connection to the LDAP server.
ldap-bindmethod
¶(default: “simple”) : How to authenticate to the LDAP server. Actually only two methods are supported: “simple”, which uses the classical DN / password, or “gssapi”, which requires a Kerberos keytab.
ldap-binddn
¶(default “”) : Path to the object to authenticate against. Should only be used, if the LDAP server doesn’t support anonymous binds and with the “simple” bindmethod.
ldap-secret
¶(default “”) : Password for authentication against the object specified by ldap-binddn. Only used when “bindmethod” is “simple”.
ldap-krb5-keytab
¶(default: “”) : Full path to the keytab file to use to authenticate. This is only used when “bindmethod” is set to “gssapi”. The keytab must, ideally, contain only one principal (or to put it otherwise, only the first principal found in the keytab will be used).
ldap-krb5-ccache
¶(default: “”) : Full path to the Kerberos credential cache file to use. Actually only files are supported, and the “FILE:” prefix must not be set. The PowerDNS process must be able to write to this file and it must be the only one able to read it.
ldap-basedn
¶(default “”) : The PowerDNS LDAP DNS backend searches below this path for objects containing the specified DNS information. The retrieval of attributes is limited to this subtree. This option must be set to the path according to the layout of your LDAP tree, e.g. ou=hosts,o=linuxnetworks,c=de is the DN to my objects containing the DNS information.
ldap-method
¶(default “simple”) :
simple
: Search the requested domain by comparing the
associatedDomain attributes with the domain string in the question.tree
: Search entries by translating the domain string into a LDAP
dn. Your LDAP tree must be designed in the same way as the DNS LDAP
tree. The question for “myhost.linuxnetworks.de” would translate into
“dc=myhost,dc=linuxnetworks,dc=de,ou=hosts=…” and the entry where
this dn points to would be evaluated for dns records.strict
: Like simple, but generates PTR records from aRecords or
aAAARecords. Using “strict”, zone transfers for reverse zones are not
possible.ldap-filter-axfr
¶(default “(:target:)” ) : LDAP filter for limiting AXFR results (zone transfers), e.g. (&(:target:)(active=yes)) for returning only entries whose attribute “active” is set to “yes”.
ldap-filter-lookup
¶(default “(:target:)” ) : LDAP filter for limiting IP or name lookups, e.g. (&(:target:)(active=yes)) for returning only entries whose attribute “active” is set to “yes”.
First off adding master support to the LDAP backend needs a schema update. This is required as some metadata must be stored by PowerDNS, such as the last successful transfer to slaves. The new schema is available in schema/pdns-domaininfo.schema.
Once the schema is loaded the zones for which you want to be a master
must be modified. The dn of the SOA record must have the object class
PdnsDomain
, and thus the PdnsDomainId
attribute. This attribute
is an integer that must be unique across all zones served by the
backend. Furthermore the PdnsDomainType
must be equal to ‘master’
(lower case).
Here is an example LDIF of a zone that’s ready for master operation (assuming the ‘tree’ style):
dn: dc=example,dc=com,ou=dns,dc=mycompany,dc=com
objectClass: top
objectClass: domainRelatedObject
objectClass: dNSDomain2
objectClass: PdnsDomain
dc: example
associatedDomain: example.com
nSRecord: ns1.example.com
sOARecord: ns1.example.com. hostmaster.example.com. 2013031101 1800 600 1209600 600
mXRecord: 10 mx1.example.com
PdnsDomainId: 1
PdnsDomainType: master
PdnsDomainMaster: 192.168.0.2
You should have one attribute PdnsDomainMaster
per master serving
this zone.
The DNS LDAP tree should be designed carefully to prevent mistakes, which are hard to correct afterwards. The best solution is to create a subtree for all host entries which will contain the DNS records. This can be done the simple way or in a tree style.
DN of a simple style example record (e.g. myhost.example.com):
dn:dc=myhost,dc=example,ou=hosts,...
DN of a tree style example record (e.g. myhost.test.example.com):
dn:dc=myhost,dc=test,dc=example,dc=com,ou=hosts,...
Each domain (or zone for BIND users) must include one object containing a SOA (Start Of Authority) record. This requirement applies to both forward and reverse zones. This object can also contain the attribute for a MX (Mail eXchange) and one or more NS (Name Server) records. These attributes allow one or more values, e.g. for a backup mail or name server:
dn:dc=example,ou=hosts,o=example,c=com
objectclass:top
objectclass:dcobject
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:example
soarecord:ns.example.com me@example.com 1 1800 3600 86400 7200
nsrecord:ns.example.com
mxrecord:10 mail.example.com
mxrecord:20 mail2.example.com
associateddomain:example.com
A simple mapping between name and IP address can be specified by an
object containing an arecord
and an associateddomain
.
dn:dc=server,dc=example,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:server
arecord:10.1.0.1
arecord:192.168.0.1
associateddomain:server.example.com
Be aware of the fact that these examples work if ldap-method
is
simple
or strict
. For tree mode, all DNs will have to be
modified according to the algorithm described in the section above.
Wild-card domains are possible by using the asterisk in the
associatedDomain
value like it is used in the BIND zone files. The
“dc” attribute can be set to any value in simple or strict mode - this
doesn’t matter.
dn:dc=any,dc=example,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:any
arecord:192.168.0.1
associateddomain:*.example.com
In tree mode wild-card entries has to look like this instead:
dn:dc=*,dc=example,dc=de,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:*
arecord:192.168.0.1
associateddomain:*.example.com
Aliases for an existing DNS object have to be defined in a separate LDAP
object. One object should be create per alias (this is a must in tree
mode) or add all aliases (as values of associateddomain
) to one
object. The only thing which is not allowed is to create loops by using
the same name in associateddomain
and in cnamerecord
.
dn:dc=server-aliases,dc=example,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:server-aliases
cnamerecord:server.example.com
associateddomain:proxy.example.com
associateddomain:mail2.example.com
associateddomain:ns.example.com
Aliases are optional. All alias domains can also be added to the
associateddomain attribute. The only difference is that these additional
domains aren’t recognized as aliases anymore, but instead as a normal
arecord
:
dn:dc=server,dc=example,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain
objectclass:domainrelatedobject
dc:server
arecord:10.1.0.1
associateddomain:server.example.com
associateddomain:proxy.example.com
associateddomain:mail2.example.com
associateddomain:ns.example.com
Currently there are two options: Set ldap-method
to strict
to
have the code automatically derive PTR records from A and AAAA records
in the tree. Or, in simple
and tree
modes, create additional
objects explicitly mapping each address to a PTR record.
For strict
or simple
modes, first create an object with an SOA
record for the reverse-lookup zone(s) corresponding to the A and AAAA
records that will be served:
dn:dc=1.10.in-addr.arpa,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain2
objectclass:domainrelatedobject
dc:1.10.in-addr.arpa
soarecord:ns.example.com me@example.com 1 1800 3600 86400 7200
nsrecord:ns.example.com
associateddomain:1.10.in-addr.arpa
In strict
mode, no other objects are required – reverse queries
that correspond to an arecord or aaaarecord of an existing object will
be automagically serviced using the associateddomain entry of that
object.
In simple
mode, you must then create objects for each reverse
mapping:
dn:dc=1.0,dc=1.10.in-addr.arpa,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain2
objectclass:domainrelatedobject
dc:1.0
ptrrecord:server.example.com
associateddomain:1.0.1.10.in-addr.arpa
Tree mode requires each component to be a dc element of its own:
dn:dc=1,dc=0,dc=1,dc=10,dc=in-addr,dc=arpa,ou=hosts,o=example,c=de
objectclass:top
objectclass:dnsdomain2
objectclass:domainrelatedobject
dc:1
ptrrecord:server.example.com
associateddomain:1.0.1.10.in-addr.arpa
To use this kind of record, add the dnsdomain2 schema to the configuration of the LDAP server.
CAUTION: ldap-method=strict
cannot be used if zone transfers
(AXFR) are needed to other name servers. Distributing zones can only be
done directly via LDAP replication in this case, because for a full zone
transfer the reverse records are missing.
There is a small utility in the PowerDNS distribution available called
zone2ldap, which can convert zone
files used by BIND to the ldif format. Ldif is a text file format
containing information about LDAP objects and can be read by every
standard compliant LDAP server. zone2ldap
needs the BIND
named.conf
(usually located in /etc) as input and writes the dns
record entries in ldif format to stdout:
zone2ldap
--basedn=YOUR_BASE_DN \
--named-conf=PATH_TO_NAMED_CONF \
--resume > zones.ldif
Alternatively zone2ldap can be used to convert only single zone files instead all zones:
zone2ldap
--basedn=YOUR_BASE_DN \
--zone-file=PATH_TO_ZONE_FILE \
--zone-name=NAME_OF_ZONE \
--resume > zone.ldif
See its manpage for a complete list of options.
When coming from the BIND LDAP sdb backend, the records can be kept in the LDAP tree also for the PowerDNS LDAP backend. The schemas both backends utilize is almost the same except for one important thing: Domains for PowerDNS are stored in the attribute “associatedDomain” whereas BIND stores them split in “relativeDomainName” and “zoneName”.
There is a migration script which creates a file in LDIF format with the necessary LDAP updates including the “associatedDomain” and “dc” attributes. The utility is executed on the command line by:
./bind2pdns-ldap
--host=HOSTNAME_OR_IP \
--basedn=YOUR_BASE_DN \
--binddn=ADMIN_DN > update.ldif
The parameter “host” and “basedn” are mandatory, “binddn” is optional. If “binddn” is given, the script will prompt for a password, otherwise an anonymous bind is executed. The updates in LDIF format are written to stdout and can be redirected to a file.
The script requires Perl and the Perl Net::LDAP module.
Updating the entries in the LDAP tree requires to make the dnsdomain2
schema known to the LDAP server. Unfortunately, both schemas (dnsdomain2
and dnszone) share the same record types and use the same OIDs so the
LDAP server can’t use both schemas at the same time. The solution is to
add the dnsdomain2
schema and
replace the dnszone schema by the dnszone-migrate
schema.
After restarting the LDAP server attributes from both schemas can be
used and updating the objects in the LDAP tree using the LDIF file
generated from bind2pdns-ldap
will work without errors.
The easiest way for migrating DNS records is to use the output of a zone
transfer (AXFR). Save the output of the dig
program provided by BIND
into a file and call zone2ldap
with the file name as option to the
--zone-file
parameter. This will generate the appropriate ldif file,
which can be imported into the LDAP tree. The bash script except below
automates this:
DNSSERVER=127.0.0.1
DOMAINS="example.com 10.10.in-addr.arpa"
for DOMAIN in $DOMAINS; do
dig @$DNSSERVER $DOMAIN AXFR> $DOMAIN.zone;
zone2ldap --zone-name=$DOMAIN --zone-file=$DOMAIN.zone> $DOMAIN.ldif;
done
To improve performance, the LDAP server can maintain indices on certain attributes. This leads to much faster searches for these type of attributes.
The LDAP DNS backend mainly searches for values in associatedDomain
,
so maintaining an index (pres,eq,sub) on this attribute is a big
performance improvement:
index associatedDomain pres,eq,sub
Furthermore, if ldap-method=strict
is set, it uses the aRecord and
aAAARecord attribute for reverse mapping of IP addresses to names. To
maintain an index (pres,eq) on these attributes also improves
performance of the LDAP server:
index aAAARecord pres,eq
index aRecord pres,eq
All other attributes than associatedDomain, aRecord or aAAARecord are only read if the object matches the specified criteria. Thus, maintaining an index on these attributes is useless.
If the DNS-entries were added before adding these statements to
slapd.conf
, the LDAP server will have to be stopped and
slapindex
should be used on the command line. This will generate the
indices for already existing attributes.
Converting the string in the dNSTTL attribute to an integer is a time
consuming task. If no separate TTL value for each entry is requires, use
the default-ttl parameter in
pdns.conf
instead. This will gain a 7% improvement in performance
for entries that aren’t cached. A dNSTTL attribute can still be added to
entries that should have a different TTL than the default TTL
The method of accessing the entries in the directory affects the performance too. By default, the “simple” method is used search for entries by using their associatedDomain attribute. Alternatively, the “tree” method can be used, whereby the search is done along the directory tree, e.g. “host.example.com” is translated into “dc=host,dc=example,dc=com,…”. This requires the LDAP DNS subtree layout to be 1:1 to the DNS tree, this will gain an additional 7% performance improvement.
The LDAP tree must contain a separate subtree of PTR records (e.g. for
1.1.10.10.in-addr.arpa) and ldap-method
can’t be set to “strict”.
For automatically generated reverse IPv6 records the aAAARecord entries must follow two restrictions: They have to be fully expanded (“FFFF::1” is not allowed and it must be “FFFF:0:0:0:0:0:0:1” instead) and they must not contain leading zeros, e.g. an entry containing “002A” is incorrect - use “2A” without zeros instead. These restrictions are due to the fact that LDAP DNS AAAA entries are pure text and doesn’t allow searching by wild-cards.
As soon as the LDAP server implementations begin to provide the features of the LDAP client update protocol (LCUP, RFC 3928), it will be possible to support the DNS notification feature for the LDAP DNS backend in case a record in the LDAP directory was changed.
Support for more authentication methods would be handy. Anyone interested may contribute.