diff --git a/README.md b/README.md index b751ba9..da38359 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,30 @@ server's upstream resolvers are controlled using `forwarders`, enabling of DNSSe using `dnssec`, and the reported version is controlled using `version`. It is unlikely that you will need to define an alternate value for `confdir` or `cachedir`. +#### Run bind daemon with chroot + +You can setup bind with chroot using the `$chroot` parameter: +Example for CentOS7: + +``` +class { 'bind': + chroot => true, + # Note: this file MUST be into the /etc/named directory so the + # RHEL7 specific setup-named-chroot.sh script will make it available into + # the chroot. + default_zones_include => '/etc/named/default-zones.conf', + forwarders => [ + '8.8.8.8', + '8.8.4.4', + ], + dnssec => true, + version => 'Controlled by Puppet', +} +``` + +Note: chroot is not supported for all operating systems. For now only +RHEL7/CentOS7 is supported. + ### `bind::updater` The `bind::updater` class is an alternate entrypoint into the module. This class installs the BIND client tools but not diff --git a/data/common.yaml b/data/common.yaml index bebbb65..b524673 100644 --- a/data/common.yaml +++ b/data/common.yaml @@ -1,5 +1,6 @@ --- bind::defaults::supported: false +bind::defaults::chroot_supported: false bind::defaults::random_device: '/dev/random' bind::forwarders: '' diff --git a/data/osfamily/CentOS-7.yaml b/data/osfamily/CentOS-7.yaml new file mode 100644 index 0000000..7fbcef1 --- /dev/null +++ b/data/osfamily/CentOS-7.yaml @@ -0,0 +1 @@ +bind::defaults::chroot_supported: true diff --git a/data/osfamily/Debian.yaml b/data/osfamily/Debian.yaml index e6ba19f..1e2f348 100644 --- a/data/osfamily/Debian.yaml +++ b/data/osfamily/Debian.yaml @@ -13,3 +13,4 @@ bind::defaults::default_zones_include: '/etc/bind/named.conf.default-zones' bind::defaults::isc_bind_keys: '/etc/bind/bind.keys' bind::updater::keydir: '/etc/bind/keys' +bind::defaults::bind_chroot_dir: '/var/lib/named/chroot' diff --git a/data/osfamily/RedHat.yaml b/data/osfamily/RedHat.yaml index 5c0a82a..df02b12 100644 --- a/data/osfamily/RedHat.yaml +++ b/data/osfamily/RedHat.yaml @@ -14,4 +14,8 @@ bind::defaults::default_zones_include: '/etc/named.default-zones.conf' bind::defaults::default_zones_source: 'puppet:///modules/bind/RedHat/named.default-zones.conf' bind::defaults::isc_bind_keys: '/etc/named.iscdlv.key' +bind::defaults::bind_chroot_package: 'bind-chroot' +bind::defaults::bind_chroot_service: 'named-chroot' +bind::defaults::bind_chroot_dir: '/var/named/chroot' + bind::updater::keydir: '/etc/named/keys' diff --git a/hiera.yaml b/hiera.yaml index 1baae4a..f61f96e 100644 --- a/hiera.yaml +++ b/hiera.yaml @@ -5,5 +5,6 @@ hierarchy: - name: "Platform" backend: yaml paths: + - "osfamily/%{facts.os.name}-%{facts.os.release.major}" - "osfamily/%{facts.os.family}" - "common" diff --git a/manifests/defaults.pp b/manifests/defaults.pp index 0930185..8916d34 100644 --- a/manifests/defaults.pp +++ b/manifests/defaults.pp @@ -2,6 +2,7 @@ class bind::defaults ( $supported = undef, + $chroot_supported = undef, $confdir = undef, $namedconf = undef, $cachedir = undef, @@ -10,7 +11,10 @@ class bind::defaults ( $bind_user = undef, $bind_group = undef, $bind_package = undef, + $bind_chroot_package = undef, $bind_service = undef, + $bind_chroot_service = undef, + $bind_chroot_dir = undef, $nsupdate_package = undef, $managed_keys_directory = undef, $default_zones_include = undef, diff --git a/manifests/init.pp b/manifests/init.pp index 395ec92..b26091f 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -12,7 +12,28 @@ class bind ( $include_local = false, $tkey_gssapi_credential = undef, $tkey_domain = undef, + $chroot = false, + $chroot_supported = $::bind::defaults::chroot_supported, + $chroot_dir = $::bind::defaults::bind_chroot_dir, + # NOTE: we need to be able to override this parameter when declaring class, + # especially when not using hiera (i.e. when using Foreman as ENC): + $default_zones_include = $::bind::defaults::default_zones_include, ) inherits bind::defaults { + if $chroot and !$chroot_supported { + fail('Chroot for bind is not supported on your OS') + } + + if $chroot { + if $::bind::defaults::bind_chroot_service { + $real_bind_service = $::bind::defaults::bind_chroot_service + } + if $::bind::defaults::bind_chroot_package { + $real_bind_package = $::bind::defaults::bind_chroot_package + } + } else { + $real_bind_service = $::bind::defaults::bind_service + $real_bind_package = $::bind::defaults::bind_package + } File { ensure => present, @@ -27,7 +48,7 @@ class bind ( package { 'bind': ensure => latest, - name => $::bind::defaults::bind_package, + name => $real_bind_package, } if $dnssec { @@ -67,7 +88,7 @@ class bind ( } if $include_default_zones and $::bind::defaults::default_zones_source { - file { $::bind::defaults::default_zones_include: + file { $default_zones_include: source => $::bind::defaults::default_zones_source, } } @@ -105,11 +126,29 @@ class bind ( content => "};\n"; } - service { 'bind': - ensure => running, - name => $::bind::defaults::bind_service, - enable => true, - hasrestart => true, - hasstatus => true, + if $chroot and $::bind::defaults::bind_chroot_service { + service { 'bind': + ensure => running, + name => $::bind::defaults::bind_chroot_service, + enable => true, + hasrestart => true, + hasstatus => true, + } + # On RHEL Family, there is a dedicated service named-chroot and we need + # to stop/disable 'named' service: + service { 'bind-no-chroot': + ensure => stopped, + name => $::bind::defaults::bind_service, + enable => false, + } + + } else { + service { 'bind': + ensure => running, + name => $::bind::defaults::bind_service, + enable => true, + hasrestart => true, + hasstatus => true, + } } } diff --git a/metadata.json b/metadata.json index b8bcc0e..3278a28 100644 --- a/metadata.json +++ b/metadata.json @@ -19,11 +19,11 @@ }, { "operatingsystem": "CentOS", - "operatingsystemrelease": [ "6" ] + "operatingsystemrelease": [ "6", "7"] }, { "operatingsystem": "RedHat", - "operatingsystemrelease": [ "6" ] + "operatingsystemrelease": [ "6", "7" ] } ], "dependencies": [ diff --git a/spec/classes/bind_spec.rb b/spec/classes/bind_spec.rb index e549b01..24a31ca 100644 --- a/spec/classes/bind_spec.rb +++ b/spec/classes/bind_spec.rb @@ -7,17 +7,21 @@ describe 'bind' do let (:facts) {facts} case facts[:os]['family'] when 'Debian' - expected_bind_pkg = 'bind9' - expected_bind_service = 'bind9' - expected_named_conf = '/etc/bind/named.conf' - expected_confdir = '/etc/bind' - expected_default_zones_include = '/etc/bind/named.conf.default-zones' + expected_bind_pkg = 'bind9' + expected_bind_service = 'bind9' + expected_bind_chroot_pkg = nil + expected_bind_chroot_service = nil + expected_named_conf = '/etc/bind/named.conf' + expected_confdir = '/etc/bind' + expected_default_zones_include= '/etc/bind/named.conf.default-zones' when 'RedHat' - expected_bind_pkg = 'bind' - expected_bind_service = 'named' - expected_named_conf = '/etc/named.conf' - expected_confdir = '/etc/named' - expected_default_zones_include = '/etc/named.default-zones.conf' + expected_bind_pkg = 'bind' + expected_bind_service = 'named' + expected_bind_chroot_pkg = 'bind-chroot' + expected_bind_chroot_service = 'named-chroot' + expected_named_conf = '/etc/named.conf' + expected_confdir = '/etc/named' + expected_default_zones_include= '/etc/named.default-zones.conf' end context 'with defaults for all parameters' do it { is_expected.to contain_class('bind::defaults') } @@ -42,13 +46,6 @@ describe 'bind' do end it { is_expected.to contain_file('/usr/local/bin/rndc-helper') } - case facts[:os]['family'] - when 'RedHat' - it { is_expected.to contain_file(expected_default_zones_include) } - when 'Debian' - it { is_expected.not_to contain_file(expected_default_zones_include) } - end - it { is_expected.to contain_concat("#{expected_confdir}/acls.conf") } it { is_expected.to contain_concat("#{expected_confdir}/keys.conf") } it { is_expected.to contain_concat("#{expected_confdir}/views.conf") } @@ -84,6 +81,93 @@ describe 'bind' do name: expected_bind_service }) end + case facts[:os]['family'] + when 'RedHat' + it { is_expected.to contain_file(expected_default_zones_include) } + it { is_expected.not_to contain_service('bind-no-chroot') } + when 'Debian' + it { is_expected.not_to contain_file(expected_default_zones_include) } + end + end + context 'with chroot enabled' do + let(:params) do + { + chroot: true, + default_zones_include: '/etc/named/default-zones.conf' + } + end + if not (facts[:os]['name'] == 'CentOS' && facts[:os]['release']['major'] == '7') + it { is_expected.to compile.and_raise_error(/Chroot for bind is not supported on your OS/) } + else + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('bind::defaults') } + it { is_expected.to contain_class('bind::keydir') } + it { is_expected.to contain_class('bind::updater') } + it { is_expected.to contain_class('bind') } + it { is_expected.to compile.with_all_deps } + it do + is_expected.to contain_package('bind').with({ + ensure: 'latest', + name: expected_bind_chroot_pkg + }) + end + it { is_expected.to contain_file('/usr/local/bin/dnssec-init') } + it do + is_expected.to contain_bind__key('rndc-key').with( + algorithm: 'hmac-md5', + secret_bits: '512', + keydir: expected_confdir, + keyfile: 'rndc.key' + ) + end + it { is_expected.to contain_file('/usr/local/bin/rndc-helper') } + + case facts[:os]['family'] + when 'RedHat' + it { is_expected.to contain_file('/etc/named/default-zones.conf') } + when 'Debian' + it { is_expected.not_to contain_file(expected_default_zones_include) } + end + + it { is_expected.to contain_concat("#{expected_confdir}/acls.conf") } + it { is_expected.to contain_concat("#{expected_confdir}/keys.conf") } + it { is_expected.to contain_concat("#{expected_confdir}/views.conf") } + it { is_expected.to contain_concat("#{expected_confdir}/servers.conf") } + it { is_expected.to contain_concat("#{expected_confdir}/logging.conf") } + it { is_expected.to contain_concat("#{expected_confdir}/view-mappings.txt") } + it { is_expected.to contain_concat("#{expected_confdir}/domain-mappings.txt") } + + it do + is_expected.to contain_concat__fragment('bind-logging-header').with( + order: '00-header', + target: "#{expected_confdir}/logging.conf", + content: "logging {\n" + ) + end + it do + is_expected.to contain_concat__fragment('bind-logging-footer').with( + order: '99-footer', + target: "#{expected_confdir}/logging.conf", + content: "};\n" + ) + end + it { is_expected.to contain_file(expected_named_conf).that_requires('Package[bind]') } + it { is_expected.to contain_file(expected_named_conf).that_notifies('Service[bind]') } + it do + is_expected.to contain_service('bind-no-chroot').with({ + ensure: 'stopped', + enable: false, + name: expected_bind_service + }) + end + it do + is_expected.to contain_service('bind').with({ + ensure: 'running', + enable: true, + name: expected_bind_chroot_service + }) + end + end end context 'with tkey-* parameters' do let(:params) do