puppet/dns/manifests/init.pp
2013-11-05 01:05:41 +02:00

659 lines
20 KiB
Puppet

# 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"
}
}
}
"debian","ubuntu": {
$bind_package = "bind9"
}
"openbsd": {
$bind_package = undef
}
default: {
$bind_package = "bind-chroot"
}
}
if $bind_package {
package { "bind":
ensure => installed,
name => $bind_package,
}
}
# 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 {
"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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
}
exec { "rndc-confgen":
command => $chroot ? {
"" => "rndc-confgen -r /dev/urandom -a",
default => "rndc-confgen -r /dev/urandom -a -t ${chroot}",
},
path => "/bin:/usr/bin:/sbin:/usr/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 ? {
"" => "/usr/sbin/named-checkconf -z",
default => "/usr/sbin/named-checkconf -z -t ${chroot}"
},
refreshonly => true,
require => Exec["rndc-confgen"],
notify => Service["named"],
}
service { "named":
name => $::operatingsystem ? {
"ubuntu" => "bind9",
default => "named",
},
ensure => running,
enable => true,
status => "/usr/sbin/rndc status",
stop => $::operatingsystem ? {
"openbsd" => "pkill -u named",
default => undef,
},
start => $::operatingsystem ? {
"openbsd" => "/usr/sbin/named ${options}",
default => undef,
},
}
file { "named.conf":
ensure => present,
path => "${chroot}${config}",
mode => "0640",
owner => "root",
group => $group,
require => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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}"],
}
}
}
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
}
}
}
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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,
require => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
notify => Exec["named-checkconf"],
}
file { "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic":
ensure => present,
mode => "0640",
owner => "root",
group => $dns::server::group,
require => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
notify => Exec["named-checkconf"],
}
file { "${dns::server::chroot}${zonedir}/db.${zonefile}-dynamic.d":
ensure => directory,
mode => "0640",
owner => "root",
group => $dns::server::group,
require => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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 => $::operatingsystem ? {
"openbsd" => undef,
default => Package["bind"],
},
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:
# <keyname> <secret>
# 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"],
}
}