# Install DNS server. # class dns::server { case $::operatingsystem { "centos","redhat": { case $::operatingsystemrelease { /^[1-5]/: { $bind_package = [ "bind-chroot", "caching-nameserver" ] } default: { $bind_package = "bind-chroot" } } $bind_service = "named" } "debian","ubuntu": { $bind_package = "bind9" $bind_service = "bind9" } "openbsd": { if versioncmp($::operatingsystemrelease, "5.8") < 0 { $bind_package = undef $bind_service = "named" } else { $bind_package = "isc-bind" $bind_service = "isc_named" } } default: { $bind_package = "bind-chroot" $bind_service = "named" } } if $bind_package { package { "bind": ensure => installed, name => $bind_package, } $package_require = Package["bind"] } else { $package_require = undef } # first set per os paths case $::operatingsystem { "fedora": { $confdir = "/etc/named" } "centos","redhat": { case $::operatingsystemrelease { /^5\..*/: { $chroot = "/var/named/chroot" } default: { $confdir = "/etc/named" } } } "ubuntu": { $confdir = "/etc/bind" $config = "${confdir}/named.conf" $rndckey = "${confdir}/rndc.key" } "openbsd": { $chroot = "/var/named" } } # if some var is not set use default value if !$confdir { $confdir = "/etc" } if !$config { $config = "/etc/named.conf" } if !$rndckey { $rndckey = "/etc/rndc.key" } if !$chroot { $chroot = "" } case $::operatingsystem { "openbsd": { if versioncmp($::operatingsystemrelease, "5.8") < 0 { $group = "named" } else { $group = "_bind" } } "ubuntu": { $group = "bind" } default: { $group = "named" } } if ! $::ipaddress6 { $options = $::operatingsystem ? { "debian" => "-u bind -4", "ubuntu" => "-u bind -4", default => "-4", } } else { $options = $::operatingsystem ? { "debian" => "-u bind", "ubuntu" => "-u bind", default => "", } } case $::operatingsystem { "debian", "ubuntu": { augeas { "set-named-default": context => "/files/etc/default/named", changes => "set OPTIONS '\"${options}\"'", notify => Service["named"], require => Package["bind"], } } "fedora","centos","redhat": { augeas { "set-named-sysconfig": changes => "set OPTIONS '\"${options}\"'", incl => "/etc/sysconfig/named", lens => "Shellvars.lns", notify => Service["named"], require => Package["bind"], } } } file { "${chroot}${rndckey}": ensure => present, mode => "0640", owner => "root", group => $group, require => $package_require, } exec { "rndc-confgen": command => $chroot ? { "" => "rndc-confgen -r /dev/urandom -a", default => "rndc-confgen -r /dev/urandom -a -t ${chroot}", }, path => "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin", unless => "test -s ${chroot}${rndckey}", require => File["${chroot}${rndckey}"], } if "${chroot}" != "" { file { "/etc/rndc.key": ensure => link, target => "${chroot}${rndckey}", owner => "root", group => $group, require => Exec["rndc-confgen"], } } exec { "named-checkconf": command => $chroot ? { "" => "named-checkconf -z", default => "named-checkconf -z -t ${chroot}" }, path => "/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin", refreshonly => true, require => Exec["rndc-confgen"], notify => Service["named"], } service { "named": name => $bind_service, ensure => running, enable => true, } file { "named.conf": ensure => present, path => "${chroot}${config}", mode => "0640", owner => "root", group => $group, require => $package_require, notify => Exec["generate-named-conf"], } file { "/usr/local/sbin/generate-named-conf.sh": ensure => present, content => template("dns/generate-named-conf.sh.erb"), mode => "0755", owner => "root", group => $::operatingsystem ? { "openbsd" => "wheel", default => "root", }, notify => Exec["generate-named-conf"], } exec { "generate-named-conf": command => "/usr/local/sbin/generate-named-conf.sh > ${chroot}${config}", path => "/bin:/usr/bin:/sbin:/usr/sbin", user => "root", refreshonly => true, require => File["/usr/local/sbin/generate-named-conf.sh"], notify => Exec["named-checkconf"], } file { "${chroot}${confdir}/named.conf.options": ensure => present, source => [ "puppet:///files/dns/named.conf.options.${::homename}", "puppet:///files/dns/named.conf.options", "puppet:///modules/dns/named.conf.options", ], mode => "0640", owner => "root", group => $group, require => $package_require, notify => Exec["named-checkconf"], } file { "${chroot}${confdir}/named.conf.local": ensure => present, source => [ "puppet:///files/dns/named.conf.local.${::homename}", "puppet:///files/dns/named.conf.local", "puppet:///modules/dns/named.conf.local", ], mode => "0640", owner => "root", group => $group, require => $package_require, notify => Exec["named-checkconf"], } } # Generate named config from LDAP # # Usage: # # Put templates you want to generate to master.in directory. # See dnsdump.py for example template tags. class dns::server::ldap inherits dns::server { include ldap::client::python file { "/usr/local/sbin/dnsdump.py": ensure => present, source => "puppet:///modules/dns/dnsdump.py", mode => 0755, owner => root, group => $::operatingsystem ? { OpenBSD => wheel, default => root, }, } file { "/var/named/master.in": ensure => directory, source => "puppet:///files/dns/master.in", recurse => true, mode => 0755, owner => root, purge => true, } exec { "generate-dns-conf": path => "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin", command => "dnsdump.py --notest /var/named/master.in /var/named/master", require => File["/usr/local/sbin/dnsdump.py"], unless => "dnsdump.py --test /var/named/master.in /var/named/master", notify => Exec["named-checkconf"], } } # Configure DNS zone. # # === Parameters # # $name: # Zone name. # $role: # The role {master, slave, dynamic, forward} of this host. # $master: # IP address of DNS master for this zone if role is slave. # IP address and FQDN of DNS master for this zone if running as # master and using autogenerated zone. # $slaves: # IP addresess and host names of the DNS slaves for this zone. # Required only when using autogenrated zones. # $forwarders: # Array of forwarder IP addresses for forward role zones. # $source: # Source file to use for zone. Defaults to auto. # $key: # Key for dynamic zones. # $keytype: # Key algorithm. Defaults to 'hmac-md5'. # $contact: # SOA contact email for autogenerated zones. # Defaults to hostmaster.$zone. # define dns::zone($role = "master", $master = "", $slaves = [], $forwarders = [], $source = "AUTO", $key = "none", $keytype = "hmac-md5", $contact = "NONE") { if $name =~ /^([^\/]+\/)?([0-9]+)\/([0-9\.]+\.in-addr\.arpa)$/ { # Special handling for RFC2317 style in-addr.arpa zones case $1 { ".": { $view = "" } "default/": { $view = "" } default: { $view = $1 } } $zone = "$2/$3" $zonefile = "$2-$3" } else { case dirname($name) { ".": { $view = "" } "default": { $view = "" } default: { $view = dirname($name) } } $zone = basename($name) $zonefile = $zone } case $role { "master": { case $::operatingsystem { "openbsd": { $zonedir = "/master/${view}" } "fedora","centos","redhat": { $zonedir = "/var/named/${view}" } "ubuntu": { $zonedir = "/etc/bind/${view}" } } } "dynamic": { if $key == "none" { fail("No key defined for dns::zone '${name}'") } case $::operatingsystem { "openbsd": { $zonedir = "/dynamic/${view}" } "fedora","centos","redhat": { $zonedir = "/var/named/dynamic/${view}" } "ubuntu": { $zonedir = "/etc/bind/dynamic/${view}" } } } "slave": { if $master == "" { fail("No master defined for dns::zone '${name}'") } case $::operatingsystem { "openbsd": { $zonedir = "/slave/${view}" } "fedora","centos","redhat": { $zonedir = "/var/named/slaves/${view}" } "ubuntu": { $zonedir = "/var/cache/bind/${view}" } } } "forward": { if $forwarders == [] { fail("No forwarders defined for dns::zone '${name}'") } $zonedir = "" } default: { fail("Unknown DNS zone type '${role}'") } } if $view != "" { if !defined(File["${dns::server::chroot}${dns::server::confdir}/${view}"]) { file { "${dns::server::chroot}${dns::server::confdir}/${view}": ensure => directory, mode => "0750", owner => "root", group => $dns::server::group, before => File["${dns::server::chroot}${dns::server::confdir}/${view}/zone.${zonefile}"], require => $::dns::server::package_require, } } } if $zonedir != "" { if !defined(File["${dns::server::chroot}${zonedir}"]) { file { "${dns::server::chroot}${zonedir}": ensure => directory, mode => $role ? { "master" => "0750", default => "0770", }, owner => "root", group => $dns::server::group, before => $role ? { "master" => File["${dns::server::chroot}${zonedir}/db.${zonefile}"], default => undef, }, require => $::dns::server::package_require, } } } file { "${dns::server::chroot}${dns::server::confdir}/${view}/zone.${zonefile}": ensure => present, content => template("dns/zone.$role.erb"), mode => "0640", owner => "root", group => $dns::server::group, require => $::dns::server::package_require, notify => Exec["generate-named-conf"], } if $role == "master" and $zone != "." { if $source != "AUTO" { file { "${dns::server::chroot}${zonedir}/db.${zonefile}": ensure => present, source => $source, mode => "0640", owner => "root", group => $dns::server::group, require => $::dns::server::package_require, notify => Exec["generate-named-conf"], } } else { if $contact == "NONE" { $soacontact = "hostmaster.${zone}" } else { $soacontact = $contact } file { "${dns::server::chroot}${zonedir}/db.${zonefile}": ensure => present, content => template("dns/db.erb"), mode => "0640", owner => "root", group => $dns::server::group, backup => false, require => $::dns::server::package_require, notify => Exec["named-checkconf"], } file { "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic": ensure => present, mode => "0640", owner => "root", group => $dns::server::group, require => $::dns::server::package_require, notify => Exec["named-checkconf"], } file { "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d": ensure => directory, mode => "0640", owner => "root", group => $dns::server::group, require => $::dns::server::package_require, purge => true, force => true, recurse => true, source => "puppet:///modules/custom/empty", notify => Service["named"], } file { "${dns::server::chroot}${zonedir}/db.${zonefile}-static": ensure => present, source => [ "puppet:///files/dns/db.${zonefile}-static.${homename}", "puppet:///files/dns/db.${zonefile}-static", "puppet:///modules/dns/empty", ], mode => "0640", owner => "root", group => $dns::server::group, require => $::dns::server::package_require, notify => Exec["named-checkconf"], } exec { "update-db.${zonefile}-dynamic": path => "/bin:/usr/bin:/sbin:/usr/sbin", command => "/bin/sh -c 'find db.${zonefile}-dynamic.d -name rr.\\* | xargs cat > db.${zonefile}-dynamic'", cwd => "${dns::server::chroot}${zonedir}", user => "root", refreshonly => true, notify => Service["named"], } Dns::Node::Record <<| tag == "dnsrec-${zone}" |>> { dbdir => "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d", notify => Exec["update-db.${zonefile}-dynamic"], require => File["${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic", "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d"], } Dns::Node::Record::Reverse <<| tag == "dnsptr-${zone}" |>> { dbdir => "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d", notify => Exec["update-db.${zonefile}-dynamic"], require => File["${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic", "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d"], } } } } # Generate dynamic DNS records for puppet node. # # === Global variables # # $dns_node_name: # A record name. Defaults to $hostname. # # $dns_node_zone: # DNS zone. Defaults to $domain. # # $dns_node_ipaddr: # IP address to use in records. Defaults to $ipaddress. # # $dns_node_netmask: # Netmask for determining reverse zone class. Defaults to $netmask. # # $dns_node_alias: # List of names used as CNAME records. # class dns::node { tag("bootstrap") if !$dns_node_name { $dns_node_name = $::hostname } if !$dns_node_zone { $dns_node_zone = $::domain } if !$dns_node_ipaddr and !$dns_node_netmask { $dns_node_ipaddr = $::ipaddress $dns_node_netmask = $::netmask } else { if !$dns_node_ipaddr or !$dns_node_netmask { fail("Must define both \$dns_node_ipaddr and \$dns_node_netmask") } } if $dns_node_alias { $dns_node_cname = inline_template("<% @dns_node_alias.each do |a| -%><%= a %>\tIN\tCNAME\t<%= @dns_node_name %>\n<% end -%>") } else { $dns_node_cname = "" } @@dns::node::record { "${dns_node_name}.${dns_node_zone}": ipaddr => $dns_node_ipaddr, host => $dns_node_name, cname => $dns_node_cname, tag => "dnsrec-${dns_node_zone}", } $dns_node_class = inline_template("<%= @dns_node_netmask.scan('255.').length -%>") $dns_node_raddr = inline_template("<%= @dns_node_ipaddr.split('.').reverse.first(4-@dns_node_class.to_i).join('.') -%>") $dns_node_rzone = inline_template("<%= @dns_node_ipaddr.split('.').reverse.last(@dns_node_class.to_i).join('.') -%>.in-addr.arpa") @@dns::node::record::reverse { "${dns_node_name}.${dns_node_zone}": ipaddr => $dns_node_raddr, host => "${dns_node_name}.${dns_node_zone}", tag => "dnsptr-${dns_node_rzone}", } } define dns::node::record($dbdir, $ipaddr, $host, $cname="") { file { "${dbdir}/rr.${name}": ensure => present, content => "${host}\tIN\tA\t${ipaddr}\n${cname}", } } define dns::node::record::reverse($dbdir, $ipaddr, $host) { file { "${dbdir}/rr.${name}": ensure => present, content => "${ipaddr}\tIN\tPTR\t${host}.\n", } } # Install dynamic DNS update script # # === Global variables # # $dns_nsupdate_name: # FQDN to update into DNS. # # $dns_nsupdate_key: # DNS key to use when updating entry. Usually in format: # # for example: # gw1.example.com. sZ6GgTZLBX83LXCoo # # $dns_nsupdate_server: # DNS server address where to update entry. # # $dns_nsupdate_zone: # Zone name to update. Defaults to domain part of # $dns_nsupdate_name variable. # class dns::nsupdate { file { "/usr/local/sbin/nsupdate.sh": ensure => present, content => template("dns/nsupdate.sh.erb"), mode => "0700", owner => root, group => $::operatingsystem ? { openbsd => wheel, default => root, }, } cron { "nsupdate": ensure => present, command => "/usr/local/sbin/nsupdate.sh", minute => "*/5", require => File["/usr/local/sbin/nsupdate.sh"], } }