From 879e46ed1534295db759ece658d8170c02a351dd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 23 Nov 2015 21:47:10 +0100 Subject: [PATCH] rewrite for knot version 2.x. closes #3 This rewrite breaks compatitiblity with Knot versions < 2. It uses the new YAML configuration syntax and supports all new features of versin 2.x. Including automatic DNSSEC signing. To upgrade from version 1 to version 2, all parameters need to be checked and updated for version 2. --- README.md | 136 ++++++++++++------ manifests/config.pp | 87 ++++++++---- manifests/init.pp | 272 +++++++++++++++++++----------------- manifests/install.pp | 28 ++-- manifests/params.pp | 73 +++------- manifests/service.pp | 15 +- manifests/signing_policy.pp | 21 +++ manifests/zone_policy.pp | 32 +++++ spec/classes/init_spec.rb | 2 +- templates/knot.conf.erb | 118 ++++++++-------- templates/zones.conf.erb | 24 ++-- tests/init.pp | 17 --- tests/ubuntu_trusty.pp | 35 ----- 13 files changed, 450 insertions(+), 410 deletions(-) create mode 100644 manifests/signing_policy.pp create mode 100644 manifests/zone_policy.pp delete mode 100644 tests/init.pp delete mode 100644 tests/ubuntu_trusty.pp diff --git a/README.md b/README.md index 91f24fd..a1b8a8c 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,9 @@ This Puppet module manages the [Knot DNS](https://www.knot-dns.cz/) server. [![Build Status](https://travis-ci.org/tobru/puppet-knot.svg?branch=master)](https://travis-ci.org/tobru/puppet-knot) [![tobru-knot](https://img.shields.io/puppetforge/v/tobru/knot.svg)](https://forge.puppetlabs.com/tobru/knot) +**Info: Module version 2.x is only compatible with Knot 2.x. If you're still on Knot 1.x, please +use the module version 1.x.** + ## Module Description Knot DNS server is a "High-performance authoritative-only DNS server". This Puppet module @@ -33,19 +36,22 @@ It also manages the installation of the package and starting/restarting the syst ### What knot affects * Package `knot` installation. If `manage_package_repo` is true, it also adds the - [official apt repository](https://www.knot-dns.cz/documentation/html/installation.html#installing-knot-dns-packages-on-debian) by using the [puppetlabs/apt](https://forge.puppetlabs.com/puppetlabs/apt) module + [official apt repository](https://www.knot-dns.cz/docs/2.0/html/installation.html#os-specific-installation) by using the [puppetlabs/apt](https://forge.puppetlabs.com/puppetlabs/apt) module * Service `knot` starting and restarting on configuration change * Writing of configuration files: * `/etc/knot/knot.conf.puppet` * `/etc/knot/zones.conf.puppet` * Creation of the folders and managing of the user and group rights - on $zone_storage and $dnssec_keydir + on `$default_storage` and `$dnssec_keydir` +* Creation of Signing Policies ### Beginning with knot A simple `include knot` installs Knot DNS from the default package source and creates a configuration file with sane defaults. When starting Knot DNS it complains `warning: no zones loaded`, this tells us that it would make sense to add some zones. +Please note: Your distro will most likely not yet include Knot 2.x. So you should set at least +the parameter `manage_package_repo` to true. Adding zones is as simple as follows: ``` @@ -58,15 +64,13 @@ class { 'knot': } ``` -Zones will be added to `/etc/knot/zones.conf` with `file "mydomain.tld.zone";`. -This means that Knot DNS expects to find a standard zone file ([Wikipedia](http://en.wikipedia.org/wiki/Zone_file#File_format)) -under `/var/lib/knot` (`storage` configuration directive under the `zones` section). +Zones will be added to `/etc/knot/zones.conf`. *Note*: The paramter `zones` is a [hash](https://docs.puppetlabs.com/puppet/latest/reference/lang_datatypes.html#hashes) ## Usage -All parameter defaults are defined in `params.pp`. To pass a parameter to +All parameter defaults are defined in `params.pp` and `init.pp`. To pass a parameter to the module, they need to be passed to the main class. Here is a usage example for some parameters which most likely will be changed by the module user: @@ -79,9 +83,7 @@ $zones = { 'notify-out' => 'server1' }, } class { 'knot': - manage_package_repo => false, - system => { 'version' => 'off' }, - groups => { 'admins' => 'server0' }, + manage_package_repo => true, keys => { 'key0.server0' => { 'algorithm' => 'hmac-md5', 'key' => 'Wg==' } @@ -100,42 +102,61 @@ to pass parameters to the module: ``` knot::manage_package_repo: true -knot::package_distcodename: 'wheezy' -knot::dnssec_enable: false -knot::system: - version: 'off' -knot::groups: - admins: 'server0' +knot::zones: + myzone.ch: + template: dnssec + _signing_policy: default_rsa + myotherzone.ch: {} +knot::server: + identity: 'noidentityhere' +knot::acls: + myacl1: + action: transfer +knot::control: + acl: myacl1 +knot::remotes: + myremote1: + address: 127.0.0.1 + key: key1 +knot::templates: + dnssec: + dnssec-signing: on + storage: /var/lib/knot + zonefile-sync: -1 + kasp-db: /var/lib/knot/kasp + file: /var/lib/knot/zones/%s.zone + _signing_policy: default_rsa + default: + storage: /var/lib/knot + file: /var/lib/knot/zones/%s.zone knot::log: - syslog: - any: 'warning' stderr: - any: 'error, warning' - server: 'info' + any: debug knot::keys: - key0.server0: - algorithm: 'hmac-md5' - key: 'Wg==' -knot::remotes: - server0: - address: '127.0.0.1' - port: '53531' - key: 'key0.server0' - via: 'all_ipv4' - server1: - address: '127.0.0.1@53001' - -knot::zone_defaults: - xfr-out: 'server0' - notify-out: 'server0' -knot::zones: - myzone.net: - myotherzone.com: - xfr-out: 'server1' -knot::manage_zones: true + key1: + algorithm: hmac-md5 + secret: c0570d4931593d46333c9ddf15894a8550e131f4 + key2: + algorithm: hmac-sha1 + secret: c0570d4931593d46333c9ddf15894a8550e131f4 +knot::signing_policies: + default_rsa: + algorithm: RSASHA256 + zsk-size: 1024 + ksk-size: 2048 +knot::modules: + dnstap: + sink: unix://var/run/sink + synth-record: + type: forward + prefix: bla + origin: blubb.ch ``` +*Note*: This is not a fully functional configuration, it's just here for an example +on how to use Hiera. + ### Managing zones (and defaults for all zones) Zones are passed to the main class in the `zones` hash. The configuration get's @@ -143,6 +164,37 @@ written to `/etc/knot/zones.conf`. To pass default values to all zones, the hash `zone_defaults` exists. Everything in this hash is applied to all zones. If a parameter needs to be overwritten for a single zone, just add this parameter to the zone, the zone parameters wins. +Since Knot 2.x gained the template functionality, this feature will most likely +only be used for setting a default template for all zones. + +### Automatic DNSSEC signing + +For an overview on how automatic DNSSEC signing works in Knot, see [official docs](https://www.knot-dns.cz/docs/2.0/html/configuration.html#automatic-dnssec-signing). +The Puppet module prepares the `DNSSEC KASP database` and is able to create signing +policies. Just pass a hash of policies to the parameter `signing_policies`. +Setting the special (Puppet module only) parameter `_signing_policy` to a name +of a signing policy under a zone or template will configure this policy to a zone. + +Overview of file locations with the following template configured: +``` +knot::templates: + dnssec: + dnssec-signing: on + storage: /var/lib/knot + zonefile-sync: -1 + kasp-db: /var/lib/knot/kasp + file: /var/lib/knot/zones/%s.zone + _signing_policy: default_rsa +``` + +* Zonefiles: `/var/lib/knot/zones/%s.zone` +* KASP DB: `/var/lib/knot/kasp` +* Zone keys: `/var/lib/knot/kasp/keys` +* Timers: `/var/lib/knot/timers` +* Signed zones: Only in memory (`zonefile-sync` is -1) and under `/var/lib/knot/.db` + +Using this configuration the directory `/var/lib/knot/zones` can be savely managed +with git. ## Reference @@ -150,11 +202,7 @@ All parameters are documented inline. Have a look at `init.pp` ## Testing -The module has some small [smoke tests](https://docs.puppetlabs.com/guides/tests_smoke.html) available under the -`tests/` subdirectory. To execute them invoke Puppet using the following simple command -in the modules root path: `puppet apply --modulepath .. --noop tests/init.pp` - -There are also rspec-puppet tests available. To run them you first need to install all +There are rspec-puppet tests available. To run them you first need to install all needed GEMs by running bundler. Then a rake task executes the Rspec tests: `bundle exec rake spec`. ## Limitations diff --git a/manifests/config.pp b/manifests/config.pp index 63e842e..26c51e8 100644 --- a/manifests/config.pp +++ b/manifests/config.pp @@ -5,41 +5,46 @@ class knot::config { # get variables from the toplevel manifest for usage in the template - $config_file = $::knot::main_config_file - $zones_file = $::knot::zones_config_file - $keys = $::knot::keys - $remotes = $::knot::remotes - $groups = $::knot::groups - $zone_storage = $::knot::zone_storage + $config_file = $::knot::main_config_file + $default_storage = $::knot::default_storage $dnssec_enable = $::knot::dnssec_enable $dnssec_keydir = $::knot::dnssec_keydir - $service_user = $::knot::service_user + $manage_zones = $::knot::manage_zones $service_group = $::knot::service_group + $service_user = $::knot::service_user + $signing_policies = $::knot::signing_policies $zone_defaults = $::knot::zone_defaults - $zone_options = $::knot::zone_options - $zones = $::knot::zones - $manage_zones = $::knot::manage_zones + $zone_options = $::knot::zone_options + $zones_file = $::knot::zones_config_file + + # knot configuration sections + $acls = $::knot::acls + $control = $::knot::control + $keys = $::knot::keys + $modules = $::knot::modules + $remotes = $::knot::remotes + $templates = $::knot::templates + $zones = $::knot::zones # merge two hashes: # * the configuration hash from the user calling $knot::config_* # * the hash containing the default values in $knot::params::config_* # When there is a duplicate key, the key in the user specified hash (rightmost) "wins" # Note: this is not a deep merge, it merges only the toplevel keys - $system = merge($::knot::params::system, $::knot::system) - $log = merge($::knot::params::log, $::knot::log) - $interfaces = merge($::knot::params::interfaces, $::knot::interfaces) - $control = merge($::knot::params::control, $::knot::control) + $server = merge($::knot::params::server, $::knot::server) + $log = merge($::knot::params::log, $::knot::log) - file { - $config_file: - ensure => file, - owner => $service_user, - group => $service_group, - content => template('knot/knot.conf.erb'); - $zone_storage: - ensure => directory, - owner => $service_user, - group => $service_group; + file { $config_file: + ensure => file, + owner => $service_user, + group => $service_group, + content => template('knot/knot.conf.erb'), + } + file { $default_storage: + ensure => directory, + owner => $service_user, + group => $service_group, + recurse => true, } if $manage_zones == false { @@ -55,13 +60,41 @@ group => $service_group, content => template('knot/zones.conf.erb'); } + if $dnssec_enable { + $_all_zones = keys($zones) + ::knot::zone_policy { $_all_zones: + zones => $zones, + templates => $templates, + dnssec_keydir => $dnssec_keydir, + user => $service_user, + group => $service_group, + require => Exec['initialize_kasp'], + } + } } if $dnssec_enable { + $_signing_policy_names = keys($signing_policies) + file { $dnssec_keydir: - ensure => directory, - owner => $service_user, - group => $service_group, + ensure => directory, + owner => $service_user, + group => $service_group, + recurse => true, + } -> + exec { 'initialize_kasp': + command => '/usr/sbin/keymgr init', + creates => "${dnssec_keydir}/keys", + cwd => $dnssec_keydir, + user => $service_user, + group => $service_group, + require => Package[$::knot::package_name], + } -> + ::knot::signing_policy { $_signing_policy_names: + data => $signing_policies, + dnssec_keydir => $dnssec_keydir, + user => $service_user, + group => $service_group, } } diff --git a/manifests/init.pp b/manifests/init.pp index bd6347c..b1da675 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -5,38 +5,35 @@ # # === Parameters # -# [*package_ensure*] -# Default: installed. See Puppet type 'package' documentation -# -# [*package_name*] -# Default: On Debian 'knot'. Package name to install knot -# # [*manage_package_repo*] # Default: false. If set to true, make sure the puppetlabs/apt module is available # as it adds the knot-dns.cz repo to the APT sources # -# [*package_repo_location*] -# Only used when $manage_package_repo is true. -# Default: Depends on $::lsbdistid, see params.pp -# Location of the package repository +# [*package_ensure*] +# Default: installed. See Puppet type 'package' documentation # -# [*package_repo_repos*] -# Only used when $manage_package_repo is true. -# Default: Depends on $::lsbdistid, see params.pp -# Repos used on the repository location +# [*package_name*] +# Default: On Debian 'knot'. Package name to install knot # # [*package_repo_key*] -# Only used when $manage_package_repo is true. # Default: Depends on $::lsbdistid, see params.pp +# Only used when $manage_package_repo is true. # Signing key of the packages # # [*package_repo_key_src*] -# Only used when $manage_package_repo is true. # Default: Depends on $::lsbdistid, see params.pp +# Only used when $manage_package_repo is true. # Source of the package signing public key # -# [*service_name*] -# Default: On Debian 'knot'. Name of the system service to manage +# [*package_repo_location*] +# Default: Depends on $::lsbdistid, see params.pp +# Only used when $manage_package_repo is true. +# Location of the package repository +# +# [*package_repo_repos*] +# Default: Depends on $::lsbdistid, see params.pp +# Only used when $manage_package_repo is true. +# Repos used on the repository location # # [*service_enable*] # Default: true. See Puppet type 'service' documentation @@ -44,98 +41,89 @@ # [*service_ensure*] # Default: running. See Puppet type 'service' documentation # +# [*service_group*] +# Default: On Debian 'knot'. Group under which the knot daemon runs +# # [*service_manage*] # Default: true. If set to false, the Puppet type 'service' will not be created # Can be usefull if the service is managed by a cluster manager # +# [*service_name*] +# Default: On Debian 'knot'. Name of the system service to manage +# +# [*service_restart*] +# Default: '/usr/sbin/knotc reload'. Command to reload Knot +# +# [*service_status*] +# Default: '/usr/sbin/knotc rstatus'. Command to check the status of Knot +# # [*service_user*] # Default: On Debian 'knot'. User under which the knot daemon runs # -# [*service_group*] -# Default: On Debian 'knot'. Group under which the knot daemon runs +# [*default_storage*] +# Default: '/var/lib/knot'. Full path to the 'storage' dir # # [*main_config_file*] # Default: '/etc/knot/knot.conf'. Full path to the main configuration file # +# [*manage_zones*] +# Default: true. Set false if you want to manage only package and service. +# +# [*zone_defaults*] +# Default: {}. Hash which contains default parameters which are added to every zone +# definition under the 'zones' statement. Can be used f.e. to set a default template. +# See https://www.knot-dns.cz/documentation/html/reference.html#zones-statement +# # [*zones_config_file*] # Default: '/etc/knot/zones.conf'. Full path to the zones configuration file # -# [*system*] -# Default: -# $system = { -# identity => 'on', -# version => 'on', -# } -# System statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#system-statement +# [*acls*] +# Default: {} +# Acl section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#acl-section +# +# [*control*] +# Default: {} +# Control section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#control-section +# +# [*keys*] +# Default: {} +# Keys section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#key-section # # [*log*] # Default: # $log = { # syslog => { # any => 'info' -# }, -# stderr => { -# any => 'warning' # } # } -# Log statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#log-statement -# -# [*interfaces*] -# Default: -# $interfaces = { -# all_ipv4 => { -# address => '0.0.0.0', -# port => 53, -# }, -# all_ipv6 => { -# address => '[::]', -# port => 53, -# } -# } -# Interfaces statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#interfaces-statement -# -# [*control*] -# Default: -# $control = { -# listen-on => 'knot.sock' -# } -# Control statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#control-statement +# Logging section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#logging-section # -# [*keys*] -# Default: undef -# Keys statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#keys-statement +# [*modules*] +# Default: {} +# Modules section. See https://www.knot-dns.cz/docs/2.0/html/reference.html -> module-X +# Key: module name without "mod-", Values: Hash of module parameters. # # [*remotes*] -# Default: undef -# Remotes statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#remotes-statement -# -# [*groups*] -# Default: undef -# Groups statement hash. See https://www.knot-dns.cz/documentation/html/reference.html#groups-statement -# -# [*dnssec_enable*] -# Default: false. When set to enable, then the $dnssec_keydir gets created and "dnssec-enable" -# set to 'on' under the 'zones' statement. +# Default: {} +# Remotes section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#remote-section # -# [*dnssec_keydir*] -# Default: '/etc/knot/dnssec_keys.d'. Full path to the 'dnssec-keydir' +# [*server*] +# Default: +# $server = { +# listen => [ +# '0.0.0.0@53', +# '::@53', +# ] +# } +# Server section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#server-section # -# [*zone_storage*] -# Default: '/var/lib/knot'. Full path to the 'storage' dir which holds the zonefiles -# -# [*zone_defaults*] -# Default: undef. Hash which contains default parameters which are added to every zone -# definition under the 'zones' statement. -# See https://www.knot-dns.cz/documentation/html/reference.html#zones-statement -# -# [*zone_options*] -# Default: undef. Hash with zone options for the 'zones' statement. -# See https://www.knot-dns.cz/documentation/html/reference.html#zones-statement +# [*templates*] +# Default: {} +# Template section. See https://www.knot-dns.cz/docs/2.0/html/reference.html#template-section # # [*zones*] -# Default: {}. Hash of zones. They will be added to the $zones_config_file file and the -# 'file' option automatically set to ".zone", which is relative to 'storage'. -# See https://www.knot-dns.cz/documentation/html/reference.html#zones-statement +# Default: {}. Hash of zones. They will be added to the $zones_config_file file. +# See https://www.knot-dns.cz/docs/2.0/html/reference.html#zone-section # Example: # $zones = { # 'myzone.net' => '', @@ -144,8 +132,15 @@ # 'notify-out' => 'server1' }, # } # -# [*manage_zones*] -# Default: true. Set false if you want to manage only package and service. +# [*dnssec_enable*] +# Default: true. When set to true, then the $dnssec_keydir gets created and KASP initialized +# +# [*dnssec_keydir*] +# Default: '/var/lib/knot/kasp'. Full path to the 'dnssec-keydir' +# +# [*signing_policies*] +# Default: {} +# Creates signing policies. See https://www.knot-dns.cz/docs/2.0/html/man_keymgr.html#policy-commands # # === Examples # @@ -161,71 +156,84 @@ # class knot ( # package installation handling - $package_ensure = $::knot::params::package_ensure, - $package_name = $::knot::params::package_name, + $manage_package_repo = false, + $package_ensure = 'installed', + $package_name = $::knot::params::package_name, + $package_repo_key = $::knot::params::package_repo_key, + $package_repo_key_src = $::knot::params::package_repo_key_src, $package_repo_location = $::knot::params::package_repo_location, - $package_repo_repos = $::knot::params::package_repo_repos, - $package_repo_key = $::knot::params::package_repo_key, - $package_repo_key_src = $::knot::params::package_repo_key_src, - $manage_package_repo = $::knot::params::manage_package_repo, + $package_repo_repos = $::knot::params::package_repo_repos, # system service configuration - $service_name = $::knot::params::service_name, - $service_enable = $::knot::params::service_enable, - $service_ensure = $::knot::params::service_ensure, - $service_manage = $::knot::params::service_manage, - $service_user = $::knot::params::service_user, - $service_group = $::knot::params::service_group, + $service_enable = true, + $service_ensure = 'running', + $service_group = $::knot::params::service_group, + $service_manage = true, + $service_name = $::knot::params::service_name, + $service_restart = '/usr/sbin/knotc reload', + $service_status = '/usr/sbin/knotc status', + $service_user = $::knot::params::service_user, # knot specific configuration - $main_config_file = $::knot::params::main_config_file, - $zones_config_file = $::knot::params::zones_config_file, - $system = $::knot::params::system, - $log = $::knot::params::log, - $interfaces = $::knot::params::interfaces, - $control = $::knot::params::control, - $keys = undef, - $remotes = undef, - $groups = undef, - $dnssec_enable = $::knot::params::dnssec_enable, - $dnssec_keydir = $::knot::params::dnssec_keydir, - $zone_storage = $::knot::params::zone_storage, - $zone_defaults = undef, - $zone_options = undef, - $zones = {}, - $manage_zones = $::knot::params::manage_zones, + $default_storage = '/var/lib/knot', + $main_config_file = '/etc/knot/knot.conf', + $manage_zones = true, + $zone_defaults = {}, + $zones_config_file = '/etc/knot/zones.conf', + # knot configuration sections + $acls = {}, + $control = {}, + $keys = {}, + $log = { 'syslog' => { 'any' => 'info'} }, + $modules = {}, + $remotes = {}, + $server = { 'listen' => [ '0.0.0.0@53', '::@53' ] }, + $templates = {}, + $zones = {}, + # DNSSEC + $dnssec_enable = true, + $dnssec_keydir = '/var/lib/knot/kasp', + $signing_policies = {} ) inherits ::knot::params { - # mandatory parameters - validate_re($package_ensure, '^installed|present|absent|purged|held|latest$') - validate_string($package_repo_location) - validate_string($package_repo_repos) + # package installation handling + validate_bool($manage_package_repo) + validate_string($package_name) validate_string($package_repo_key) validate_string($package_repo_key_src) - validate_string($package_name) - validate_bool($manage_package_repo) - validate_string($service_name) + validate_string($package_repo_location) + validate_string($package_repo_repos) + + # system service configuration validate_bool($service_enable) validate_re($service_ensure, '^stopped|false|running|true$') + validate_string($service_group) validate_bool($service_manage) + validate_string($service_name) + validate_string($service_restart) + validate_string($service_status) validate_string($service_user) - validate_string($service_group) + + # knot specific configuration + validate_absolute_path($default_storage) validate_absolute_path($main_config_file) + validate_bool($manage_zones) + validate_hash($zone_defaults) validate_absolute_path($zones_config_file) - validate_hash($system) - validate_hash($log) - validate_hash($interfaces) + + # knot configuration sections + validate_hash($acls) validate_hash($control) - validate_string($zone_storage) - validate_bool($dnssec_enable) - validate_string($dnssec_keydir) + validate_hash($keys) + validate_hash($log) + validate_hash($modules) + validate_hash($remotes) + validate_hash($server) + validate_hash($templates) validate_hash($zones) - validate_bool($manage_zones) - # optional parameters - if $keys { validate_hash($keys) } - if $remotes { validate_hash($remotes) } - if $groups { validate_hash($groups) } - if $zone_options { validate_hash($zone_options) } - if $zone_defaults { validate_hash($zone_defaults) } + # DNSSEC + validate_bool($dnssec_enable) + validate_absolute_path($dnssec_keydir) + validate_hash($signing_policies) class { '::knot::install': } -> class { '::knot::config': } ~> diff --git a/manifests/install.pp b/manifests/install.pp index f856d12..e0de5ec 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -4,37 +4,29 @@ # class knot::install { - $package_name = $::knot::package_name - $package_ensure = $::knot::package_ensure - $manage_package_repo = $::knot::manage_package_repo - # only do repo management when on a Debian-like system - if $manage_package_repo and $::osfamily == 'Debian' { - $package_repo_location = $::knot::package_repo_location - $package_repo_repos = $::knot::package_repo_repos - $package_repo_key = $::knot::package_repo_key - $package_repo_key_src = $::knot::package_repo_key_src - + if ($::knot::manage_package_repo) and ($::osfamily == 'Debian') { ::apt::source { 'knot': comment => 'Official repository for Knot DNS provided by knot-dns.cz', - location => $package_repo_location, + location => $::knot::package_repo_location, release => $::lsbdistcodename, - repos => $package_repo_repos, + repos => $::knot::package_repo_repos, key => { - 'id' => $package_repo_key, - 'source' => $package_repo_key_src, + 'id' => $::knot::package_repo_key, + 'source' => $::knot::package_repo_key_src, }, include => { 'deb' => true, 'src' => false, }, } -> - package { $package_name: - ensure => $package_ensure, + package { $::knot::package_name: + ensure => $::knot::package_ensure, + require => Exec['apt_update'], } } else { - package { $package_name: - ensure => $package_ensure, + package { $::knot::package_name: + ensure => $::knot::package_ensure, } } } diff --git a/manifests/params.pp b/manifests/params.pp index 14d1c2b..a380da8 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -8,24 +8,24 @@ # OS specific parameters case $::osfamily { 'Debian': { - $package_name = 'knot' - $service_name = 'knot' - $service_user = 'knot' - $service_group = 'knot' + $package_name = 'knot' + $service_name = 'knot' + $service_user = 'knot' + $service_group = 'knot' # Choose repo location according to LSB distribution id # Only used when manage_package_repo and on a Debian based OS case $::lsbdistid { 'Debian': { $package_repo_location = 'http://deb.knot-dns.cz/debian/' - $package_repo_repos = 'main' - $package_repo_key = 'DF3D585DB8F0EB658690A554AC0E47584A7A714D' - $package_repo_key_src = 'http://deb.knot-dns.cz/debian/apt.key' + $package_repo_repos = 'main' + $package_repo_key = 'DF3D585DB8F0EB658690A554AC0E47584A7A714D' + $package_repo_key_src = 'http://deb.knot-dns.cz/debian/apt.key' } 'Ubuntu': { $package_repo_location = 'http://ppa.launchpad.net/cz.nic-labs/knot-dns/ubuntu' - $package_repo_repos = 'main' - $package_repo_key = '52463488670E69A092007C24F2331238F9C59A45' - $package_repo_key_src = undef + $package_repo_repos = 'main' + $package_repo_key = '52463488670E69A092007C24F2331238F9C59A45' + $package_repo_key_src = undef } default: { fail("LSB distid ${::lsbdistid} not supported") @@ -33,61 +33,28 @@ } } 'RedHat': { - $package_name = 'knot' - $service_name = 'knot' - $service_user = 'knot' - $service_group = 'knot' + $package_name = 'knot' + $service_name = 'knot' + $service_user = 'knot' + $service_group = 'knot' $package_repo_location = undef - $package_repo_repos = undef - $package_repo_key = undef - $package_repo_key_src = undef + $package_repo_repos = undef + $package_repo_key = undef + $package_repo_key_src = undef } default: { fail("OS family ${::osfamily} not supported") } } - # package parameters - $package_ensure = present - $manage_package_repo = false - - # service parameters - $service_enable = true - $service_ensure = running - $service_manage = true - - # knot configuration defaults - # coming from the package installation - $dnssec_enable = false - $main_config_file = '/etc/knot/knot.conf' - $zones_config_file = '/etc/knot/zones.conf' - $system = { - 'identity' => 'on', - 'version' => 'on', + ## Default parameters + $server = { + 'listen' => [ '0.0.0.0@53', '::@53' ] } $log = { 'syslog' => { 'any' => 'info' }, - 'stderr' => { - 'any' => 'warning' - } - } - $interfaces = { - 'all_ipv4' => { - 'address' => '0.0.0.0', - 'port' => 53, - }, - 'all_ipv6' => { - 'address' => '[::]', - 'port' => 53, - } - } - $control = { - 'listen-on' => 'knot.sock' } - $zone_storage = '/var/lib/knot' - $dnssec_keydir = '/etc/knot/dnssec_keys.d' - $manage_zones = true } diff --git a/manifests/service.pp b/manifests/service.pp index 79bb246..8d0d50b 100644 --- a/manifests/service.pp +++ b/manifests/service.pp @@ -5,20 +5,17 @@ # class knot::service { - $service_manage = $::knot::service_manage - $service_name = $::knot::service_name - $service_ensure = $::knot::service_ensure - $service_enable = $::knot::service_enable - - if $service_manage { + if $::knot::service_manage { # check config before managing service exec { 'check_knot_configuration': command => "/usr/sbin/knotc -c ${::knot::main_config_file} checkconf", refreshonly => true, } -> - service { $service_name: - ensure => $service_ensure, - enable => $service_enable, + service { $::knot::service_name: + ensure => $::knot::service_ensure, + enable => $::knot::service_enable, + restart => $::knot::service_restart, + status => $::knot::service_status, hasstatus => true, hasrestart => true, } diff --git a/manifests/signing_policy.pp b/manifests/signing_policy.pp new file mode 100644 index 0000000..1ecac27 --- /dev/null +++ b/manifests/signing_policy.pp @@ -0,0 +1,21 @@ +# +define knot::signing_policy ( + $data, + $dnssec_keydir, + $user, + $group, +) { + + $_params_hash = $data[$name] + $_params = inline_template("<%- @_params_hash.each do |k,v| -%><%= k -%> <%= v -%> <% end -%>") + + exec { "create_signing_policy_${name}": + command => "/usr/sbin/keymgr policy add ${name} ${_params}", + creates => "${dnssec_keydir}/policy_${name}.json", + cwd => $dnssec_keydir, + user => $user, + group => $group, + require => Package[$::knot::package_name], + } + +} diff --git a/manifests/zone_policy.pp b/manifests/zone_policy.pp new file mode 100644 index 0000000..deaece5 --- /dev/null +++ b/manifests/zone_policy.pp @@ -0,0 +1,32 @@ +# +define knot::zone_policy ( + $dnssec_keydir, + $group, + $templates, + $user, + $zones, +) { + + $_zone_config = $zones[$name] + + if $_zone_config['_signing_policy'] { + $_policy = $_zone_config['_signing_policy'] + } elsif $_zone_config['template'] { + $_template = $_zone_config['template'] + if $templates[$_template]['_signing_policy'] { + $_policy = $templates[$_template]['_signing_policy'] + } + } + + if $_policy { + exec { "create_zone_signing_policy_${name}": + command => "/usr/sbin/keymgr zone add ${name} policy ${_policy}", + creates => "${dnssec_keydir}/zone_${name}.json", + cwd => $dnssec_keydir, + user => $user, + group => $group, + require => ::Knot::Signing_policy[$_policy], + } + } + +} diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb index 4b21a22..7afd6de 100644 --- a/spec/classes/init_spec.rb +++ b/spec/classes/init_spec.rb @@ -18,7 +18,7 @@ it { is_expected.to contain_class('knot::service').that_subscribes_to('knot::config') } it { is_expected.to contain_service('knot') } - it { is_expected.to contain_package('knot').with_ensure('present') } + it { is_expected.to contain_package('knot').with_ensure('installed') } it do is_expected.to contain_file('/etc/knot/knot.conf') \ diff --git a/templates/knot.conf.erb b/templates/knot.conf.erb index 6f3ffa1..e4f0160 100644 --- a/templates/knot.conf.erb +++ b/templates/knot.conf.erb @@ -1,74 +1,66 @@ # THIS CONFIGURATION IS MANAGED BY PUPPET # see man 5 knot.conf for all available configuration options -system { - user <%= @service_user %>.<%= @service_group %>; -<%- @system.each do |k,v| -%> - <%= k %> <%= v %>; -<%- end -%> -} -<%- if @keys -%> -keys { -<%- @keys.each do |k,v| -%> - <%= k %> <%= v['algorithm'] %> "<%= v['key'] %>"; -<%- end -%> -} -<%- end -%> +server: + user: <%= @service_user %>:<%= @service_group %> + <%- @server.sort.each do |k,v| -%> + <%= k %>: <%= v %> + <%- end -%> -interfaces { -<%- @interfaces.each do |k,v| -%> - <%= k -%> { - <%- v.each do |y,z| -%> - <%= y %> <%= z %>; - <%- end -%> - } +log: +<%- @log.sort.each do |k,v| -%> + - target: <%= k %> + <%- v.sort.each do |y,z| -%> + <%= y %>: <%= z %> + <%- end -%> <%- end -%> -} -<%- if @remotes -%> -remotes { -<%- @remotes.each do |k,v| -%> - <%= k -%> { - <%- v.each do |y,z| -%> - <%= y %> <%= z %>; - <%- end -%> - } -<%- end -%> -} -<%- end -%> +key: +<%- if @keys then @keys.sort.each do |k,v| -%> + - id: <%= k %> + <%- v.sort.each do |y,z| -%> + <%= y %>: <%= z %> + <%- end -%> +<%- end end -%> -<%- if @groups -%> -groups { -<%- @groups.each do |k,v| -%> - <%= k %> { <%= v %> } -<%- end -%> -} -<%- end -%> +remote: +<%- if @remotes then @remotes.sort.each do |k,v| -%> + - id: <%= k %> + <%- v.sort.each do |y,z| -%> + <%= y %>: <%= z %> + <%- end -%> +<%- end end -%> -control { -<%- @control.each do |k,v| -%> - <%= k %> <%= v %>; -<%- end -%> -} +acl: +<%- if @acls then @acls.sort.each do |k,v| -%> + - id: <%= k %> + <%- v.sort.each do |y,z| -%> + <%= y %>: <%= z %> + <%- end -%> +<%- end end -%> -zones { - storage "<%= @zone_storage %>"; -<%- if @dnssec_enable -%> - dnssec-enable on; - dnssec-keydir "<%= @dnssec_keydir %>"; -<%- end -%> -<%- if @zone_options then @zone_options.each do |k,v| -%> - <%= k %> <%= v %>; +template: +<%- if @templates then @templates.sort.each do |k,v| -%> + - id: <%= k %> + <%- v.sort.each do |y,z| -%> + <%- next if y.start_with?('_') -%> + <%= y %>: <%= z %> + <%- end -%> <%- end end -%> - include "<%= @zones_file %>"; -} -log { -<%- @log.each do |k,v| -%> - <%= k -%> { - <%- v.each do |y,z| -%> - <%= y %> <%= z %>; - <%- end -%> - } -<%- end -%> -} +control: +<%- if @control then @control.sort.each do |k,v| -%> + <%= k %>: <%= v %> +<%- end end -%> + +<%- if @modules then @modules.sort.each do |k,v| -%> +mod-<%= k %>: + - id: <%= k %> + <%- v.sort.each do |y,z| -%> + <%- next if y == 'id' -%> + <%= y %>: <%= z %> + <%- end %> +<%- end end -%> + +# Include zones configuration file +include: "<%= @zones_config_file %>" diff --git a/templates/zones.conf.erb b/templates/zones.conf.erb index 405e44b..0848c2d 100644 --- a/templates/zones.conf.erb +++ b/templates/zones.conf.erb @@ -1,14 +1,16 @@ # THIS CONFIGURATION IS MANAGED BY PUPPET # see man 5 knot.conf for all available configuration options -<%- @zones.each do |k,v| -%> -<%= k -%> { - file "<%= k.gsub(/\//, "_") -%>.zone"; -<%- if (@zone_defaults && v && v.length > 0) then _v = @zone_defaults.merge(v) -%> -<%- elsif (v && v.length > 0) then _v = v -%> -<%- elsif (@zone_defaults && @zone_defaults.length > 0) then _v = @zone_defaults -%> -<%- end -%> -<%- if (_v && _v.length > 0) then _v.each do |y,z| -%> - <%= y %> <%= z %>; -<%- end end -%> -} + +zone: + <%- @zones.sort.each do |k,v| -%> + - domain: <%= k -%> + <%- if (@zone_defaults && v && v.length > 0) then _v = @zone_defaults.merge(v) -%> + <%- elsif (v && v.length > 0) then _v = v -%> + <%- elsif (@zone_defaults && @zone_defaults.length > 0) then _v = @zone_defaults -%> + <%- end -%> + <%- if (_v && _v.length > 0) then _v.sort.each do |y,z| -%> + <%- next if y.start_with?('_') -%> + <%= y %>: <%= z %> + <%- end end -%> <%- end -%> + diff --git a/tests/init.pp b/tests/init.pp deleted file mode 100644 index c4a508c..0000000 --- a/tests/init.pp +++ /dev/null @@ -1,17 +0,0 @@ -# The baseline for module testing used by Puppet Labs is that each manifest -# should have a corresponding test manifest that declares that class or defined -# type. -# -# Tests are then run by using puppet apply --noop (to check for compilation -# errors and view a log of events) or by fully applying the test in a virtual -# environment (to compare the resulting system state to the desired state). -# -# Learn more about module testing here: -# http://docs.puppetlabs.com/guides/tests_smoke.html -# -class { 'knot': - zones => { 'myzone.net' => '', - 'myotherzone.com' => { - 'xfr-out' => 'server1' }, - }, -} diff --git a/tests/ubuntu_trusty.pp b/tests/ubuntu_trusty.pp deleted file mode 100644 index 2d5d6d3..0000000 --- a/tests/ubuntu_trusty.pp +++ /dev/null @@ -1,35 +0,0 @@ -# This is an example on how to invoke the module using some -# parameters on Ubuntu 14.04 (see also README.md) -# -$zones = { - 'myzone.net' => '', - 'myotherzone.com' => { - 'xfr-out' => 'server1', - 'notify-out' => 'server1' }, -} - -class { 'knot': - manage_package_repo => false, - system => { 'version' => 'off' }, - groups => { 'admins' => 'server0' }, - log => { 'syslog' => { 'any' => 'warning' }, - 'stderr' => { 'any' => 'error', - 'server' => 'info' } - }, - keys => { 'key0.server0' => { - 'algorithm' => 'hmac-md5', - 'key' => 'Wg==' } - }, - remotes => { 'server0' => { - 'address' => '127.0.0.1', - 'port' => '53531', - 'key' => 'key0.server0', - 'via' => 'all_ipv4' }, - 'server1' => { - 'address' => '127.0.0.1@53001' }, - }, - zone_options => { 'semantic-checks' => 'on' }, - zone_defaults => { 'xfr-out' => 'server0', - 'notify-out' => 'server0' }, - zones => $zones, -}