From 5a3baec36c4c6645e1a1c4d0a3c04f8b3b27a60b Mon Sep 17 00:00:00 2001 From: Blerim Sheqa Date: Mon, 30 Jan 2017 16:13:30 +0100 Subject: [PATCH 1/6] Generate SSL certificates on Icinga 2 CA master --- manifests/pki/ca.pp | 60 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/manifests/pki/ca.pp b/manifests/pki/ca.pp index 6570f8a42..27d1d7d09 100644 --- a/manifests/pki/ca.pp +++ b/manifests/pki/ca.pp @@ -30,31 +30,73 @@ # # class icinga2::pki::ca( + $ssl_key_path = undef, + $ssl_cert_path = undef, + $ssl_cacert_path = undef, $ca_cert = undef, $ca_key = undef, ) { include icinga2::params - $ca_dir = $::icinga2::params::ca_dir - $user = $::icinga2::params::user - $group = $::icinga2::params::group - + $ca_dir = $::icinga2::params::ca_dir + $pki_dir = $::icinga2::params::pki_dir + $user = $::icinga2::params::user + $group = $::icinga2::params::group + $node_name = $::icinga2::_constants['NodeName'] + File { owner => $user, group => $group, } + # Set defaults for certificate stuff and/or do validation + if $ssl_key_path { + validate_absolute_path($ssl_key_path) + $_ssl_key_path = $ssl_key_path } + else { + $_ssl_key_path = "${pki_dir}/${node_name}.key" } + if $ssl_cert_path { + validate_absolute_path($ssl_cert_path) + $_ssl_cert_path = $ssl_cert_path } + else { + $_ssl_cert_path = "${pki_dir}/${node_name}.crt" } + if $ssl_cacert_path { + validate_absolute_path($ssl_cacert_path) + $_ssl_cacert_path = $ssl_cacert_path } + else { + $_ssl_cacert_path = "${pki_dir}/ca.crt" } + if !$ca_cert or !$ca_key { + $path = $::osfamily ? { + 'windows' => 'C:/ProgramFiles/ICINGA2/sbin', + default => '/bin:/usr/bin:/sbin:/usr/sbin', + } + exec { 'create-icinga2-ca': - path => $::osfamily ? { - 'windows' => 'C:/ProgramFiles/ICINGA2/sbin', - default => '/bin:/usr/bin:/sbin:/usr/sbin', - }, + path => $path, command => 'icinga2 pki new-ca', creates => "${ca_dir}/ca.crt", notify => Class['::icinga2::service'], + } -> + + file { "${_ssl_cacert_path}": + source => "${ca_dir}/ca.crt", + } -> + + exec { 'icinga2 pki create certificate and key': + path => $path, + command => "icinga2 pki new-cert --cn '${::fqdn}' --key '${_ssl_key_path}' --cert '${_ssl_cert_path}'", + creates => $_ssl_key_path, + notify => Class['::icinga2::service'], + } -> + + file { + $_ssl_key_path: + mode => '0600'; + $_ssl_cert_path: } + } else { validate_string($ca_cert) validate_string($ca_key) @@ -89,4 +131,6 @@ tag => 'icinga2::config::file', } } + + } From 72aa547132682c76537bde27e74dcb7e97c8eefb Mon Sep 17 00:00:00 2001 From: Blerim Sheqa Date: Mon, 30 Jan 2017 16:51:34 +0100 Subject: [PATCH 2/6] Add 'ca' case for feature::api This commit adds a mechanism to create a CA and corresponding SSL certificates and keys in one single step by using the feature::api class. --- manifests/feature/api.pp | 26 ++++++++++++++++++++++++-- manifests/pki/ca.pp | 39 +-------------------------------------- 2 files changed, 25 insertions(+), 40 deletions(-) diff --git a/manifests/feature/api.pp b/manifests/feature/api.pp index d4d63eb94..aa4801348 100644 --- a/manifests/feature/api.pp +++ b/manifests/feature/api.pp @@ -147,6 +147,7 @@ $conf_dir = $::icinga2::params::conf_dir $pki_dir = $::icinga2::params::pki_dir + $ca_dir = $::icinga2::params::ca_dir $user = $::icinga2::params::user $group = $::icinga2::params::group $node_name = $::icinga2::_constants['NodeName'] @@ -164,8 +165,8 @@ # validation validate_re($ensure, [ '^present$', '^absent$' ], "${ensure} isn't supported. Valid values are 'present' and 'absent'.") - validate_re($pki, [ '^puppet$', '^none$', '^icinga2' ], - "${pki} isn't supported. Valid values are 'puppet', 'none' and 'icinga2'.") + validate_re($pki, [ '^puppet$', '^none$', '^icinga2', '^ca' ], + "${pki} isn't supported. Valid values are 'puppet', 'none', 'icinga2' and 'ca'.") validate_bool($accept_config) validate_bool($accept_commands) validate_string($ticket_salt) @@ -293,6 +294,27 @@ } -> file { $_ssl_cacert_path: } } # icinga2 + + 'ca': { + class { '::icinga2::pki::ca': } -> + + file { "${_ssl_cacert_path}": + source => "${ca_dir}/ca.crt", + } -> + + exec { 'icinga2 pki create certificate and key': + path => $path, + command => "icinga2 pki new-cert --cn '${::fqdn}' --key '${_ssl_key_path}' --cert '${_ssl_cert_path}'", + creates => $_ssl_key_path, + notify => Class['::icinga2::service'], + } -> + + file { + $_ssl_key_path: + mode => '0600'; + $_ssl_cert_path: + } + } } # pki # compose attributes diff --git a/manifests/pki/ca.pp b/manifests/pki/ca.pp index 27d1d7d09..104fd599c 100644 --- a/manifests/pki/ca.pp +++ b/manifests/pki/ca.pp @@ -40,33 +40,14 @@ include icinga2::params $ca_dir = $::icinga2::params::ca_dir - $pki_dir = $::icinga2::params::pki_dir $user = $::icinga2::params::user $group = $::icinga2::params::group - $node_name = $::icinga2::_constants['NodeName'] File { owner => $user, group => $group, } - # Set defaults for certificate stuff and/or do validation - if $ssl_key_path { - validate_absolute_path($ssl_key_path) - $_ssl_key_path = $ssl_key_path } - else { - $_ssl_key_path = "${pki_dir}/${node_name}.key" } - if $ssl_cert_path { - validate_absolute_path($ssl_cert_path) - $_ssl_cert_path = $ssl_cert_path } - else { - $_ssl_cert_path = "${pki_dir}/${node_name}.crt" } - if $ssl_cacert_path { - validate_absolute_path($ssl_cacert_path) - $_ssl_cacert_path = $ssl_cacert_path } - else { - $_ssl_cacert_path = "${pki_dir}/ca.crt" } - if !$ca_cert or !$ca_key { $path = $::osfamily ? { 'windows' => 'C:/ProgramFiles/ICINGA2/sbin', @@ -78,25 +59,7 @@ command => 'icinga2 pki new-ca', creates => "${ca_dir}/ca.crt", notify => Class['::icinga2::service'], - } -> - - file { "${_ssl_cacert_path}": - source => "${ca_dir}/ca.crt", - } -> - - exec { 'icinga2 pki create certificate and key': - path => $path, - command => "icinga2 pki new-cert --cn '${::fqdn}' --key '${_ssl_key_path}' --cert '${_ssl_cert_path}'", - creates => $_ssl_key_path, - notify => Class['::icinga2::service'], - } -> - - file { - $_ssl_key_path: - mode => '0600'; - $_ssl_cert_path: - } - + } } else { validate_string($ca_cert) validate_string($ca_key) From 7b9324c6f9d23689b55439ea921f315ca09d9ea9 Mon Sep 17 00:00:00 2001 From: Blerim Sheqa Date: Mon, 30 Jan 2017 16:57:37 +0100 Subject: [PATCH 3/6] Remove obsolete parameters from pki::ca --- manifests/feature/api.pp | 2 +- manifests/pki/ca.pp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/manifests/feature/api.pp b/manifests/feature/api.pp index aa4801348..826616700 100644 --- a/manifests/feature/api.pp +++ b/manifests/feature/api.pp @@ -314,7 +314,7 @@ mode => '0600'; $_ssl_cert_path: } - } + } # ca } # pki # compose attributes diff --git a/manifests/pki/ca.pp b/manifests/pki/ca.pp index 104fd599c..5ad5b62af 100644 --- a/manifests/pki/ca.pp +++ b/manifests/pki/ca.pp @@ -30,9 +30,6 @@ # # class icinga2::pki::ca( - $ssl_key_path = undef, - $ssl_cert_path = undef, - $ssl_cacert_path = undef, $ca_cert = undef, $ca_key = undef, ) { From 83cd07ee3f66ec61fd54cf4707bbfa8c19873122 Mon Sep 17 00:00:00 2001 From: Erez Zarum Date: Tue, 31 Jan 2017 15:47:29 +0200 Subject: [PATCH 4/6] The certificate must be signed by the CA refs Icinga/puppet-icinga2#218 - Remove invalid byte sequence in UTF-8 - Set correct permissions for pki dir - Sign the certificate with icinga2 local CA --- manifests/feature/api.pp | 35 ++++++++++++++++++++++++++++------- manifests/install.pp | 2 ++ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/manifests/feature/api.pp b/manifests/feature/api.pp index 826616700..9931fe4c2 100644 --- a/manifests/feature/api.pp +++ b/manifests/feature/api.pp @@ -28,6 +28,12 @@ # C:/ProgramData/icinga2/etc/icinga2/pki/NodeName.crt on Windows # The Value of NodeName comes from the corresponding constant. # +# [*ssl_csr_path*] +# Location of the certificate signing request. Default depends on platform: +# /etc/icinga2/pki/NodeName.csr on Linux +# C:/ProgramData/icinga2/etc/icinga2/pki/NodeName.csr on Windows +# The Value of NodeName comes from the corresponding constant. +# # [*ssl_cacert_path*] # Location of the CA certificate. Default is: # /etc/icinga2/pki/ca.crt on Linux @@ -130,6 +136,7 @@ $pki = 'puppet', $ssl_key_path = undef, $ssl_cert_path = undef, + $ssl_csr_path = undef, $ssl_cacert_path = undef, $accept_config = false, $accept_commands = false, @@ -184,6 +191,11 @@ $_ssl_cert_path = $ssl_cert_path } else { $_ssl_cert_path = "${pki_dir}/${node_name}.crt" } + if $ssl_csr_path { + validate_absolute_path($ssl_csr_path) + $_ssl_csr_path = $ssl_csr_path } + else { + $_ssl_csr_path = "${pki_dir}/${node_name}.csr" } if $ssl_cacert_path { validate_absolute_path($ssl_cacert_path) $_ssl_cacert_path = $ssl_cacert_path } @@ -293,26 +305,35 @@ notify => Class['::icinga2::service'], } -> file { $_ssl_cacert_path: } - } # icinga2 + } # icinga2 'ca': { - class { '::icinga2::pki::ca': } -> + class { '::icinga2::pki::ca': } -> file { "${_ssl_cacert_path}": source => "${ca_dir}/ca.crt", } -> - exec { 'icinga2 pki create certificate and key': + exec { 'icinga2 pki create certificate signing request': path => $path, - command => "icinga2 pki new-cert --cn '${::fqdn}' --key '${_ssl_key_path}' --cert '${_ssl_cert_path}'", + command => "icinga2 pki new-cert --cn '${::fqdn}' --key '${_ssl_key_path}' --csr '${_ssl_csr_path}'", creates => $_ssl_key_path, - notify => Class['::icinga2::service'], } -> - file { $_ssl_key_path: mode => '0600'; - $_ssl_cert_path: + } + + exec { 'icinga2 pki sign certificate': + command => "icinga2 pki sign-csr --csr '${_ssl_csr_path}' --cert '${_ssl_cert_path}'", + subscribe => Exec['icinga2 pki create certificate signing request'], + refreshonly => true, + notify => Class['::icinga2::service'], + } -> + file { + $_ssl_cert_path:; + $_ssl_csr_path: + ensure => absent; } } # ca } # pki diff --git a/manifests/install.pp b/manifests/install.pp index a2e9b36f6..5e8b5598b 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -46,6 +46,8 @@ file { $pki_dir: ensure => directory, group => $group, + mode => '0660', + recurse => true, require => Package[$package] } } From 45bafecfcbe512101ae6b41f20ceb446d3c9891b Mon Sep 17 00:00:00 2001 From: Erez Zarum Date: Tue, 31 Jan 2017 17:18:05 +0200 Subject: [PATCH 5/6] Fix pki directory permission. refs Icinga/puppet-icinga2#218 --- manifests/install.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/install.pp b/manifests/install.pp index 5e8b5598b..c734660db 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -45,8 +45,8 @@ } file { $pki_dir: ensure => directory, + owner => $user, group => $group, - mode => '0660', recurse => true, require => Package[$package] } From c133c3ccf98487a91fd4d2e71a8383a834ae42a7 Mon Sep 17 00:00:00 2001 From: Blerim Sheqa Date: Tue, 31 Jan 2017 17:03:08 +0100 Subject: [PATCH 6/6] Add docs for 'ca' pki mode in api feature --- README.md | 28 +++++++++++++++++++++++++++- manifests/feature/api.pp | 2 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a0b318b5f..bbb3c2cfb 100644 --- a/README.md +++ b/README.md @@ -490,7 +490,7 @@ requires SSL/TLS client certificates. This module offers multiple choices to con One of your Icinga master needs to behave as a CA. With the class `icinga2::pki::ca` you can do following to fulfil this requirement: -* Use the ability of the icinga2 CLI to generate a complete new CA +* Use the the `icinga2` CLI to generate a complete new CA ``` puppet include ::icinga2 class { '::icinga2::pki::ca': @@ -520,6 +520,30 @@ file { '/var/lib/icinga2/ca/ca.key': } ``` +* Create a new CA with the `icinga2` CLI command and a certificate signed by this new CA. This is especially useful when +seting up a fresh Icinga 2 master from scratch. +``` +class { '::icinga2': + constants => { + 'TicketSalt' => '5a3d695b8aef8f18452fc494593056a4', + } +} + +class { '::icinga2::feature::api': + pki => 'ca', + endpoints => { + 'localhost' => { + 'host' => 'localhost', + } + }, + zones => { + 'master' => { + 'endpoints' => ['localhost'] + } + } +} +``` + If you are looking for an option to use your Puppet CA, have a look to the [Client/Satellite Certificates](#clientsatellite-certificates) section. @@ -1116,6 +1140,8 @@ Provides multiple sources for the certificate and key. the configured 'ticket_salt' in a custom function. * `none` Does nothing and you either have to manage the files yourself as file resources or use the `ssl_key`, `ssl_cert`, `ssl_ca` parameters. +* `ca` Includes the `::icinga2::pki::ca` class to generate a fresh CA and generates an SSL certificate and key signed by +this new CA. Defaults to `puppet` diff --git a/manifests/feature/api.pp b/manifests/feature/api.pp index 9931fe4c2..080f30d3e 100644 --- a/manifests/feature/api.pp +++ b/manifests/feature/api.pp @@ -15,6 +15,8 @@ # Puppetmaster by using the configured 'ticket_salt' in a custom function. # - none: Does nothing and you either have to manage the files yourself as file resources # or use the ssl_key, ssl_cert, ssl_cacert parameters. Defaults to puppet. +# - ca: Includes the '::icinga2::pki::ca' class to generate a fresh CA and generates an SSL certificate and +# key signed by this new CA. # # [*ssl_key_path*] # Location of the private key. Default depends on platform: