diff options
Diffstat (limited to 'puppet/modules')
185 files changed, 3972 insertions, 752 deletions
| diff --git a/puppet/modules/apt b/puppet/modules/apt -Subproject 1a72a99693c1d77bfe891546408f88264fca98e +Subproject 64fb988c0e37d64fb3e241dc95f156072e43bf2 diff --git a/puppet/modules/backupninja b/puppet/modules/backupninja new file mode 160000 +Subproject daeb1a1f112a4dbf6b39565f0dea461e46a6468 diff --git a/puppet/modules/check_mk b/puppet/modules/check_mk new file mode 160000 +Subproject 5c11597a055858b5ddc1ce8f7f8db249f5f1b33 diff --git a/puppet/modules/couchdb b/puppet/modules/couchdb -Subproject 20deb0652ccfe105eddec6ba2ad32b8d633705f +Subproject c8f5443e0998d3d3d43505ff5a6fdf8c438d6c2 diff --git a/puppet/modules/git b/puppet/modules/git -Subproject 497a1034489e0dc3cab5dab2fb0a85778576973 +Subproject ba5dd8d5c8e09d521ff49f1ebc753601e449f82 diff --git a/puppet/modules/leap_mx/manifests/init.pp b/puppet/modules/leap_mx/manifests/init.pp new file mode 100644 index 00000000..b59eac01 --- /dev/null +++ b/puppet/modules/leap_mx/manifests/init.pp @@ -0,0 +1,62 @@ +class leap_mx { + +  $leap_mx          = hiera('couchdb_leap_mx_user') +  $couchdb_user     = $leap_mx['username'] +  $couchdb_password = $leap_mx['password'] + +  $couchdb_host     = 'localhost' +  $couchdb_port     = '4096' + +  include soledad::common +  include site_apt::preferences::twisted + +  # +  # USER AND GROUP +  # + +  group { 'leap-mx': +    ensure    => present, +    allowdupe => false; +  } + +  user { 'leap-mx': +    ensure    => present, +    allowdupe => false, +    gid       => 'leap-mx', +    home      => '/etc/leap', +    require   => Group['leap-mx']; +  } + +  # +  # LEAP-MX CONFIG +  # + +  file { '/etc/leap/mx.conf': +    content => template('leap_mx/mx.conf.erb'), +    owner   => 'leap-mx', +    group   => 'leap-mx', +    mode    => '0600', +    notify  => Service['leap-mx']; +  } + +  # +  # LEAP-MX CODE +  # + +  package { 'leap-mx': +    ensure  => installed, +    require => Class['site_apt::preferences::twisted'] +  } + +  # +  # LEAP-MX DAEMON +  # + +  service { 'leap-mx': +    ensure     => running, +    enable     => true, +    hasstatus  => true, +    hasrestart => true, +    require    => [ Package['leap-mx'] ]; +  } +} diff --git a/puppet/modules/leap_mx/templates/mx.conf.erb b/puppet/modules/leap_mx/templates/mx.conf.erb new file mode 100644 index 00000000..e05bc150 --- /dev/null +++ b/puppet/modules/leap_mx/templates/mx.conf.erb @@ -0,0 +1,15 @@ +[mail1] +path=/var/mail/vmail/Maildir +recursive=True + +[couchdb] +user=<%= @couchdb_user %> +password=<%= @couchdb_password %> +server=<%= @couchdb_host %> +port=<%= @couchdb_port %> + +[alias map] +port=4242 + +[check recipient] +port=2244 diff --git a/puppet/modules/postfix b/puppet/modules/postfix new file mode 160000 +Subproject 1103a73ab4253712c6446bba7a443619fe51671 diff --git a/puppet/modules/rsyslog b/puppet/modules/rsyslog new file mode 160000 +Subproject 20fbda6b91472e656331a9c64630fb207e9f578 diff --git a/puppet/modules/rubygems b/puppet/modules/rubygems -Subproject 1e5ed3dbef9381bb9d5e2a7b4957bb3f5288d6a +Subproject ef820cfec3321d17be99ef814318adb4e3cc1e9 diff --git a/puppet/modules/site_apache/files/conf.d/security b/puppet/modules/site_apache/files/conf.d/security new file mode 100644 index 00000000..a5ae5bdc --- /dev/null +++ b/puppet/modules/site_apache/files/conf.d/security @@ -0,0 +1,55 @@ +# +# Disable access to the entire file system except for the directories that +# are explicitly allowed later. +# +# This currently breaks the configurations that come with some web application +# Debian packages. It will be made the default for the release after lenny. +# +#<Directory /> +#	AllowOverride None +#	Order Deny,Allow +#	Deny from all +#</Directory> + + +# Changing the following options will not really affect the security of the +# server, but might make attacks slightly more difficult in some cases. + +# +# ServerTokens +# This directive configures what you return as the Server HTTP response +# Header. The default is 'Full' which sends information about the OS-Type +# and compiled in modules. +# Set to one of:  Full | OS | Minimal | Minor | Major | Prod +# where Full conveys the most information, and Prod the least. +# +#ServerTokens Minimal +ServerTokens Prod + +# +# Optionally add a line containing the server version and virtual host +# name to server-generated pages (internal error documents, FTP directory +# listings, mod_status and mod_info output etc., but not CGI generated +# documents or custom error documents). +# Set to "EMail" to also include a mailto: link to the ServerAdmin. +# Set to one of:  On | Off | EMail +# +#ServerSignature Off +ServerSignature Off + +# +# Allow TRACE method +# +# Set to "extended" to also reflect the request body (only for testing and +# diagnostic purposes). +# +# Set to one of:  On | Off | extended +# +#TraceEnable Off +TraceEnable On + +# Setting this header will prevent other sites from embedding pages from this +# site as frames. This defends against clickjacking attacks. +# Requires mod_headers to be enabled. +# +Header set X-Frame-Options: "DENY" diff --git a/puppet/modules/site_apache/manifests/common.pp b/puppet/modules/site_apache/manifests/common.pp new file mode 100644 index 00000000..72f24838 --- /dev/null +++ b/puppet/modules/site_apache/manifests/common.pp @@ -0,0 +1,26 @@ +class site_apache::common { +  # installs x509 cert + key and common config +  # that both nagios + leap webapp use + +  $web_domain       = hiera('domain') +  $domain_name      = $web_domain['name'] + +  include x509::variables +  include site_config::x509::commercial::cert +  include site_config::x509::commercial::key +  include site_config::x509::commercial::ca + +  Class['Site_config::X509::Commercial::Key'] ~> Service[apache] +  Class['Site_config::X509::Commercial::Cert'] ~> Service[apache] +  Class['Site_config::X509::Commercial::Ca'] ~> Service[apache] + +  include site_apache::module::rewrite + +  class { '::apache': no_default_site => true, ssl => true } + +  apache::vhost::file { +    'common': +      content => template('site_apache/vhosts.d/common.conf.erb') +  } + +} diff --git a/puppet/modules/site_apache/manifests/module/alias.pp b/puppet/modules/site_apache/manifests/module/alias.pp new file mode 100644 index 00000000..c1f5e185 --- /dev/null +++ b/puppet/modules/site_apache/manifests/module/alias.pp @@ -0,0 +1,5 @@ +class site_apache::module::alias ( $ensure = present ) +{ + +  apache::module { 'alias': ensure => $ensure } +} diff --git a/puppet/modules/site_apache/manifests/module/expires.pp b/puppet/modules/site_apache/manifests/module/expires.pp new file mode 100644 index 00000000..f73a5607 --- /dev/null +++ b/puppet/modules/site_apache/manifests/module/expires.pp @@ -0,0 +1,4 @@ +class site_apache::module::expires ( $ensure = present ) +{ +  apache::module { 'expires': ensure => $ensure } +} diff --git a/puppet/modules/site_apache/manifests/module/headers.pp b/puppet/modules/site_apache/manifests/module/headers.pp new file mode 100644 index 00000000..f7caa28c --- /dev/null +++ b/puppet/modules/site_apache/manifests/module/headers.pp @@ -0,0 +1,5 @@ +class site_apache::module::headers ( $ensure = present ) +{ + +  apache::module {'headers': ensure => $ensure } +} diff --git a/puppet/modules/site_apache/manifests/module/removeip.pp b/puppet/modules/site_apache/manifests/module/removeip.pp new file mode 100644 index 00000000..f106167a --- /dev/null +++ b/puppet/modules/site_apache/manifests/module/removeip.pp @@ -0,0 +1,5 @@ +class site_apache::module::removeip ( $ensure = present ) +{ +  package { 'libapache2-mod-removeip': ensure => $ensure } +  apache::module { 'removeip': ensure => $ensure } +} diff --git a/puppet/modules/site_apache/manifests/module/rewrite.pp b/puppet/modules/site_apache/manifests/module/rewrite.pp new file mode 100644 index 00000000..7ad00a0c --- /dev/null +++ b/puppet/modules/site_apache/manifests/module/rewrite.pp @@ -0,0 +1,5 @@ +class site_apache::module::rewrite ( $ensure = present ) +{ + +  apache::module { 'rewrite': ensure => $ensure } +} diff --git a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb index ae894cd4..3360ac59 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb @@ -10,17 +10,26 @@ Listen 0.0.0.0:<%= api_port %>    ServerName <%= api_domain %>    SSLEngine on -  SSLProtocol -all +SSLv3 +TLSv1 -  SSLCipherSuite HIGH:MEDIUM:!aNULL:!SSLv2:!MD5:@STRENGTH +  SSLProtocol all -SSLv2    SSLHonorCipherOrder on +  SSLCompression off +  SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK"    SSLCACertificatePath /etc/ssl/certs -  SSLCertificateChainFile /etc/ssl/certs/leap_api.pem -  SSLCertificateKeyFile /etc/x509/keys/leap_api.key -  SSLCertificateFile /etc/x509/certs/leap_api.crt +  SSLCertificateChainFile <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::ca_name') %>.crt +  SSLCertificateKeyFile <%= scope.lookupvar('x509::variables::keys') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.key +  SSLCertificateFile <%= scope.lookupvar('x509::variables::certs') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.crt    RequestHeader set X_FORWARDED_PROTO 'https' +  <IfModule mod_headers.c> +<% if @webapp['secure'] -%> +    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" +<% end -%> +    Header always unset X-Powered-By +    Header always unset X-Runtime +  </IfModule> +    DocumentRoot /srv/leap/webapp/public    # Check for maintenance file and redirect all requests diff --git a/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb new file mode 100644 index 00000000..ed430510 --- /dev/null +++ b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb @@ -0,0 +1,73 @@ +<VirtualHost *:80> +  ServerName <%= domain %> +  ServerAlias www.<%= domain %> +  RewriteEngine On +  RewriteRule ^.*$ https://<%= domain -%>%{REQUEST_URI} [R=permanent,L] +</VirtualHost> + +<VirtualHost *:443> +  ServerName <%= domain_name %> +  ServerAlias <%= domain %> +  ServerAlias www.<%= domain %> + +  SSLEngine on +  SSLProtocol all -SSLv2 +  SSLHonorCipherOrder on +  SSLCompression off +  SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK" + +  SSLCACertificatePath /etc/ssl/certs +  SSLCertificateChainFile <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::commercial_ca_name') %>.crt +  SSLCertificateKeyFile <%= scope.lookupvar('x509::variables::keys') %>/<%= scope.lookupvar('site_config::params::commercial_cert_name') %>.key +  SSLCertificateFile <%= scope.lookupvar('x509::variables::certs') %>/<%= scope.lookupvar('site_config::params::commercial_cert_name') %>.crt + +  RequestHeader set X_FORWARDED_PROTO 'https' + +  <IfModule mod_headers.c> +<% if (defined? @services) and (@services.include? 'webapp') and (@webapp['secure']) -%> +    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains" +<% end -%> +    Header always unset X-Powered-By +    Header always unset X-Runtime +  </IfModule> + +<% if (defined? @services) and (@services.include? 'webapp') -%> +  DocumentRoot /srv/leap/webapp/public + +  RewriteEngine On +  # Check for maintenance file and redirect all requests +  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f +  RewriteCond %{SCRIPT_FILENAME} !maintenance.html +  RewriteCond %{REQUEST_URI} !/images/maintenance.jpg +  RewriteRule ^.*$ %{DOCUMENT_ROOT}/system/maintenance.html [L] + +  # http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerallowencodedslashes_lt_on_off_gt +  AllowEncodedSlashes on +  PassengerAllowEncodedSlashes on +  PassengerFriendlyErrorPages off +  SetEnv TMPDIR /var/tmp + +  # Allow rails assets to be cached for a very long time (since the URLs change whenever the content changes) +  <Location /assets/> +    Header unset ETag +    FileETag None +    ExpiresActive On +    ExpiresDefault "access plus 1 year" +  </Location> +<% end -%> + + +<% if (defined? @services) and (@services.include? 'monitor') -%> + <DirectoryMatch (/usr/share/nagios3/htdocs|/usr/lib/cgi-bin/nagios3|/etc/nagios3/stylesheets)> + <% if (defined? @services) and (@services.include? 'webapp') -%> +    PassengerEnabled off + <% end -%> +    AllowOverride all +    # Nagios won't work with setting this option to "DENY", +    # as set in conf.d/security (#4169). Therefor we allow +    # it here, only for nagios. +    Header set X-Frame-Options: "ALLOW" +  </DirectoryMatch> +<% end -%> +</VirtualHost> + diff --git a/puppet/modules/site_apache/templates/vhosts.d/leap_webapp.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/leap_webapp.conf.erb deleted file mode 100644 index 4b051699..00000000 --- a/puppet/modules/site_apache/templates/vhosts.d/leap_webapp.conf.erb +++ /dev/null @@ -1,46 +0,0 @@ -<VirtualHost *:80> -  ServerName <%= domain %> -  ServerAlias www.<%= domain %> -  RewriteEngine On -  RewriteRule ^.*$ https://<%= domain -%>%{REQUEST_URI} [R=permanent,L] -</VirtualHost> - -<VirtualHost *:443> -  ServerName <%= domain %> -  ServerAlias www.<%= domain %> - -  SSLEngine on -  SSLProtocol -all +SSLv3 +TLSv1 -  SSLCipherSuite HIGH:MEDIUM:!aNULL:!SSLv2:!MD5:@STRENGTH -  SSLHonorCipherOrder on - -  SSLCACertificatePath /etc/ssl/certs -  SSLCertificateChainFile /etc/ssl/certs/leap_webapp.pem -  SSLCertificateKeyFile /etc/x509/keys/leap_webapp.key -  SSLCertificateFile /etc/x509/certs/leap_webapp.crt - -  RequestHeader set X_FORWARDED_PROTO 'https' - -  DocumentRoot /srv/leap/webapp/public - -  RewriteEngine On -  # Check for maintenance file and redirect all requests -  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f -  RewriteCond %{SCRIPT_FILENAME} !maintenance.html -  RewriteCond %{REQUEST_URI} !/images/maintenance.jpg -  RewriteRule ^.*$ %{DOCUMENT_ROOT}/system/maintenance.html [L] - -  # http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerallowencodedslashes_lt_on_off_gt -  AllowEncodedSlashes on -  PassengerAllowEncodedSlashes on -  PassengerFriendlyErrorPages off -  SetEnv TMPDIR /var/tmp - - <% if (defined? @services) and (@services.include? 'monitor') -%> - <DirectoryMatch (/usr/share/nagios3/htdocs|/usr/lib/cgi-bin/nagios3|/etc/nagios3/stylesheets)> -    PassengerEnabled off -    AllowOverride all -  </DirectoryMatch> - <% end -%> -</VirtualHost> - diff --git a/puppet/modules/site_apt/files/keys/cloudant-key.asc b/puppet/modules/site_apt/files/keys/cloudant-key.asc deleted file mode 100644 index 99716a3c..00000000 --- a/puppet/modules/site_apt/files/keys/cloudant-key.asc +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.11 (GNU/Linux) - -mQINBFE7fhIBEACrDREcODnhdugNozMeBawOm2irpNCP54yMljST/DOXx1uo3gQw -HnVcQ4lL7lXhbfL6Tp0WhrNYTWbbWHO0DaQbW0GQMHa2BGG0Xm0HPrjr3j55tAcM -NPr0ArDuplq4Py2pwviZiEtQkkn+biH9oV+N3jNO+8+zVHLVU7pHaX6Yd7HAxFM8 -XX+7SeVtplZ7nvSxUREiMNxQb9o0kYNRPS+b0UjiIXHrFO9afl7lTdg/I8AhKWa0 -3jJoY/IRvVopJblISQNGFipR11Lpu5sOHghgz4V8mk/in7JLMmoqSl5DP5VhRII8 -OyADBjaUJD2mkv5cGaevqpB4AId78X9+Y62gFJrGkIHY9uBxIUkRe+leYI4Zz4Bm -D9qBIbEY/kKkblTlC1G7u3qbGQcsbCRVIOnhruCih7vifcP40YwGUk5NmDA5AE78 -OovCGYGp4zMepDTSJxGT3sJOTEbzN09so6C7fQWBeQiiG5Uepp1q+VnaGpT1L4rc -Y6yRbu9dOFj6WzY4W5HtnbalzTIEYy+SIGZqRkJt6jREYLiFfyrpSFIgGoJAs0yx -9M0McXfeOod69TPufB1PeppnBwFcTmYNYxakusQxAebRDPEBZqoEgl0gMmxWbAdI -nxGMWWnSsN/Dj0dXRf1MG/5akOhX2zQcUzBOE2m/Xr5kjDPYFtFxVJDGzQARAQAB -tDNDbG91ZGFudCBQYWNrYWdlIFNpZ25pbmcgS2V5IDxzdXBwb3J0QGNsb3VkYW50 -LmNvbT6JAj4EEwECACgFAlE7fhICGwMFCQHhM4AGCwkIBwMCBhUIAgkKCwQWAgMB -Ah4BAheAAAoJEFngH70Vvo4mciIP/AlqHA/LDtSYfrFwdXifY2ImCMyzYvH40Ko2 -DHCw2qDjvK5UXn1iWuzXidT7DrxOfYoZpzySRP7VGyHxa3VPhOtzLDZSvTpk9ELo -2x2IczUwLC17M0Iis4CpqlxSFIBYGX78pMzvsEyC4TFqUDfXRlye3apjD0iwK0hE -kdP1+TPdJjhWImJm+3TLu45zTw3Ph5dnf5pLQPNhKfBSdku+vRrd35N5hHso9S1y -Z3NrxcQlWnXuqkLIA14gM7qbBFD+el9Y+tZ7ERGYg3s5uNDQRTb0QC8zg/um2+zW -4hHmuRcWY3n8IgHcYUruC1VyrrsFIWWMyLv7SZkAAoSY+jKyESDfYpJQ8jtZ4EF9 -2/gYm4FgZR8j4gWkzHSLGVt/4EIykJZb0yIg/QEovmmHqpy8xYri3goMSl4h7tfF -TOCZLTzTyQ7xONdyEsrvQPhmdtXEgvSo5S7ZU9kkx32OjCoshLLjhtqAipBgEXqb -hElFo1oSyOVoGc7UNh7KNBjWfeP8dNdCbIbIYPMeM0/CVjD60kW5ZEVDuYglT+Rz -enJJvS4Hs+fq8cFNxMB+l64qE7iS+I6RP2bPeQM2aBa2UZNWxUIbXF7bb3zLrCGn -GT8GF1AFRoW3GiDzB7QnLVp8BhIaqFUzbDim+5mFFG8wguxHTiz4snDdQXq2Es6V -UETFsNsluQINBFE7fhIBEADIyLHyBh8AKJKQHksFAPHOyA48ocxgQDpQnqYlQcAK -D8eUbRXciIz4ePBmvjaQmz8wJgWULc04u4i9jK8Jd/Ks+VhEz3AjRBfjvkBaVMog -FMPKaoDn9LVMBSZJ3fcC1DVck1oO8LnFIdktt0zhvzG+pV5b/UTRsVZmwNh1p2dM -4cJswxlksJXYnI9tFA74qiomDCPYM0zpv7TEjX23PZTLqTSHP5aWctx+MIEtdoqp -EsEDL6npvYBRz/tuL41cUWs7CItH131Hyuizo4vGrxgWPnoXIxLmLOOZCMk/kbx0 -XCSvengqYwNgAOlIjewtTw+WJm1gtNQQeKmaXBX7njf2Wz7LI/0KVxttEpKT5/5y -embOGn7My9i7zOc1frMCDivIOTQDBZTzR9o7/6wUJ69DIoFLMlO8UcCK3R7o5VUI -ezx+XYsOAD7D2vKoiD8Se65Vnax2rfFlLP7OQqdem5l2lkHpJzP3lA8qmA2MfJ7V -jsk7eDSyJQjG5c6KBoaFlYGhp/E2kR82cAKVaFIbW3euMM4XK6Mgzy3+DVKfk8mu -AEuHub7plfxM+65yjLNAK6l6IKtY1HfM7F4GFyNSd3mNNcWN7ceIHh8Ur4DeD2Tp -7r3XcWd6/czLYNsw2BAHeVUxnMTCeGN99UZTtHgVq9IJMOCDOPwMSzHFfZ6sNaYL -qQARAQABiQIlBBgBAgAPBQJRO34SAhsMBQkB4TOAAAoJEFngH70Vvo4mpokP/jJJ -2mXdhMVqZCtZhwphJfdxg8nBERzrd6ebXxKbTq1MmSN/fDwLknPabFHUpzk1ADCf -6mh2o0HB+67yMzo1UVtyfPOaHgCE/pWer5ultJM8gOdpBfSWL8jRwU8ZQ4fDu3z8 -AC6zTNq7znOVLEzZPy8U7q5Rt5/6QdQYoTLe6DwlLmkflzWP5VWi/mTGvtu/t5OV -tGZkzBYQ5QAXRXXkKswqkJpQFuW6d1vlYm9+x/+Q1+2kGT+CKbRAkqkf77qVcyJR -1M2JQSs4ko+rLMZzr01sYA+EBD17nxqV8vUdYebNc9Qnk8Aphid1zarUbySgAdnJ -5SLAjLe/6N6IEE9F3uKsPEs87gJrnwrYHRrmu0wAPwA0cMmtgD4Bz7Iiz4CLYPFW -rHpQCA313K+rS/LLfLBL66wIRKcPuYIFR9N03jX9eGR6qtk0b5Zb3YjWOo4V9Q1r -o+g6IB0Us5vH6ISuokq7Bv+8cXhEMVoctL9A8xWN1KDkweZ+7dNWCGV8lUWKy3Hw -ig6hENH6H7J57U8H2v2aZTeUo6e7VDP9gddNKPSEEeoBKfVnWYGoG8mVPQ2PzTgZ -ZO2vwp4c3Ix/kIV3xe+/Opcq1lxYhD7HSre1MB7HOeFmis6tBBjMJPaatZVfzj1v -6Uhz5oUCwcPol8rsp69DvGVUPSHfDwBxurDX71oG -=lEm7 ------END PGP PUBLIC KEY BLOCK----- diff --git a/puppet/modules/site_apt/files/keys/leap_key.asc b/puppet/modules/site_apt/files/keys/leap_key.asc index b69251f0..b6b5077b 100644 --- a/puppet/modules/site_apt/files/keys/leap_key.asc +++ b/puppet/modules/site_apt/files/keys/leap_key.asc @@ -1,5 +1,5 @@  -----BEGIN PGP PUBLIC KEY BLOCK----- -Version: GnuPG v1.4.11 (GNU/Linux) +Version: GnuPG v1.4.14 (GNU/Linux)  mQINBFESwt0BEAC2CR+XgW04DVwT427v2T4+qz+O/xGOwQcalVaSOUuguYgf29en  Apb6mUqROOTuJWN1nw1lvXiA6iFxg6DjDUhsp6j54X7GAAAjZ9QuavPgcsractsJ @@ -36,7 +36,19 @@ y9k8peFB7wwf0sW3Eg78XFsfy4gyV619VnBR+PbfOpKqFFXAodF1mFiIrPeefaVp  F9fiQ5Owt0sJjDaJnYT83ksAO2Aj+VsY3UjnDrGFaiV8Neit9y/8W8DqmZ3EZEF/  M3iS0yDjqqt9ACFD+jkGlKYsyHv7gbpTq0yi6u/kRXHUTIvVwFL9M6Z6AUcG8gzo  qbKhXGfWKEq0lN5HAjJ//V9ro3DekFd0A+NQOlFV6XtspZwphVdtW1WS078HmVlw -F5dbD8pcfT/RjbkCDQRREsLdARAA3Frw+j6H9McEIi/gjiGwvxnIdGc8McWchnFp +F5dbD8pcfT/RjYkCPQQTAQoAJwIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAUC +UvT9ZgUJA8NuBQAKCRAeNKGCjiB5AXB+D/9k/BzZdAczQ3/v7hKrN9y3/D8kOEYK +rF8HdcBOH522sN6mqvm7wGkf3RmNSi731m6vzlbBSonrAT5KDMpj+THOmUcY29V5 +a1YOgFCCkToOfl+LmlLiuqfrGCJyE28MKMrsi2zMBKhsSxhvcI0EhJkQpPBu8gUs +XW1GSHuh5CYzwf/i8eNDpVrhHjRF0AVCOWIq52LTR62QchR+6ci/wVDHWd9Ase5X +8rxNnt2/pCbgATklQbmRcQS6efTVk3oXk1DZ8M46vayJ1g2BFuIi7pohiekLAAAt +MCwRKHTHvtPkGAUAEXExPGS78qHxLHIau2VCtSBxm+bQX+ZyCMANDpI+ZTFp1APJ +9SpbtGozuQOpWFjWY1rERunrbyWHIb2DuVVNKGiHlkMJB76zzysvbIPYWx1RqD6s +KFJBkjrM0xn8H+D6qzwzGfmX1Yaw12oYA6pcai4aK5sO7KHt+THAxYAcVF7qxGU7 +lnDifM56hrH/DbE5InlDC8OUqDysj0cHacRee+ZYtj7TiEykWfP5RrZCLQ7L6Jd/ +HtgQti/9TVUaFkIlQCfvF+l4BYZQYvnhx3MVK7ChKLmy6AVQLWnDrBrDvl07HLvW +6pslRzVHfWyIYng0pZ0HvK+MpQztCoUcDK470mjlpAtjNHuyKh6r6TtaiVK8MgbR +Sx/NMHb1/PXQJrkCDQRREsLdARAA3Frw+j6H9McEIi/gjiGwvxnIdGc8McWchnFp  OWvdhTW9056v+y22DoKbULjT8k+8GzuRQ0xp4VwCC1rX3UExwceczzGs+tSKuIGm  g1ELygsaOZHdQBNLGPvn+TZNGlaYXPlQo7m8YhXGHwgQrdKyjcFD5xnOHxe981LT  q+IQ6jVYhho7/Qik9rVE1XHxoOfYvnNZJD0cFdf9OcX47YoqmM4sZYPMoOmKoVQT @@ -59,5 +71,5 @@ Dxix2FBXQU/4pVpGHjXTQP6RqeTrAedXvpgCHWP1UIlswIQecGmQcJ/hRZjd+0vl  cjfCYhZHr7N96Da6Cy8v2fZiZHaSAt7T2oIZ9X3gEh/kOlLDcuIdvMHUfojn0MrP  Ce1AqOHyQQqhkVylvZpS0PdE0VW3PmJ98uKfX2FVAOTUD4Rw3n9Ew7bfM249HuP4  JOXi/Skp4sBB/xgrtV1u+E+BW0SS/BOiwfrI4xUy+MrWuw== -=4STg +=Om8x  -----END PGP PUBLIC KEY BLOCK----- diff --git a/puppet/modules/site_apt/manifests/init.pp b/puppet/modules/site_apt/manifests/init.pp index 8821c110..9facf4cc 100644 --- a/puppet/modules/site_apt/manifests/init.pp +++ b/puppet/modules/site_apt/manifests/init.pp @@ -1,15 +1,6 @@  class site_apt  { -  # on couchdb we need to include squeeze in apt preferences, -  # so the cloudant package can pull some packages from squeeze -  # template() must be unquoted ! -  if 'couchdb' in $::services { -    $custom_preferences = template("site_apt/preferences.include_squeeze") -  } else { -    $custom_preferences = '' -  }    class { 'apt': -    custom_preferences => $custom_preferences,      custom_key_dir     => 'puppet:///modules/site_apt/keys'    } @@ -37,6 +28,6 @@ class site_apt  {    # The creation of sources.list depends on the lsb package    File['/etc/apt/preferences'] -> -    Exec['refresh_apt'] -    Package <| ( title != 'lsb' ) |> +    Exec['refresh_apt'] -> +      Package <| ( title != 'lsb' ) |>  } diff --git a/puppet/modules/site_apt/manifests/preferences/check_mk.pp b/puppet/modules/site_apt/manifests/preferences/check_mk.pp new file mode 100644 index 00000000..580e0d3f --- /dev/null +++ b/puppet/modules/site_apt/manifests/preferences/check_mk.pp @@ -0,0 +1,9 @@ +class site_apt::preferences::check_mk { + +  apt::preferences_snippet { 'check-mk': +    package  => 'check-mk-*', +    release  => "${::lsbdistcodename}-backports", +    priority => 999; +  } + +} diff --git a/puppet/modules/site_apt/manifests/preferences/twisted.pp b/puppet/modules/site_apt/manifests/preferences/twisted.pp new file mode 100644 index 00000000..abff6838 --- /dev/null +++ b/puppet/modules/site_apt/manifests/preferences/twisted.pp @@ -0,0 +1,9 @@ +class site_apt::preferences::twisted { + +  apt::preferences_snippet { 'python-twisted': +    package  => 'python-twisted*', +    release  => "${::lsbdistcodename}-backports", +    priority => 999; +  } + +} diff --git a/puppet/modules/site_apt/templates/wheezy/postfix.seeds b/puppet/modules/site_apt/templates/wheezy/postfix.seeds new file mode 100644 index 00000000..1a878ccc --- /dev/null +++ b/puppet/modules/site_apt/templates/wheezy/postfix.seeds @@ -0,0 +1 @@ +postfix	postfix/main_mailer_type	select	No configuration diff --git a/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh b/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh new file mode 100644 index 00000000..1dd0afc9 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/local_checks/all_hosts/run_node_tests.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# +# runs node tests + +/srv/leap/bin/run_tests --checkmk diff --git a/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh b/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh new file mode 100755 index 00000000..b8687c9a --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/local_checks/mx/check_leap_mx.sh @@ -0,0 +1,33 @@ +#!/bin/bash + + +WARN=1 +CRIT=5 + +# in minutes +MAXAGE=10 + +STATUS[0]='OK' +STATUS[1]='Warning' +STATUS[2]='Critical' +CHECKNAME='Leap_MX_Queue' + +WATCHDIR='/var/mail/vmail/Maildir/new/' + + +total=`find $WATCHDIR -type f -mmin +$MAXAGE | wc -l` + +if [ $total -lt $WARN ] +then +  exitcode=0 +else +  if [ $total -le $CRIT ] +  then +    exitcode=1 +  else +      exitcode=2 +  fi +fi + +echo "${exitcode} ${CHECKNAME} stale_files=${total} ${STATUS[exitcode]}: ${total} stale files (>=${MAXAGE} min) in ${WATCHDIR}." + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg new file mode 100644 index 00000000..28f333b0 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg @@ -0,0 +1,20 @@ +/opt/bigcouch/var/log/bigcouch.log nocontext=1 +# ignore requests that are fine + I undefined - -.*200$ + I undefined - -.*201$ + I 127.0.0.1 undefined.* ok + I 127.0.0.1 localhost:5984 .* ok + # https://leap.se/code/issues/5246 + I Shutting down group server + # ignore "Uncaught error in HTTP request: {exit, normal}" error + # it's suppressed in later versions of bigcouch anhow + # see https://leap.se/code/issues/5226 + I Uncaught error in HTTP request: {exit,normal} + I Uncaught error in HTTP request: {exit, + C Uncaught error in HTTP request: {error, + C Response abnormally terminated: {nodedown, + C rexi_DOWN,noproc + C rexi_DOWN,noconnection + C error + C Connection attempt from disallowed node + W Apache CouchDB has started diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg new file mode 100644 index 00000000..c71c5392 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/leap_mx.cfg @@ -0,0 +1,4 @@ +/var/log/leap_mx.log + W Don't know how to deliver mail + W No public key, stopping the processing chain + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg new file mode 100644 index 00000000..4f16d1bd --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/logwatch.cfg @@ -0,0 +1,31 @@ +# This file is managed by Puppet. DO NOT EDIT. + +# logwatch.cfg +# This file configures mk_logwatch. Define your logfiles +# and patterns to be looked for here. + +# Name one or more logfiles +/var/log/messages +# Patterns are indented with one space are prefixed with: +# C: Critical messages +# W: Warning messages +# I: ignore these lines (OK) +# The first match decided. Lines that do not match any pattern +# are ignored + C Fail event detected on md device + I mdadm.*: Rebuild.*event detected + W mdadm\[ + W ata.*hard resetting link + W ata.*soft reset failed (.*FIS failed) + W device-mapper: thin:.*reached low water mark + C device-mapper: thin:.*no free space + +/var/log/auth.log + W sshd.*Corrupted MAC on input + +/var/log/kern.log + C panic + C Oops + W generic protection rip + W .*Unrecovered read error - auto reallocate failed + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg new file mode 100644 index 00000000..623d1e46 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/soledad.cfg @@ -0,0 +1,5 @@ +/var/log/soledad.log + C WSGI application error + C Error + C error + W Timing out client: diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg new file mode 100644 index 00000000..f546135a --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg @@ -0,0 +1,7 @@ + C /usr/local/bin/couch-doc-update.*failed + C /usr/local/bin/couch-doc-update.*ERROR +# on one-node bigcouch setups, we'll get this msg +# a lot, so we ignore it here until we fix +# https://leap.se/code/issues/5244 + I epmd: got partial packet only on file descriptor + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg new file mode 100644 index 00000000..d58e876d --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/openvpn.cfg @@ -0,0 +1,7 @@ +# ignore openvpn TLS initialization errors when clients +# suddenly hangup before properly establishing +# a tls connection + I ovpn-.*TLS Error: Unroutable control packet received from + I ovpn-.*TLS Error: TLS key negotiation failed to occur within 60 seconds (check your network connectivity) + I ovpn-.*TLS Error: TLS handshake failed + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg new file mode 100644 index 00000000..eb3131f2 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/stunnel.cfg @@ -0,0 +1,9 @@ +# check for stunnel failures +# +# these are temporary failures and happen very often, so we +# ignore them until we tuned stunnel timeouts/logging, +# see https://leap.se/code/issues/5218 + I stunnel:.*Connection reset by peer + I stunnel:.*Peer suddenly disconnected + I stunnel:.*Connection refused + diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg new file mode 100644 index 00000000..93ce0311 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/tapicero.cfg @@ -0,0 +1,8 @@ + C tapicero.*RestClient::InternalServerError: +# possible race condition between multiple tapicero +# instances, so we ignore it +# see https://leap.se/code/issues/5168 + I tapicero.*RestClient::PreconditionFailed: + C tapicero.*Creating database.*failed due to: + C tapicero.*failed + W tapicero.*Couch stream ended unexpectedly. diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg new file mode 100644 index 00000000..00f9c7fd --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/webapp.cfg @@ -0,0 +1,5 @@ +# check for webapp errors + C webapp.*Could not connect to couch database messages due to 401 Unauthorized: {"error":"unauthorized","reason":"You are not a server admin."} +# ignore RoutingErrors that rails throw when it can't handle a url +# see https://leap.se/code/issues/5173 + I webapp.*ActionController::RoutingError diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg new file mode 100644 index 00000000..f60d752b --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_header.cfg @@ -0,0 +1 @@ +/var/log/syslog diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg new file mode 100644 index 00000000..450b9e90 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog_tail.cfg @@ -0,0 +1,11 @@ +# some general patterns + C panic + C Oops + I Error: Driver 'pcspkr' is already registered, aborting... + C Error + C error + W generic protection rip + W .*Unrecovered read error - auto reallocate failed +# 401 Unauthorized error logged by webapp and possible other +# applications + C Unauthorized diff --git a/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl b/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl new file mode 100755 index 00000000..06163d49 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/nagios_plugins/check_unix_open_fds.pl @@ -0,0 +1,322 @@ +#!/usr/bin/perl -w + +# check_unix_open_fds Nagios Plugin +# +# TComm - Carlos Peris Pla +# +# This nagios plugin is free software, and comes with ABSOLUTELY  +# NO WARRANTY. It may be used, redistributed and/or modified under  +# the terms of the GNU General Public Licence (see  +# http://www.fsf.org/licensing/licenses/gpl.txt). + + +# MODULE DECLARATION + +use strict; +use Nagios::Plugin; + + +# FUNCTION DECLARATION + +sub CreateNagiosManager (); +sub CheckArguments (); +sub PerformCheck (); + + +# CONSTANT DEFINITION + +use constant NAME => 	'check_unix_open_fds'; +use constant VERSION => '0.1b'; +use constant USAGE => 	"Usage:\ncheck_unix_open_fds -w <process_threshold,application_threshold> -c <process_threshold,application_threshold>\n". +						"\t\t[-V <version>]\n"; +use constant BLURB => 	"This plugin checks, in UNIX systems with the command lsof installed and with its SUID bit activated, the number\n". +						"of file descriptors opened by an application and its processes.\n"; +use constant LICENSE => "This nagios plugin is free software, and comes with ABSOLUTELY\n". +						"no WARRANTY. It may be used, redistributed and/or modified under\n". +						"the terms of the GNU General Public Licence\n". +						"(see http://www.fsf.org/licensing/licenses/gpl.txt).\n"; +use constant EXAMPLE => "\n\n". +						"Example:\n". +						"\n". +						"check_unix_open_fds -a /usr/local/nagios/bin/ndo2db -w 20,75 -c 25,85\n". +						"\n". +						"It returns CRITICAL if number of file descriptors opened by ndo2db is higher than 85,\n". +						"if not it returns WARNING if number of file descriptors opened by ndo2db is higher \n". +						"than 75, if not it returns CRITICAL if number of file descriptors opened by any process\n". +						"of ndo2db is higher than 25, if not it returns WARNING if number of file descriptors \n". +						"opened by any process of ndo2db is higher than 20.\n". +						"In other cases it returns OK if check has been performed succesfully.\n\n"; + +								 +# VARIABLE DEFINITION + +my $Nagios; +my $Error; +my $PluginResult; +my $PluginOutput; +my @WVRange; +my @CVRange; + + +# MAIN FUNCTION + +# Get command line arguments +$Nagios = &CreateNagiosManager(USAGE, VERSION, BLURB, LICENSE, NAME, EXAMPLE); +eval {$Nagios->getopts}; + +if (!$@) { +	# Command line parsed +	if (&CheckArguments($Nagios, \$Error, \@WVRange, \@CVRange)) { +		# Argument checking passed +		$PluginResult = &PerformCheck($Nagios, \$PluginOutput, \@WVRange, \@CVRange) +	} +	else { +		# Error checking arguments +		$PluginOutput = $Error; +		$PluginResult = UNKNOWN; +	} +	$Nagios->nagios_exit($PluginResult,$PluginOutput); +} +else { +	# Error parsing command line +	$Nagios->nagios_exit(UNKNOWN,$@); +} + +		 +	 +# FUNCTION DEFINITIONS + +# Creates and configures a Nagios plugin object +# Input: strings (usage, version, blurb, license, name and example) to configure argument parsing functionality +# Return value: reference to a Nagios plugin object + +sub CreateNagiosManager() { +	# Create GetOpt object +	my $Nagios = Nagios::Plugin->new(usage => $_[0], version =>  $_[1], blurb =>  $_[2], license =>  $_[3], plugin =>  $_[4], extra =>  $_[5]); +	 +	# Add argument units +	$Nagios->add_arg(spec => 'application|a=s', +				help => 'Application path for which you want to check the number of open file descriptors', +				required => 1);				 +	 +	# Add argument warning +	$Nagios->add_arg(spec => 'warning|w=s', +				help => "Warning thresholds. Format: <process_threshold,application_threshold>", +				required => 1); +	# Add argument critical +	$Nagios->add_arg(spec => 'critical|c=s', +				help => "Critical thresholds. Format: <process_threshold,application_threshold>", +				required => 1); +								 +	# Return value +	return $Nagios; +} + + +# Checks argument values and sets some default values +# Input: Nagios Plugin object +# Output: reference to Error description string, Memory Unit, Swap Unit, reference to WVRange ($_[4]), reference to CVRange ($_[5]) +# Return value: True if arguments ok, false if not + +sub CheckArguments() { +	my ($Nagios, $Error, $WVRange, $CVRange) = @_; +	my $commas; +	my $units; +	my $i; +	my $firstpos; +	my $secondpos; +	 +	# Check Warning thresholds list +	$commas = $Nagios->opts->warning =~ tr/,//;  +	if ($commas !=1){ +		${$Error} = "Invalid Warning list format. One comma is expected."; +		return 0; +	} +	else{ +		$i=0; +		$firstpos=0; +		my $warning=$Nagios->opts->warning; +		while ($warning =~ /[,]/g) { +			$secondpos=pos $warning; +			if ($secondpos - $firstpos==1){ +				@{$WVRange}[$i] = "~:"; +			}		 +			else{ +				@{$WVRange}[$i] = substr $Nagios->opts->warning, $firstpos, ($secondpos-$firstpos-1); +			} +			$firstpos=$secondpos; +			$i++ +		} +		if (length($Nagios->opts->warning) - $firstpos==0){#La coma es el ultimo elemento del string +			@{$WVRange}[$i] = "~:"; +		} +		else{ +			@{$WVRange}[$i] = substr $Nagios->opts->warning, $firstpos, (length($Nagios->opts->warning)-$firstpos); +		}	 +		 +		if (@{$WVRange}[0] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/){ +			${$Error} = "Invalid Process Warning threshold in ${$WVRange[0]}"; +			return 0; +		}if (@{$WVRange}[1] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/){ +			${$Error} = "Invalid Application Warning threshold in ${$WVRange[1]}"; +			return 0; +		} +	} +	 +	# Check Critical thresholds list +	$commas = $Nagios->opts->critical =~ tr/,//;  +	if ($commas !=1){ +		${$Error} = "Invalid Critical list format. One comma is expected."; +		return 0; +	} +	else{ +		$i=0; +		$firstpos=0; +		my $critical=$Nagios->opts->critical; +		while ($critical  =~ /[,]/g) { +			$secondpos=pos $critical ; +			if ($secondpos - $firstpos==1){ +				@{$CVRange}[$i] = "~:"; +			}		 +			else{ +				@{$CVRange}[$i] =substr $Nagios->opts->critical, $firstpos, ($secondpos-$firstpos-1); +			} +			$firstpos=$secondpos; +			$i++ +		} +		if (length($Nagios->opts->critical) - $firstpos==0){#La coma es el ultimo elemento del string +			@{$CVRange}[$i] = "~:"; +		} +		else{ +			@{$CVRange}[$i] = substr $Nagios->opts->critical, $firstpos, (length($Nagios->opts->critical)-$firstpos); +		}		 + +		if (@{$CVRange}[0] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/) { +			${$Error} = "Invalid Process Critical threshold in @{$CVRange}[0]"; +			return 0; +		} +		if (@{$CVRange}[1] !~/^(@?(\d+|(\d+|~):(\d+)?))?$/) { +			${$Error} = "Invalid Application Critical threshold in @{$CVRange}[1]"; +			return 0; +		} +	} +	 +	return 1; +} + + +# Performs whole check:  +# Input: Nagios Plugin object, reference to Plugin output string, Application, referece to WVRange, reference to CVRange +# Output: Plugin output string +# Return value: Plugin return value + +sub PerformCheck() { +	my ($Nagios, $PluginOutput, $WVRange, $CVRange) = @_; +	my $Application; +	my @AppNameSplitted; +	my $ApplicationName; +	my $PsCommand; +	my $PsResult; +	my @PsResultLines; +	my $ProcLine; +	my $ProcPid; +	my $LsofCommand; +	my $LsofResult; +	my $ProcCount = 0; +	my $FDCount = 0; +	my $ProcFDAvg = 0; +	my $PerProcMaxFD = 0; +	my $ProcOKFlag = 0; +	my $ProcWarningFlag = 0; +	my $ProcCriticalFlag = 0; +	my $OKFlag = 0; +	my $WarningFlag = 0; +	my $CriticalFlag = 0; +	my $LastWarningProcFDs = 0; +	my $LastWarningProc = -1; +	my $LastCriticalProcFDs = 0; +	my $LastCriticalProc = -1; +	my $ProcPluginReturnValue = UNKNOWN; +	my $AppPluginReturnValue = UNKNOWN; + 	my $PluginReturnValue = UNKNOWN; + 	my $PerformanceData = ""; +	my $PerfdataUnit = "FDs"; +	 +	$Application = $Nagios->opts->application; +	$PsCommand = "ps -eaf | grep $Application"; +	$PsResult = `$PsCommand`; +	@AppNameSplitted = split(/\//, $Application); +	$ApplicationName = $AppNameSplitted[$#AppNameSplitted]; +	@PsResultLines = split(/\n/, $PsResult); +	if ( $#PsResultLines > 1 ) { +	    foreach my $Proc (split(/\n/, $PsResult)) { +		if ($Proc !~ /check_unix_open_fds/ && $Proc !~ / grep /) { +				$ProcCount += 1; +			    $ProcPid = (split(/\s+/, $Proc))[1]; +			    $LsofCommand = "lsof -p $ProcPid | wc -l"; +			    $LsofResult = `$LsofCommand`; +			    $LsofResult = ($LsofResult > 0 ) ? ($LsofResult - 1) : 0; +			    $FDCount += $LsofResult; +			    if ($LsofResult >= $PerProcMaxFD) { $PerProcMaxFD = $LsofResult; } +			    $ProcPluginReturnValue = $Nagios->check_threshold(check => $LsofResult,warning => @{$WVRange}[0],critical => @{$CVRange}[0]); +			    if ($ProcPluginReturnValue eq OK) { +			    	$ProcOKFlag = 1; +			    } +			    elsif ($ProcPluginReturnValue eq WARNING) { +					$ProcWarningFlag = 1; +					if ($LsofResult >= $LastWarningProcFDs) { +					    $LastWarningProcFDs = $LsofResult; +					    $LastWarningProc = $ProcPid; +					} +			    } +				#if ($LsofResult >= $PCT) { +				elsif ($ProcPluginReturnValue eq CRITICAL) { +				    $ProcCriticalFlag = 1; +				    if ($LsofResult >= $LastCriticalProcFDs) { +						$LastCriticalProcFDs = $LsofResult; +						$LastCriticalProc = $ProcPid; +				    } +				} +		    } +	    } +	    if ($ProcCount) { $ProcFDAvg = int($FDCount / $ProcCount); } +	    $AppPluginReturnValue = $Nagios->check_threshold(check => $FDCount,warning => @{$WVRange}[1],critical => @{$CVRange}[1]); +	    #if ($FDCount >= $TWT) { +	    if ($AppPluginReturnValue eq OK) { $OKFlag = 1; } +	    elsif ($AppPluginReturnValue eq WARNING) { $WarningFlag = 1; } +	    elsif ($AppPluginReturnValue eq CRITICAL) { $CriticalFlag = 1; } +	 +	    # PluginReturnValue and PluginOutput +	    if ($CriticalFlag) { +	    	$PluginReturnValue = CRITICAL; +			${$PluginOutput} .= "$ApplicationName handling $FDCount files (critical threshold set to @{$CVRange}[1])"; +	    } +	    elsif ($WarningFlag) { +	    	$PluginReturnValue = WARNING; +			${$PluginOutput} .= "$ApplicationName handling $FDCount files (warning threshold set to @{$WVRange}[1])"; +	    } +	    elsif ($ProcCriticalFlag) { +	    	$PluginReturnValue = CRITICAL; +			${$PluginOutput} .= "Process ID $LastCriticalProc handling $LastCriticalProcFDs files (critical threshold set to @{$CVRange}[0])"; +	    } +	    elsif ($ProcWarningFlag) { +	    	$PluginReturnValue = WARNING; +			${$PluginOutput} .= "Process ID $LastWarningProc handling $LastWarningProcFDs files (warning threshold set to @{$WVRange}[0])"; +	    } +	    elsif ($OKFlag && $ProcOKFlag) { +	    	$PluginReturnValue = OK; +			${$PluginOutput} .= "$ApplicationName handling $FDCount files"; +	    } +	} +	else { +	    ${$PluginOutput} .= "No existe la aplicacion $ApplicationName"; +	} + +      +	$PerformanceData .= "ProcCount=$ProcCount$PerfdataUnit FDCount=$FDCount$PerfdataUnit ProcFDAvg=$ProcFDAvg$PerfdataUnit PerProcMaxFD=$PerProcMaxFD$PerfdataUnit"; + +	# Output with performance data: +	${$PluginOutput} .= " | $PerformanceData"; + + 	return $PluginReturnValue; +} diff --git a/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 b/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 new file mode 100755 index 00000000..3dbca322 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/plugins/mk_logwatch.1.2.4 @@ -0,0 +1,374 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +------------------------------------------------------------------+ +# |             ____ _               _        __  __ _  __           | +# |            / ___| |__   ___  ___| | __   |  \/  | |/ /           | +# |           | |   | '_ \ / _ \/ __| |/ /   | |\/| | ' /            | +# |           | |___| | | |  __/ (__|   <    | |  | | . \            | +# |            \____|_| |_|\___|\___|_|\_\___|_|  |_|_|\_\           | +# |                                                                  | +# | Copyright Mathias Kettner 2010             mk@mathias-kettner.de | +# +------------------------------------------------------------------+ +# +# This file is part of Check_MK. +# The official homepage is at http://mathias-kettner.de/check_mk. +# +# check_mk is free software;  you can redistribute it and/or modify it +# under the  terms of the  GNU General Public License  as published by +# the Free Software Foundation in version 2.  check_mk is  distributed +# in the hope that it will be useful, but WITHOUT ANY WARRANTY;  with- +# out even the implied warranty of  MERCHANTABILITY  or  FITNESS FOR A +# PARTICULAR PURPOSE. See the  GNU General Public License for more de- +# ails.  You should have  received  a copy of the  GNU  General Public +# License along with GNU Make; see the file  COPYING.  If  not,  write +# to the Free Software Foundation, Inc., 51 Franklin St,  Fifth Floor, +# Boston, MA 02110-1301 USA. + +# Call with -d for debug mode: colored output, no saving of status + +import sys, os, re, time +import glob + +if '-d' in sys.argv[1:] or '--debug' in sys.argv[1:]: +    tty_red     = '\033[1;31m' +    tty_green   = '\033[1;32m' +    tty_yellow  = '\033[1;33m' +    tty_blue    = '\033[1;34m' +    tty_normal  = '\033[0m' +    debug = True +else: +    tty_red     = '' +    tty_green   = '' +    tty_yellow  = '' +    tty_blue    = '' +    tty_normal  = '' +    debug = False + +# The configuration file and status file are searched +# in the directory named by the environment variable +# LOGWATCH_DIR. If that is not set, MK_CONFDIR is used. +# If that is not set either, the current directory ist +# used. +logwatch_dir = os.getenv("LOGWATCH_DIR") +if not logwatch_dir: +    logwatch_dir = os.getenv("MK_CONFDIR") +    if not logwatch_dir: +        logwatch_dir = "." + +print "<<<logwatch>>>" + +config_filename = logwatch_dir + "/logwatch.cfg" +status_filename = logwatch_dir + "/logwatch.state" +config_dir      = logwatch_dir + "/logwatch.d/*.cfg" + +def is_not_comment(line): +    if line.lstrip().startswith('#') or \ +       line.strip() == '': +        return False +    return True + +def parse_filenames(line): +    return line.split() + +def parse_pattern(level, pattern): +    if level not in [ 'C', 'W', 'I', 'O' ]: +        raise(Exception("Invalid pattern line '%s'" % line)) +    try: +        compiled = re.compile(pattern) +    except: +        raise(Exception("Invalid regular expression in line '%s'" % line)) +    return (level, compiled) + +def read_config(): +    config_lines = [ line.rstrip() for line in filter(is_not_comment, file(config_filename).readlines()) ] +    # Add config from a logwatch.d folder +    for config_file in glob.glob(config_dir): +        config_lines += [ line.rstrip() for line in filter(is_not_comment, file(config_file).readlines()) ] + +    have_filenames = False +    config = [] + +    for line in config_lines: +        rewrite = False +        if line[0].isspace(): # pattern line +            if not have_filenames: +                raise Exception("Missing logfile names") +            level, pattern = line.split(None, 1) +            if level == 'A': +                cont_list.append(parse_cont_pattern(pattern)) +            elif level == 'R': +                rewrite_list.append(pattern) +            else: +                level, compiled = parse_pattern(level, pattern) +                cont_list = [] # List of continuation patterns +                rewrite_list = [] # List of rewrite patterns +                patterns.append((level, compiled, cont_list, rewrite_list)) +        else: # filename line +            patterns = [] +            config.append((parse_filenames(line), patterns)) +            have_filenames = True +    return config + +def parse_cont_pattern(pattern): +    try: +        return int(pattern) +    except: +        try: +            return re.compile(pattern) +        except: +            if debug: +                raise +            raise Exception("Invalid regular expression in line '%s'" % pattern)  + +# structure of statusfile +# # LOGFILE         OFFSET    INODE +# /var/log/messages|7767698|32455445 +# /var/test/x12134.log|12345|32444355 +def read_status(): +    if debug: +        return {} + +    status = {} +    for line in file(status_filename): +        # TODO: Remove variants with spaces. rsplit is +        # not portable. split fails if logfilename contains +        # spaces +        inode = -1 +        try: +            parts = line.split('|') +            filename = parts[0] +            offset = parts[1] +            if len(parts) >= 3: +                inode = parts[2] + +        except: +            try: +                filename, offset = line.rsplit(None, 1) +            except: +                filename, offset = line.split(None, 1) +        status[filename] = int(offset), int(inode) +    return status + +def save_status(status): +    f = file(status_filename, "w") +    for filename, (offset, inode) in status.items(): +        f.write("%s|%d|%d\n" % (filename, offset, inode)) + +pushed_back_line = None +def next_line(f): +    global pushed_back_line +    if pushed_back_line != None: +        line = pushed_back_line +        pushed_back_line = None +        return line +    else: +        try: +            line = f.next() +            return line +        except: +            return None + + +def process_logfile(logfile, patterns): +    global pushed_back_line + +    # Look at which file offset we have finished scanning +    # the logfile last time. If we have never seen this file +    # before, we set the offset to -1 +    offset, prev_inode = status.get(logfile, (-1, -1)) +    try: +        fl = os.open(logfile, os.O_RDONLY) +        inode = os.fstat(fl)[1] # 1 = st_ino +    except: +        if debug: +            raise +        print "[[[%s:cannotopen]]]" % logfile +        return + +    print "[[[%s]]]" % logfile + +    # Seek to the current end in order to determine file size +    current_end = os.lseek(fl, 0, 2) # os.SEEK_END not available in Python 2.4 +    status[logfile] = current_end, inode +         +    # If we have never seen this file before, we just set the +    # current pointer to the file end. We do not want to make +    # a fuss about ancient log messages... +    if offset == -1: +	if not debug: +            return +    	else: +	    offset = 0 +    + +    # If the inode of the logfile has changed it has appearently +    # been started from new (logfile rotation). At least we must +    # assume that. In some rare cases (restore of a backup, etc) +    # we are wrong and resend old log messages +    if prev_inode >= 0 and inode != prev_inode: +        offset = 0 + +    # Our previously stored offset is the current end -> +    # no new lines in this file +    if offset == current_end: +        return # nothing new + +    # If our offset is beyond the current end, the logfile has been +    # truncated or wrapped while keeping the same inode. We assume +    # that it contains all new data in that case and restart from +    # offset 0. +    if offset > current_end: +        offset = 0 + +    # now seek to offset where interesting data begins +    os.lseek(fl, offset, 0) # os.SEEK_SET not available in Python 2.4 +    f = os.fdopen(fl) +    worst = -1 +    outputtxt = "" +    lines_parsed = 0 +    start_time = time.time() + +    while True: +        line = next_line(f) +        if line == None: +            break # End of file + +        lines_parsed += 1 +        # Check if maximum number of new log messages is exceeded +        if opt_maxlines != None and lines_parsed > opt_maxlines: +            outputtxt += "%s Maximum number (%d) of new log messages exceeded.\n" % ( +               opt_overflow, opt_maxlines) +            worst = max(worst, opt_overflow_level) +            os.lseek(fl, 0, 2) # Seek to end of file, skip all other messages +            break + +        # Check if maximum processing time (per file) is exceeded. Check only +        # every 100'th line in order to save system calls +        if opt_maxtime != None and lines_parsed % 100 == 10 \ +            and time.time() - start_time > opt_maxtime: +            outputtxt += "%s Maximum parsing time (%.1f sec) of this log file exceeded.\n" % ( +               opt_overflow, opt_maxtime) +            worst = max(worst, opt_overflow_level) +            os.lseek(fl, 0, 2) # Seek to end of file, skip all other messages +            break + +        level = "." +        for lev, pattern, cont_patterns, replacements in patterns: +            matches = pattern.search(line[:-1]) +            if matches: +                level = lev +                levelint = {'C': 2, 'W': 1, 'O': 0, 'I': -1, '.': -1}[lev] +                worst = max(levelint, worst) + +                # Check for continuation lines +                for cont_pattern in cont_patterns: +                    if type(cont_pattern) == int: # add that many lines +                        for x in range(cont_pattern): +                            cont_line = next_line(f) +                            if cont_line == None: # end of file +                                break +                            line = line[:-1] + "\1" + cont_line  + +                    else: # pattern is regex +                        while True: +                            cont_line = next_line(f) +                            if cont_line == None: # end of file +                                break +                            elif cont_pattern.search(cont_line[:-1]): +                                line = line[:-1] + "\1" + cont_line  +                            else: +                                pushed_back_line = cont_line # sorry for stealing this line +                                break + +                # Replacement +                for replace in replacements: +                    line = replace.replace('\\0', line) + "\n" +                    for nr, group in enumerate(matches.groups()): +                        line = line.replace('\\%d' % (nr+1), group) + +                break # matching rule found and executed + +        color = {'C': tty_red, 'W': tty_yellow, 'O': tty_green, 'I': tty_blue, '.': ''}[level] +        if debug: +            line = line.replace("\1", "\nCONT:") +        if level == "I": +            level = "." +        if opt_nocontext and level == '.': +            continue +        outputtxt += "%s%s %s%s\n" % (color, level, line[:-1], tty_normal) + +    new_offset = os.lseek(fl, 0, 1) # os.SEEK_CUR not available in Python 2.4 +    status[logfile] = new_offset, inode + +    # output all lines if at least one warning, error or ok has been found +    if worst > -1: +        sys.stdout.write(outputtxt) +        sys.stdout.flush() + +try: +    config = read_config() +except Exception, e: +    if debug: +        raise +    print "CANNOT READ CONFIG FILE: %s" % e +    sys.exit(1) + +# Simply ignore errors in the status file.  In case of a corrupted status file we simply begin +# with an empty status. That keeps the monitoring up and running - even if we might loose a +# message in the extreme case of a corrupted status file. +try: +    status = read_status() +except Exception, e: +    status = {} + + +# The filename line may contain options like 'maxlines=100' or 'maxtime=10' +for filenames, patterns in config: +    # Initialize options with default values +    opt_maxlines = None +    opt_maxtime = None +    opt_regex = None +    opt_overflow = 'C' +    opt_overflow_level = 2 +    opt_nocontext = False +    try: +        options = [ o.split('=', 1) for o in filenames if '=' in o ] +        for key, value in options: +            if key == 'maxlines': +                opt_maxlines = int(value) +            elif key == 'maxtime': +                opt_maxtime = float(value) +            elif key == 'overflow': +                if value not in [ 'C', 'I', 'W', 'O' ]: +                    raise Exception("Invalid value %s for overflow. Allowed are C, I, O and W" % value) +                opt_overflow = value +                opt_overflow_level = {'C':2, 'W':1, 'O':0, 'I':0}[value] +            elif key == 'regex': +                opt_regex = re.compile(value) +            elif key == 'iregex': +                opt_regex = re.compile(value, re.I) +            elif key == 'nocontext': +                opt_nocontext = True +            else: +                raise Exception("Invalid option %s" % key) +    except Exception, e: +        if debug: +            raise +        print "INVALID CONFIGURATION: %s" % e +        sys.exit(1) + + +    for glob in filenames: +        if '=' in glob: +            continue +        logfiles = [ l.strip() for l in os.popen("ls %s 2>/dev/null" % glob).readlines() ] +        if opt_regex: +            logfiles = [ f for f in logfiles if opt_regex.search(f) ] +        if len(logfiles) == 0: +            print '[[[%s:missing]]]' % glob +        else: +            for logfile in logfiles: +                process_logfile(logfile, patterns) + +if not debug: +    save_status(status) diff --git a/puppet/modules/site_check_mk/manifests/agent.pp b/puppet/modules/site_check_mk/manifests/agent.pp new file mode 100644 index 00000000..589041eb --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent.pp @@ -0,0 +1,28 @@ +class site_check_mk::agent { + +  $ssh_hash = hiera('ssh') +  $pubkey   = $ssh_hash['authorized_keys']['monitor']['key'] +  $type     = $ssh_hash['authorized_keys']['monitor']['type'] + +  class { 'site_apt::preferences::check_mk': } -> + +  class { 'check_mk::agent': +    agent_package_name          => 'check-mk-agent', +    agent_logwatch_package_name => 'check-mk-agent-logwatch', +    method                      => 'ssh', +    homedir                     => '/etc/nagios/check_mk', +    register_agent              => false +  } -> + +  class { 'site_check_mk::agent::mrpe': } -> +  class { 'site_check_mk::agent::logwatch': } -> + +  file { +    [ '/srv/leap/nagios', '/srv/leap/nagios/plugins' ]: +      ensure  => directory; +    '/usr/lib/check_mk_agent/local/run_node_tests.sh': +      source => 'puppet:///modules/site_check_mk/agent/local_checks/all_hosts/run_node_tests.sh', +      mode   => '0755'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/couchdb.pp b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp new file mode 100644 index 00000000..01e2b886 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp @@ -0,0 +1,36 @@ +class site_check_mk::agent::couchdb { + +  # watch logs +  file { '/etc/check_mk/logwatch.d/bigcouch.cfg': +    source => 'puppet:///modules/site_check_mk/agent/logwatch/bigcouch.cfg', +  } +  concat::fragment { 'syslog_couchdb': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/couchdb.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + + +  # check bigcouch processes +  file_line { +    'Bigcouch_epmd_procs': +      line => 'Bigcouch_epmd_procs  /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/epmd', +      path => '/etc/check_mk/mrpe.cfg'; +    'Bigcouch_beam_procs': +      line => 'Bigcouch_beam_procs  /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/beam', +      path => '/etc/check_mk/mrpe.cfg'; +  } + +  # check open files for bigcouch proc +  include site_check_mk::agent::package::perl_plugin +  file { '/srv/leap/nagios/plugins/check_unix_open_fds.pl': +    source => 'puppet:///modules/site_check_mk/agent/nagios_plugins/check_unix_open_fds.pl', +    mode   => '0755' +  } +  file_line { +    'Bigcouch_open_files': +      line => 'Bigcouch_open_files /srv/leap/nagios/plugins/check_unix_open_fds.pl -a beam -w 750,750 -c 1000,1000', +      path => '/etc/check_mk/mrpe.cfg'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/haproxy.pp b/puppet/modules/site_check_mk/manifests/agent/haproxy.pp new file mode 100644 index 00000000..e7986db1 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/haproxy.pp @@ -0,0 +1,12 @@ +class site_check_mk::agent::haproxy { + +  include site_check_mk::agent::package::nagios_plugins_contrib + +  # local nagios plugin checks via mrpe +  file_line { +    'haproxy': +      line => 'Haproxy  /usr/lib/nagios/plugins/check_haproxy -u "http://localhost:8000/haproxy;csv"', +      path => '/etc/check_mk/mrpe.cfg'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/logwatch.pp b/puppet/modules/site_check_mk/manifests/agent/logwatch.pp new file mode 100644 index 00000000..423cace2 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/logwatch.pp @@ -0,0 +1,36 @@ +class site_check_mk::agent::logwatch { +  # Deploy mk_logwatch 1.2.4 so we can split the config +  # into multiple config files in /etc/check_mk/logwatch.d +  # see https://leap.se/code/issues/5135 + +  file { '/usr/lib/check_mk_agent/plugins/mk_logwatch': +    source  => 'puppet:///modules/site_check_mk/agent/plugins/mk_logwatch.1.2.4', +    mode    => '0755', +    require => Package['check-mk-agent-logwatch'] +  } + +  # only config files that watch a distinct logfile should go in logwatch.d/ +  file { '/etc/check_mk/logwatch.d': +    ensure  => directory, +    recurse => true, +    purge   => true, +    require => Package['check-mk-agent-logwatch'] +  } + +  # service that share a common logfile (i.e. /var/log/syslog) need to get +  # concanated in one file, otherwise the last file sourced will override +  # the config before +  # see mk_logwatch: "logwatch.cfg overwrites config files in logwatch.d", +  # https://leap.se/code/issues/5155 + +  # first, we need to deploy a custom logwatch.cfg that doesn't include +  # a section about /var/log/syslog + +  file { '/etc/check_mk/logwatch.cfg': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/logwatch.cfg', +    require => Package['check_mk-agent-logwatch'] +  } + +  include concat::setup +  include site_check_mk::agent::logwatch::syslog +} diff --git a/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp b/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp new file mode 100644 index 00000000..c927780d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/logwatch/syslog.pp @@ -0,0 +1,18 @@ +class site_check_mk::agent::logwatch::syslog { + +  concat { '/etc/check_mk/logwatch.d/syslog.cfg': +    warn    => true +  } + +  concat::fragment { 'syslog_header': +    source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog_header.cfg', +    target => '/etc/check_mk/logwatch.d/syslog.cfg', +    order  => '01'; +  } +  concat::fragment { 'syslog_tail': +    source => 'puppet:///modules/site_check_mk/agent/logwatch/syslog_tail.cfg', +    target => '/etc/check_mk/logwatch.d/syslog.cfg', +    order  => '99'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/mrpe.pp b/puppet/modules/site_check_mk/manifests/agent/mrpe.pp new file mode 100644 index 00000000..6921574f --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/mrpe.pp @@ -0,0 +1,18 @@ +class site_check_mk::agent::mrpe { +  # check_mk can use standard nagios plugins using +  # a wrapper called mrpe +  # see http://mathias-kettner.de/checkmk_mrpe.html + +  package { 'nagios-plugins-basic': +    ensure => latest, +  } + +  file { '/etc/check_mk/mrpe.cfg': +    ensure  => present, +    require => Package['check-mk-agent'] +  } -> +  file_line { 'Apt': +    line => 'APT    /usr/lib/nagios/plugins/check_apt', +    path => '/etc/check_mk/mrpe.cfg', +  } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/mx.pp b/puppet/modules/site_check_mk/manifests/agent/mx.pp new file mode 100644 index 00000000..35a4e9a5 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/mx.pp @@ -0,0 +1,23 @@ +class site_check_mk::agent::mx { + +  # watch logs +  file { '/etc/check_mk/logwatch.d/leap_mx.cfg': +    source => 'puppet:///modules/site_check_mk/agent/logwatch/leap_mx.cfg', +  } + +  # local nagios plugin checks via mrpe +  file_line { +    'Leap_MX_Procs': +      line => 'Leap_MX_Procs  /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a leap_mx', +      path => '/etc/check_mk/mrpe.cfg'; +  } + + +  # check stale files in queue dir +  file { '/usr/lib/check_mk_agent/local/check_leap_mx.sh': +    source  => 'puppet:///modules/site_check_mk/agent/local_checks/mx/check_leap_mx.sh', +    mode    => '0755', +    require => Package['check_mk-agent'] +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/openvpn.pp b/puppet/modules/site_check_mk/manifests/agent/openvpn.pp new file mode 100644 index 00000000..919a408d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/openvpn.pp @@ -0,0 +1,10 @@ +class site_check_mk::agent::openvpn { + +  # check syslog +  concat::fragment { 'syslog_openpvn': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/openvpn.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp b/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp new file mode 100644 index 00000000..95a60d17 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/package/nagios_plugins_contrib.pp @@ -0,0 +1,5 @@ +class site_check_mk::agent::package::nagios_plugins_contrib  { +  package { 'nagios-plugins-contrib': +    ensure => installed, +  } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp b/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp new file mode 100644 index 00000000..4feda375 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/package/perl_plugin.pp @@ -0,0 +1,5 @@ +class site_check_mk::agent::package::perl_plugin  { +  package { 'libnagios-plugin-perl': +    ensure => installed, +  } +} diff --git a/puppet/modules/site_check_mk/manifests/agent/soledad.pp b/puppet/modules/site_check_mk/manifests/agent/soledad.pp new file mode 100644 index 00000000..cbae81fe --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/soledad.pp @@ -0,0 +1,14 @@ +class site_check_mk::agent::soledad { + +  file { '/etc/check_mk/logwatch.d/soledad.cfg': +    source => 'puppet:///modules/site_check_mk/agent/logwatch/soledad.cfg', +  } + +  # local nagios plugin checks via mrpe +  file_line { +    'Soledad_Procs': +      line => 'Soledad_Procs  /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a soledad', +      path => '/etc/check_mk/mrpe.cfg'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/stunnel.pp b/puppet/modules/site_check_mk/manifests/agent/stunnel.pp new file mode 100644 index 00000000..64022824 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/stunnel.pp @@ -0,0 +1,9 @@ +class site_check_mk::agent::stunnel { + +  concat::fragment { 'syslog_stunnel': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/stunnel.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/tapicero.pp b/puppet/modules/site_check_mk/manifests/agent/tapicero.pp new file mode 100644 index 00000000..369ed00b --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/tapicero.pp @@ -0,0 +1,16 @@ +class site_check_mk::agent::tapicero { + +  concat::fragment { 'syslog_tapicero': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/tapicero.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + +  # local nagios plugin checks via mrpe +  file_line { +    'Tapicero_Procs': +      line => 'Tapicero_Procs  /usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a tapicero', +      path => '/etc/check_mk/mrpe.cfg'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/webapp.pp b/puppet/modules/site_check_mk/manifests/agent/webapp.pp new file mode 100644 index 00000000..64f5ea6d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/webapp.pp @@ -0,0 +1,26 @@ +class site_check_mk::agent::webapp { + +  # check webapp login + soledad sync +  package { [ 'python-srp', 'python-requests', 'python-yaml', 'python-u1db' ]: +    ensure => installed +  } +  file { '/usr/lib/check_mk_agent/local/nagios-webapp_login.py': +    ensure  => link, +    target  => '/srv/leap/webapp/test/nagios/webapp_login.py', +    require => Package['check_mk-agent'] +  } +  file { '/usr/lib/check_mk_agent/local/soledad_sync.py': +    ensure  => link, +    target  => '/srv/leap/webapp/test/nagios/soledad_sync.py', +    require => Package['check_mk-agent'] +  } + + +  # check syslog +  concat::fragment { 'syslog_webapp': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/webapp.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/server.pp b/puppet/modules/site_check_mk/manifests/server.pp new file mode 100644 index 00000000..e544ef0d --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/server.pp @@ -0,0 +1,64 @@ +class site_check_mk::server { + +  $ssh_hash = hiera('ssh') +  $pubkey   = $ssh_hash['authorized_keys']['monitor']['key'] +  $type     = $ssh_hash['authorized_keys']['monitor']['type'] +  $seckey   = $ssh_hash['monitor']['private_key'] + +  $nagios_hiera   = hiera_hash('nagios') +  $nagios_hosts   = $nagios_hiera['hosts'] + +  $hosts          = hiera_hash('hosts') +  $all_hosts      = inline_template ('<% @hosts.keys.sort.each do |key| -%>"<%= @hosts[key]["domain_internal"] %>", <% end -%>') + +  package { 'check-mk-server': +    ensure => installed, +  } + +  # override paths to use the system check_mk rather than OMD +  class { 'check_mk::config': +    site              => '', +    etc_dir           => '/etc', +    nagios_subdir     => 'nagios3', +    bin_dir           => '/usr/bin', +    host_groups       => undef, +    use_storedconfigs => false, +    require           => Package['check-mk-server'] +  } + +  Exec['check_mk-reload'] -> +    Exec['check_mk-refresh-inventory-daily'] -> +    Service['nagios'] + +  file { +    '/etc/check_mk/conf.d/use_ssh.mk': +      content => template('site_check_mk/use_ssh.mk'), +      notify  => Exec['check_mk-refresh'], +      require => Package['check-mk-server']; +    '/etc/check_mk/all_hosts_static': +      content => $all_hosts, +      notify  => Exec['check_mk-refresh'], +      require => Package['check-mk-server']; +    '/etc/check_mk/.ssh': +      ensure  => directory, +      require => Package['check-mk-server']; +    '/etc/check_mk/.ssh/id_rsa': +      content => $seckey, +      owner   => 'nagios', +      mode    => '0600', +      require => Package['check-mk-server']; +    '/etc/check_mk/.ssh/id_rsa.pub': +      content => "${type} ${pubkey} monitor", +      owner   => 'nagios', +      mode    => '0644', +      require => Package['check-mk-server']; +    # check_icmp must be suid root or called by sudo +    # see https://leap.se/code/issues/5171 +    '/usr/lib/nagios/plugins/check_icmp': +      mode    => '4755', +      require => Package['nagios-plugins-basic']; +  } + + +  include check_mk::agent::local_checks +} diff --git a/puppet/modules/site_check_mk/templates/use_ssh.mk b/puppet/modules/site_check_mk/templates/use_ssh.mk new file mode 100644 index 00000000..0bebebcf --- /dev/null +++ b/puppet/modules/site_check_mk/templates/use_ssh.mk @@ -0,0 +1,6 @@ +# http://mathias-kettner.de/checkmk_datasource_programs.html +datasource_programs = [ +<% nagios_hosts.sort.each do |name,config| %> + ( "ssh -l root -i /etc/check_mk/.ssh/id_rsa -p <%=config['ssh_port']%> <%=config['domain_internal']%> check_mk_agent", [ "<%=config['domain_internal']%>" ], ),<%- end -%> + +] diff --git a/puppet/modules/site_config/manifests/caching_resolver.pp b/puppet/modules/site_config/manifests/caching_resolver.pp index 922c394f..3d7b9206 100644 --- a/puppet/modules/site_config/manifests/caching_resolver.pp +++ b/puppet/modules/site_config/manifests/caching_resolver.pp @@ -1,4 +1,5 @@  class site_config::caching_resolver { +  tag 'leap_base'    # Setup a conf.d directory to place additional unbound configuration files.    # There must be at least one file in the directory, or unbound will not start, diff --git a/puppet/modules/site_config/manifests/default.pp b/puppet/modules/site_config/manifests/default.pp index 00eee9d0..7e421a21 100644 --- a/puppet/modules/site_config/manifests/default.pp +++ b/puppet/modules/site_config/manifests/default.pp @@ -2,19 +2,27 @@ class site_config::default {    tag 'leap_base'    $domain_hash = hiera('domain') +  include site_config::params -  include concat::setup +  # make sure apt is updated before any packages are installed +  include apt::update +  Package { require => Exec['apt_updated'] } + +  include site_config::slow    # default class, used by all hosts    include lsb, git -  # configure apt -  include site_apt +  # configure sysctl parameters +  include site_config::sysctl    # configure ssh and include ssh-keys    include site_config::sshd +  # include classes for special environments +  # i.e. openstack/aws nodes, vagrant nodes +    # fix dhclient from changing resolver information    if $::ec2_instance_id {      include site_config::dhclient @@ -26,13 +34,11 @@ class site_config::default {    # configure caching, local resolver    include site_config::caching_resolver -  # configure /etc/hosts -  class { 'site_config::hosts': -    stage => setup, -  } +  # install/configure syslog +  include site_config::syslog    # install/remove base packages -  include site_config::base_packages +  include site_config::packages::base    # include basic shorewall config    include site_shorewall::defaults @@ -41,4 +47,19 @@ class site_config::default {    # include basic shell config    include site_config::shell + +  # set up core leap files and directories +  include site_config::files + +  if $::services !~ /\bmx\b/ { +    include site_postfix::satellite +  } + +  # if class site_custom exists, include it. +  # possibility for users to define custom puppet recipes +  if defined( '::site_custom') { +    include ::site_custom +  } + +  include site_check_mk::agent  } diff --git a/puppet/modules/site_config/manifests/files.pp b/puppet/modules/site_config/manifests/files.pp new file mode 100644 index 00000000..684d3ad0 --- /dev/null +++ b/puppet/modules/site_config/manifests/files.pp @@ -0,0 +1,23 @@ +class site_config::files { + +  file { +    '/srv/leap': +      ensure  => directory, +      owner   => 'root', +      group   => 'root', +      mode    => '0711'; + +    '/var/lib/leap': +      ensure => directory, +      owner  => root, +      group  => 'root', +      mode   => '0755'; + +    '/var/log/leap': +      ensure => directory, +      owner  => root, +      group  => 'adm', +      mode   => '0750'; +  } + +} diff --git a/puppet/modules/site_config/manifests/hosts.pp b/puppet/modules/site_config/manifests/hosts.pp index ccedf036..e5d4dd70 100644 --- a/puppet/modules/site_config/manifests/hosts.pp +++ b/puppet/modules/site_config/manifests/hosts.pp @@ -1,8 +1,9 @@  class site_config::hosts() { -  $hosts         = hiera('hosts','') +  $hosts         = hiera('hosts', false)    $hostname      = hiera('name')    $domain_hash   = hiera('domain')    $domain_public = $domain_hash['full_suffix'] +  $api           = hiera('api', '')    file { '/etc/hostname':      ensure  => present, diff --git a/puppet/modules/site_config/manifests/initial_firewall.pp b/puppet/modules/site_config/manifests/initial_firewall.pp new file mode 100644 index 00000000..51cceb31 --- /dev/null +++ b/puppet/modules/site_config/manifests/initial_firewall.pp @@ -0,0 +1,62 @@ +class site_config::initial_firewall { + +  # This class is intended to setup an initial firewall, before shorewall is +  # configured. The purpose of this is for the rare case where shorewall fails +  # to start, we should not expose services to the public. + +  $ssh_config = hiera('ssh') +  $ssh_port   = $ssh_config['port'] + +  package { 'iptables': +    ensure => present +  } + +  file { +    # This firewall enables ssh access, dns lookups and web lookups (for +    # package installation) but otherwise restricts all outgoing and incoming +    # ports +    '/etc/network/ipv4firewall_up.rules': +      content => template('site_config/ipv4firewall_up.rules.erb'), +      owner   => root, +      group   => 0, +      mode    => '0644'; + +    # This firewall denys all ipv6 traffic - we will need to change this +    # when we begin to support ipv6 +    '/etc/network/ipv6firewall_up.rules': +      content => template('site_config/ipv6firewall_up.rules.erb'), +      owner   => root, +      group   => 0, +      mode    => '0644'; + +    # Run the iptables-restore in if-pre-up so that the network is locked down +    # until the correct interfaces and ips are connected +    '/etc/network/if-pre-up.d/ipv4tables': +      content => "#!/bin/sh\n/sbin/iptables-restore < /etc/network/ipv4firewall_up.rules\n", +      owner   => root, +      group   => 0, +      mode    => '0744'; + +    # Same as above for IPv6 +    '/etc/network/if-pre-up.d/ipv6tables': +      content => "#!/bin/sh\n/sbin/ip6tables-restore < /etc/network/ipv6firewall_up.rules\n", +      owner   => root, +      group   => 0, +      mode    => '0744'; +  } + +  # Immediately setup these firewall rules, but only if shorewall is not running +  exec { +    'default_ipv4_firewall': +      command   => '/sbin/iptables-restore < /etc/network/ipv4firewall_up.rules', +      logoutput => true, +      unless    => 'test -x /etc/init.d/shorewall && /etc/init.d/shorewall status', +      require   => File['/etc/network/ipv4firewall_up.rules']; + +    'default_ipv6_firewall': +      command   => '/sbin/ip6tables-restore < /etc/network/ipv6firewall_up.rules', +      logoutput => true, +      unless    => 'test -x /etc/init.d/shorewall && /etc/init.d/shorewall status', +      require   => File['/etc/network/ipv6firewall_up.rules']; +  } +} diff --git a/puppet/modules/site_config/manifests/base_packages.pp b/puppet/modules/site_config/manifests/packages/base.pp index 3d40f7a2..ae47963c 100644 --- a/puppet/modules/site_config/manifests/base_packages.pp +++ b/puppet/modules/site_config/manifests/packages/base.pp @@ -1,12 +1,13 @@ -class site_config::base_packages { +class site_config::packages::base { +    # base set of packages that we want to have installed everywhere -  package { [ 'etckeeper', 'screen', 'less' ]: +  package { [ 'etckeeper', 'screen', 'less', 'ntp' ]:      ensure => installed,    }    # base set of packages that we want to remove everywhere -  package { [ 'acpi', 'acpid', 'acpi-support-base',  'eject', 'ftp', +  package { [ 'acpi', 'acpid', 'acpi-support-base',  'eject', 'ftp', 'fontconfig-config',                'laptop-detect', 'lpr', 'nfs-common', 'nfs-kernel-server',                'portmap', 'pppconfig', 'pppoe', 'pump', 'qstat', 'rpcbind',                'samba-common', 'samba-common-bin', 'smbclient', 'tcl8.5', @@ -14,15 +15,4 @@ class site_config::base_packages {                'x11-utils', 'xterm' ]:      ensure => absent;    } - -  if $::virtual == 'virtualbox' { -    $virtualbox_ensure = present -  } else { -    $virtualbox_ensure = absent -  } - -  package { [ 'build-essential', 'fontconfig-config', 'g++', 'g++-4.7', 'gcc', -              'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev' ]: -                ensure => $virtualbox_ensure -  }  } diff --git a/puppet/modules/site_config/manifests/packages/build_essential.pp b/puppet/modules/site_config/manifests/packages/build_essential.pp new file mode 100644 index 00000000..7dfb8b03 --- /dev/null +++ b/puppet/modules/site_config/manifests/packages/build_essential.pp @@ -0,0 +1,11 @@ +# +# include this whenever you want to ensure build-essential package and related compilers are installed. +# +class site_config::packages::build_essential { +  if !defined(Package['build-essential']) { +    package { +      ['build-essential', 'g++', 'g++-4.7', 'gcc', 'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev']: +        ensure => present +    } +  } +}
\ No newline at end of file diff --git a/puppet/modules/site_config/manifests/packages/gnutls.pp b/puppet/modules/site_config/manifests/packages/gnutls.pp new file mode 100644 index 00000000..b1f17480 --- /dev/null +++ b/puppet/modules/site_config/manifests/packages/gnutls.pp @@ -0,0 +1,5 @@ +class site_config::packages::gnutls { + +  package { 'gnutls-bin': ensure => installed } + +} diff --git a/puppet/modules/site_config/manifests/packages/uninstall.pp b/puppet/modules/site_config/manifests/packages/uninstall.pp new file mode 100644 index 00000000..12f527d9 --- /dev/null +++ b/puppet/modules/site_config/manifests/packages/uninstall.pp @@ -0,0 +1,16 @@ +# +# Uninstall build-essential and compilers, unless they have been explicitly installed elsewhere. +# +class site_config::packages::uninstall { +  tag 'leap_base' + +  # generally, dev packages are needed for installing ruby gems with native extensions. +  # (nickserver, webapp, etc) + +  if !defined(Package['build-essential']) { +    package { +      ['build-essential', 'g++', 'g++-4.7', 'gcc', 'gcc-4.6', 'gcc-4.7', 'cpp', 'cpp-4.6', 'cpp-4.7', 'libc6-dev']: +        ensure => purged +    } +  } +}
\ No newline at end of file diff --git a/puppet/modules/site_config/manifests/params.pp b/puppet/modules/site_config/manifests/params.pp index 237ee454..012b3ce0 100644 --- a/puppet/modules/site_config/manifests/params.pp +++ b/puppet/modules/site_config/manifests/params.pp @@ -3,9 +3,12 @@ class site_config::params {    $ip_address               = hiera('ip_address')    $ip_address_interface     = getvar("interface_${ip_address}")    $ec2_local_ipv4_interface = getvar("interface_${::ec2_local_ipv4}") +  $environment              = hiera('environment', undef) -  if $::virtual == 'virtualbox' { -    $interface = [ 'eth0', 'eth1' ] + +  if $environment == 'local' { +    $interface = 'eth1' +    include site_config::packages::build_essential    }    elsif hiera('interface','') != '' {      $interface = hiera('interface') @@ -17,9 +20,16 @@ class site_config::params {      $interface = $ec2_local_ipv4_interface    }    elsif $::interfaces =~ /eth0/ { -    $interface = eth0 +    $interface = 'eth0'    }    else {      fail("unable to determine a valid interface, please set a valid interface for this node in nodes/${::hostname}.json")    } + +  $ca_name              = 'leap_ca' +  $client_ca_name       = 'leap_client_ca' +  $ca_bundle_name       = 'leap_ca_bundle' +  $cert_name            = 'leap' +  $commercial_ca_name   = 'leap_commercial_ca' +  $commercial_cert_name = 'leap_commercial'  } diff --git a/puppet/modules/site_config/manifests/resolvconf.pp b/puppet/modules/site_config/manifests/resolvconf.pp index 271c5043..05990c67 100644 --- a/puppet/modules/site_config/manifests/resolvconf.pp +++ b/puppet/modules/site_config/manifests/resolvconf.pp @@ -2,12 +2,13 @@ class site_config::resolvconf {    $domain_public = $site_config::default::domain_hash['full_suffix'] -  # 127.0.0.1:      caching-only local bind -  # 87.118.100.175: http://server.privacyfoundation.de -  # 62.141.58.13:   http://www.privacyfoundation.ch/de/service/server.html    class { '::resolvconf':      domain      => $domain_public,      search      => $domain_public, -    nameservers => [ '127.0.0.1', '87.118.100.175', '62.141.58.13' ] +    nameservers => [ +      '127.0.0.1      # local caching-only, unbound', +      '85.214.20.141  # Digitalcourage, a german privacy organisation: (https://en.wikipedia.org/wiki/Digitalcourage)', +      '77.109.138.45  # Swiss privacy Foundation (http://www.privacyfoundation.ch/de/service/server.html)' +    ]    }  } diff --git a/puppet/modules/site_config/manifests/ruby/dev.pp b/puppet/modules/site_config/manifests/ruby/dev.pp new file mode 100644 index 00000000..3ea6ca96 --- /dev/null +++ b/puppet/modules/site_config/manifests/ruby/dev.pp @@ -0,0 +1,8 @@ +class site_config::ruby::dev inherits site_config::ruby { +  Class['::ruby'] { +    ruby_version => '1.9.3', +    install_dev  => true +  } +  # building gems locally probably requires build-essential and gcc: +  include site_config::packages::build_essential +} diff --git a/puppet/modules/site_config/manifests/setup.pp b/puppet/modules/site_config/manifests/setup.pp new file mode 100644 index 00000000..6d89be86 --- /dev/null +++ b/puppet/modules/site_config/manifests/setup.pp @@ -0,0 +1,50 @@ +class site_config::setup { +  tag 'leap_base' + +  # +  # this is applied before each run of site.pp +  # +  #$services = '' + +  Exec { path => '/usr/bin:/usr/sbin/:/bin:/sbin:/usr/local/bin:/usr/local/sbin' } + +  include site_config::params + +  include concat::setup +  include stdlib + +  # configure /etc/hosts +  class { 'site_config::hosts': +    stage => setup, +  } + +  include site_config::initial_firewall + +  include site_apt + +  package { 'facter': +    ensure  => latest, +    require => Exec['refresh_apt'] +  } + +  # if squid_deb_proxy_client is set to true, install and configure +  # squid_deb_proxy_client for apt caching +  if hiera('squid_deb_proxy_client', false) { +    include site_squid_deb_proxy::client +  } + +  # shorewall is installed/half-configured during setup.pp (Bug #3871) +  # we need to include shorewall::interface{eth0} in setup.pp so +  # packages can be installed during main puppetrun, even before shorewall +  # is configured completly +  if ( $::site_config::params::environment == 'local' ) { +    include site_config::vagrant +  } + +  # if class site_custom::setup exists, include it. +  # possibility for users to define custom puppet recipes +  if defined( '::site_custom::setup') { +    include ::site_custom::setup +  } + +} diff --git a/puppet/modules/site_config/manifests/sysctl.pp b/puppet/modules/site_config/manifests/sysctl.pp new file mode 100644 index 00000000..99f75123 --- /dev/null +++ b/puppet/modules/site_config/manifests/sysctl.pp @@ -0,0 +1,8 @@ +class site_config::sysctl { + +  sysctl::config { +    'net.ipv4.ip_nonlocal_bind': +      value   => 1, +      comment => 'Allow applications to bind to an address when link is down (see https://leap.se/code/issues/4506)' +  } +} diff --git a/puppet/modules/site_config/manifests/syslog.pp b/puppet/modules/site_config/manifests/syslog.pp new file mode 100644 index 00000000..d3abeca1 --- /dev/null +++ b/puppet/modules/site_config/manifests/syslog.pp @@ -0,0 +1,28 @@ +class site_config::syslog { + +  # we need to pull in rsyslog from the leap repository until it is availbale in +  # wheezy-backports +  apt::preferences_snippet { 'fixed_rsyslog_anon_package': +    package  => 'rsyslog*', +    priority => '999', +    pin      => 'release o=leap.se', +    before   => Class['rsyslog::install'] +  } + +  apt::preferences_snippet { 'rsyslog_anon_depends': +    package  => 'libestr0 librelp0', +    priority => '999', +    pin      => 'release a=wheezy-backports', +    before   => Class['rsyslog::install'] +  } + +  class { 'rsyslog::client': +    log_remote => false, +    log_local  => true +  } + +  rsyslog::snippet { '00-anonymize_logs': +    content => '$ModLoad mmanon +action(type="mmanon" ipv4.bits="32" mode="rewrite")' +  } +} diff --git a/puppet/modules/site_config/manifests/vagrant.pp b/puppet/modules/site_config/manifests/vagrant.pp new file mode 100644 index 00000000..8f50b305 --- /dev/null +++ b/puppet/modules/site_config/manifests/vagrant.pp @@ -0,0 +1,11 @@ +class site_config::vagrant { +  # class for vagrant nodes + +  include site_shorewall::defaults +  # eth0 on vagrant nodes is the uplink if +  shorewall::interface { 'eth0': +    zone      => 'net', +    options   => 'tcpflags,blacklist,nosmurfs'; +  } + +} diff --git a/puppet/modules/site_config/manifests/x509/ca.pp b/puppet/modules/site_config/manifests/x509/ca.pp new file mode 100644 index 00000000..b16d0eeb --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/ca.pp @@ -0,0 +1,9 @@ +class site_config::x509::ca { + +  $x509      = hiera('x509') +  $ca        = $x509['ca_cert'] + +  x509::ca { $site_config::params::ca_name: +    content => $ca +  } +} diff --git a/puppet/modules/site_config/manifests/x509/ca_bundle.pp b/puppet/modules/site_config/manifests/x509/ca_bundle.pp new file mode 100644 index 00000000..4cbe574a --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/ca_bundle.pp @@ -0,0 +1,16 @@ +class site_config::x509::ca_bundle { + +  # CA bundle -- we want to have the possibility of allowing multiple CAs. +  # For now, the reason is to transition to using client CA. In the future, +  # we will want to be able to smoothly phase out one CA and phase in another. +  # I tried "--capath" for this, but it did not work. + + +  $x509      = hiera('x509') +  $ca        = $x509['ca_cert'] +  $client_ca = $x509['client_ca_cert'] + +  x509::ca { $site_config::params::ca_bundle_name: +    content => "${ca}${client_ca}" +  } +} diff --git a/puppet/modules/site_config/manifests/x509/cert.pp b/puppet/modules/site_config/manifests/x509/cert.pp new file mode 100644 index 00000000..7ed42959 --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/cert.pp @@ -0,0 +1,10 @@ +class site_config::x509::cert { + +  $x509      = hiera('x509') +  $cert      = $x509['cert'] + +  x509::cert { $site_config::params::cert_name: +    content => $cert +  } + +} diff --git a/puppet/modules/site_config/manifests/x509/client_ca/ca.pp b/puppet/modules/site_config/manifests/x509/client_ca/ca.pp new file mode 100644 index 00000000..0f313898 --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/client_ca/ca.pp @@ -0,0 +1,14 @@ +class site_config::x509::client_ca::ca { + +  ## +  ## This is for the special CA that is used exclusively for generating +  ## client certificates by the webapp. +  ## + +  $x509 = hiera('x509') +  $cert = $x509['client_ca_cert'] + +  x509::ca { $site_config::params::client_ca_name: +    content => $cert +  } +} diff --git a/puppet/modules/site_config/manifests/x509/client_ca/key.pp b/puppet/modules/site_config/manifests/x509/client_ca/key.pp new file mode 100644 index 00000000..f9ef3f52 --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/client_ca/key.pp @@ -0,0 +1,14 @@ +class site_config::x509::client_ca::key { + +  ## +  ## This is for the special CA that is used exclusively for generating +  ## client certificates by the webapp. +  ## + +  $x509 = hiera('x509') +  $key  = $x509['client_ca_key'] + +  x509::key { $site_config::params::client_ca_name: +    content => $key +  } +} diff --git a/puppet/modules/site_config/manifests/x509/commercial/ca.pp b/puppet/modules/site_config/manifests/x509/commercial/ca.pp new file mode 100644 index 00000000..8f35759f --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/commercial/ca.pp @@ -0,0 +1,9 @@ +class site_config::x509::commercial::ca { + +  $x509      = hiera('x509') +  $ca        = $x509['commercial_ca_cert'] + +  x509::ca { $site_config::params::commercial_ca_name: +    content => $ca +  } +} diff --git a/puppet/modules/site_config/manifests/x509/commercial/cert.pp b/puppet/modules/site_config/manifests/x509/commercial/cert.pp new file mode 100644 index 00000000..0c71a705 --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/commercial/cert.pp @@ -0,0 +1,10 @@ +class site_config::x509::commercial::cert { + +  $x509      = hiera('x509') +  $cert      = $x509['commercial_cert'] + +  x509::cert { $site_config::params::commercial_cert_name: +    content => $cert +  } + +} diff --git a/puppet/modules/site_config/manifests/x509/commercial/key.pp b/puppet/modules/site_config/manifests/x509/commercial/key.pp new file mode 100644 index 00000000..d32e85ef --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/commercial/key.pp @@ -0,0 +1,9 @@ +class site_config::x509::commercial::key { + +  $x509      = hiera('x509') +  $key       = $x509['commercial_key'] + +  x509::key { $site_config::params::commercial_cert_name: +    content => $key +  } +} diff --git a/puppet/modules/site_config/manifests/x509/key.pp b/puppet/modules/site_config/manifests/x509/key.pp new file mode 100644 index 00000000..32b59726 --- /dev/null +++ b/puppet/modules/site_config/manifests/x509/key.pp @@ -0,0 +1,9 @@ +class site_config::x509::key { + +  $x509      = hiera('x509') +  $key       = $x509['key'] + +  x509::key { $site_config::params::cert_name: +    content => $key +  } +} diff --git a/puppet/modules/site_config/templates/hosts b/puppet/modules/site_config/templates/hosts index 2c784b05..bfcabaa5 100644 --- a/puppet/modules/site_config/templates/hosts +++ b/puppet/modules/site_config/templates/hosts @@ -1,10 +1,12 @@  # This file is managed by puppet, any changes will be overwritten!  127.0.0.1    localhost -127.0.1.1    <%= @hostname %>.<%= @domain_public %> <%= @hostname %> +127.0.1.1    <%= @hostname %>.<%= @domain_public %> <%= @hostname %> <% if (defined? @services) and (@services.include? 'webapp') -%><%= @domain_public %> <%= @api['domain'] %><% end -%> +  <%- if @hosts then -%> -<%   @hosts.each do |name, props| -%> +<%   @hosts.keys.sort.each do |name| -%> +<%-     props = @hosts[name] -%>  <%=     props["ip_address"] %> <%= props["domain_full"] %> <%= props["domain_internal"] %> <%= name %>  <%   end -%>  <% end -%> diff --git a/puppet/modules/site_config/templates/ipv4firewall_up.rules.erb b/puppet/modules/site_config/templates/ipv4firewall_up.rules.erb new file mode 100644 index 00000000..524ae308 --- /dev/null +++ b/puppet/modules/site_config/templates/ipv4firewall_up.rules.erb @@ -0,0 +1,22 @@ +# Generated by iptables-save v1.4.14 on Tue Aug 20 14:40:40 2013 +*filter +:INPUT DROP [0:0] +:FORWARD DROP [0:0] +:OUTPUT DROP [0:0] +-A INPUT -i lo -j ACCEPT +-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p tcp -m state --state NEW,ESTABLISHED --dport <%= @ssh_port %> -j ACCEPT +-A INPUT -p udp -m udp --sport 53 -j ACCEPT +-A INPUT -p icmp -m icmp --icmp-type 8 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT +-A INPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 +-A OUTPUT -o lo -j ACCEPT +-A OUTPUT -p icmp -m icmp --icmp-type 0 -m state --state RELATED,ESTABLISHED -j ACCEPT +-A OUTPUT -p icmp -m icmp --icmp-type 8 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT +-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --sport <%= @ssh_port %> -j ACCEPT +-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 80 -j ACCEPT +-A OUTPUT -p tcp -m state --state NEW,ESTABLISHED --dport 443 -j ACCEPT +-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT +-A OUTPUT -p udp -m udp --dport 123 -j ACCEPT +-A OUTPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7 +COMMIT diff --git a/puppet/modules/site_config/templates/ipv6firewall_up.rules.erb b/puppet/modules/site_config/templates/ipv6firewall_up.rules.erb new file mode 100644 index 00000000..e7fae52e --- /dev/null +++ b/puppet/modules/site_config/templates/ipv6firewall_up.rules.erb @@ -0,0 +1,7 @@ +# Generated by ip6tables-save v1.4.20 on Tue Aug 20 12:19:43 2013 +*filter +:INPUT DROP [24:1980] +:FORWARD DROP [0:0] +:OUTPUT DROP [14:8030] +COMMIT +# Completed on Tue Aug 20 12:19:43 2013 diff --git a/puppet/modules/site_couchdb/files/couchdb_scripts_defaults.conf b/puppet/modules/site_couchdb/files/couchdb_scripts_defaults.conf new file mode 100644 index 00000000..1565e1a1 --- /dev/null +++ b/puppet/modules/site_couchdb/files/couchdb_scripts_defaults.conf @@ -0,0 +1,4 @@ +# space separated list of excluded DBs for dumping +# sourced by couchdb_dumpall.sh  +EXCLUDE_DBS='sessions tokens' + diff --git a/puppet/modules/site_couchdb/files/designs/Readme.md b/puppet/modules/site_couchdb/files/designs/Readme.md new file mode 100644 index 00000000..983f629f --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/Readme.md @@ -0,0 +1,14 @@ +This directory contains design documents for the leap platform. + +They need to be uploaded to the couch database in order to query the  +database in certain ways. + +Each subdirectory corresponds to a couch database and contains the design +documents that need to be added to that particular database. + +Here's an example of how to upload the users design document: +```bash +HOST="http://localhost:5984" +curl -X PUT $HOST/users/_design/User --data @users/User.json + +``` diff --git a/puppet/modules/site_couchdb/files/designs/customers/Customer.json b/puppet/modules/site_couchdb/files/designs/customers/Customer.json new file mode 100644 index 00000000..1b4bbddd --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/customers/Customer.json @@ -0,0 +1,18 @@ +{ +  "_id": "_design/Customer", +  "language": "javascript", +  "views": { +    "by_user_id": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Customer') && (doc['user_id'] != null)) {\n                    emit(doc['user_id'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_braintree_customer_id": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Customer') && (doc['braintree_customer_id'] != null)) {\n                    emit(doc['braintree_customer_id'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Customer') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    } +  }, +  "couchrest-hash": "688c401ec0230b75625c176a88fc4a02" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/identities/Identity.json b/puppet/modules/site_couchdb/files/designs/identities/Identity.json new file mode 100644 index 00000000..2ac092ab --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/identities/Identity.json @@ -0,0 +1,28 @@ +{ +  "_id": "_design/Identity", +  "language": "javascript", +  "views": { +    "by_user_id": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['user_id'] != null)) {\n                    emit(doc['user_id'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_address_and_destination": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null) && (doc['destination'] != null)) {\n                    emit([doc['address'], doc['destination']], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_address": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null)) {\n                    emit(doc['address'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "pgp_key_by_email": { +      "map": "      function(doc) {\n        if (doc.type != 'Identity') {\n          return;\n        }\n        if (typeof doc.keys === \"object\") {\n          emit(doc.address, doc.keys[\"pgp\"]);\n        }\n      }\n" +    }, +    "disabled": { +      "map": "      function(doc) {\n        if (doc.type != 'Identity') {\n          return;\n        }\n        if (typeof doc.user_id === \"undefined\") {\n          emit(doc._id, 1);\n        }\n      }\n" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Identity') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    } +  }, +  "couchrest-hash": "e9004d70e26770c621a9667536429a68" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/messages/Message.json b/puppet/modules/site_couchdb/files/designs/messages/Message.json new file mode 100644 index 00000000..7bcd74c7 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/messages/Message.json @@ -0,0 +1,18 @@ +{ +  "_id": "_design/Message", +  "language": "javascript", +  "views": { +    "by_user_ids_to_show_and_created_at": { +      "map": "// not using at moment\n// call with something like Message.by_user_ids_to_show_and_created_at.startkey([user_id, start_date]).endkey([user_id,end_date])\nfunction (doc) {\n  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n    doc.user_ids_to_show.forEach(function (userId) {\n      emit([userId, doc.created_at], 1);\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_user_ids_to_show": { +      "map": "function (doc) {\n  if (doc.type === 'Message' && doc.user_ids_to_show && Array.isArray(doc.user_ids_to_show)) {\n    doc.user_ids_to_show.forEach(function (userId) {\n      emit(userId, 1);\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Message') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    } +  }, +  "couchrest-hash": "0967e7cc5bb1e61edc1c085f6f0cecbf" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/sessions/Session.json b/puppet/modules/site_couchdb/files/designs/sessions/Session.json new file mode 100644 index 00000000..70202780 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/sessions/Session.json @@ -0,0 +1,8 @@ +{ +   "views": { +       "by_expires": { +           "reduce": "_sum", +           "map": "function(doc) {\n  if(typeof doc.expires !== \"undefined\") {\n    emit(doc.expires, 1);\n  }\n}\n" +       } +   } +} diff --git a/puppet/modules/site_couchdb/files/designs/shared/docs.json b/puppet/modules/site_couchdb/files/designs/shared/docs.json new file mode 100644 index 00000000..004180cd --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/shared/docs.json @@ -0,0 +1,8 @@ +{ +   "_id": "_design/docs",  +   "views": { +      "get": { +         "map": "function(doc) {\n    if (doc.u1db_rev) {\n        var is_tombstone = true;\n        var has_conflicts = false;\n        if (doc._attachments) {\n            if (doc._attachments.u1db_content)\n                is_tombstone = false;\n            if (doc._attachments.u1db_conflicts)\n                has_conflicts = true;\n        }\n        emit(doc._id,\n            {\n                \"couch_rev\": doc._rev,\n                \"u1db_rev\": doc.u1db_rev,\n                \"is_tombstone\": is_tombstone,\n                \"has_conflicts\": has_conflicts,\n            }\n        );\n    }\n}\n" +      } +   } +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/shared/syncs.json b/puppet/modules/site_couchdb/files/designs/shared/syncs.json new file mode 100644 index 00000000..bab5622f --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/shared/syncs.json @@ -0,0 +1,11 @@ +{ +   "_id": "_design/syncs",  +   "updates": { +      "put": "function(doc, req){\n    if (!doc) {\n        doc = {}\n        doc['_id'] = 'u1db_sync_log';\n        doc['syncs'] = [];\n    }\n    body = JSON.parse(req.body);\n    // remove outdated info\n    doc['syncs'] = doc['syncs'].filter(\n        function (entry) {\n            return entry[0] != body['other_replica_uid'];\n        }\n    );\n    // store u1db rev\n    doc['syncs'].push([\n        body['other_replica_uid'],\n        body['other_generation'],\n        body['other_transaction_id']\n    ]);\n    return [doc, 'ok'];\n}\n\n" +   },  +   "views": { +      "log": { +         "map": "function(doc) {\n    if (doc._id == 'u1db_sync_log') {\n        if (doc.syncs)\n            doc.syncs.forEach(function (entry) {\n                emit(entry[0],\n                    {\n                        'known_generation': entry[1],\n                        'known_transaction_id': entry[2]\n                    });\n            });\n    }\n}\n" +      } +   } +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/shared/transactions.json b/puppet/modules/site_couchdb/files/designs/shared/transactions.json new file mode 100644 index 00000000..106ad46c --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/shared/transactions.json @@ -0,0 +1,13 @@ +{ +   "_id": "_design/transactions",  +   "lists": { +      "generation": "function(head, req) {\n    var row;\n    var rows=[];\n    // fetch all rows\n    while(row = getRow()) {\n        rows.push(row);\n    }\n    if (rows.length > 0)\n        send(JSON.stringify({\n            \"generation\": rows.length,\n            \"doc_id\": rows[rows.length-1]['id'],\n            \"transaction_id\": rows[rows.length-1]['value']\n        }));\n    else\n        send(JSON.stringify({\n            \"generation\": 0,\n            \"doc_id\": \"\",\n            \"transaction_id\": \"\",\n        }));\n}\n",  +      "trans_id_for_gen": "function(head, req) {\n    var row;\n    var rows=[];\n    var i = 1;\n    var gen = 1;\n    if (req.query.gen)\n        gen = parseInt(req.query['gen']);\n    // fetch all rows\n    while(row = getRow())\n        rows.push(row);\n    if (gen <= rows.length)\n        send(JSON.stringify({\n            \"generation\": gen,\n            \"doc_id\": rows[gen-1]['id'],\n            \"transaction_id\": rows[gen-1]['value'],\n        }));\n    else\n        send('{}');\n}\n",  +      "whats_changed": "function(head, req) {\n    var row;\n    var gen = 1;\n    var old_gen = 0;\n    if (req.query.old_gen)\n        old_gen = parseInt(req.query['old_gen']);\n    send('{\"transactions\":[\\n');\n    // fetch all rows\n    while(row = getRow()) {\n        if (gen > old_gen) {\n            if (gen > old_gen+1)\n                send(',\\n');\n            send(JSON.stringify({\n                \"generation\": gen,\n                \"doc_id\": row[\"id\"],\n                \"transaction_id\": row[\"value\"]\n            }));\n        }\n        gen++;\n    }\n    send('\\n]}');\n}\n" +   },  +   "views": { +      "log": { +         "map": "function(doc) {\n    if (doc.u1db_transactions)\n        doc.u1db_transactions.forEach(function(t) {\n            emit(t[0],  // use timestamp as key so the results are ordered\n                 t[1]); // value is the transaction_id\n        });\n}\n" +      } +   } +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json b/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json new file mode 100644 index 00000000..2c9408b8 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json @@ -0,0 +1,50 @@ +{ +  "_id": "_design/Ticket", +  "language": "javascript", +  "views": { +    "by_updated_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Ticket') && (doc['updated_at'] != null)) {\n                    emit(doc['updated_at'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_created_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Ticket') && (doc['created_at'] != null)) {\n                    emit(doc['created_at'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_created_by": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Ticket') && (doc['created_by'] != null)) {\n                    emit(doc['created_by'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_is_open_and_created_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Ticket') && (doc['is_open'] != null) && (doc['created_at'] != null)) {\n                    emit([doc['is_open'], doc['created_at']], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_is_open_and_updated_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Ticket') && (doc['is_open'] != null) && (doc['updated_at'] != null)) {\n                    emit([doc['is_open'], doc['updated_at']], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "by_includes_post_by_and_is_open_and_created_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.is_open, doc.created_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_includes_post_by_and_is_open_and_updated_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.is_open, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_includes_post_by_and_updated_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.updated_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_includes_post_by": { +      "map": "// TODO: This view is only used in tests--should we keep it?\nfunction(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit(comment.posted_by, 1);\n      }\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_includes_post_by_and_created_at": { +      "map": "function(doc) {\n  var arr = {}\n  if (doc['type'] == 'Ticket' && doc.comments) {\n    doc.comments.forEach(function(comment){\n      if (comment.posted_by && !arr[comment.posted_by]) {\n        //don't add duplicates\n        arr[comment.posted_by] = true;\n        emit([comment.posted_by, doc.created_at], 1);\n      }\n    });\n  }\n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Ticket') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    } +  }, +  "couchrest-hash": "9978e2cbeacbe8622c2a7f103bf8130f" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/tokens/Token.json b/puppet/modules/site_couchdb/files/designs/tokens/Token.json new file mode 100644 index 00000000..b9025f15 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/tokens/Token.json @@ -0,0 +1,14 @@ +{ +  "_id": "_design/Token", +  "language": "javascript", +  "views": { +    "by_last_seen_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Token') && (doc['last_seen_at'] != null)) {\n                    emit(doc['last_seen_at'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Token') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    } +  }, +  "couchrest-hash": "541dd924551c42a2317b345effbe65cc" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/users/User.json b/puppet/modules/site_couchdb/files/designs/users/User.json new file mode 100644 index 00000000..4089ad97 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/users/User.json @@ -0,0 +1,22 @@ +{ +  "_id": "_design/User", +  "language": "javascript", +  "views": { +    "by_login": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'User') && (doc['login'] != null)) {\n                    emit(doc['login'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    }, +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'User') {\n                    emit(doc._id, null);\n                  }\n                }\n" +    }, +    "by_created_at_and_one_month_warning_not_sent": { +      "map": "function (doc) {\n  if ((doc['type'] == 'User') && (doc['created_at'] != null) && (doc['one_month_warning_sent'] == null)) {\n    emit(doc['created_at'], 1);\n  }    \n}\n", +      "reduce": "function(key, values, rereduce) { return sum(values); }" +    }, +    "by_created_at": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'User') && (doc['created_at'] != null)) {\n                    emit(doc['created_at'], 1);\n                  }\n                }\n", +      "reduce": "_sum" +    } +  }, +  "couchrest-hash": "61840ab3ec0f94ef8bbd6dd208db3b70" +}
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/manifests/add_users.pp b/puppet/modules/site_couchdb/manifests/add_users.pp new file mode 100644 index 00000000..f9ea7349 --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/add_users.pp @@ -0,0 +1,54 @@ +class site_couchdb::add_users { + +  # Couchdb users + +  ## leap_mx couchdb user +  ## read: identities +  ## write access to user-<uuid> +  couchdb::add_user { $site_couchdb::couchdb_leap_mx_user: +    roles   => '["identities"]', +    pw      => $site_couchdb::couchdb_leap_mx_pw, +    salt    => $site_couchdb::couchdb_leap_mx_salt, +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## nickserver couchdb user +  ## r: identities +  ## r/w: keycache +  couchdb::add_user { $site_couchdb::couchdb_nickserver_user: +    roles   => '["identities","keycache"]', +    pw      => $site_couchdb::couchdb_nickserver_pw, +    salt    => $site_couchdb::couchdb_nickserver_salt, +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## soledad couchdb user +  ## r/w: user-<uuid>, shared +  ## read: tokens +  couchdb::add_user { $site_couchdb::couchdb_soledad_user: +    roles   => '["tokens"]', +    pw      => $site_couchdb::couchdb_soledad_pw, +    salt    => $site_couchdb::couchdb_soledad_salt, +    require => Couchdb::Query::Setup['localhost'] +  } + +  ### tapicero couchdb user +  ### admin: needs to be able to create user-<uuid> databases +  ### read: users +  couchdb::add_user { $site_couchdb::couchdb_tapicero_user: +    roles   => '["users"]', +    pw      => $site_couchdb::couchdb_tapicero_pw, +    salt    => $site_couchdb::couchdb_tapicero_salt, +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## webapp couchdb user +  ## read/write: users, tokens, sessions, tickets, identities, customer +  couchdb::add_user { $site_couchdb::couchdb_webapp_user: +    roles   => '["tokens","identities","users"]', +    pw      => $site_couchdb::couchdb_webapp_pw, +    salt    => $site_couchdb::couchdb_webapp_salt, +    require => Couchdb::Query::Setup['localhost'] +  } + +} diff --git a/puppet/modules/site_couchdb/manifests/backup.pp b/puppet/modules/site_couchdb/manifests/backup.pp new file mode 100644 index 00000000..8b5aa6ea --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/backup.pp @@ -0,0 +1,23 @@ +class site_couchdb::backup { + +  # general backupninja config +  backupninja::config { 'backupninja_config': +    usecolors     => false, +  } + +  # dump all DBs locally to /var/backups/couchdb once a day +  backupninja::sh { 'couchdb_backup': +    command_string => "cd /srv/leap/couchdb/scripts \n./couchdb_dumpall.sh" +  } + +  # Deploy /etc/leap/couchdb_scripts_defaults.conf so we can exclude +  # some databases + +  file { '/etc/leap/couchdb_scripts_defaults.conf': +    source => 'puppet:///modules/site_couchdb/couchdb_scripts_defaults.conf', +    mode   => '0644', +    owner  => 'root', +    group  => 'root', +  } + +} diff --git a/puppet/modules/site_couchdb/manifests/bigcouch/add_nodes.pp b/puppet/modules/site_couchdb/manifests/bigcouch/add_nodes.pp index 241a4914..97e85785 100644 --- a/puppet/modules/site_couchdb/manifests/bigcouch/add_nodes.pp +++ b/puppet/modules/site_couchdb/manifests/bigcouch/add_nodes.pp @@ -1,5 +1,8 @@  class site_couchdb::bigcouch::add_nodes {    # loop through neighbors array and add nodes    $nodes = $::site_couchdb::bigcouch_config['neighbors'] -  couchdb::bigcouch::add_node { $nodes: } + +  couchdb::bigcouch::add_node { $nodes: +    require => Couchdb::Query::Setup['localhost'] +  }  } diff --git a/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp b/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp new file mode 100644 index 00000000..84aab4ef --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/bigcouch/compaction.pp @@ -0,0 +1,8 @@ +class site_couchdb::bigcouch::compaction { +  cron { +    'compact_all_shards': +      command     => '/srv/leap/couchdb/scripts/bigcouch_compact_all_shards.sh >> /var/log/bigcouch/compaction.log', +      hour        => 3, +      minute      => 17; +  } +} diff --git a/puppet/modules/site_couchdb/manifests/bigcouch/settle_cluster.pp b/puppet/modules/site_couchdb/manifests/bigcouch/settle_cluster.pp new file mode 100644 index 00000000..aa843e2e --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/bigcouch/settle_cluster.pp @@ -0,0 +1,11 @@ +class site_couchdb::bigcouch::settle_cluster { + +  exec { 'wait_for_couch_nodes': +    command => '/srv/leap/bin/run_tests --test CouchDB/Are_configured_nodes_online? --retry 6 --wait 10' +  } + +  exec { 'settle_cluster_membership': +    command => '/srv/leap/bin/run_tests --test CouchDB/Is_cluster_membership_ok? --retry 6 --wait 10', +    require => Exec['wait_for_couch_nodes'] +  } +} diff --git a/puppet/modules/site_couchdb/manifests/create_dbs.pp b/puppet/modules/site_couchdb/manifests/create_dbs.pp new file mode 100644 index 00000000..41500d3a --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/create_dbs.pp @@ -0,0 +1,70 @@ +class site_couchdb::create_dbs { + +  # Couchdb databases + +  ### customer database +  ### r/w: webapp, +  couchdb::create_db { 'customers': +    members => "{ \"names\": [\"$site_couchdb::couchdb_webapp_user\"], \"roles\": [] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## identities database +  ## r: nickserver, leap_mx - needs to be restrict with design document +  ## r/w: webapp +  couchdb::create_db { 'identities': +    members => "{ \"names\": [], \"roles\": [\"identities\"] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## keycache database +  ## r/w: nickserver +  couchdb::create_db { 'keycache': +    members => "{ \"names\": [], \"roles\": [\"keycache\"] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## sessions database +  ## r/w: webapp +  couchdb::create_db { 'sessions': +    members => "{ \"names\": [\"$site_couchdb::couchdb_webapp_user\"], \"roles\": [] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## shared database +  ## r/w: soledad +  couchdb::create_db { 'shared': +    members => "{ \"names\": [\"$site_couchdb::couchdb_soledad_user\"], \"roles\": [] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## tickets database +  ## r/w: webapp +  couchdb::create_db { 'tickets': +    members => "{ \"names\": [\"$site_couchdb::couchdb_webapp_user\"], \"roles\": [] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## tokens database +  ## r: soledad - needs to be restricted with a design document +  ## r/w: webapp +  couchdb::create_db { 'tokens': +    members => "{ \"names\": [], \"roles\": [\"tokens\"] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## users database +  ## r/w: webapp +  couchdb::create_db { 'users': +    members => "{ \"names\": [], \"roles\": [\"users\"] }", +    require => Couchdb::Query::Setup['localhost'] +  } + +  ## messages db +  ## store messages to the clients such as payment reminders +  ## r/w: webapp +  couchdb::create_db { 'messages': +    members => "{ \"names\": [\"$site_couchdb::couchdb_webapp_user\"], \"roles\": [] }", +    require => Couchdb::Query::Setup['localhost'] +  } +} diff --git a/puppet/modules/site_couchdb/manifests/designs.pp b/puppet/modules/site_couchdb/manifests/designs.pp new file mode 100644 index 00000000..9e88de64 --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/designs.pp @@ -0,0 +1,20 @@ +class site_couchdb::designs { + +  Class['site_couchdb::create_dbs'] +    -> Class['site_couchdb::designs'] + +  file { '/srv/leap/couchdb/designs': +    ensure  => directory, +    source  => 'puppet:///modules/site_couchdb/designs', +    recurse => true, +    purge   => true, +    mode    => '0755' +  } + +  exec { '/srv/leap/couchdb/scripts/load_design_documents.sh': +    require     => Vcsrepo['/srv/leap/couchdb/scripts'], +    refreshonly => false +  } + +} + diff --git a/puppet/modules/site_couchdb/manifests/init.pp b/puppet/modules/site_couchdb/manifests/init.pp index 802f3224..3614661d 100644 --- a/puppet/modules/site_couchdb/manifests/init.pp +++ b/puppet/modules/site_couchdb/manifests/init.pp @@ -1,83 +1,118 @@  class site_couchdb {    tag 'leap_service' -  $x509                   = hiera('x509') -  $key                    = $x509['key'] -  $cert                   = $x509['cert'] -  $ca                     = $x509['ca_cert'] - -  $couchdb_config         = hiera('couch') -  $couchdb_users          = $couchdb_config['users'] -  $couchdb_admin          = $couchdb_users['admin'] -  $couchdb_admin_user     = $couchdb_admin['username'] -  $couchdb_admin_pw       = $couchdb_admin['password'] -  $couchdb_admin_salt     = $couchdb_admin['salt'] -  $couchdb_webapp         = $couchdb_users['webapp'] -  $couchdb_webapp_user    = $couchdb_webapp['username'] -  $couchdb_webapp_pw      = $couchdb_webapp['password'] -  $couchdb_webapp_salt    = $couchdb_webapp['salt'] -  $couchdb_soledad        = $couchdb_users['soledad'] -  $couchdb_soledad_user   = $couchdb_soledad['username'] -  $couchdb_soledad_pw     = $couchdb_soledad['password'] -  $couchdb_soledad_salt   = $couchdb_soledad['salt'] - -  $bigcouch_config        = $couchdb_config['bigcouch'] -  $bigcouch_cookie        = $bigcouch_config['cookie'] - -  $ednp_port              = $bigcouch_config['ednp_port'] +  $couchdb_config          = hiera('couch') +  $couchdb_users           = $couchdb_config['users'] + +  $couchdb_admin           = $couchdb_users['admin'] +  $couchdb_admin_user      = $couchdb_admin['username'] +  $couchdb_admin_pw        = $couchdb_admin['password'] +  $couchdb_admin_salt      = $couchdb_admin['salt'] + +  $couchdb_leap_mx         = $couchdb_users['leap_mx'] +  $couchdb_leap_mx_user    = $couchdb_leap_mx['username'] +  $couchdb_leap_mx_pw      = $couchdb_leap_mx['password'] +  $couchdb_leap_mx_salt    = $couchdb_leap_mx['salt'] + +  $couchdb_nickserver      = $couchdb_users['nickserver'] +  $couchdb_nickserver_user = $couchdb_nickserver['username'] +  $couchdb_nickserver_pw   = $couchdb_nickserver['password'] +  $couchdb_nickserver_salt = $couchdb_nickserver['salt'] + +  $couchdb_soledad         = $couchdb_users['soledad'] +  $couchdb_soledad_user    = $couchdb_soledad['username'] +  $couchdb_soledad_pw      = $couchdb_soledad['password'] +  $couchdb_soledad_salt    = $couchdb_soledad['salt'] + +  $couchdb_tapicero        = $couchdb_users['tapicero'] +  $couchdb_tapicero_user   = $couchdb_tapicero['username'] +  $couchdb_tapicero_pw     = $couchdb_tapicero['password'] +  $couchdb_tapicero_salt   = $couchdb_tapicero['salt'] + +  $couchdb_webapp          = $couchdb_users['webapp'] +  $couchdb_webapp_user     = $couchdb_webapp['username'] +  $couchdb_webapp_pw       = $couchdb_webapp['password'] +  $couchdb_webapp_salt     = $couchdb_webapp['salt'] + +  $couchdb_backup          = $couchdb_config['backup'] + +  $bigcouch_config         = $couchdb_config['bigcouch'] +  $bigcouch_cookie         = $bigcouch_config['cookie'] + +  $ednp_port               = $bigcouch_config['ednp_port']    class { 'couchdb': -    bigcouch        => true, -    admin_pw        => $couchdb_admin_pw, -    admin_salt      => $couchdb_admin_salt, -    bigcouch_cookie => $bigcouch_cookie, -    ednp_port       => $ednp_port +    bigcouch            => true, +    admin_pw            => $couchdb_admin_pw, +    admin_salt          => $couchdb_admin_salt, +    bigcouch_cookie     => $bigcouch_cookie, +    ednp_port           => $ednp_port, +    chttpd_bind_address => '127.0.0.1' +  } + +  # ensure that we don't have leftovers from previous installations +  # where we installed the cloudant bigcouch package +  # https://leap.se/code/issues/4971 +  class { 'couchdb::bigcouch::package::cloudant': +    ensure => absent    } -  class { 'couchdb::bigcouch::package::cloudant': } +  Class['site_config::default'] +    -> Class['couchdb::bigcouch::package::cloudant'] +    -> Service['shorewall'] +    -> Class['site_couchdb::stunnel'] +    -> Service['couchdb'] +    -> File['/root/.netrc'] +    -> Class['site_couchdb::bigcouch::add_nodes'] +    -> Class['site_couchdb::bigcouch::settle_cluster'] +    -> Class['site_couchdb::create_dbs'] +    -> Class['site_couchdb::add_users'] -  Class ['couchdb::bigcouch::package::cloudant'] -    -> Service ['couchdb'] -    -> Class ['site_couchdb::bigcouch::add_nodes'] -    -> Couchdb::Create_db['users'] -    -> Couchdb::Create_db['tokens'] -    -> Couchdb::Add_user[$couchdb_webapp_user] -    -> Couchdb::Add_user[$couchdb_soledad_user] +  # /etc/couchdb/couchdb.netrc is deployed by couchdb::query::setup +  # we symlink this to /root/.netrc for couchdb_scripts (eg. backup) +  # and makes life easier for the admin (i.e. using curl/wget without +  # passing credentials) +  file { +    '/root/.netrc': +      ensure  => link, +      target  => '/etc/couchdb/couchdb.netrc'; -  class { 'site_couchdb::stunnel': -    key  => $key, -    cert => $cert, -    ca   => $ca +    '/srv/leap/couchdb': +      ensure => directory    } -  class { 'site_couchdb::bigcouch::add_nodes': } -    couchdb::query::setup { 'localhost':      user  => $couchdb_admin_user,      pw    => $couchdb_admin_pw,    } -  # Populate couchdb -  couchdb::add_user { $couchdb_webapp_user: -    roles => '["auth"]', -    pw    => $couchdb_webapp_pw, -    salt  => $couchdb_webapp_salt +  vcsrepo { '/srv/leap/couchdb/scripts': +    ensure   => present, +    provider => git, +    source   => 'https://leap.se/git/couchdb_scripts', +    revision => 'origin/master', +    require  => File['/srv/leap/couchdb']    } -  couchdb::add_user { $couchdb_soledad_user: -    roles => '["auth"]', -    pw    => $couchdb_soledad_pw, -    salt  => $couchdb_soledad_salt -  } - -  couchdb::create_db { 'users': -    readers => "{ \"names\": [\"$couchdb_webapp_user\"], \"roles\": [] }" -  } +  include site_couchdb::stunnel +  include site_couchdb::bigcouch::add_nodes +  include site_couchdb::bigcouch::settle_cluster +  include site_couchdb::create_dbs +  include site_couchdb::add_users +  include site_couchdb::designs +  include site_couchdb::logrotate +  include site_couchdb::bigcouch::compaction -  couchdb::create_db { 'tokens': -    readers => "{ \"names\": [], \"roles\": [\"auth\"] }" -  } +  if $couchdb_backup { include site_couchdb::backup }    include site_shorewall::couchdb    include site_shorewall::couchdb::bigcouch + +  include site_check_mk::agent::couchdb +  include site_check_mk::agent::tapicero + +  file { '/var/log/bigcouch': +    ensure => directory +  } +  } diff --git a/puppet/modules/site_couchdb/manifests/logrotate.pp b/puppet/modules/site_couchdb/manifests/logrotate.pp new file mode 100644 index 00000000..e1039d49 --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/logrotate.pp @@ -0,0 +1,12 @@ +class site_couchdb::logrotate { + +  augeas { +    'logrotate_bigcouch': +      context => '/files/etc/logrotate.d/bigcouch/rule', +      changes => [ 'set file /opt/bigcouch/var/log/*.log', 'set rotate 7', +                   'set schedule daily', 'set compress compress', +                   'set missingok missingok', 'set ifempty notifempty', +                   'set copytruncate copytruncate' ] +  } + +} diff --git a/puppet/modules/site_couchdb/manifests/stunnel.pp b/puppet/modules/site_couchdb/manifests/stunnel.pp index d982013e..91f1e3aa 100644 --- a/puppet/modules/site_couchdb/manifests/stunnel.pp +++ b/puppet/modules/site_couchdb/manifests/stunnel.pp @@ -1,4 +1,4 @@ -class site_couchdb::stunnel ($key, $cert, $ca) { +class site_couchdb::stunnel {    $stunnel              = hiera('stunnel') @@ -18,22 +18,16 @@ class site_couchdb::stunnel ($key, $cert, $ca) {    $ednp_server_connect  = $ednp_server['connect']    $ednp_clients         = $stunnel['ednp_clients'] + + +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca +    include x509::variables -  $cert_name = 'leap_couchdb' -  $ca_name   = 'leap_ca' -  $ca_path   = "${x509::variables::local_CAs}/${ca_name}.crt" -  $cert_path = "${x509::variables::certs}/${cert_name}.crt" -  $key_path  = "${x509::variables::keys}/${cert_name}.key" - -  # basic setup: ensure cert, key, ca files are in place, and some generic -  # stunnel things are done -  class { 'site_stunnel::setup': -    cert_name => $cert_name, -    key       => $key, -    cert      => $cert, -    ca_name   => $ca_name, -    ca        => $ca -  } +  $ca_path   = "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt" +  $cert_path = "${x509::variables::certs}/${site_config::params::cert_name}.crt" +  $key_path  = "${x509::variables::keys}/${site_config::params::cert_name}.key"    # setup a stunnel server for the webapp to connect to couchdb    stunnel::service { 'couch_server': @@ -46,7 +40,11 @@ class site_couchdb::stunnel ($key, $cert, $ca) {      verify     => '2',      pid        => '/var/run/stunnel4/couchserver.pid',      rndfile    => '/var/lib/stunnel4/.rnd', -    debuglevel => '4' +    debuglevel => '4', +    require    => [ +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ];    } @@ -62,7 +60,11 @@ class site_couchdb::stunnel ($key, $cert, $ca) {      verify     => '2',      pid        => '/var/run/stunnel4/epmd_server.pid',      rndfile    => '/var/lib/stunnel4/.rnd', -    debuglevel => '4' +    debuglevel => '4', +    require    => [ +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ];    }    # setup stunnel clients for Erlang Port Mapper Daemon (epmd) to connect @@ -88,7 +90,11 @@ class site_couchdb::stunnel ($key, $cert, $ca) {      verify     => '2',      pid        => '/var/run/stunnel4/ednp_server.pid',      rndfile    => '/var/lib/stunnel4/.rnd', -    debuglevel => '4' +    debuglevel => '4', +    require    => [ +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ];    }    # setup stunnel clients for Erlang Distributed Node Protocol (ednp) to connect @@ -101,4 +107,6 @@ class site_couchdb::stunnel ($key, $cert, $ca) {    }    create_resources(site_stunnel::clients, $ednp_clients, $ednp_client_defaults) + +  include site_check_mk::agent::stunnel  } diff --git a/puppet/modules/site_haproxy/files/haproxy-stats.cfg b/puppet/modules/site_haproxy/files/haproxy-stats.cfg new file mode 100644 index 00000000..e6335ba2 --- /dev/null +++ b/puppet/modules/site_haproxy/files/haproxy-stats.cfg @@ -0,0 +1,6 @@ +# provide access to stats for the nagios plugin +listen stats 127.0.0.1:8000 +    mode http +    stats enable +    stats uri /haproxy + diff --git a/puppet/modules/site_haproxy/manifests/init.pp b/puppet/modules/site_haproxy/manifests/init.pp index ace88a7b..1a681373 100644 --- a/puppet/modules/site_haproxy/manifests/init.pp +++ b/puppet/modules/site_haproxy/manifests/init.pp @@ -2,7 +2,6 @@ class site_haproxy {      class { 'haproxy':      enable           => true, -    version          => '1.4.23-0.1~leap60+1',      manage_service   => true,      global_options   => {        'log'     => '127.0.0.1 local0', @@ -23,4 +22,11 @@ class site_haproxy {      }    } +  # monitor haproxy +  concat::fragment { 'stats': +    target => '/etc/haproxy/haproxy.cfg', +    order  => '90', +    source => 'puppet:///modules/site_haproxy/haproxy-stats.cfg'; +  } +  include site_check_mk::agent::haproxy  } diff --git a/puppet/modules/site_mx/manifests/couchdb.pp b/puppet/modules/site_mx/manifests/couchdb.pp new file mode 100644 index 00000000..b1f3bd02 --- /dev/null +++ b/puppet/modules/site_mx/manifests/couchdb.pp @@ -0,0 +1,23 @@ +class site_mx::couchdb { + +  $stunnel = hiera('stunnel') +  $couch_client            = $stunnel['couch_client'] +  $couch_client_connect    = $couch_client['connect'] + +  include x509::variables +  $ca_path                 = "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt" +  $cert_path               = "${x509::variables::certs}/${site_config::params::cert_name}.crt" +  $key_path                = "${x509::variables::keys}/${site_config::params::cert_name}.key" + +  include site_stunnel + +  $couchdb_stunnel_client_defaults = { +    'connect_port' => $couch_client_connect, +    'client'     => true, +    'cafile'     => $ca_path, +    'key'        => $key_path, +    'cert'       => $cert_path, +  } + +  create_resources(site_stunnel::clients, $couch_client, $couchdb_stunnel_client_defaults) +} diff --git a/puppet/modules/site_mx/manifests/haproxy.pp b/puppet/modules/site_mx/manifests/haproxy.pp new file mode 100644 index 00000000..988eeaf3 --- /dev/null +++ b/puppet/modules/site_mx/manifests/haproxy.pp @@ -0,0 +1,14 @@ +class site_mx::haproxy { + +  include site_haproxy + +  $haproxy     = hiera('haproxy') +  $local_ports = $haproxy['local_ports'] + +  # Template uses $global_options, $defaults_options +  concat::fragment { 'leap_haproxy_webapp_couchdb': +    target  => '/etc/haproxy/haproxy.cfg', +    order   => '20', +    content => template('site_webapp/haproxy_couchdb.cfg.erb'), +  } +} diff --git a/puppet/modules/site_mx/manifests/init.pp b/puppet/modules/site_mx/manifests/init.pp new file mode 100644 index 00000000..3949c787 --- /dev/null +++ b/puppet/modules/site_mx/manifests/init.pp @@ -0,0 +1,19 @@ +class site_mx { +  tag 'leap_service' +  Class['site_config::default'] -> Class['site_mx'] + +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca +  include site_config::x509::client_ca::ca +  include site_config::x509::client_ca::key + + +  include site_postfix::mx +  include site_mx::haproxy +  include site_shorewall::mx +  include site_shorewall::service::smtp +  include site_mx::couchdb +  include leap_mx +  include site_check_mk::agent::mx +} diff --git a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg index 753d1610..e46ebf62 100644 --- a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg +++ b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg @@ -1,6 +1,6 @@  ##############################################################################  # -# NAGIOS.CFG - Sample Main Config File for Nagios  +# NAGIOS.CFG - Sample Main Config File for Nagios  #  #  ############################################################################## @@ -8,7 +8,7 @@  # LOG FILE  # This is the main log file where service and host events are logged -# for historical purposes.  This should be the first option specified  +# for historical purposes.  This should be the first option specified  # in the config file!!!  log_file=/var/log/nagios3/nagios.log @@ -25,6 +25,9 @@ log_file=/var/log/nagios3/nagios.log  # Puppet-managed configuration files  cfg_dir=/etc/nagios3/conf.d +# check-mk managed configuration files +cfg_dir=/etc/nagios3/local +  # Debian also defaults to using the check commands defined by the debian  # nagios-plugins package  cfg_dir=/etc/nagios-plugins/config @@ -33,7 +36,7 @@ cfg_dir=/etc/nagios-plugins/config  # OBJECT CACHE FILE  # This option determines where object definitions are cached when -# Nagios starts/restarts.  The CGIs read object definitions from  +# Nagios starts/restarts.  The CGIs read object definitions from  # this cache file (rather than looking at the object config files  # directly) in order to prevent inconsistencies that can occur  # when the config files are modified after Nagios starts. @@ -49,7 +52,7 @@ object_cache_file=/var/cache/nagios3/objects.cache  # file.  You can then start Nagios with the -u option to have it read  # object definitions from this precached file, rather than the standard  # object configuration files (see the cfg_file and cfg_dir options above). -# Using a precached object file can speed up the time needed to (re)start  +# Using a precached object file can speed up the time needed to (re)start  # the Nagios process if you've got a large and/or complex configuration.  # Read the documentation section on optimizing Nagios to find our more  # about how this feature works. @@ -83,7 +86,7 @@ status_file=/var/cache/nagios3/status.dat  # STATUS FILE UPDATE INTERVAL  # This option determines the frequency (in seconds) that -# Nagios will periodically dump program, host, and  +# Nagios will periodically dump program, host, and  # service status data.  status_update_interval=10 @@ -91,7 +94,7 @@ status_update_interval=10  # NAGIOS USER -# This determines the effective user that Nagios should run as.   +# This determines the effective user that Nagios should run as.  # You can either supply a username or a UID.  nagios_user=nagios @@ -99,7 +102,7 @@ nagios_user=nagios  # NAGIOS GROUP -# This determines the effective group that Nagios should run as.   +# This determines the effective group that Nagios should run as.  # You can either supply a group name or a GID.  nagios_group=nagios @@ -125,7 +128,7 @@ check_external_commands=1  # Nagios to check for external commands every minute.  If you specify a  # number followed by an "s" (i.e. 15s), this will be interpreted to mean  # actual seconds rather than a multiple of the interval_length variable. -# Note: In addition to reading the external command file at regularly  +# Note: In addition to reading the external command file at regularly  # scheduled intervals, Nagios will also check for external commands after  # event handlers are executed.  # NOTE: Setting this value to -1 causes Nagios to check the external @@ -140,7 +143,7 @@ command_check_interval=-1  # This is the file that Nagios checks for external command requests.  # It is also where the command CGI will write commands that are submitted  # by users, so it must be writeable by the user that the web server -# is running as (usually 'nobody').  Permissions should be set at the  +# is running as (usually 'nobody').  Permissions should be set at the  # directory level instead of on the file, as the file is deleted every  # time its contents are processed.  # Debian Users: In case you didn't read README.Debian yet, _NOW_ is the @@ -152,9 +155,9 @@ command_file=/var/lib/nagios3/rw/nagios.cmd  # EXTERNAL COMMAND BUFFER SLOTS  # This settings is used to tweak the number of items or "slots" that -# the Nagios daemon should allocate to the buffer that holds incoming  -# external commands before they are processed.  As external commands  -# are processed by the daemon, they are removed from the buffer.   +# the Nagios daemon should allocate to the buffer that holds incoming +# external commands before they are processed.  As external commands +# are processed by the daemon, they are removed from the buffer.  external_command_buffer_slots=4096 @@ -232,12 +235,12 @@ event_broker_options=-1  #	w	= Weekly rotation (midnight on Saturday evening)  #	m	= Monthly rotation (midnight last day of month) -log_rotation_method=d +log_rotation_method=n  # LOG ARCHIVE PATH -# This is the directory where archived (rotated) log files should be  +# This is the directory where archived (rotated) log files should be  # placed (assuming you've chosen to do log rotation).  log_archive_path=/var/log/nagios3/archives @@ -248,7 +251,7 @@ log_archive_path=/var/log/nagios3/archives  # If you want messages logged to the syslog facility, as well as the  # Nagios log file set this option to 1.  If not, set it to 0. -use_syslog=1 +use_syslog=0 @@ -400,7 +403,7 @@ max_host_check_spread=30  # MAXIMUM CONCURRENT SERVICE CHECKS -# This option allows you to specify the maximum number of  +# This option allows you to specify the maximum number of  # service checks that can be run in parallel at any given time.  # Specifying a value of 1 for this variable essentially prevents  # any service checks from being parallelized.  A value of 0 @@ -422,7 +425,7 @@ check_result_reaper_frequency=10  # MAX CHECK RESULT REAPER TIME  # This is the max amount of time (in seconds) that  a single -# check result reaper event will be allowed to run before  +# check result reaper event will be allowed to run before  # returning control back to Nagios so it can perform other  # duties. @@ -436,7 +439,7 @@ max_check_result_reaper_time=30  # service checks that have not yet been processed.  #  # Note: Make sure that only one instance of Nagios has access -# to this directory!   +# to this directory!  check_result_path=/var/lib/nagios3/spool/checkresults @@ -445,7 +448,7 @@ check_result_path=/var/lib/nagios3/spool/checkresults  # MAX CHECK RESULT FILE AGE  # This option determines the maximum age (in seconds) which check -# result files are considered to be valid.  Files older than this  +# result files are considered to be valid.  Files older than this  # threshold will be mercilessly deleted without further processing.  max_check_result_file_age=3600 @@ -507,14 +510,14 @@ enable_predictive_service_dependency_checks=1  # SOFT STATE DEPENDENCIES -# This option determines whether or not Nagios will use soft state  -# information when checking host and service dependencies. Normally  -# Nagios will only use the latest hard host or service state when  +# This option determines whether or not Nagios will use soft state +# information when checking host and service dependencies. Normally +# Nagios will only use the latest hard host or service state when  # checking dependencies. If you want it to use the latest state (regardless -# of whether its a soft or hard state type), enable this option.  +# of whether its a soft or hard state type), enable this option.  # Values: -#  0 = Don't use soft state dependencies (default)  -#  1 = Use soft state dependencies  +#  0 = Don't use soft state dependencies (default) +#  1 = Use soft state dependencies  soft_state_dependencies=0 @@ -532,7 +535,7 @@ soft_state_dependencies=0  # This option determines whether or not Nagios will attempt to  # automatically reschedule active host and service checks to  # "smooth" them out over time.  This can help balance the load on -# the monitoring server.   +# the monitoring server.  # WARNING: THIS IS AN EXPERIMENTAL FEATURE - IT CAN DEGRADE  # PERFORMANCE, RATHER THAN INCREASE IT, IF USED IMPROPERLY @@ -595,7 +598,7 @@ perfdata_timeout=5  # This setting determines whether or not Nagios will save state  # information for services and hosts before it shuts down.  Upon  # startup Nagios will reload all saved service and host state -# information before starting to monitor.  This is useful for  +# information before starting to monitor.  This is useful for  # maintaining long-term data on state statistics, etc, but will  # slow Nagios down a bit when it (re)starts.  Since its only  # a one-time penalty, I think its well worth the additional @@ -607,7 +610,7 @@ retain_state_information=1  # STATE RETENTION FILE  # This is the file that Nagios should use to store host and -# service state information before it shuts down.  The state  +# service state information before it shuts down.  The state  # information in this file is also read immediately prior to  # starting to monitor the network when Nagios is restarted.  # This file is used only if the preserve_state_information @@ -630,7 +633,7 @@ retention_update_interval=60  # USE RETAINED PROGRAM STATE -# This setting determines whether or not Nagios will set  +# This setting determines whether or not Nagios will set  # program status variables based on the values saved in the  # retention file.  If you want to use retained program status  # information, set this value to 1.  If not, set this value @@ -657,7 +660,7 @@ use_retained_scheduling_info=1  # program restarts.  #  # The values of the masks are bitwise ANDs of values specified -# by the "MODATTR_" definitions found in include/common.h.   +# by the "MODATTR_" definitions found in include/common.h.  # For example, if you do not want the current enabled/disabled state  # of flap detection and event handlers for hosts to be retained, you  # would use a value of 24 for the host attribute mask... @@ -708,7 +711,7 @@ use_aggressive_host_checking=0  # SERVICE CHECK EXECUTION OPTION  # This determines whether or not Nagios will actively execute -# service checks when it initially starts.  If this option is  +# service checks when it initially starts.  If this option is  # disabled, checks are not actively made, but Nagios can still  # receive and process passive check results that come in.  Unless  # you're implementing redundant hosts or have a special need for @@ -730,7 +733,7 @@ accept_passive_service_checks=1  # HOST CHECK EXECUTION OPTION  # This determines whether or not Nagios will actively execute -# host checks when it initially starts.  If this option is  +# host checks when it initially starts.  If this option is  # disabled, checks are not actively made, but Nagios can still  # receive and process passive check results that come in.  Unless  # you're implementing redundant hosts or have a special need for @@ -787,7 +790,7 @@ process_performance_data=0  # These commands are run after every host and service check is  # performed.  These commands are executed only if the  # enable_performance_data option (above) is set to 1.  The command -# argument is the short name of a command definition that you  +# argument is the short name of a command definition that you  # define in your host configuration file.  Read the HTML docs for  # more information on performance data. @@ -867,7 +870,7 @@ obsess_over_services=0  # OBSESSIVE COMPULSIVE SERVICE PROCESSOR COMMAND  # This is the command that is run for every service check that is  # processed by Nagios.  This command is executed only if the -# obsess_over_services option (above) is set to 1.  The command  +# obsess_over_services option (above) is set to 1.  The command  # argument is the short name of a command definition that you  # define in your host configuration file. Read the HTML docs for  # more information on implementing distributed monitoring. @@ -891,7 +894,7 @@ obsess_over_hosts=0  # OBSESSIVE COMPULSIVE HOST PROCESSOR COMMAND  # This is the command that is run for every host check that is  # processed by Nagios.  This command is executed only if the -# obsess_over_hosts option (above) is set to 1.  The command  +# obsess_over_hosts option (above) is set to 1.  The command  # argument is the short name of a command definition that you  # define in your host configuration file. Read the HTML docs for  # more information on implementing distributed monitoring. @@ -930,9 +933,9 @@ passive_host_checks_are_soft=0  # ORPHANED HOST/SERVICE CHECK OPTIONS -# These options determine whether or not Nagios will periodically  +# These options determine whether or not Nagios will periodically  # check for orphaned host service checks.  Since service checks are -# not rescheduled until the results of their previous execution  +# not rescheduled until the results of their previous execution  # instance are processed, there exists a possibility that some  # checks may never get rescheduled.  A similar situation exists for  # host checks, although the exact scheduling details differ a bit @@ -1000,9 +1003,9 @@ additional_freshness_latency=15  # FLAP DETECTION OPTION  # This option determines whether or not Nagios will try -# and detect hosts and services that are "flapping".   +# and detect hosts and services that are "flapping".  # Flapping occurs when a host or service changes between -# states too frequently.  When Nagios detects that a  +# states too frequently.  When Nagios detects that a  # host or service is flapping, it will temporarily suppress  # notifications for that host/service until it stops  # flapping.  Flap detection is very experimental, so read @@ -1046,7 +1049,7 @@ date_format=iso8601  # the system configured timezone.  #  # NOTE: In order to display the correct timezone in the CGIs, you -# will also need to alter the Apache directives for the CGI path  +# will also need to alter the Apache directives for the CGI path  # to include your timezone.  Example:  #  #   <Directory "/usr/local/nagios/sbin/"> @@ -1083,7 +1086,7 @@ enable_embedded_perl=1  # This option determines whether or not Nagios will process Perl plugins  # and scripts with the embedded Perl interpreter if the plugins/scripts  # do not explicitly indicate whether or not it is okay to do so. Read -# the HTML documentation on the embedded Perl interpreter for more  +# the HTML documentation on the embedded Perl interpreter for more  # information on how this option works.  use_embedded_perl_implicitly=1 @@ -1130,7 +1133,7 @@ use_regexp_matching=0  # "TRUE" REGULAR EXPRESSION MATCHING -# This option controls whether or not "true" regular expression  +# This option controls whether or not "true" regular expression  # matching takes place in the object config files.  This option  # only has an effect if regular expression matching is enabled  # (see above).  If this option is DISABLED, regular expression @@ -1183,7 +1186,7 @@ use_large_installation_tweaks=0  # This option determines whether or not Nagios will make all standard  # macros available as environment variables when host/service checks  # and system commands (event handlers, notifications, etc.) are -# executed.  Enabling this option can cause performance issues in  +# executed.  Enabling this option can cause performance issues in  # large installations, as it will consume a bit more memory and (more  # importantly) consume more CPU.  # Values: 1 - Enable environment variable macros (default) @@ -1224,7 +1227,7 @@ enable_environment_macros=1  # This option determines how much (if any) debugging information will  # be written to the debug file.  OR values together to log multiple  # types of information. -# Values:  +# Values:  #          -1 = Everything  #          0 = Nothing  #	   1 = Functions diff --git a/puppet/modules/site_nagios/manifests/add_host.pp b/puppet/modules/site_nagios/manifests/add_host.pp deleted file mode 100644 index 498552b5..00000000 --- a/puppet/modules/site_nagios/manifests/add_host.pp +++ /dev/null @@ -1,31 +0,0 @@ -define site_nagios::add_host { -  $nagios_host       = $name -  $nagios_hostname   = $name['domain_internal'] -  $nagios_ip         = $name['ip_address'] -  $nagios_services   = $name['services'] -  $nagios_openvpn_gw = $name['openvpn_gateway_address'] - -  # Add Nagios host -  nagios_host { $nagios_hostname: -    address => $nagios_ip, -    use     => 'generic-host', -  } - -  # Add Nagios service - -  # First, we need to turn the serice array into hash, using a "hash template" -  # see https://github.com/ashak/puppet-resource-looping -  $nagios_service_hashpart = { -    'hostname'    => $nagios_hostname, -    'ip_address'  => $nagios_ip, -    'openvpn_gw'  => $nagios_openvpn_gw, -  } -  $dynamic_parameters = { -    'service' => '%s' -  } -  $nagios_servicename = "${nagios_hostname}_%s" - -  $nagios_service_hash = create_resources_hash_from($nagios_servicename, $nagios_services, $nagios_service_hashpart, $dynamic_parameters) - -  create_resources ( site_nagios::add_service, $nagios_service_hash ) -} diff --git a/puppet/modules/site_nagios/manifests/add_host_services.pp b/puppet/modules/site_nagios/manifests/add_host_services.pp new file mode 100644 index 00000000..279809d1 --- /dev/null +++ b/puppet/modules/site_nagios/manifests/add_host_services.pp @@ -0,0 +1,28 @@ +define site_nagios::add_host_services ( +  $domain_full_suffix, +  $domain_internal, +  $ip_address, +  $services, +  $ssh_port, +  $openvpn_gateway_address='' ) { + +    $nagios_hostname = $domain_internal + +    # Add Nagios service + +    # First, we need to turn the serice array into hash, using a "hash template" +    # see https://github.com/ashak/puppet-resource-looping +    $nagios_service_hashpart = { +      'hostname'    => $nagios_hostname, +      'ip_address'  => $ip_address, +      'openvpn_gw'  => $openvpn_gateway_address, +    } +    $dynamic_parameters = { +      'service' => '%s' +    } +    $nagios_servicename = "${nagios_hostname}_%s" + +    $nagios_service_hash = create_resources_hash_from($nagios_servicename, $services, $nagios_service_hashpart, $dynamic_parameters) + +    create_resources ( site_nagios::add_service, $nagios_service_hash ) +} diff --git a/puppet/modules/site_nagios/manifests/add_service.pp b/puppet/modules/site_nagios/manifests/add_service.pp index 6ef3cbf5..8d2a310b 100644 --- a/puppet/modules/site_nagios/manifests/add_service.pp +++ b/puppet/modules/site_nagios/manifests/add_service.pp @@ -3,19 +3,19 @@ define site_nagios::add_service (    case $service {      'webapp': { -      $check_command       = 'check_https_cert' -      $service_description = 'Website Certificate' +      nagios_service { +        "${name}_cert": +          use                 => 'generic-service', +          check_command       => 'check_https_cert', +          service_description => 'Website Certificate', +          host_name           => $hostname; +        "${name}_website": +          use                 => 'generic-service', +          check_command       => 'check_https', +          service_description => 'Website', +          host_name           => $hostname +      }      } -    default:  { -      #notice ("No Nagios service check for service \"$service\"") -    } -  } - -  if ( $check_command != '' ) { -    nagios_service { $name: -      use                 => 'generic-service', -      check_command       => $check_command, -      service_description => $service_description, -      host_name           => $hostname } +    default:  {}    }  } diff --git a/puppet/modules/site_nagios/manifests/init.pp b/puppet/modules/site_nagios/manifests/init.pp index cab32905..eb08cdcb 100644 --- a/puppet/modules/site_nagios/manifests/init.pp +++ b/puppet/modules/site_nagios/manifests/init.pp @@ -1,4 +1,6 @@  class site_nagios  {    tag 'leap_service' +  Class['site_config::default'] -> Class['site_nagios'] +    include site_nagios::server  } diff --git a/puppet/modules/site_nagios/manifests/server.pp b/puppet/modules/site_nagios/manifests/server.pp index c114a39a..85443917 100644 --- a/puppet/modules/site_nagios/manifests/server.pp +++ b/puppet/modules/site_nagios/manifests/server.pp @@ -1,26 +1,34 @@  class site_nagios::server inherits nagios::base {    # First, purge old nagios config (see #1467) -  class { 'site_nagios::server::purge': -    stage => setup -  } +  class { 'site_nagios::server::purge': } -  $nagios_hiera=hiera('nagios') +  $nagios_hiera   = hiera('nagios')    $nagiosadmin_pw = htpasswd_sha1($nagios_hiera['nagiosadmin_pw']) -  $hosts = $nagios_hiera['hosts'] +  $nagios_hosts   = $nagios_hiera['hosts']    include nagios::defaults    include nagios::base -  #Class ['nagios'] -> Class ['nagios::defaults'] -  class {'nagios::apache': +  class {'nagios': +    # don't manage apache class from nagios, cause we already include +    # it in site_apache::common +    httpd              => 'absent',      allow_external_cmd => true,      stored_config      => false, -    #before             => Class ['nagios::defaults']    } +  file { '/etc/apache2/conf.d/nagios3.conf': +    ensure => link, +    target => '/usr/share/doc/nagios3-common/examples/apache2.conf', +    notify => Service['apache'] +  } + +  include site_apache::common +  include site_apache::module::headers +    File ['nagios_htpasswd'] {      source  => undef, -    content => "nagiosadmin:$nagiosadmin_pw", +    content => "nagiosadmin:${nagiosadmin_pw}",      mode    => '0640',    } @@ -33,6 +41,18 @@ class site_nagios::server inherits nagios::base {      group  => 'nagios',    } -  site_nagios::add_host {$hosts:} +  create_resources ( site_nagios::add_host_services, $nagios_hosts ) + +  include site_nagios::server::apache +  include site_check_mk::server    include site_shorewall::monitor + +  augeas { +    'logrotate_nagios': +      context => '/files/etc/logrotate.d/nagios/rule', +      changes => [ 'set file /var/log/nagios3/nagios.log', 'set rotate 7', +        'set schedule daily', 'set compress compress', +        'set missingok missingok', 'set ifempty notifempty', +        'set copytruncate copytruncate' ] +  }  } diff --git a/puppet/modules/site_nagios/manifests/server/apache.pp b/puppet/modules/site_nagios/manifests/server/apache.pp new file mode 100644 index 00000000..8dbc7e9b --- /dev/null +++ b/puppet/modules/site_nagios/manifests/server/apache.pp @@ -0,0 +1,7 @@ +class site_nagios::server::apache { +  include x509::variables +  include site_config::x509::commercial::cert +  include site_config::x509::commercial::key +  include site_config::x509::commercial::ca + +} diff --git a/puppet/modules/site_nagios/manifests/server/purge.pp b/puppet/modules/site_nagios/manifests/server/purge.pp index 39735cd3..6815a703 100644 --- a/puppet/modules/site_nagios/manifests/server/purge.pp +++ b/puppet/modules/site_nagios/manifests/server/purge.pp @@ -1,7 +1,19 @@ -class site_nagios::server::purge { -  exec {'purge_conf.d': -    command => '/bin/rm -rf /etc/nagios3/conf.d/*', -    onlyif  => 'test -e /etc/nagios3/conf.d' +class site_nagios::server::purge inherits nagios::base { +  # we don't want to get /etc/nagios3 and /etc/nagios3/conf.d +  # purged, cause the check-mk-config-nagios3 package +  # places its templates in /etc/nagios3/conf.d/check_mk, +  # and check_mk -O updated it's nagios config in /etc/nagios3/conf.d/check_mk +  File['nagios_cfgdir'] { +    purge => false +  } +  File['nagios_confd'] { +    purge => false    } +  # only purge files in the /etc/nagios3/conf.d/ dir, not in any subdir +  exec {'purge_conf.d': +    command => '/usr/bin/find /etc/nagios3/conf.d/ -maxdepth 1 -type f -exec rm {} \;', +    onlyif  => '/usr/bin/find /etc/nagios3/conf.d/ -maxdepth 1 -type f | grep -q "/etc/nagios3/conf.d"', +    require => Package['nagios'] +  }  } diff --git a/puppet/modules/site_nickserver/manifests/init.pp b/puppet/modules/site_nickserver/manifests/init.pp index 7dfa2603..eaf90d55 100644 --- a/puppet/modules/site_nickserver/manifests/init.pp +++ b/puppet/modules/site_nickserver/manifests/init.pp @@ -1,37 +1,47 @@  # -# TODO: currently, this is dependent on some things that are set up in site_webapp +# TODO: currently, this is dependent on some things that are set up in +# site_webapp  #  # (1) HAProxy -> couchdb  # (2) Apache  # -# It would be good in the future to make nickserver installable independently of site_webapp. +# It would be good in the future to make nickserver installable independently of +# site_webapp.  #  class site_nickserver {    tag 'leap_service' -  include site_config::ruby +  Class['site_config::default'] -> Class['site_nickserver'] + +  include site_config::ruby::dev    #    # VARIABLES    #    $nickserver        = hiera('nickserver') -  $nickserver_port   = $nickserver['port']  # the port that public connects to (should be 6425) -  $nickserver_local_port = '64250'          # the port that nickserver is actually running on    $nickserver_domain = $nickserver['domain'] +  $couchdb_user      = $nickserver['couchdb_nickserver_user']['username'] +  $couchdb_password  = $nickserver['couchdb_nickserver_user']['password'] + +  # the port that public connects to (should be 6425) +  $nickserver_port   = $nickserver['port'] +  # the port that nickserver is actually running on +  $nickserver_local_port = '64250' -  $couchdb_user      = $nickserver['couchdb_user']['username'] -  $couchdb_password  = $nickserver['couchdb_user']['password'] -  $couchdb_host      = 'localhost'    # couchdb is available on localhost via haproxy, which is bound to 4096. -  $couchdb_port      = '4096'         # See site_webapp/templates/haproxy_couchdb.cfg.erg +  # couchdb is available on localhost via haproxy, which is bound to 4096. +  $couchdb_host      = 'localhost' +  # See site_webapp/templates/haproxy_couchdb.cfg.erg +  $couchdb_port      = '4096'    # temporarily for now:    $domain          = hiera('domain')    $address_domain  = $domain['full_suffix'] -  $x509            = hiera('x509') -  $x509_key        = $x509['key'] -  $x509_cert       = $x509['cert'] -  $x509_ca         = $x509['ca_cert'] + + +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca    #    # USER AND GROUP @@ -41,6 +51,7 @@ class site_nickserver {      ensure    => present,      allowdupe => false;    } +    user { 'nickserver':      ensure    => present,      allowdupe => false, @@ -50,31 +61,33 @@ class site_nickserver {    }    # -  # NICKSERVER CODE -  # NOTE: in order to support TLS, libssl-dev must be installed before EventMachine gem -  # is built/installed. +  # NICKSERVER CODE NOTE: in order to support TLS, libssl-dev must be installed +  # before EventMachine gem is built/installed.    # -  package { -    'libssl-dev': ensure => installed; -  } +  package { 'libssl-dev': ensure => installed } +    vcsrepo { '/srv/leap/nickserver':      ensure   => present,      revision => 'origin/master',      provider => git, -    source   => 'git://code.leap.se/nickserver', +    source   => 'https://leap.se/git/nickserver',      owner    => 'nickserver',      group    => 'nickserver',      require  => [ User['nickserver'], Group['nickserver'] ],      notify   => Exec['nickserver_bundler_update'];    } +    exec { 'nickserver_bundler_update':      cwd     => '/srv/leap/nickserver',      command => '/bin/bash -c "/usr/bin/bundle check || /usr/bin/bundle install --path vendor/bundle"',      unless  => '/usr/bin/bundle check',      user    => 'nickserver',      timeout => 600, -    require => [ Class['bundler::install'], Vcsrepo['/srv/leap/nickserver'], Package['libssl-dev'] ], +    require => [ +      Class['bundler::install'], Vcsrepo['/srv/leap/nickserver'], +      Package['libssl-dev'], Class['site_config::ruby::dev'] ], +      notify  => Service['nickserver'];    } @@ -82,7 +95,7 @@ class site_nickserver {    # NICKSERVER CONFIG    # -  file { '/etc/leap/nickserver.yml': +  file { '/etc/nickserver.yml':      content => template('site_nickserver/nickserver.yml.erb'),      owner   => nickserver,      group   => nickserver, @@ -99,8 +112,11 @@ class site_nickserver {        ensure  => link,        target  => '/srv/leap/nickserver/bin/nickserver',        require => Vcsrepo['/srv/leap/nickserver']; +      '/etc/init.d/nickserver': -      owner   => root, group => 0, mode => '0755', +      owner   => root, +      group   => 0, +      mode    => '0755',        source  => '/srv/leap/nickserver/dist/debian-init-script',        require => Vcsrepo['/srv/leap/nickserver'];    } @@ -110,7 +126,11 @@ class site_nickserver {      enable     => true,      hasrestart => true,      hasstatus  => true, -    require    => File['/etc/init.d/nickserver']; +    require    => [ +      File['/etc/init.d/nickserver'], +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ];    }    # @@ -119,7 +139,7 @@ class site_nickserver {    #    file { '/etc/shorewall/macro.nickserver': -    content => "PARAM   -       -       tcp    $nickserver_port", +    content => "PARAM   -       -       tcp    ${nickserver_port}",      notify  => Service['shorewall'],      require => Package['shorewall'];    } @@ -142,21 +162,8 @@ class site_nickserver {    }    apache::vhost::file { -    'nickserver': content => template('site_nickserver/nickserver-proxy.conf.erb') -  } - -  x509::key { 'nickserver': -    content => $x509_key, -    notify  => Service[apache]; +    'nickserver': +      content => template('site_nickserver/nickserver-proxy.conf.erb')    } -  x509::cert { 'nickserver': -    content => $x509_cert, -    notify  => Service[apache]; -  } - -  x509::ca { 'nickserver': -    content => $x509_ca, -    notify  => Service[apache]; -  } -}
\ No newline at end of file +} diff --git a/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb b/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb index 67896cd3..ae06410e 100644 --- a/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb +++ b/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb @@ -14,9 +14,9 @@ Listen 0.0.0.0:<%= @nickserver_port -%>    SSLHonorCipherOrder on    SSLCACertificatePath /etc/ssl/certs -  SSLCertificateChainFile /etc/ssl/certs/nickserver.pem -  SSLCertificateKeyFile /etc/x509/keys/nickserver.key -  SSLCertificateFile /etc/x509/certs/nickserver.crt +  SSLCertificateChainFile <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::ca_name') %>.crt +  SSLCertificateKeyFile <%= scope.lookupvar('x509::variables::keys') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.key +  SSLCertificateFile <%= scope.lookupvar('x509::variables::certs') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.crt    ProxyPass / http://localhost:<%= @nickserver_local_port %>/    ProxyPreserveHost On  # preserve Host header in HTTP request diff --git a/puppet/modules/site_nickserver/templates/nickserver.yml.erb b/puppet/modules/site_nickserver/templates/nickserver.yml.erb index 7aab5605..e717cbaa 100644 --- a/puppet/modules/site_nickserver/templates/nickserver.yml.erb +++ b/puppet/modules/site_nickserver/templates/nickserver.yml.erb @@ -6,7 +6,7 @@ domain: "<%= @address_domain %>"  couch_host: "<%= @couchdb_host %>"  couch_port: <%= @couchdb_port %> -couch_database: "users" +couch_database: "identities"  couch_user: "<%= @couchdb_user %>"  couch_password: "<%= @couchdb_password %>" diff --git a/puppet/modules/site_openvpn/manifests/dh_key.pp b/puppet/modules/site_openvpn/manifests/dh_key.pp new file mode 100644 index 00000000..13cc0f5b --- /dev/null +++ b/puppet/modules/site_openvpn/manifests/dh_key.pp @@ -0,0 +1,10 @@ +class site_openvpn::dh_key { + +  $x509_config      = hiera('x509') + +  file { '/etc/openvpn/keys/dh.pem': +    content => $x509_config['dh'], +    mode    => '0644', +  } + +} diff --git a/puppet/modules/site_openvpn/manifests/init.pp b/puppet/modules/site_openvpn/manifests/init.pp index 4f900623..7aec0faa 100644 --- a/puppet/modules/site_openvpn/manifests/init.pp +++ b/puppet/modules/site_openvpn/manifests/init.pp @@ -5,8 +5,9 @@  #   (2) unlimited only  #   (3) limited only  # -# The difference is that 'unlimited' gateways only allow client certs that match the 'unlimited_prefix', -# and 'limited' gateways only allow certs that match the 'limited_prefix'. +# The difference is that 'unlimited' gateways only allow client certs that match +# the 'unlimited_prefix', and 'limited' gateways only allow certs that match the +# 'limited_prefix'.  #  # We potentially create four openvpn config files (thus four daemons):  # @@ -19,23 +20,30 @@  class site_openvpn {    tag 'leap_service' -  $openvpn_config   = hiera('openvpn') -  $x509_config      = hiera('x509') -  $openvpn_ports    = $openvpn_config['ports'] +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca_bundle + + +  Class['site_config::default'] -> Class['site_openvpn'] + +  $openvpn          = hiera('openvpn') +  $openvpn_ports    = $openvpn['ports'] +  $openvpn_config   = $openvpn['configuration']    if $::ec2_instance_id {      $openvpn_gateway_address = $::ipaddress    } else { -    $openvpn_gateway_address         = $openvpn_config['gateway_address'] -    if $openvpn_config['second_gateway_address'] { -      $openvpn_second_gateway_address = $openvpn_config['second_gateway_address'] +    $openvpn_gateway_address         = $openvpn['gateway_address'] +    if $openvpn['second_gateway_address'] { +      $openvpn_second_gateway_address = $openvpn['second_gateway_address']      } else {        $openvpn_second_gateway_address = undef      }    } -  $openvpn_allow_unlimited              = $openvpn_config['allow_unlimited'] -  $openvpn_unlimited_prefix             = $openvpn_config['unlimited_prefix'] +  $openvpn_allow_unlimited              = $openvpn['allow_unlimited'] +  $openvpn_unlimited_prefix             = $openvpn['unlimited_prefix']    $openvpn_unlimited_tcp_network_prefix = '10.41.0'    $openvpn_unlimited_tcp_netmask        = '255.255.248.0'    $openvpn_unlimited_tcp_cidr           = '21' @@ -44,9 +52,9 @@ class site_openvpn {    $openvpn_unlimited_udp_cidr           = '21'    if !$::ec2_instance_id { -    $openvpn_allow_limited                = $openvpn_config['allow_limited'] -    $openvpn_limited_prefix               = $openvpn_config['limited_prefix'] -    $openvpn_rate_limit                   = $openvpn_config['rate_limit'] +    $openvpn_allow_limited                = $openvpn['allow_limited'] +    $openvpn_limited_prefix               = $openvpn['limited_prefix'] +    $openvpn_rate_limit                   = $openvpn['rate_limit']      $openvpn_limited_tcp_network_prefix   = '10.43.0'      $openvpn_limited_tcp_netmask          = '255.255.248.0'      $openvpn_limited_tcp_cidr             = '21' @@ -55,8 +63,14 @@ class site_openvpn {      $openvpn_limited_udp_cidr             = '21'    } -  # deploy ca + server keys -  include site_openvpn::keys +  # find out the netmask in cidr format of the primary IF +  # thx to https://blog.kumina.nl/tag/puppet-tips-and-tricks/ +  # we can do this using an inline_template: +  $factname_primary_netmask = "netmask_cidr_${::site_config::params::interface}" +  $primary_netmask = inline_template('<%= scope.lookupvar(factname_primary_netmask) %>') + +  # deploy dh keys +  include site_openvpn::dh_key    if $openvpn_allow_unlimited and $openvpn_allow_limited {      $unlimited_gateway_address = $openvpn_gateway_address @@ -77,7 +91,8 @@ class site_openvpn {        tls_remote  => "\"${openvpn_unlimited_prefix}\"",        server      => "${openvpn_unlimited_tcp_network_prefix}.0 ${openvpn_unlimited_tcp_netmask}",        push        => "\"dhcp-option DNS ${openvpn_unlimited_tcp_network_prefix}.1\"", -      management  => '127.0.0.1 1000' +      management  => '127.0.0.1 1000', +      config      => $openvpn_config      }      site_openvpn::server_config { 'udp_config':        port        => '1194', @@ -86,11 +101,12 @@ class site_openvpn {        tls_remote  => "\"${openvpn_unlimited_prefix}\"",        server      => "${openvpn_unlimited_udp_network_prefix}.0 ${openvpn_unlimited_udp_netmask}",        push        => "\"dhcp-option DNS ${openvpn_unlimited_udp_network_prefix}.1\"", -      management  => '127.0.0.1 1001' +      management  => '127.0.0.1 1001', +      config      => $openvpn_config      }    } else { -    tidy { "/etc/openvpn/tcp_config.conf": } -    tidy { "/etc/openvpn/udp_config.conf": } +    tidy { '/etc/openvpn/tcp_config.conf': } +    tidy { '/etc/openvpn/udp_config.conf': }    }    if $openvpn_allow_limited { @@ -101,7 +117,8 @@ class site_openvpn {        tls_remote  => "\"${openvpn_limited_prefix}\"",        server      => "${openvpn_limited_tcp_network_prefix}.0 ${openvpn_limited_tcp_netmask}",        push        => "\"dhcp-option DNS ${openvpn_limited_tcp_network_prefix}.1\"", -      management  => '127.0.0.1 1002' +      management  => '127.0.0.1 1002', +      config      => $openvpn_config      }      site_openvpn::server_config { 'limited_udp_config':        port        => '1194', @@ -110,11 +127,12 @@ class site_openvpn {        tls_remote  => "\"${openvpn_limited_prefix}\"",        server      => "${openvpn_limited_udp_network_prefix}.0 ${openvpn_limited_udp_netmask}",        push        => "\"dhcp-option DNS ${openvpn_limited_udp_network_prefix}.1\"", -      management  => '127.0.0.1 1003' +      management  => '127.0.0.1 1003', +      config      => $openvpn_config      }    } else { -    tidy { "/etc/openvpn/limited_tcp_config.conf": } -    tidy { "/etc/openvpn/limited_udp_config.conf": } +    tidy { '/etc/openvpn/limited_tcp_config.conf': } +    tidy { '/etc/openvpn/limited_udp_config.conf': }    }    file { @@ -131,7 +149,12 @@ class site_openvpn {      command     => '/etc/init.d/openvpn restart',      refreshonly => true,      subscribe   => File['/etc/openvpn'], -    require     => [ Package['openvpn'], File['/etc/openvpn'] ]; +    require     => [ +      Package['openvpn'], +      File['/etc/openvpn'], +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca_bundle'] ];    }    cron { 'add_gateway_ips.sh': @@ -155,7 +178,9 @@ class site_openvpn {        ensure     => running,        hasrestart => true,        hasstatus  => true, -      require    => Exec['concat_/etc/default/openvpn']; +      require    => [ +        Package['openvpn'], +        Exec['concat_/etc/default/openvpn'] ];    }    file { @@ -193,4 +218,7 @@ class site_openvpn {        target  => '/etc/default/openvpn',        order   => 10;    } + +  include site_check_mk::agent::openvpn +  } diff --git a/puppet/modules/site_openvpn/manifests/keys.pp b/puppet/modules/site_openvpn/manifests/keys.pp deleted file mode 100644 index f3c5b423..00000000 --- a/puppet/modules/site_openvpn/manifests/keys.pp +++ /dev/null @@ -1,51 +0,0 @@ -class site_openvpn::keys { - -  x509::key { -    'leap_openvpn': -      content => $site_openvpn::x509_config['key'], -      notify  => Service[openvpn]; -  } - -  x509::cert { -    'leap_openvpn': -      content => $site_openvpn::x509_config['cert'], -      notify  => Service[openvpn]; -  } - -  x509::ca { -    'leap_ca': -      content => $site_openvpn::x509_config['ca_cert'], -      notify  => Service[openvpn]; -  } - -  file { '/etc/openvpn/keys/dh.pem': -    content => $site_openvpn::x509_config['dh'], -    mode    => '0644', -  } - -  # -  # CA bundle -- we want to have the possibility of allowing multiple CAs. -  # For now, the reason is to transition to using client CA. In the future, -  # we will want to be able to smoothly phase out one CA and phase in another. -  # I tried "--capath" for this, but it did not work. -  # - -  concat { -    '/etc/openvpn/ca_bundle.pem': -      owner  => root, -      group  => root, -      mode   => 644, -      warn   => true, -      notify => Service['openvpn']; -  } - -  concat::fragment { -    'client_ca_cert': -      content => $site_openvpn::x509_config['client_ca_cert'], -      target  => '/etc/openvpn/ca_bundle.pem'; -    'ca_cert': -      content => $site_openvpn::x509_config['ca_cert'], -      target  => '/etc/openvpn/ca_bundle.pem'; -  } - -} diff --git a/puppet/modules/site_openvpn/manifests/resolver.pp b/puppet/modules/site_openvpn/manifests/resolver.pp index c1bce858..c74fb509 100644 --- a/puppet/modules/site_openvpn/manifests/resolver.pp +++ b/puppet/modules/site_openvpn/manifests/resolver.pp @@ -60,25 +60,25 @@ class site_openvpn::resolver {        path    => '/etc/unbound/unbound.conf',        line    => 'server: include: /etc/unbound/conf.d/vpn_unlimited_tcp_resolver',        notify  => Service['unbound'], -      require => Package['unbound']; +      require => [ Package['openvpn'], Package['unbound'] ];      'add_unlimited_udp_resolver':        ensure  => $ensure_unlimited,        path    => '/etc/unbound/unbound.conf',        line    => 'server: include: /etc/unbound/conf.d/vpn_unlimited_udp_resolver',        notify  => Service['unbound'], -      require => Package['unbound']; +      require => [ Package['openvpn'], Package['unbound'] ];      'add_limited_tcp_resolver':        ensure  => $ensure_limited,        path    => '/etc/unbound/unbound.conf',        line    => 'server: include: /etc/unbound/conf.d/vpn_limited_tcp_resolver',        notify  => Service['unbound'], -      require => Package['unbound']; -    'add_limited_udp_resolver': +      require => [ Package['openvpn'], Package['unbound'] ]; +      'add_limited_udp_resolver':        ensure  => $ensure_limited,        path    => '/etc/unbound/unbound.conf',        line    => 'server: include: /etc/unbound/conf.d/vpn_limited_udp_resolver',        notify  => Service['unbound'], -      require => Package['unbound'] +      require => [ Package['openvpn'], Package['unbound'] ];    }  } diff --git a/puppet/modules/site_openvpn/manifests/server_config.pp b/puppet/modules/site_openvpn/manifests/server_config.pp index 6106cfbb..b1f4997c 100644 --- a/puppet/modules/site_openvpn/manifests/server_config.pp +++ b/puppet/modules/site_openvpn/manifests/server_config.pp @@ -54,7 +54,7 @@  define site_openvpn::server_config(    $port, $proto, $local, $server, $push, -  $management, $tls_remote = undef) { +  $management, $config, $tls_remote = undef) {    $openvpn_configname = $name @@ -70,97 +70,97 @@ define site_openvpn::server_config(    if $tls_remote != undef {      openvpn::option { -      "tls-remote $openvpn_configname": -         key     => 'tls-remote', -         value   => $tls_remote, -         server  => $openvpn_configname; +      "tls-remote ${openvpn_configname}": +        key     => 'tls-remote', +        value   => $tls_remote, +        server  => $openvpn_configname;      }    }    openvpn::option { -    "ca $openvpn_configname": +    "ca ${openvpn_configname}":          key     => 'ca', -        value   => '/etc/openvpn/ca_bundle.pem', +        value   => "${x509::variables::local_CAs}/${site_config::params::ca_bundle_name}.crt",          server  => $openvpn_configname; -    "cert $openvpn_configname": +    "cert ${openvpn_configname}":          key     => 'cert', -        value   => '/etc/x509/certs/leap_openvpn.crt', +        value   => "${x509::variables::certs}/${site_config::params::cert_name}.crt",          server  => $openvpn_configname; -    "key $openvpn_configname": +    "key ${openvpn_configname}":          key     => 'key', -        value   => '/etc/x509/keys/leap_openvpn.key', +        value   => "${x509::variables::keys}/${site_config::params::cert_name}.key",          server  => $openvpn_configname; -    "dh $openvpn_configname": +    "dh ${openvpn_configname}":          key     => 'dh',          value   => '/etc/openvpn/keys/dh.pem',          server  => $openvpn_configname; -    "tls-cipher $openvpn_configname": +    "tls-cipher ${openvpn_configname}":          key     => 'tls-cipher', -        value   => 'DHE-RSA-AES128-SHA', +        value   => $config['tls-cipher'],          server  => $openvpn_configname; -    "auth $openvpn_configname": +    "auth ${openvpn_configname}":          key     => 'auth', -        value   => 'SHA1', +        value   => $config['auth'],          server  => $openvpn_configname; -    "cipher $openvpn_configname": +    "cipher ${openvpn_configname}":          key     => 'cipher', -        value   => 'AES-128-CBC', +        value   => $config['cipher'],          server  => $openvpn_configname; -    "dev $openvpn_configname": +    "dev ${openvpn_configname}":          key    => 'dev',          value  => 'tun',          server => $openvpn_configname; -    "duplicate-cn $openvpn_configname": +    "duplicate-cn ${openvpn_configname}":          key    => 'duplicate-cn',          server => $openvpn_configname; -    "keepalive $openvpn_configname": +    "keepalive ${openvpn_configname}":          key    => 'keepalive', -        value  => '5 20', +        value  => $config['keepalive'],          server => $openvpn_configname; -    "local $openvpn_configname": +    "local ${openvpn_configname}":          key    => 'local',          value  => $local,          server => $openvpn_configname; -    "mute $openvpn_configname": +    "mute ${openvpn_configname}":          key    => 'mute',          value  => '5',          server => $openvpn_configname; -    "mute-replay-warnings $openvpn_configname": +    "mute-replay-warnings ${openvpn_configname}":          key    => 'mute-replay-warnings',          server => $openvpn_configname; -    "management $openvpn_configname": +    "management ${openvpn_configname}":          key    => 'management',          value  => $management,          server => $openvpn_configname; -    "proto $openvpn_configname": +    "proto ${openvpn_configname}":          key    => 'proto',          value  => $proto,          server => $openvpn_configname; -    "push1 $openvpn_configname": +    "push1 ${openvpn_configname}":          key    => 'push',          value  => $push,          server => $openvpn_configname; -    "push2 $openvpn_configname": +    "push2 ${openvpn_configname}":          key    => 'push',          value  => '"redirect-gateway def1"',          server => $openvpn_configname; -    "script-security $openvpn_configname": +    "script-security ${openvpn_configname}":          key    => 'script-security',          value  => '2',          server => $openvpn_configname; -    "server $openvpn_configname": +    "server ${openvpn_configname}":          key    => 'server',          value  => $server,          server => $openvpn_configname; -    "status $openvpn_configname": +    "status ${openvpn_configname}":          key    => 'status',          value  => '/var/run/openvpn-status 10',          server => $openvpn_configname; -    "status-version $openvpn_configname": +    "status-version ${openvpn_configname}":          key    => 'status-version',          value  => '3',          server => $openvpn_configname; -    "topology $openvpn_configname": +    "topology ${openvpn_configname}":          key    => 'topology',          value  => 'subnet',          server => $openvpn_configname; @@ -169,7 +169,7 @@ define site_openvpn::server_config(      #    key    => 'up',      #    value  => '/etc/openvpn/server-up.sh',      #    server => $openvpn_configname; -    "verb $openvpn_configname": +    "verb ${openvpn_configname}":          key    => 'verb',          value  => '3',          server => $openvpn_configname; diff --git a/puppet/modules/site_openvpn/templates/add_gateway_ips.sh.erb b/puppet/modules/site_openvpn/templates/add_gateway_ips.sh.erb index 05f3d16b..e76b756b 100644 --- a/puppet/modules/site_openvpn/templates/add_gateway_ips.sh.erb +++ b/puppet/modules/site_openvpn/templates/add_gateway_ips.sh.erb @@ -1,11 +1,11 @@  #!/bin/sh -ip addr show dev <%= scope.lookupvar('site_config::params::interface') %> | grep -q <%= @openvpn_gateway_address %>/24 || -  ip addr add <%= @openvpn_gateway_address %>/24 dev <%= scope.lookupvar('site_config::params::interface') %> +ip addr show dev <%= scope.lookupvar('site_config::params::interface') %> | grep -q <%= @openvpn_gateway_address %>/<%= @primary_netmask %> || +  ip addr add <%= @openvpn_gateway_address %>/<%= @primary_netmask %> dev <%= scope.lookupvar('site_config::params::interface') %>  <% if @openvpn_second_gateway_address %> -ip addr show dev <%= scope.lookupvar('site_config::params::interface') %> | grep -q <%= @openvpn_second_gateway_address %>/24 || -  ip addr add <%= @openvpn_second_gateway_address %>/24 dev <%= scope.lookupvar('site_config::params::interface') %> +ip addr show dev <%= scope.lookupvar('site_config::params::interface') %> | grep -q <%= @openvpn_second_gateway_address %>/<%= @primary_netmask %> || +  ip addr add <%= @openvpn_second_gateway_address %>/<%= @primary_netmask %> dev <%= scope.lookupvar('site_config::params::interface') %>  <% end %>  /bin/echo 1 > /proc/sys/net/ipv4/ip_forward diff --git a/puppet/modules/site_postfix/files/checks/received_anon b/puppet/modules/site_postfix/files/checks/received_anon new file mode 100644 index 00000000..2822973e --- /dev/null +++ b/puppet/modules/site_postfix/files/checks/received_anon @@ -0,0 +1,2 @@ +/^Received: from (.* \([-._[:alnum:]]+ \[[.[:digit:]]{7,15}\]\))([[:space:]]+).*(\(using [.[:alnum:]]+ with cipher [-A-Z0-9]+ \([0-9]+\/[0-9]+ bits\)\))[[:space:]]+\(Client CN "([[:alnum:]]+)", Issuer "[[:print:]]+" \(verified OK\)\)[[:space:]]+by ([.[:alnum:]]+) \(([^)]+)\) with (E?SMTPS?A?) id ([A-F[:digit:]]+).*/ + REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])${2}${3}${2}(Authenticated sender: $4)${2}with $7 id $8 diff --git a/puppet/modules/site_postfix/manifests/debug.pp b/puppet/modules/site_postfix/manifests/debug.pp new file mode 100644 index 00000000..f370d166 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/debug.pp @@ -0,0 +1,9 @@ +class site_postfix::debug { + +  postfix::config { +    'debug_peer_list':      value => '127.0.0.1'; +    'debug_peer_level':     value => '1'; +    'smtpd_tls_loglevel':   value => '1'; +  } + +} diff --git a/puppet/modules/site_postfix/manifests/mx.pp b/puppet/modules/site_postfix/manifests/mx.pp new file mode 100644 index 00000000..bdfee665 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx.pp @@ -0,0 +1,74 @@ +class site_postfix::mx { + +  $domain_hash         = hiera ('domain') +  $domain              = $domain_hash['full_suffix'] +  $host_domain         = $domain_hash['full'] +  $cert_name           = hiera('name') +  $mynetworks          = join(hiera('mynetworks'), ' ') + +  $root_mail_recipient = hiera ('contacts') +  $postfix_smtp_listen = 'all' + +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::client_ca::ca +  include site_config::x509::client_ca::key + +  postfix::config { +    'mynetworks': +      value => "127.0.0.0/8 [::1]/128 [fe80::]/64 ${mynetworks}"; +    'mydestination': +      value => "\$myorigin, localhost, localhost.\$mydomain, ${domain}"; +    'myhostname': +      value => $host_domain; +    'mailbox_size_limit': +      value => '0'; +    'home_mailbox': +      value => 'Maildir/'; +    'virtual_alias_maps': +      value => 'tcp:localhost:4242'; +    'luser_relay': +      value => 'vmail'; +    'smtpd_tls_received_header': +      value => 'yes'; +    # Note: we are setting this here, instead of in site_postfix::mx::smtp_tls +    # because the satellites need to have a different value +    'smtp_tls_security_level': +      value => 'may'; +  } + +  include site_postfix::mx::smtpd_checks +  include site_postfix::mx::checks +  include site_postfix::mx::smtp_tls +  include site_postfix::mx::smtpd_tls +  include site_postfix::mx::reserved_aliases + +  # greater verbosity for debugging, take out for production +  #include site_postfix::debug + +  user { 'vmail': +    ensure     => present, +    comment    => 'Leap Mailspool', +    home       => '/var/mail/vmail', +    shell      => '/bin/false', +    managehome => true, +  } + +  class { 'postfix': +    preseed             => true, +    root_mail_recipient => $root_mail_recipient, +    smtp_listen         => 'all', +    mastercf_tail       => +    "smtps     inet  n       -       -       -       -       smtpd +  -o smtpd_tls_wrappermode=yes +  -o smtpd_tls_security_level=encrypt +  -o smtpd_recipient_restrictions=\$smtps_recipient_restrictions +  -o smtpd_helo_restrictions=\$smtps_helo_restrictions", +    require             => [ +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Client_ca::Key'], +      Class['Site_config::X509::Client_ca::Ca'], +      User['vmail'] ] +  } +} diff --git a/puppet/modules/site_postfix/manifests/mx/checks.pp b/puppet/modules/site_postfix/manifests/mx/checks.pp new file mode 100644 index 00000000..5d75a5e5 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/checks.pp @@ -0,0 +1,41 @@ +class site_postfix::mx::checks { + +  file { +    '/etc/postfix/checks': +      ensure  => directory, +      mode    => '0755', +      owner   => root, +      group   => postfix, +      require => Package['postfix']; + +    '/etc/postfix/checks/helo_checks': +      content => template('site_postfix/checks/helo_access.erb'), +      mode    => '0644', +      owner   => root, +      group   => root; +  } + +  exec { +    '/usr/sbin/postmap /etc/postfix/checks/helo_checks': +      refreshonly => true, +      subscribe   => File['/etc/postfix/checks/helo_checks']; +  } + +  # Anonymize the user's home IP from the email headers (Feature #3866) +  package { 'postfix-pcre': ensure => installed, require => Package['postfix'] } + +  file { '/etc/postfix/checks/received_anon': +    source  => 'puppet:///modules/site_postfix/checks/received_anon', +    mode    => '0644', +    owner   => root, +    group   => root, +    notify  => Service['postfix'] +  } + +  postfix::config { +    'header_checks': +      value   => 'pcre:/etc/postfix/checks/received_anon', +      require => File['/etc/postfix/checks/received_anon']; +  } + +} diff --git a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp new file mode 100644 index 00000000..83e27376 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp @@ -0,0 +1,15 @@ +# Defines which mail addresses shouldn't be available and where they should fwd +class site_postfix::mx::reserved_aliases { + +  postfix::mailalias { +    [ 'abuse', 'admin', 'arin-admin', 'administrator', 'bin', 'cron', +      'certmaster', 'domainadmin', 'games', 'ftp', 'hostmaster', 'lp', +      'maildrop', 'mysql', 'news', 'nobody', 'noc', 'postmaster', 'postgresql', +      'security', 'ssladmin', 'sys', 'usenet', 'uucp', 'webmaster', 'www', +      'www-data', +    ]: +      ensure    => present, +      recipient => 'root' +  } + +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtp_auth.pp b/puppet/modules/site_postfix/manifests/mx/smtp_auth.pp new file mode 100644 index 00000000..afa70527 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/smtp_auth.pp @@ -0,0 +1,6 @@ +class site_postfix::mx::smtp_auth { + +  postfix::config { +    'smtpd_tls_ask_ccert': value => 'yes'; +  } +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp new file mode 100644 index 00000000..d9b59f40 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp @@ -0,0 +1,27 @@ +class site_postfix::mx::smtp_tls { + +  include x509::variables +  $ca_path   = "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt" +  $cert_path = "${x509::variables::certs}/${site_config::params::cert_name}.crt" +  $key_path  = "${x509::variables::keys}/${site_config::params::cert_name}.key" + +  # smtp TLS +  postfix::config { +    'smtp_use_tls':        value  => 'yes'; +    'smtp_tls_CApath':     value  => '/etc/ssl/certs/'; +    'smtp_tls_CAfile':     value  => $ca_path; +    'smtp_tls_cert_file':  value  => $cert_path; +    'smtp_tls_key_file':   value  => $key_path; +    'smtp_tls_loglevel':   value  => '1'; +    'smtp_tls_exclude_ciphers': +      value => 'aNULL, MD5, DES'; +    # upstream default is md5 (since 2.5 and older used it), we force sha1 +    'smtp_tls_fingerprint_digest': +      value => 'sha1'; +    'smtp_tls_session_cache_database': +      value => 'btree:${data_directory}/smtp_cache'; +    # see issue #4011 +    'smtp_tls_protocols': +      value => '!SSLv2, !SSLv3'; +  } +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp new file mode 100644 index 00000000..0ec40277 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp @@ -0,0 +1,31 @@ +class site_postfix::mx::smtpd_checks { + +  postfix::config { +    'smtpd_helo_required': +      value => 'yes'; +    'checks_dir': +      value => '$config_directory/checks'; +    'smtpd_client_restrictions': +      value => 'permit_mynetworks,permit'; +    'smtpd_data_restrictions': +      value => 'permit_mynetworks, reject_unauth_pipelining, permit'; +    'smtpd_delay_reject': +      value => 'yes'; +    'smtpd_helo_restrictions': +      value => 'permit_mynetworks, reject_invalid_helo_hostname, reject_non_fqdn_helo_hostname, check_helo_access hash:$checks_dir/helo_checks, permit'; +    'smtpd_recipient_restrictions': +      value => 'reject_unknown_recipient_domain, permit_mynetworks, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; +    # We should change from permit_tls_all_clientcerts to permit_tls_clientcerts +    # with a lookup on $relay_clientcerts! Right now we are listing the only +    # valid CA that client certificates can use in the $smtp_tls_CAfile parameter +    # but we cannot cut off a certificate that should no longer be used unless +    # we use permit_tls_clientcerts with the $relay_clientcerts lookup +    'smtps_recipient_restrictions': +      value => 'permit_tls_all_clientcerts, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; +    'smtps_helo_restrictions': +      value => 'permit_mynetworks, check_helo_access hash:$checks_dir/helo_checks, permit'; +    'smtpd_sender_restrictions': +      value => 'permit_mynetworks, reject_non_fqdn_sender, reject_unknown_sender_domain, permit'; +    } + +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp new file mode 100644 index 00000000..0809c75f --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp @@ -0,0 +1,55 @@ +class site_postfix::mx::smtpd_tls { + +  include x509::variables +  $ca_path   = "${x509::variables::local_CAs}/${site_config::params::client_ca_name}.crt" +  $cert_path = "${x509::variables::certs}/${site_config::params::cert_name}.crt" +  $key_path  = "${x509::variables::keys}/${site_config::params::cert_name}.key" + + +  postfix::config { +    'smtpd_use_tls':        value  => 'yes'; +    'smtpd_tls_CAfile':     value  => $ca_path; +    'smtpd_tls_cert_file':  value  => $cert_path; +    'smtpd_tls_key_file':   value  => $key_path; +    'smtpd_tls_ask_ccert':  value  => 'yes'; +    'smtpd_tls_security_level': +      value  => 'may'; +    'smtpd_tls_eecdh_grade': +      value => 'ultra'; +    'smtpd_tls_session_cache_database': +      value => 'btree:${data_directory}/smtpd_scache'; +  } + +  # Setup DH parameters +  # Instead of using the dh parameters that are created by leap cli, it is more +  # secure to generate new parameter files that will only be used for postfix, +  # for each machine + +  include site_config::packages::gnutls + +  # Note, the file name is called dh_1024.pem, but we are generating 2048bit dh +  # parameters Neither Postfix nor OpenSSL actually care about the size of the +  # prime in "smtpd_tls_dh1024_param_file".  You can make it 2048 bits + +  exec { 'certtool-postfix-gendh': +    command => 'certtool --generate-dh-params --bits 2048 --outfile /etc/postfix/smtpd_tls_dh_param.pem', +    user    => root, +    group   => root, +    creates => '/etc/postfix/smtpd_tls_dh_param.pem', +    require => [ Package['gnutls-bin'], Package['postfix'] ] +  } + +  # Make sure the dh params file has correct ownership and mode +  file { +    '/etc/postfix/smtpd_tls_dh_param.pem': +      owner   => root, +      group   => root, +      mode    => '0600', +      require => Exec['certtool-postfix-gendh']; +  } + +  postfix::config { 'smtpd_tls_dh1024_param_file': +    value   => '/etc/postfix/smtpd_tls_dh_param.pem', +    require => File['/etc/postfix/smtpd_tls_dh_param.pem'] +  } +} diff --git a/puppet/modules/site_postfix/manifests/satellite.pp b/puppet/modules/site_postfix/manifests/satellite.pp new file mode 100644 index 00000000..5725e6b8 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/satellite.pp @@ -0,0 +1,47 @@ +class site_postfix::satellite { + +  $root_mail_recipient = hiera ('contacts') +  $mail                = hiera ('mail') +  $relayhost           = $mail['smarthost'] +  $cert_name           = hiera('name') + +  class { '::postfix::satellite': +    relayhost           => $relayhost, +    root_mail_recipient => $root_mail_recipient +  } + +  # There are special conditions for satellite hosts that will make them not be +  # able to contact their relayhost: +  # +  # 1. they are on openstack/amazon/PC and are on the same cluster as the relay +  # host, the MX lookup for the relay host will use the public IP, which cannot +  # be contacted +  # +  # 2. When a domain is used that is not in DNS, because it is internal, +  # a testing domain, etc. eg. a .local domain cannot be looked up in DNS +  # +  # to resolve this, so the satellite can contact the relayhost, we need to set +  # the http://www.postfix.org/postconf.5.html#smtp_host_lookup to be 'native' +  # which will cause the lookup to use the native naming service +  # (nsswitch.conf), which typically defaults to 'files, dns' allowing the +  # /etc/hosts to be consulted first, then DNS if the entry doesn't exist. +  # +  # NOTE: this will make it not possible to enable DANE support through DNSSEC +  # with http://www.postfix.org/postconf.5.html#smtp_dns_support_level - but +  # this parameter is not available until 2.11. If this ends up being important +  # we could also make this an optional parameter for providers without +  # dns / local domains + +  postfix::config { +    'smtp_host_lookup': +      value => 'native'; + +    # Note: we are setting this here, instead of in site_postfix::mx::smtp_tls +    # because the mx server has to have a different value +    'smtp_tls_security_level': +      value => 'encrypt'; +  } + +  include site_postfix::mx::smtp_tls + +} diff --git a/puppet/modules/site_postfix/templates/checks/helo_access.erb b/puppet/modules/site_postfix/templates/checks/helo_access.erb new file mode 100644 index 00000000..bef3c11d --- /dev/null +++ b/puppet/modules/site_postfix/templates/checks/helo_access.erb @@ -0,0 +1,21 @@ +# THIS FILE IS MANAGED BY PUPPET +# To make changes to this file, please edit your platform directory under +# puppet/modules/site_postfix/templates/checks/helo_access.erb and then deploy + +# The format of this file is the HELO/EHLO domain followed by an action. +# The action could be OK to allow it, REJECT to reject it, or a custom +# status code and message. Any lines that are prefixed by an octothorpe (#) +# will be considered comments. + +# Some examples: +# +# Reject anyone that HELO's with foobar: +# foobar REJECT +# +# Allow the switches to skip this check: +# switch1 OK +# switch2 OK + +# Reject anybody that HELO's as being in our own domain(s) +# anyone who identifies themselves as us is a virus/spammer +<%= domain %> 554 You are not in domain <%= domain %> diff --git a/puppet/modules/site_shorewall/manifests/defaults.pp b/puppet/modules/site_shorewall/manifests/defaults.pp index c62c9307..8f56ac42 100644 --- a/puppet/modules/site_shorewall/manifests/defaults.pp +++ b/puppet/modules/site_shorewall/manifests/defaults.pp @@ -1,9 +1,12 @@  class site_shorewall::defaults { +    include shorewall    include site_config::params    # be safe for development -  #if ( $::virtual == 'virtualbox') { $shorewall_startup='0' } +  # if ( $::site_config::params::environment == 'local' ) { +  #  $shorewall_startup='0' +  # }    # If you want logging:    shorewall::params { @@ -18,8 +21,6 @@ class site_shorewall::defaults {      options   => 'tcpflags,blacklist,nosmurfs';    } -  shorewall::routestopped { $site_config::params::interface: } -    shorewall::policy {      'fw-to-all':        sourcezone      => 'fw', @@ -42,5 +43,32 @@ class site_shorewall::defaults {          order       => 200;    } +  package { 'shorewall-init': +    ensure => installed +  } + +  augeas { +    # stop instead of clear firewall on shutdown +    'shorewall_SAFESTOP': +      changes => 'set /files/etc/shorewall/shorewall.conf/SAFESTOP Yes', +      lens    => 'Shellvars.lns', +      incl    => '/etc/shorewall/shorewall.conf', +      require => Package['shorewall'], +      notify  => Service[shorewall]; +    # require that the interface exist +    'shorewall_REQUIRE_INTERFACE': +      changes => 'set /files/etc/shorewall/shorewall.conf/REQUIRE_INTERFACE Yes', +      lens    => 'Shellvars.lns', +      incl    => '/etc/shorewall/shorewall.conf', +      require => Package['shorewall'], +      notify  => Service[shorewall]; +    # configure shorewall-init +    'shorewall-init': +      changes => 'set /files/etc/default/shorewall-init/PRODUCTS shorewall', +      lens    => 'Shellvars.lns', +      incl    => '/etc/default/shorewall-init', +      require => [ Package['shorewall-init'], Service['shorewall'] ] +  } +    include site_shorewall::sshd  } diff --git a/puppet/modules/site_shorewall/manifests/mx.pp b/puppet/modules/site_shorewall/manifests/mx.pp new file mode 100644 index 00000000..332f164e --- /dev/null +++ b/puppet/modules/site_shorewall/manifests/mx.pp @@ -0,0 +1,24 @@ +class site_shorewall::mx { + +  include site_shorewall::defaults + +  $smtpd_ports = '25,465,587' + +  # define macro for incoming services +  file { '/etc/shorewall/macro.leap_mx': +    content => "PARAM   -       -       tcp    ${smtpd_ports} ", +    notify  => Service['shorewall'], +    require => Package['shorewall'] +  } + + +  shorewall::rule { +      'net2fw-mx': +        source      => 'net', +        destination => '$FW', +        action      => 'leap_mx(ACCEPT)', +        order       => 200; +  } + +  include site_shorewall::service::smtp +} diff --git a/puppet/modules/site_shorewall/manifests/service/smtp.pp b/puppet/modules/site_shorewall/manifests/service/smtp.pp new file mode 100644 index 00000000..7fbdf14e --- /dev/null +++ b/puppet/modules/site_shorewall/manifests/service/smtp.pp @@ -0,0 +1,13 @@ +class site_shorewall::service::smtp { + +  include site_shorewall::defaults + +  shorewall::rule { +      'fw2net-http': +        source      => '$FW', +        destination => 'net', +        action      => 'SMTP(ACCEPT)', +        order       => 200; +  } + +} diff --git a/puppet/modules/site_shorewall/manifests/soledad.pp b/puppet/modules/site_shorewall/manifests/soledad.pp new file mode 100644 index 00000000..518d8689 --- /dev/null +++ b/puppet/modules/site_shorewall/manifests/soledad.pp @@ -0,0 +1,23 @@ +class site_shorewall::soledad { + +  $soledad      = hiera('soledad') +  $soledad_port = $soledad['port'] + +  include site_shorewall::defaults + +  # define macro for incoming services +  file { '/etc/shorewall/macro.leap_soledad': +    content => "PARAM   -       -       tcp    ${soledad_port}", +    notify  => Service['shorewall'], +    require => Package['shorewall'] +  } + +  shorewall::rule { +    'net2fw-soledad': +      source      => 'net', +      destination => '$FW', +      action      => 'leap_soledad(ACCEPT)', +      order       => 200; +  } +} + diff --git a/puppet/modules/site_shorewall/manifests/sshd.pp b/puppet/modules/site_shorewall/manifests/sshd.pp index a8e09e42..88b4102c 100644 --- a/puppet/modules/site_shorewall/manifests/sshd.pp +++ b/puppet/modules/site_shorewall/manifests/sshd.pp @@ -21,4 +21,10 @@ class site_shorewall::sshd {          action      => 'leap_sshd(ACCEPT)',          order       => 200;    } + +  # setup a routestopped rule to allow ssh when shorewall is stopped +  shorewall::routestopped { $site_config::params::interface: +    options => "-   tcp   ${ssh_port}" +  } +  } diff --git a/puppet/modules/site_squid_deb_proxy/manifests/client.pp b/puppet/modules/site_squid_deb_proxy/manifests/client.pp new file mode 100644 index 00000000..27844270 --- /dev/null +++ b/puppet/modules/site_squid_deb_proxy/manifests/client.pp @@ -0,0 +1,5 @@ +class site_squid_deb_proxy::client { +  include squid_deb_proxy::client +  include site_shorewall::defaults +  include shorewall::rules::mdns +} diff --git a/puppet/modules/site_sshd/manifests/authorized_keys.pp b/puppet/modules/site_sshd/manifests/authorized_keys.pp index c18f691c..f36fe20f 100644 --- a/puppet/modules/site_sshd/manifests/authorized_keys.pp +++ b/puppet/modules/site_sshd/manifests/authorized_keys.pp @@ -1,4 +1,7 @@  define site_sshd::authorized_keys ($keys, $ensure = 'present', $home = '') { +  # We use a custom define here to deploy the authorized_keys file +  # cause puppet doesn't allow purgin before populating this file +  # (see https://tickets.puppetlabs.com/browse/PUP-1174)    # This line allows default homedir based on $title variable.    # If $home is empty, the default is used.    $homedir = $home ? {'' => "/home/${title}", default => $home} diff --git a/puppet/modules/site_sshd/manifests/init.pp b/puppet/modules/site_sshd/manifests/init.pp index 90dd2d0e..d9bc1d51 100644 --- a/puppet/modules/site_sshd/manifests/init.pp +++ b/puppet/modules/site_sshd/manifests/init.pp @@ -1,5 +1,6 @@  class site_sshd {    $ssh = hiera_hash('ssh') +  $hosts = hiera('hosts', '')    ##    ## SETUP AUTHORIZED KEYS @@ -12,6 +13,23 @@ class site_sshd {    }    ## +  ## SETUP KNOWN HOSTS and SSH_CONFIG +  ## + +  file { +    '/etc/ssh/ssh_known_hosts': +      owner   => root, +      group   => root, +      mode    => '0644', +      content => template('site_sshd/ssh_known_hosts.erb'); +    '/etc/ssh/ssh_config': +      owner => root, +      group => root, +      mode => '0644', +      content => template('site_sshd/ssh_config.erb'); +  } + +  ##    ## OPTIONAL MOSH SUPPORT    ## diff --git a/puppet/modules/site_sshd/templates/authorized_keys.erb b/puppet/modules/site_sshd/templates/authorized_keys.erb index 3c65e8ab..69f4d8e6 100644 --- a/puppet/modules/site_sshd/templates/authorized_keys.erb +++ b/puppet/modules/site_sshd/templates/authorized_keys.erb @@ -2,5 +2,9 @@  # all manually added keys will be overridden  <% keys.sort.each do |user, hash| -%> +<% if user == 'monitor' -%> +command="/usr/bin/check_mk_agent",no-port-forwarding,no-x11-forwarding,no-agent-forwarding,no-pty,no-user-rc, <%=hash['type']-%> <%=hash['key']%> <%=user%>  +<% else -%>  <%=hash['type']-%> <%=hash['key']%> <%=user%>  +<% end -%>  <% end -%>  diff --git a/puppet/modules/site_sshd/templates/ssh_config.erb b/puppet/modules/site_sshd/templates/ssh_config.erb new file mode 100644 index 00000000..7e967413 --- /dev/null +++ b/puppet/modules/site_sshd/templates/ssh_config.erb @@ -0,0 +1,23 @@ +# This file is generated by Puppet +# This is the ssh client system-wide configuration file.  See +# ssh_config(5) for more information.  This file provides defaults for +# users, and the values can be changed in per-user configuration files +# or on the command line. + +Host * +    SendEnv LANG LC_* +    HashKnownHosts yes +    GSSAPIAuthentication yes +    GSSAPIDelegateCredentials no +<% if scope.lookupvar('::site_config::params::environment') == 'local' -%> +    # +    # Vagrant nodes should have strict host key checking +    # turned off. The problem is that the host key for a vagrant +    # node is specific to the particular instance of the vagrant +    # node you have running locally. For this reason, we can't +    # track the host keys, or your host key for vpn1 would conflict +    # with my host key for vpn1. +    # +    StrictHostKeyChecking no +<% end -%> + diff --git a/puppet/modules/site_sshd/templates/ssh_known_hosts.erb b/puppet/modules/site_sshd/templates/ssh_known_hosts.erb new file mode 100644 index 00000000..002ab732 --- /dev/null +++ b/puppet/modules/site_sshd/templates/ssh_known_hosts.erb @@ -0,0 +1,7 @@ +# This file is generated by Puppet + +<% @hosts.sort.each do |name, hash| -%> +<%   if hash['host_pub_key'] -%> +<%=    name%>,<%=hash['domain_full']%>,<%=hash['domain_internal']%>,<%=hash['ip_address']%> <%=hash['host_pub_key']%> +<%   end -%> +<% end -%> diff --git a/puppet/modules/site_static/README b/puppet/modules/site_static/README new file mode 100644 index 00000000..bc719782 --- /dev/null +++ b/puppet/modules/site_static/README @@ -0,0 +1,3 @@ +Deploy one or more static websites to a node. + +For now, it only supports `amber` based static sites. Should support plain html and jekyll in the future. diff --git a/puppet/modules/site_static/manifests/domain.pp b/puppet/modules/site_static/manifests/domain.pp new file mode 100644 index 00000000..8af2230f --- /dev/null +++ b/puppet/modules/site_static/manifests/domain.pp @@ -0,0 +1,28 @@ +define site_static::domain ( +  $locations, +  $ca_cert, +  $key, +  $cert, +  $tls_only) { + +  $domain = $name +  $base_dir = '/srv/static' + +  create_resources(site_static::location, $locations) + +  x509::cert { $domain: content => $cert } +  x509::key  { $domain: content => $key } +  x509::ca   { "${domain}_ca": content => $ca_cert } + +  class { '::apache': no_default_site => true, ssl => true } +  include site_apache::module::headers +  include site_apache::module::alias +  include site_apache::module::expires +  include site_apache::module::removeip +  include site_apache::module::rewrite + +  apache::vhost::file { $domain: +    content => template('site_static/apache.conf.erb') +  } + +} diff --git a/puppet/modules/site_static/manifests/init.pp b/puppet/modules/site_static/manifests/init.pp new file mode 100644 index 00000000..91a4a7a9 --- /dev/null +++ b/puppet/modules/site_static/manifests/init.pp @@ -0,0 +1,17 @@ +class site_static { +  tag 'leap_service' +  $static        = hiera('static') +  $domains       = $static['domains'] +  $formats       = $static['formats'] + +  if (member($formats, 'amber')) { +    include site_config::ruby::dev +    rubygems::gem{'amber': } +  } + +  create_resources(site_static::domain, $domains) + +  include site_shorewall::defaults +  include site_shorewall::service::http +  include site_shorewall::service::https +}
\ No newline at end of file diff --git a/puppet/modules/site_static/manifests/location.pp b/puppet/modules/site_static/manifests/location.pp new file mode 100644 index 00000000..1ba6807e --- /dev/null +++ b/puppet/modules/site_static/manifests/location.pp @@ -0,0 +1,25 @@ +define site_static::location($path, $format, $source) { + +  $file_path = "/srv/static/${name}" + +  if ($format == 'amber') { +    exec {"amber_build_${name}": +      cwd     => $file_path, +      command => 'amber rebuild', +      user    => 'www-data', +      timeout => 600, +      subscribe => Vcsrepo[$file_path] +    } +  } + +  vcsrepo { $file_path: +    ensure   => present, +    force    => true, +    revision => $source['revision'], +    provider => $source['type'], +    source   => $source['repo'], +    owner    => 'www-data', +    group    => 'www-data' +  } + +} diff --git a/puppet/modules/site_static/templates/apache.conf.erb b/puppet/modules/site_static/templates/apache.conf.erb new file mode 100644 index 00000000..2abe1a98 --- /dev/null +++ b/puppet/modules/site_static/templates/apache.conf.erb @@ -0,0 +1,77 @@ +<%- +  ## +  ## An apache config for static websites. +  ## +  def location_directory(name, location) +    if location['format'] == 'amber' +      File.join(@base_dir, name, 'public') +    else +      File.join(@base_dir, name) +    end +  end +  document_root = '/var/www' +  @locations.each do |name, location| +    if location['path'] == '/' +      document_root = location_directory(name, location) +    end +  end +  document_root = document_root.gsub(%r{^/|/$}, '') +-%> + +<VirtualHost *:80> +  ServerName <%= @domain %> +  ServerAlias www.<%= @domain %> +  RewriteEngine On +  RewriteRule ^.*$ https://<%= @domain -%>%{REQUEST_URI} [R=permanent,L] +</VirtualHost> + +<VirtualHost *:443> +  ServerName <%= @domain %> +  ServerAlias www.<%= @domain %> + +  #RewriteLog "/var/log/apache2/rewrite.log" +  #RewriteLogLevel 3 + +  SSLEngine on +  SSLProtocol all -SSLv2 +  SSLHonorCipherOrder on +  SSLCompression off +  SSLCipherSuite "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:AES128:AES256:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK" + +  Header add Strict-Transport-Security: "max-age=15768000;includeSubdomains" +  Header set X-Frame-Options "deny" + +  SSLCertificateKeyFile    /etc/x509/keys/<%= @domain %>.key +  SSLCertificateFile       /etc/x509/certs/<%= @domain %>.crt +  SSLCertificateChainFile  /etc/ssl/certs/<%= @domain %>_ca.pem + +  RequestHeader set X_FORWARDED_PROTO 'https' + +  DocumentRoot "/<%= document_root %>/" +  AccessFileName .htaccess + +<%- @locations.each do |name, location| -%> +  <%- path = location['path'].gsub(%r{^/|/$}, '') -%> +  <%- directory = location_directory(name, location) -%> +  ## +  ## <%= name %> +  ## +  <%- if path == '' -%> +  <Directory "/<%= document_root %>/"> +    AllowOverride FileInfo Indexes Options=All,MultiViews +    Order deny,allow +    Allow from all +  </Directory> +  <%- else -%> +  AliasMatch ^/[a-z]{2}/<%=path%>(/.+|/|)$ "/<%=directory%>/$1" +  Alias /<%=path%> "/<%=directory%>/" +  <Directory "/<%=directory%>/"> +    AllowOverride FileInfo Indexes Options=All,MultiViews +    Order deny,allow +    Allow from all +  </Directory> +  <%- end -%> + +<%- end -%> + +</VirtualHost> diff --git a/puppet/modules/site_stunnel/manifests/clients.pp b/puppet/modules/site_stunnel/manifests/clients.pp index ed766e1a..837665a3 100644 --- a/puppet/modules/site_stunnel/manifests/clients.pp +++ b/puppet/modules/site_stunnel/manifests/clients.pp @@ -21,6 +21,13 @@ define site_stunnel::clients (      verify     => $verify,      pid        => "/var/run/stunnel4/${pid}.pid",      rndfile    => $rndfile, -    debuglevel => $debuglevel +    debuglevel => $debuglevel, +    require    => [ +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ]; +    } + +  include site_check_mk::agent::stunnel  } diff --git a/puppet/modules/site_stunnel/manifests/setup.pp b/puppet/modules/site_stunnel/manifests/setup.pp deleted file mode 100644 index 92eeb425..00000000 --- a/puppet/modules/site_stunnel/manifests/setup.pp +++ /dev/null @@ -1,24 +0,0 @@ -class site_stunnel::setup ($cert_name, $key, $cert, $ca_name, $ca) { - -  include site_stunnel - -  x509::key { -    $cert_name: -      content => $key, -      notify  => Service['stunnel']; -  } - -  x509::cert { -    $cert_name: -      content => $cert, -      notify  => Service['stunnel']; -  } - -  x509::ca { -    $ca_name: -      content => $ca, -      notify  => Service['stunnel']; -  } - -} - diff --git a/puppet/modules/site_tor/manifests/init.pp b/puppet/modules/site_tor/manifests/init.pp index 50ab636b..02368a0e 100644 --- a/puppet/modules/site_tor/manifests/init.pp +++ b/puppet/modules/site_tor/manifests/init.pp @@ -1,11 +1,12 @@  class site_tor {    tag 'leap_service' +  Class['site_config::default'] -> Class['site_tor']    $tor            = hiera('tor')    $bandwidth_rate = $tor['bandwidth_rate']    $tor_type       = $tor['type']    $nickname       = $tor['nickname'] -  $contact_email  = $tor['contacts'] +  $contact_emails = join($tor['contacts'],', ')    $address        = hiera('ip_address') @@ -13,17 +14,22 @@ class site_tor {    tor::daemon::relay { $nickname:      port             => 9001,      address          => $address, -    contact_info     => $contact_email, +    contact_info     => obfuscate_email($contact_emails),      bandwidth_rate   => $bandwidth_rate,      my_family        => '$2A431444756B0E7228A7918C85A8DACFF7E3B050',    } -  tor::daemon::directory { $::hostname: port => 80 } - -  include site_shorewall::tor - -  if ( $tor_type != 'exit' ) { +  if ( $tor_type == 'exit'){ +    tor::daemon::directory { $::hostname: port => 80 } +  } +  else { +    tor::daemon::directory { $::hostname: +      port            => 80, +      port_front_page => ''; +    }      include site_tor::disable_exit    } +  include site_shorewall::tor +  } diff --git a/puppet/modules/site_webapp/files/migrate_design_documents b/puppet/modules/site_webapp/files/migrate_design_documents deleted file mode 100644 index 6e24aa5b..00000000 --- a/puppet/modules/site_webapp/files/migrate_design_documents +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/sh - -cd /srv/leap/webapp - -# use admin credentials -cp config/couchdb.yml.admin config/couchdb.yml -chown leap-webapp:leap-webapp config/couchdb.yml - -# needs to be run twice  -RAILS_ENV=production /usr/bin/bundle exec rake couchrest:migrate -RAILS_ENV=production /usr/bin/bundle exec rake couchrest:migrate - -# use user credentials and remove admin credentials -cp config/couchdb.yml.webapp config/couchdb.yml -chown leap-webapp:leap-webapp config/couchdb.yml - diff --git a/puppet/modules/site_webapp/manifests/apache.pp b/puppet/modules/site_webapp/manifests/apache.pp index 8b340160..21243d34 100644 --- a/puppet/modules/site_webapp/manifests/apache.pp +++ b/puppet/modules/site_webapp/manifests/apache.pp @@ -4,61 +4,20 @@ class site_webapp::apache {    $api_domain       = $web_api['domain']    $api_port         = $web_api['port'] -  $x509             = hiera('x509') -  $commercial_key   = $x509['commercial_key'] -  $commercial_cert  = $x509['commercial_cert'] -  $commercial_root  = $x509['commercial_ca_cert'] -  $api_key          = $x509['key'] -  $api_cert         = $x509['cert'] -  $api_root         = $x509['ca_cert'] +  $web_domain       = hiera('domain') +  $domain_name      = $web_domain['name'] -  class { '::apache': no_default_site => true, ssl => true } - -  apache::module { -    'alias':   ensure => present; -    'rewrite': ensure => present; -    'headers': ensure => present; -  } +  include site_apache::common +  include site_apache::module::headers +  include site_apache::module::alias +  include site_apache::module::expires +  include site_apache::module::removeip    class { 'passenger': use_munin => false }    apache::vhost::file { -    'leap_webapp': -      content => template('site_apache/vhosts.d/leap_webapp.conf.erb') -  } - -  apache::vhost::file {      'api':        content => template('site_apache/vhosts.d/api.conf.erb')    } -  x509::key { -    'leap_webapp': -      content => $commercial_key, -      notify  => Service[apache]; - -    'leap_api': -      content => $api_key, -      notify  => Service[apache]; -  } - -  x509::cert { -    'leap_webapp': -      content => $commercial_cert, -      notify  => Service[apache]; - -    'leap_api': -      content => $api_cert, -      notify  => Service[apache]; -  } - -  x509::ca { -    'leap_webapp': -      content => $commercial_root, -      notify  => Service[apache]; - -    'leap_api': -      content => $api_root, -      notify  => Service[apache]; -  }  } diff --git a/puppet/modules/site_webapp/manifests/client_ca.pp b/puppet/modules/site_webapp/manifests/client_ca.pp deleted file mode 100644 index 0d9b15d6..00000000 --- a/puppet/modules/site_webapp/manifests/client_ca.pp +++ /dev/null @@ -1,25 +0,0 @@ -## -## This is for the special CA that is used exclusively for generating -## client certificates by the webapp. -## - -class site_webapp::client_ca { -  include x509::variables - -  $x509 = hiera('x509') -  $cert_path = "${x509::variables::certs}/leap_client_ca.crt" -  $key_path = "${x509::variables::keys}/leap_client_ca.key" - -  x509::key { -    'leap_client_ca': -      source => $x509['client_ca_key'], -      group  => 'leap-webapp', -      notify  => Service[apache]; -  } - -  x509::cert { -    'leap_client_ca': -      source => $x509['client_ca_cert'], -      notify  => Service[apache]; -  } -} diff --git a/puppet/modules/site_webapp/manifests/couchdb.pp b/puppet/modules/site_webapp/manifests/couchdb.pp index b4ef0980..ff743fba 100644 --- a/puppet/modules/site_webapp/manifests/couchdb.pp +++ b/puppet/modules/site_webapp/manifests/couchdb.pp @@ -4,8 +4,6 @@ class site_webapp::couchdb {    # haproxy listener on port localhost:4096, see site_webapp::haproxy    $couchdb_host            = 'localhost'    $couchdb_port            = '4096' -  $couchdb_admin_user      = $webapp['couchdb_admin_user']['username'] -  $couchdb_admin_password  = $webapp['couchdb_admin_user']['password']    $couchdb_webapp_user     = $webapp['couchdb_webapp_user']['username']    $couchdb_webapp_password = $webapp['couchdb_webapp_user']['password'] @@ -14,65 +12,38 @@ class site_webapp::couchdb {    $couch_client_connect    = $couch_client['connect']    include x509::variables -  $x509                    = hiera('x509') -  $key                     = $x509['key'] -  $cert                    = $x509['cert'] -  $ca                      = $x509['ca_cert'] -  $cert_name               = 'leap_couchdb' -  $ca_name                 = 'leap_ca' -  $ca_path                 = "${x509::variables::local_CAs}/${ca_name}.crt" -  $cert_path               = "${x509::variables::certs}/${cert_name}.crt" -  $key_path                = "${x509::variables::keys}/${cert_name}.key"    file { -    '/srv/leap/webapp/config/couchdb.yml.admin': -      content => template('site_webapp/couchdb.yml.admin.erb'), +    '/srv/leap/webapp/config/couchdb.yml': +      content => template('site_webapp/couchdb.yml.erb'),        owner   => leap-webapp,        group   => leap-webapp,        mode    => '0600',        require => Vcsrepo['/srv/leap/webapp']; -    '/srv/leap/webapp/config/couchdb.yml.webapp': -      content => template('site_webapp/couchdb.yml.erb'), +    '/srv/leap/webapp/log': +      ensure  => directory,        owner   => leap-webapp,        group   => leap-webapp, -      mode    => '0600', +      mode    => '0755',        require => Vcsrepo['/srv/leap/webapp']; -    '/srv/leap/webapp/logs/production.log': +    '/srv/leap/webapp/log/production.log': +      ensure  => present,        owner   => leap-webapp,        group   => leap-webapp,        mode    => '0666',        require => Vcsrepo['/srv/leap/webapp']; - -    '/usr/local/sbin/migrate_design_documents': -      source => 'puppet:///modules/site_webapp/migrate_design_documents', -      owner  => root, -      group  => root, -      mode   => '0744';    } -  class { 'site_stunnel::setup': -    cert_name => $cert_name, -    key       => $key, -    cert      => $cert, -    ca_name   => $ca_name, -    ca        => $ca -  } - -  exec { 'migrate_design_documents': -    cwd      => '/srv/leap/webapp', -    command  => '/usr/local/sbin/migrate_design_documents', -    require  => Exec['bundler_update'], -    notify   => Service['apache']; -  } +  include site_stunnel    $couchdb_stunnel_client_defaults = {      'connect_port' => $couch_client_connect, -    'client'     => true, -    'cafile'     => $ca_path, -    'key'        => $key_path, -    'cert'       => $cert_path, +    'client'       => true, +    'cafile'       => "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt", +    'key'          => "${x509::variables::keys}/${site_config::params::cert_name}.key", +    'cert'         => "${x509::variables::certs}/${site_config::params::cert_name}.crt",    }    create_resources(site_stunnel::clients, $couch_client, $couchdb_stunnel_client_defaults) diff --git a/puppet/modules/site_webapp/manifests/cron.pp b/puppet/modules/site_webapp/manifests/cron.pp new file mode 100644 index 00000000..811ad11d --- /dev/null +++ b/puppet/modules/site_webapp/manifests/cron.pp @@ -0,0 +1,17 @@ +class site_webapp::cron { + +  # cron tasks that need to be performed to cleanup the database +  cron { +    'remove_expired_sessions': +      command     => 'cd /srv/leap/webapp && bundle exec rake cleanup:sessions', +      environment => 'RAILS_ENV=production', +      hour        => 2, +      minute      => 30; + +    'remove_expired_tokens': +      command     => 'cd /srv/leap/webapp && bundle exec rake cleanup:tokens', +      environment => 'RAILS_ENV=production', +      hour        => 3, +      minute      => 0; +  } +} diff --git a/puppet/modules/site_webapp/manifests/haproxy.pp b/puppet/modules/site_webapp/manifests/haproxy.pp index 4a7e3c25..b69c69da 100644 --- a/puppet/modules/site_webapp/manifests/haproxy.pp +++ b/puppet/modules/site_webapp/manifests/haproxy.pp @@ -3,7 +3,6 @@ class site_webapp::haproxy {    include site_haproxy    $haproxy     = hiera('haproxy') -  $local_ports = $haproxy['local_ports']    # Template uses $global_options, $defaults_options    concat::fragment { 'leap_haproxy_webapp_couchdb': diff --git a/puppet/modules/site_webapp/manifests/init.pp b/puppet/modules/site_webapp/manifests/init.pp index e743dc07..d02a7261 100644 --- a/puppet/modules/site_webapp/manifests/init.pp +++ b/puppet/modules/site_webapp/manifests/init.pp @@ -11,11 +11,18 @@ class site_webapp {    $api_version      = $webapp['api_version']    $secret_token     = $webapp['secret_token'] -  include site_config::ruby +  Class['site_config::default'] -> Class['site_webapp'] + +  include site_config::ruby::dev    include site_webapp::apache    include site_webapp::couchdb -  include site_webapp::client_ca    include site_webapp::haproxy +  include site_webapp::cron +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca +  include site_config::x509::client_ca::ca +  include site_config::x509::client_ca::key    group { 'leap-webapp':      ensure    => present, @@ -31,19 +38,12 @@ class site_webapp {      require   => [ Group['leap-webapp'] ];    } -  file { '/srv/leap/webapp': -    ensure  => directory, -    owner   => 'leap-webapp', -    group   => 'leap-webapp', -    require => User['leap-webapp']; -  } -    vcsrepo { '/srv/leap/webapp':      ensure   => present,      force    => true, -    revision => 'origin/master', +    revision => $webapp['git']['revision'],      provider => git, -    source   => 'git://code.leap.se/leap_web', +    source   => $webapp['git']['source'],      owner    => 'leap-webapp',      group    => 'leap-webapp',      require  => [ User['leap-webapp'], Group['leap-webapp'] ], @@ -56,38 +56,58 @@ class site_webapp {      unless  => '/usr/bin/bundle check',      user    => 'leap-webapp',      timeout => 600, -    require => [ Class['bundler::install'], Vcsrepo['/srv/leap/webapp'] ], +    require => [ +      Class['bundler::install'], +      Vcsrepo['/srv/leap/webapp'], +      Class['site_config::ruby::dev'], +      Service['shorewall'] ],      notify  => Service['apache'];    } +  # +  # NOTE: in order to support a webapp that is running on a subpath and not the +  # root of the domain assets:precompile needs to be run with +  # RAILS_RELATIVE_URL_ROOT=/application-root +  # +    exec { 'compile_assets': -    cwd     => '/srv/leap/webapp', -    command => '/bin/bash -c "/usr/bin/bundle exec rake assets:precompile"', -    user    => 'leap-webapp', -    require => Exec['bundler_update'], -    notify  => Service['apache']; +    cwd       => '/srv/leap/webapp', +    command   => '/bin/bash -c "RAILS_ENV=production /usr/bin/bundle exec rake assets:precompile"', +    user      => 'leap-webapp', +    logoutput => on_failure, +    require   => Exec['bundler_update'], +    notify    => Service['apache'];    }    file { -    '/srv/leap/webapp/public/provider.json': +    '/srv/leap/webapp/config/provider': +      ensure  => directory, +      require => Vcsrepo['/srv/leap/webapp'], +      owner   => leap-webapp, group => leap-webapp, mode => '0755'; + +    '/srv/leap/webapp/config/provider/provider.json':        content => $provider,        require => Vcsrepo['/srv/leap/webapp'],        owner   => leap-webapp, group => leap-webapp, mode => '0644'; +    # old provider.json location. this can be removed after everyone upgrades. +    '/srv/leap/webapp/public/provider.json': +      ensure => absent; +      '/srv/leap/webapp/public/ca.crt':        ensure  => link,        require => Vcsrepo['/srv/leap/webapp'], -      target  => '/usr/local/share/ca-certificates/leap_api.crt'; +      target  => "${x509::variables::local_CAs}/${site_config::params::ca_name}.crt";      "/srv/leap/webapp/public/${api_version}": -      ensure => directory, +      ensure  => directory,        require => Vcsrepo['/srv/leap/webapp'], -      owner  => leap-webapp, group => leap-webapp, mode => '0755'; +      owner   => leap-webapp, group => leap-webapp, mode => '0755';      "/srv/leap/webapp/public/${api_version}/config/": -      ensure => directory, +      ensure  => directory,        require => Vcsrepo['/srv/leap/webapp'], -      owner  => leap-webapp, group => leap-webapp, mode => '0755'; +      owner   => leap-webapp, group => leap-webapp, mode => '0755';      "/srv/leap/webapp/public/${api_version}/config/eip-service.json":        content => $eip_service, @@ -106,25 +126,24 @@ class site_webapp {    }    try::file { -    '/srv/leap/webapp/public/favicon.ico': -      ensure  => 'link', -      require => Vcsrepo['/srv/leap/webapp'], -      target  => $webapp['favicon']; - -    '/srv/leap/webapp/app/assets/stylesheets/tail.scss': -      ensure  => 'link', -      require => Vcsrepo['/srv/leap/webapp'], -      target  => $webapp['tail_scss']; - -    '/srv/leap/webapp/app/assets/stylesheets/head.scss': -      ensure  => 'link', +    '/srv/leap/webapp/config/customization': +      ensure  => directory, +      recurse => true, +      purge   => true, +      force   => true, +      owner   => leap-webapp, +      group   => leap-webapp, +      mode    => 'u=rwX,go=rX',        require => Vcsrepo['/srv/leap/webapp'], -      target  => $webapp['head_scss']; +      notify  => Exec['compile_assets'], +      source  => $webapp['customization_dir']; +  } -    '/srv/leap/webapp/public/img': -      ensure  => 'link', +  git::changes { +    'public/favicon.ico': +      cwd     => '/srv/leap/webapp',        require => Vcsrepo['/srv/leap/webapp'], -      target  => $webapp['img_dir']; +      user    => 'leap-webapp';    }    file { @@ -138,5 +157,5 @@ class site_webapp {    }    include site_shorewall::webapp - +  include site_check_mk::agent::webapp  } diff --git a/puppet/modules/site_webapp/templates/config.yml.erb b/puppet/modules/site_webapp/templates/config.yml.erb index df562cd9..98f8564e 100644 --- a/puppet/modules/site_webapp/templates/config.yml.erb +++ b/puppet/modules/site_webapp/templates/config.yml.erb @@ -1,9 +1,10 @@  <%- cert_options = @webapp['client_certificates'] -%>  production: -  admins: [admin] +  admins: <%= @webapp['admins'].inspect %>    domain: <%= @provider_domain %> -  client_ca_key: <%= scope.lookupvar('site_webapp::client_ca::key_path') %> -  client_ca_cert: <%= scope.lookupvar('site_webapp::client_ca::cert_path') %> +  force_ssl: <%= @webapp['secure'] %> +  client_ca_key: <%= scope.lookupvar('x509::variables::keys') %>/<%= scope.lookupvar('site_config::params::client_ca_name') %>.key +  client_ca_cert: <%= scope.lookupvar('x509::variables::local_CAs') %>/<%= scope.lookupvar('site_config::params::client_ca_name') %>.crt    secret_token: "<%= @secret_token %>"    client_cert_lifespan: <%= cert_options['life_span'].to_i %>    client_cert_bit_size: <%= cert_options['bit_size'].to_i %> @@ -13,3 +14,4 @@ production:    allow_anonymous_certs: <%= @webapp['allow_anonymous_certs'].inspect %>    limited_cert_prefix: "<%= cert_options['limited_prefix'] %>"    unlimited_cert_prefix: "<%= cert_options['unlimited_prefix'] %>" +  minimum_client_version: "<%= @webapp['client_version']['min'] %>" diff --git a/puppet/modules/site_webapp/templates/couchdb.yml.admin.erb b/puppet/modules/site_webapp/templates/couchdb.yml.admin.erb deleted file mode 100644 index a0921add..00000000 --- a/puppet/modules/site_webapp/templates/couchdb.yml.admin.erb +++ /dev/null @@ -1,9 +0,0 @@ -production: -  prefix: "" -  protocol: 'http' -  host: <%= @couchdb_host %> -  port: <%= @couchdb_port %> -  auto_update_design_doc: false -  username: <%= @couchdb_admin_user %> -  password: <%= @couchdb_admin_password %> - diff --git a/puppet/modules/site_webapp/templates/haproxy_couchdb.cfg.erb b/puppet/modules/site_webapp/templates/haproxy_couchdb.cfg.erb index f08161ee..1fa01b96 100644 --- a/puppet/modules/site_webapp/templates/haproxy_couchdb.cfg.erb +++ b/puppet/modules/site_webapp/templates/haproxy_couchdb.cfg.erb @@ -1,16 +1,23 @@  listen bigcouch-in -  mode http +  mode     http    balance  roundrobin -  option httplog -  option dontlognull -  option httpchk GET / -  option http-server-close -   +  option   httplog +  option   dontlognull +  option   httpchk GET /        # health check using simple get to root +  option   http-server-close    # use client keep-alive, but close server connection. +  option   allbackups           # balance among all backups, not just one. +    bind localhost:4096 -<% for port in @local_ports -%> -  server couchdb_<%=port%> localhost:<%=port%> check inter 3000 fastinter 1000 downinter 1000 rise 2 fall 1 -<% end -%> +  default-server inter 3000 fastinter 1000 downinter 1000 rise 2 fall 1 + +<%- if @haproxy['servers'] -%> +<%-   @haproxy['servers'].sort.each do |name,server| -%> +<%-     backup = server['backup'] ? 'backup' : '' -%> +  # <%=name%> +  server couchdb_<%=server['port']%> <%=server['host']%>:<%=server['port']%> <%=backup%> weight <%=server['weight']%> check +<%-   end -%> +<%- end -%> diff --git a/puppet/modules/soledad/manifests/common.pp b/puppet/modules/soledad/manifests/common.pp new file mode 100644 index 00000000..8a1d664a --- /dev/null +++ b/puppet/modules/soledad/manifests/common.pp @@ -0,0 +1,10 @@ +class soledad::common { + +  include soledad + +  package { 'soledad-common': +    ensure  => latest, +    require => User['soledad'] +  } + +} diff --git a/puppet/modules/soledad/manifests/init.pp b/puppet/modules/soledad/manifests/init.pp new file mode 100644 index 00000000..7cf0b729 --- /dev/null +++ b/puppet/modules/soledad/manifests/init.pp @@ -0,0 +1,29 @@ +class soledad { + +  group { 'soledad': +    ensure    => present, +    allowdupe => false; +  } + +  user { 'soledad': +    ensure    => present, +    allowdupe => false, +    gid       => 'soledad', +    home      => '/srv/leap/soledad', +    require   => Group['soledad']; +  } + +  file { +    '/srv/leap/soledad': +      ensure  => directory, +      owner   => 'soledad', +      group   => 'soledad', +      require => User['soledad']; + +    '/var/lib/soledad': +      ensure  => directory, +      owner   => 'soledad', +      group   => 'soledad', +      require => User['soledad']; +  } +} diff --git a/puppet/modules/soledad/manifests/server.pp b/puppet/modules/soledad/manifests/server.pp new file mode 100644 index 00000000..394e6032 --- /dev/null +++ b/puppet/modules/soledad/manifests/server.pp @@ -0,0 +1,63 @@ +class soledad::server { +  tag 'leap_service' +  include soledad +  include site_apt::preferences::twisted + +  $soledad           = hiera('soledad') +  $couchdb_user      = $soledad['couchdb_soledad_user']['username'] +  $couchdb_password  = $soledad['couchdb_soledad_user']['password'] + +  $couchdb_host = 'localhost' +  $couchdb_port = '5984' + +  $soledad_port = $soledad['port'] + +  include site_config::x509::cert +  include site_config::x509::key +  include site_config::x509::ca + +  # +  # SOLEDAD CONFIG +  # + +  file { '/etc/leap/soledad-server.conf': +    content => template('soledad/soledad-server.conf.erb'), +    owner   => 'soledad', +    group   => 'soledad', +    mode    => '0600', +    notify  => Service['soledad-server'], +    require => Class['soledad']; +  } + +  package { 'soledad-server': +    ensure  => latest, +    require => [ +      Class['site_apt::preferences::twisted'], +      Class['site_apt::leap_repo'] ]; +  } + +  file { '/etc/default/soledad': +    content => template('soledad/default-soledad.erb'), +    owner   => 'soledad', +    group   => 'soledad', +    mode    => '0600', +    notify  => Service['soledad-server'], +    require => Class['soledad']; +  } + +  service { 'soledad-server': +    ensure     => running, +    enable     => true, +    hasstatus  => true, +    hasrestart => true, +    require    => Class['soledad'], +    subscribe  => [ +      Package['soledad-server'], +      Class['Site_config::X509::Key'], +      Class['Site_config::X509::Cert'], +      Class['Site_config::X509::Ca'] ]; +  } + +  include site_shorewall::soledad +  include site_check_mk::agent::soledad +} diff --git a/puppet/modules/soledad/templates/default-soledad.erb b/puppet/modules/soledad/templates/default-soledad.erb new file mode 100644 index 00000000..32504e38 --- /dev/null +++ b/puppet/modules/soledad/templates/default-soledad.erb @@ -0,0 +1,5 @@ +# this file is managed by puppet +START=yes +CERT_PATH=<%= scope.lookupvar('x509::variables::certs') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.crt +PRIVKEY_PATH=<%= scope.lookupvar('x509::variables::keys') %>/<%= scope.lookupvar('site_config::params::cert_name') %>.key +HTTPS_PORT=<%=@soledad_port%> diff --git a/puppet/modules/soledad/templates/soledad-server.conf.erb b/puppet/modules/soledad/templates/soledad-server.conf.erb new file mode 100644 index 00000000..47d1f6e4 --- /dev/null +++ b/puppet/modules/soledad/templates/soledad-server.conf.erb @@ -0,0 +1,3 @@ +[soledad-server] +couch_url = http://<%= @couchdb_user %>:<%= @couchdb_password %>@<%= @couchdb_host %>:<%= @couchdb_port %> + diff --git a/puppet/modules/squid_deb_proxy b/puppet/modules/squid_deb_proxy new file mode 160000 +Subproject e796aac43aa9781069e167459253d040504c209 diff --git a/puppet/modules/sshd b/puppet/modules/sshd -Subproject bd2e283ab59430a7b3194804f1c8da7a9b58f8f +Subproject 1eabfe1b590f6663c2558f949408a08fc5f58fa diff --git a/puppet/modules/stdlib b/puppet/modules/stdlib -Subproject 66e0fa8f1bc5062e9d753598ad17602c378a299 +Subproject 71cb0f4c2c3bf95f62c9f189f5cef155b09a968 diff --git a/puppet/modules/stunnel b/puppet/modules/stunnel -Subproject fc1589a5f09d80f58d730d4e1f6a8058483f61f +Subproject ec49fd93c2469bc5c13f7e6a7d25468613e1b84 diff --git a/puppet/modules/sysctl b/puppet/modules/sysctl new file mode 160000 +Subproject 975852b7acc1125b4cd9d4d490b9abd8d31217e diff --git a/puppet/modules/tapicero/files/tapicero.init b/puppet/modules/tapicero/files/tapicero.init new file mode 100755 index 00000000..7a9af45f --- /dev/null +++ b/puppet/modules/tapicero/files/tapicero.init @@ -0,0 +1,60 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides:          tapicero +# Required-Start:    $remote_fs $syslog +# Required-Stop:     $remote_fs $syslog +# Default-Start:     2 3 4 5 +# Default-Stop:      0 1 6 +# Short-Description: tapicero initscript +# Description:       Controls tapicero daemon +### END INIT INFO + +PATH=/sbin:/usr/sbin:/bin:/usr/bin +BUNDLER=/usr/bin/bundle +NAME=tapicero +HOME="/srv/leap" +DAEMON="${HOME}/${NAME}/bin/${NAME}" +BUNDLE_GEMFILE="${HOME}/${NAME}/Gemfile" + +export BUNDLE_GEMFILE + +# exit if the daemon doesn't exist +[ -x "$DAEMON" ] || exit 0 + +. /lib/init/vars.sh +. /lib/lsb/init-functions + +if [ "$VERBOSE" != no ]; then +    OPTIONS="--verbose" +else +    OPTIONS="" +fi + +case "$1" in +    start) +        $BUNDLER exec $DAEMON start $OPTIONS +        exit $? +        ;; +    stop) +        $BUNDLER exec $DAEMON stop $OPTIONS +        exit $? +        ;; +    restart) +        $BUNDLER exec $DAEMON restart $OPTIONS +        exit $? +        ;; +    reload) +        $BUNDLER exec $DAEMON reload $OPTIONS +        exit $? +        ;; +    status) +        $BUNDLER exec $DAEMON status $OPTIONS +        exit $? +        ;; +    *) +        echo "Usage: /etc/init.d/$NAME {start|stop|reload|restart|status}" +        exit 1 +esac + +exit 0 diff --git a/puppet/modules/tapicero/manifests/init.pp b/puppet/modules/tapicero/manifests/init.pp new file mode 100644 index 00000000..743e8a84 --- /dev/null +++ b/puppet/modules/tapicero/manifests/init.pp @@ -0,0 +1,123 @@ +class tapicero { +  tag 'leap_service' + +  $couchdb                 = hiera('couch') +  $couchdb_port            = $couchdb['port'] + +  $couchdb_users           = $couchdb['users'] + +  $couchdb_admin_user      = $couchdb_users['admin']['username'] +  $couchdb_admin_password  = $couchdb_users['admin']['password'] + +  $couchdb_soledad_user    = $couchdb_users['soledad']['username'] +  $couchdb_leap_mx_user    = $couchdb_users['leap_mx']['username'] + + +  Class['site_config::default'] -> Class['tapicero'] + +  include site_config::ruby::dev + +  # +  # USER AND GROUP +  # + +  group { 'tapicero': +    ensure    => present, +    allowdupe => false; +  } + +  user { 'tapicero': +    ensure    => present, +    allowdupe => false, +    gid       => 'tapicero', +    home      => '/srv/leap/tapicero', +    require   => Group['tapicero']; +  } + +  # +  # TAPICERO FILES +  # + +  file { + +    ## +    ## TAPICERO DIRECTORIES +    ## + +    '/srv/leap/tapicero': +      ensure  => directory, +      owner   => 'tapicero', +      group   => 'tapicero', +      require => User['tapicero']; + +    '/var/lib/leap/tapicero': +      ensure  => directory, +      owner   => 'tapicero', +      group   => 'tapicero', +      require => User['tapicero']; + +    ## +    ## TAPICERO CONFIG +    ## + +    '/etc/leap/tapicero.yaml': +      content => template('tapicero/tapicero.yaml.erb'), +      owner   => 'tapicero', +      group   => 'tapicero', +      mode    => '0600', +      notify  => Service['tapicero']; + +    ## +    ## TAPICERO INIT +    ## + +    '/etc/init.d/tapicero': +      source  => 'puppet:///modules/tapicero/tapicero.init', +      owner   => root, +      group   => 0, +      mode    => '0755', +      require => Vcsrepo['/srv/leap/tapicero']; +  } + +  # +  # TAPICERO CODE +  # + +  vcsrepo { '/srv/leap/tapicero': +    ensure   => present, +    force    => true, +    revision => 'origin/master', +    provider => git, +    source   => 'https://leap.se/git/tapicero', +    owner    => 'tapicero', +    group    => 'tapicero', +    require  => [ User['tapicero'], Group['tapicero'] ], +    notify   => Exec['tapicero_bundler_update'] +  } + +  exec { 'tapicero_bundler_update': +    cwd     => '/srv/leap/tapicero', +    command => '/bin/bash -c "/usr/bin/bundle check || /usr/bin/bundle install --path vendor/bundle --without test development"', +    unless  => '/usr/bin/bundle check', +    user    => 'tapicero', +    timeout => 600, +    require => [ +                Class['bundler::install'], +                Vcsrepo['/srv/leap/tapicero'], +                Class['site_config::ruby::dev'] ], +    notify  => Service['tapicero']; +  } + +  # +  # TAPICERO DAEMON +  # + +  service { 'tapicero': +    ensure     => running, +    enable     => true, +    hasstatus  => true, +    hasrestart => true, +    require    => File['/etc/init.d/tapicero']; +  } + +} diff --git a/puppet/modules/tapicero/templates/tapicero.yaml.erb b/puppet/modules/tapicero/templates/tapicero.yaml.erb new file mode 100644 index 00000000..8e19b22f --- /dev/null +++ b/puppet/modules/tapicero/templates/tapicero.yaml.erb @@ -0,0 +1,42 @@ +# +# Default configuration options for Tapicero +# + +# couch connection configuration +connection: +  protocol: "http" +  host: "localhost" +  port: <%= @couchdb_port %> +  username: <%= @couchdb_admin_user %> +  password: <%= @couchdb_admin_password %> +  prefix : "" +  suffix : "" + +# file to store the last processed user record in so we can resume after +# a restart: +seq_file: "/var/lib/leap/tapicero/tapicero.seq" + +# Configure log_file like this if you want to log to a file instead of syslog: +# log_file: "/var/leap/log/tapicero.log" +log_level: info + +# tapicero specific options +options: +  # prefix for per user databases: +  db_prefix: "user-" + +  # security settings to be used for the per user databases +  security: +    admins: +      names: +        # We explicitly allow the admin user to access per user databases, even +        # though admin access ignores per database security we just do this to be +        # explicit about this +        - <%= @couchdb_admin_user %> +      roles: [] +    readers: +      names: +        - <%= @couchdb_soledad_user %> +        - <%= @couchdb_leap_mx_user %> +      roles: [] + diff --git a/puppet/modules/tor b/puppet/modules/tor -Subproject a780e84001177f10a86a7bf824589c0553f513a +Subproject dcb6e748864e7dfd3c14f4f2aba4c9120f12b78 diff --git a/puppet/modules/try/manifests/file.pp b/puppet/modules/try/manifests/file.pp index 47a8c269..cd1bb035 100644 --- a/puppet/modules/try/manifests/file.pp +++ b/puppet/modules/try/manifests/file.pp @@ -1,60 +1,112 @@  # -# like built-in type "file", but gets gracefully ignored if the target does not exist or is undefined. +# Works like the built-in type "file", but gets gracefully ignored if the target/source does not exist or is undefined.  # -# /bin/true and /usr/bin/test are hardcoded to their paths in debian. +# Also, if the source or target doesn't exist, and the destination is a git repo, then the file is restored from git. +# +# All executable paths are hardcoded to their paths in debian. +# +# known limitations: +# * this is far too noisy +# * $restore does not work for directories +# * only file:// $source is supported +# * $content is not supported, only $target or $source. +# * does not auto-require all the parent directories like 'file' does  # -  define try::file (    $ensure = undef,    $target = undef, +  $source = undef, +  $owner = undef, +  $group = undef, +  $recurse = undef, +  $purge = undef, +  $force = undef, +  $mode = undef,    $restore = true) { -  if $target != undef { -    exec { "check_${name}": -      command => "/bin/true", -      onlyif => "/usr/bin/test -e '${target}'", -      loglevel => info; +  # dummy exec to propagate requires: +  # metaparameter 'require' will get triggered by this dummy exec +  # so then we just need to depend on this to capture all requires. +  # exec { $name: command => "/bin/true" } + +  exec { +    "chmod_${name}": +      command => "/bin/chmod -R ${mode} '${name}'", +      onlyif => "/usr/bin/test $mode", +      refreshonly => true, +      loglevel => debug; +    "chown_${name}": +      command => "/bin/chown -R ${owner} '${name}'", +      onlyif => "/usr/bin/test $owner", +      refreshonly => true, +      loglevel => debug; +    "chgrp_${name}": +      command => "/bin/chgrp -R ${group} '${name}'", +      onlyif => "/usr/bin/test $group", +      refreshonly => true, +      loglevel => debug; +  } + +  if $target { +    exec { "symlink_${name}": +      command => "/bin/ln -s ${target} ${name}", +      onlyif => "/usr/bin/test -d '${target}'",      } -    file { "$name": -      ensure => $ensure, -      target => $target, -      require => $require ? { -        undef   => Exec["check_${name}"], -        default => [ $require, Exec["check_${name}"] ] -      }, -      loglevel => info; +  } elsif $source { +    if $ensure == 'directory' { +      if $purge { +        exec { "rsync_${name}": +          command => "/usr/bin/rsync -r --delete '${source}/' '${name}'", +          onlyif => "/usr/bin/test -d '${source}'", +          unless => "/usr/bin/diff -rq '${source}' '${name}'", +          notify => [Exec["chmod_${name}"], Exec["chown_${name}"], Exec["chgrp_${name}"]] +        } +      } else { +        exec { "cp_r_${name}": +          command => "/bin/cp -r '${source}' '${name}'", +          onlyif => "/usr/bin/test -d '${source}'", +          unless => "/usr/bin/diff -rq '${source}' '${name}'", +          notify => [Exec["chmod_${name}"], Exec["chown_${name}"], Exec["chgrp_${name}"]] +        } +      } +    } else { +      exec { "cp_${name}": +        command => "/bin/cp --remove-destination '${source}' '${name}'", +        onlyif => "/usr/bin/test -e '${source}'", +        unless => "/usr/bin/test ! -h '${name}' && /usr/bin/diff -q '${source}' '${name}'", +        notify => [Exec["chmod_${name}"], Exec["chown_${name}"], Exec["chgrp_${name}"]] +      }      }    }    # -  # if the target does not exist (or is undef), and the file happens to be in a git repo, +  # if the target/source does not exist (or is undef), and the file happens to be in a git repo,    # then restore the file to its original state.    # -  if $target == undef or $restore { + +  if $target { +    $target_or_source = $target +  } else { +    $target_or_source = $source +  } + +  if ($target_or_source == undef) or $restore {      $file_basename = basename($name)      $file_dirname  = dirname($name)      $command = "git rev-parse && unlink '${name}'; git checkout -- '${file_basename}' && chown --reference='${file_dirname}' '${name}'; true"      debug($command) -    if $target == undef { +    if $target_or_source == undef {        exec { "restore_${name}":          command => $command,          cwd => $file_dirname, -        require => $require ? { -          undef   => undef, -          default => [ $require ] -        },          loglevel => info;        }      } else {        exec { "restore_${name}": -        unless => "/usr/bin/test -e '${target}'", +        unless => "/usr/bin/test -e '${target_or_source}'",          command => $command,          cwd => $file_dirname, -        require => $require ? { -          undef   => undef, -          default => [ $require ] -        },          loglevel => info;        }      } diff --git a/puppet/modules/vcsrepo b/puppet/modules/vcsrepo -Subproject 4db1120c78763f5244dc6c9d2e0d064a6ef363e +Subproject f92d09226cfddb0c7e5e342dd199d8ea05b497c | 
