diff options
Diffstat (limited to 'puppet')
195 files changed, 2817 insertions, 1562 deletions
| diff --git a/puppet/lib/puppet/parser/functions/sorted_yaml.rb b/puppet/lib/puppet/parser/functions/sorted_yaml.rb new file mode 100644 index 00000000..46cd46ce --- /dev/null +++ b/puppet/lib/puppet/parser/functions/sorted_yaml.rb @@ -0,0 +1,400 @@ +# encoding: UTF-8 +# +# provides sorted_yaml() function, using Ya2YAML. +# see https://github.com/afunai/ya2yaml +# + +class Ya2YAML +  # +  # Author::    Akira FUNAI +  # Copyright:: Copyright (c) 2006-2010 Akira FUNAI +  # License::   MIT License +  # + +  def initialize(opts = {}) +    options = opts.dup +    options[:indent_size] = 2          if options[:indent_size].to_i <= 0 +    options[:minimum_block_length] = 0 if options[:minimum_block_length].to_i <= 0 +    options.update( +      { +        :printable_with_syck  => true, +        :escape_b_specific    => true, +        :escape_as_utf8       => true, +      } +    ) if options[:syck_compatible] + +    @options = options +  end + +  def _ya2yaml(obj) +    #raise 'set $KCODE to "UTF8".' if (RUBY_VERSION < '1.9.0') && ($KCODE != 'UTF8') +    if (RUBY_VERSION < '1.9.0') +      $KCODE = 'UTF8' +    end +    '--- ' + emit(obj, 1) + "\n" +  rescue SystemStackError +    raise ArgumentError, "ya2yaml can't handle circular references" +  end + +  private + +  def emit(obj, level) +    case obj +      when Array +        if (obj.length == 0) +          '[]' +        else +          indent = "\n" + s_indent(level - 1) +          ### +          ### NOTE: a minor modification to normal Ya2YAML... +          ### We want arrays to be output in sorted order, not just +          ### Hashes. +          ### +          #obj.collect {|o| +          #  indent + '- ' + emit(o, level + 1) +          #}.join('') +          obj.sort {|a,b| a.to_s <=> b.to_s}.collect {|o| +            indent + '- ' + emit(o, level + 1) +          }.join('') +        end +      when Hash +        if (obj.length == 0) +          '{}' +        else +          indent = "\n" + s_indent(level - 1) +          hash_order = @options[:hash_order] +          if (hash_order && level == 1) +            hash_keys = obj.keys.sort {|x, y| +              x_order = hash_order.index(x) ? hash_order.index(x) : Float::MAX +              y_order = hash_order.index(y) ? hash_order.index(y) : Float::MAX +              o = (x_order <=> y_order) +              (o != 0) ? o : (x.to_s <=> y.to_s) +            } +          elsif @options[:preserve_order] +            hash_keys = obj.keys +          else +            hash_keys = obj.keys.sort {|x, y| x.to_s <=> y.to_s } +          end +          hash_keys.collect {|k| +            key = emit(k, level + 1) +            if ( +              is_one_plain_line?(key) || +              key =~ /\A(#{REX_BOOL}|#{REX_FLOAT}|#{REX_INT}|#{REX_NULL})\z/x +            ) +              indent + key + ': ' + emit(obj[k], level + 1) +            else +              indent + '? ' + key + +              indent + ': ' + emit(obj[k], level + 1) +            end +          }.join('') +        end +      when NilClass +        '~' +      when String +        emit_string(obj, level) +      when TrueClass, FalseClass +        obj.to_s +      when Fixnum, Bignum, Float +        obj.to_s +      when Date +        obj.to_s +      when Time +        offset = obj.gmtoff +        off_hm = sprintf( +          '%+.2d:%.2d', +          (offset / 3600.0).to_i, +          (offset % 3600.0) / 60 +        ) +        u_sec = (obj.usec != 0) ? sprintf(".%.6d", obj.usec) : '' +        obj.strftime("%Y-%m-%d %H:%M:%S#{u_sec} #{off_hm}") +      when Symbol +        '!ruby/symbol ' + emit_string(obj.to_s, level) +      when Range +        '!ruby/range ' + obj.to_s +      when Regexp +        '!ruby/regexp ' + obj.inspect +      else +        case +          when obj.is_a?(Struct) +            struct_members = {} +            obj.each_pair{|k, v| struct_members[k.to_s] = v } +            '!ruby/struct:' + obj.class.to_s.sub(/^(Struct::(.+)|.*)$/, '\2') + ' ' + +            emit(struct_members, level + 1) +          else +            # serialized as a generic object +            object_members = {} +            obj.instance_variables.each{|k, v| +              object_members[k.to_s.sub(/^@/, '')] = obj.instance_variable_get(k) +            } +            '!ruby/object:' + obj.class.to_s + ' ' + +            emit(object_members, level + 1) +        end +    end +  end + +  def emit_string(str, level) +    (is_string, is_printable, is_one_line, is_one_plain_line) = string_type(str) +    if is_string +      if is_printable +        if is_one_plain_line +          emit_simple_string(str, level) +        else +          (is_one_line || str.length < @options[:minimum_block_length]) ? +            emit_quoted_string(str, level) : +            emit_block_string(str, level) +        end +      else +        emit_quoted_string(str, level) +      end +    else +      emit_base64_binary(str, level) +    end +  end + +  def emit_simple_string(str, level) +    str +  end + +  def emit_block_string(str, level) +    str = normalize_line_break(str) + +    indent = s_indent(level) +    indentation_indicator = (str =~ /\A /) ? indent.size.to_s : '' +    str =~ /(#{REX_NORMAL_LB}*)\z/ +    chomping_indicator = case $1.length +      when 0 +        '-' +      when 1 +        '' +      else +        '+' +    end + +    str.chomp! +    str.gsub!(/#{REX_NORMAL_LB}/) { +      $1 + indent +    } +    '|' + indentation_indicator + chomping_indicator + "\n" + indent + str +  end + +  def emit_quoted_string(str, level) +    str = yaml_escape(normalize_line_break(str)) +    if (str.length < @options[:minimum_block_length]) +      str.gsub!(/#{REX_NORMAL_LB}/) { ESCAPE_SEQ_LB[$1] } +    else +      str.gsub!(/#{REX_NORMAL_LB}$/) { ESCAPE_SEQ_LB[$1] } +      str.gsub!(/(#{REX_NORMAL_LB}+)(.)/) { +        trail_c = $3 +        $1 + trail_c.sub(/([\t ])/) { ESCAPE_SEQ_WS[$1] } +      } +      indent = s_indent(level) +      str.gsub!(/#{REX_NORMAL_LB}/) { +        ESCAPE_SEQ_LB[$1] + "\\\n" + indent +      } +    end +    '"' + str + '"' +  end + +  def emit_base64_binary(str, level) +    indent = "\n" + s_indent(level) +    base64 = [str].pack('m') +    '!binary |' + indent + base64.gsub(/\n(?!\z)/, indent) +  end + +  def string_type(str) +    if str.respond_to?(:encoding) && (!str.valid_encoding? || str.encoding == Encoding::ASCII_8BIT) +      return false, false, false, false +    end +    (ucs_codes = str.unpack('U*')) rescue ( +      # ArgumentError -> binary data +      return false, false, false, false +    ) +    if ( +      @options[:printable_with_syck] && +      str =~ /\A#{REX_ANY_LB}* | #{REX_ANY_LB}*\z|#{REX_ANY_LB}{2}\z/ +    ) +      # detour Syck bug +      return true, false, nil, false +    end +    ucs_codes.each {|ucs_code| +      return true, false, nil, false unless is_printable?(ucs_code) +    } +    return true, true, is_one_line?(str), is_one_plain_line?(str) +  end + +  def is_printable?(ucs_code) +    # YAML 1.1 / 4.1.1. +    ( +      [0x09, 0x0a, 0x0d, 0x85].include?(ucs_code)   || +      (ucs_code <=     0x7e && ucs_code >=    0x20) || +      (ucs_code <=   0xd7ff && ucs_code >=    0xa0) || +      (ucs_code <=   0xfffd && ucs_code >=  0xe000) || +      (ucs_code <= 0x10ffff && ucs_code >= 0x10000) +    ) && +    !( +      # treat LS/PS as non-printable characters +      @options[:escape_b_specific] && +      (ucs_code == 0x2028 || ucs_code == 0x2029) +    ) +  end + +  def is_one_line?(str) +    str !~ /#{REX_ANY_LB}(?!\z)/ +  end + +  def is_one_plain_line?(str) +    # YAML 1.1 / 4.6.11. +    str !~ /^([\-\?:,\[\]\{\}\#&\*!\|>'"%@`\s]|---|\.\.\.)/    && +    str !~ /[:\#\s\[\]\{\},]/                                  && +    str !~ /#{REX_ANY_LB}/                                     && +    str !~ /^(#{REX_BOOL}|#{REX_FLOAT}|#{REX_INT}|#{REX_MERGE} +      |#{REX_NULL}|#{REX_TIMESTAMP}|#{REX_VALUE})$/x +  end + +  def s_indent(level) +    # YAML 1.1 / 4.2.2. +    ' ' * (level * @options[:indent_size]) +  end + +  def normalize_line_break(str) +    # YAML 1.1 / 4.1.4. +    str.gsub(/(#{REX_CRLF}|#{REX_CR}|#{REX_NEL})/, "\n") +  end + +  def yaml_escape(str) +    # YAML 1.1 / 4.1.6. +    str.gsub(/[^a-zA-Z0-9]/u) {|c| +      ucs_code, = (c.unpack('U') rescue [??]) +      case +        when ESCAPE_SEQ[c] +          ESCAPE_SEQ[c] +        when is_printable?(ucs_code) +          c +        when @options[:escape_as_utf8] +          c.respond_to?(:bytes) ? +            c.bytes.collect {|b| '\\x%.2x' % b }.join : +            '\\x' + c.unpack('H2' * c.size).join('\\x') +        when ucs_code == 0x2028 || ucs_code == 0x2029 +          ESCAPE_SEQ_LB[c] +        when ucs_code <= 0x7f +          sprintf('\\x%.2x', ucs_code) +        when ucs_code <= 0xffff +          sprintf('\\u%.4x', ucs_code) +        else +          sprintf('\\U%.8x', ucs_code) +      end +    } +  end + +  module Constants +    UCS_0X85   = [0x85].pack('U')   #   c285@UTF8 Unicode next line +    UCS_0XA0   = [0xa0].pack('U')   #   c2a0@UTF8 Unicode non-breaking space +    UCS_0X2028 = [0x2028].pack('U') # e280a8@UTF8 Unicode line separator +    UCS_0X2029 = [0x2029].pack('U') # e280a9@UTF8 Unicode paragraph separator + +    # non-break characters +    ESCAPE_SEQ = { +      "\x00" => '\\0', +      "\x07" => '\\a', +      "\x08" => '\\b', +      "\x0b" => '\\v', +      "\x0c" => '\\f', +      "\x1b" => '\\e', +      "\""   => '\\"', +      "\\"   => '\\\\', +    } + +    # non-breaking space +    ESCAPE_SEQ_NS = { +      UCS_0XA0 => '\\_', +    } + +    # white spaces +    ESCAPE_SEQ_WS = { +      "\x09" => '\\t', +      " "    => '\\x20', +    } + +    # line breaks +    ESCAPE_SEQ_LB ={ +      "\x0a"     => '\\n', +      "\x0d"     => '\\r', +      UCS_0X85   => '\\N', +      UCS_0X2028 => '\\L', +      UCS_0X2029 => '\\P', +    } + +    # regexps for line breaks +    REX_LF   = Regexp.escape("\x0a") +    REX_CR   = Regexp.escape("\x0d") +    REX_CRLF = Regexp.escape("\x0d\x0a") +    REX_NEL  = Regexp.escape(UCS_0X85) +    REX_LS   = Regexp.escape(UCS_0X2028) +    REX_PS   = Regexp.escape(UCS_0X2029) + +    REX_ANY_LB    = /(#{REX_LF}|#{REX_CR}|#{REX_NEL}|#{REX_LS}|#{REX_PS})/ +    REX_NORMAL_LB = /(#{REX_LF}|#{REX_LS}|#{REX_PS})/ + +    # regexps for language-Independent types for YAML1.1 +    REX_BOOL = / +       y|Y|yes|Yes|YES|n|N|no|No|NO +      |true|True|TRUE|false|False|FALSE +      |on|On|ON|off|Off|OFF +    /x +    REX_FLOAT = / +       [-+]?([0-9][0-9_]*)?\.[0-9.]*([eE][-+][0-9]+)? # (base 10) +      |[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*      # (base 60) +      |[-+]?\.(inf|Inf|INF)                           # (infinity) +      |\.(nan|NaN|NAN)                                # (not a number) +    /x +    REX_INT = / +       [-+]?0b[0-1_]+                   # (base 2) +      |[-+]?0[0-7_]+                    # (base 8) +      |[-+]?(0|[1-9][0-9_]*)            # (base 10) +      |[-+]?0x[0-9a-fA-F_]+             # (base 16) +      |[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+ # (base 60) +    /x +    REX_MERGE = / +      << +    /x +    REX_NULL = / +       ~              # (canonical) +      |null|Null|NULL # (English) +      |               # (Empty) +    /x +    REX_TIMESTAMP = / +       [0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] # (ymd) +      |[0-9][0-9][0-9][0-9]                       # (year) +       -[0-9][0-9]?                               # (month) +       -[0-9][0-9]?                               # (day) +       ([Tt]|[ \t]+)[0-9][0-9]?                   # (hour) +       :[0-9][0-9]                                # (minute) +       :[0-9][0-9]                                # (second) +       (\.[0-9]*)?                                # (fraction) +       (([ \t]*)Z|[-+][0-9][0-9]?(:[0-9][0-9])?)? # (time zone) +    /x +    REX_VALUE = / +      = +    /x +  end + +  include Constants +end + +module Puppet::Parser::Functions +  newfunction(:sorted_yaml, +    :type => :rvalue, +    :doc => "This function outputs yaml, but ensures the keys are sorted." +    ) do |arguments| + +    if arguments.is_a?(Array) +      if arguments.size != 1 +        raise(Puppet::ParseError, "sorted_yaml(): Wrong number of arguments given (#{arguments.size} for 1)") +      end +      yaml = arguments.first +    else +      yaml = arguments +    end +    return Ya2YAML.new()._ya2yaml(yaml) +  end +end diff --git a/puppet/manifests/site.pp b/puppet/manifests/site.pp index 912234ac..ecda4012 100644 --- a/puppet/manifests/site.pp +++ b/puppet/manifests/site.pp @@ -2,30 +2,37 @@  # the logoutput exec parameter defaults to "on_error" in puppet 3,  # but to "false" in puppet 2.7, so we need to set this globally here  Exec { -    logoutput => on_failure, -      path    => '/usr/bin:/usr/sbin/:/bin:/sbin:/usr/local/bin:/usr/local/sbin' +  logoutput => on_failure, +  path      => '/usr/bin:/usr/sbin/:/bin:/sbin:/usr/local/bin:/usr/local/sbin'  } -include site_config::setup -include site_config::default +Package <| provider == 'apt' |>  { +  install_options => ['--no-install-recommends'], +}  $services = hiera('services', [])  $services_str = join($services, ', ')  notice("Services for ${fqdn}: ${services_str}") +# In the default deployment case, we want to run an 'apt-get dist-upgrade' +# to ensure the latest packages are installed. This is done by including the +# class 'site_config::slow' here. However, you only changed a small bit of +# the platform and want to skip this slow part of deployment, you can do that +# by using 'leap deploy --fast' which will only apply those resources that are +# tagged with 'leap_base' or 'leap_service'. +# See https://leap.se/en/docs/platform/details/under-the-hood#tags +include site_config::slow +  if member($services, 'openvpn') {    include site_openvpn -  include site_obfsproxy  }  if member($services, 'couchdb') {    include site_couchdb -  include tapicero  }  if member($services, 'webapp') {    include site_webapp -  include site_nickserver  }  if member($services, 'soledad') { @@ -51,5 +58,3 @@ if member($services, 'static') {  if member($services, 'obfsproxy') {    include site_obfsproxy  } - -include site_config::packages::uninstall diff --git a/puppet/modules/apache b/puppet/modules/apache -Subproject c3e92a9b3cb02f1546b6b1570f10a968d380005 +Subproject 117bed9a9263c21d253d86b667eb165948efdc2 diff --git a/puppet/modules/apt b/puppet/modules/apt -Subproject fca103484ddc1f647a54135b6a902edabf45955 +Subproject 33c61e8df59db1abbed379a9e9790946060a8f1 diff --git a/puppet/modules/backupninja b/puppet/modules/backupninja -Subproject daeb1a1f112a4dbf6b39565f0dea461e46a6468 +Subproject 497513547be79f9d3c8e96f1650ec43ee634b27 diff --git a/puppet/modules/check_mk b/puppet/modules/check_mk -Subproject 205859d87884ac4ceee6d1365548e7dc55640bf +Subproject aa02571537af90ac73309e6e216c9417802548c diff --git a/puppet/modules/clamav/files/01-leap.conf b/puppet/modules/clamav/files/01-leap.conf new file mode 100644 index 00000000..a7e49d17 --- /dev/null +++ b/puppet/modules/clamav/files/01-leap.conf @@ -0,0 +1,58 @@ +# If running clamd in "LocalSocket" mode (*NOT* in TCP/IP mode), and +# either "SOcket Cat" (socat) or the "IO::Socket::UNIX" perl module +# are installed on the system, and you want to report whether clamd +# is running or not, uncomment the "clamd_socket" variable below (you +# will be warned if neither socat nor IO::Socket::UNIX are found, but +# the script will still run).  You will also need to set the correct +# path to your clamd socket file (if unsure of the path, check the +# "LocalSocket" setting in your clamd.conf file for socket location). +clamd_socket="/run/clamav/clamd.ctl" + +# If you would like to attempt to restart ClamD if detected not running, +# uncomment the next 2 lines.  Confirm the path to the "clamd_lock" file +# (usually can be found in the clamd init script) and also enter the clamd +# start command for your particular distro for the "start_clamd" variable +# (the sample start command shown below should work for most linux distros). +# NOTE: these 2 variables are dependant on the "clamd_socket" variable +# shown above - if not enabled, then the following 2 variables will be +# ignored, whether enabled or not. +clamd_lock="/run/clamav/clamd.pid" +start_clamd="clamdscan --reload" + +ss_dbs=" +   junk.ndb +   phish.ndb +   rogue.hdb +   sanesecurity.ftm +   scam.ndb +   sigwhitelist.ign2 +   spamattach.hdb +   spamimg.hdb +   winnow.attachments.hdb +   winnow_bad_cw.hdb +   winnow_extended_malware.hdb +   winnow_malware.hdb +   winnow_malware_links.ndb +   malwarehash.hsb +   doppelstern.hdb +   bofhland_cracked_URL.ndb +   bofhland_malware_attach.hdb +   bofhland_malware_URL.ndb +   bofhland_phishing_URL.ndb +   crdfam.clamav.hdb +   phishtank.ndb +   porcupine.ndb +   spear.ndb +   spearl.ndb +" + +# ======================== +# SecuriteInfo Database(s) +# ======================== +# Add or remove database file names between quote marks as needed.  To +# disable any SecuriteInfo database downloads, remove the appropriate +# lines below.  To disable all SecuriteInfo database file downloads, +# comment all of the following lines. +si_dbs="" + +mbl_dbs=""
\ No newline at end of file diff --git a/puppet/modules/clamav/files/clamav-daemon_default b/puppet/modules/clamav/files/clamav-daemon_default new file mode 100644 index 00000000..b4cd6a4f --- /dev/null +++ b/puppet/modules/clamav/files/clamav-daemon_default @@ -0,0 +1,8 @@ +# This is a file designed only t0 set special environment variables +# eg TMP or TMPDIR.  It is sourced from a shell script, so anything +# put in here must be in variable=value format, suitable for sourcing +# from a shell script. +# Examples: +# export TMPDIR=/dev/shm +export TMP=/var/tmp +export TMPDIR=/var/tmp diff --git a/puppet/modules/clamav/files/clamav-milter_default b/puppet/modules/clamav/files/clamav-milter_default new file mode 100644 index 00000000..5e33e822 --- /dev/null +++ b/puppet/modules/clamav/files/clamav-milter_default @@ -0,0 +1,14 @@ +# +# clamav-milter init options +# + +## SOCKET_RWGROUP +# by default, the socket created by the milter has permissions +# clamav:clamav:755. SOCKET_RWGROUP changes the group and changes the +# permissions to 775 to give read-write access to that group. +# +# If you are using postfix to speak to the milter, you have to give permission +# to the postfix group to write +# +SOCKET_RWGROUP=postfix +export TMPDIR=/var/tmp diff --git a/puppet/modules/clamav/manifests/daemon.pp b/puppet/modules/clamav/manifests/daemon.pp new file mode 100644 index 00000000..2e13a8fb --- /dev/null +++ b/puppet/modules/clamav/manifests/daemon.pp @@ -0,0 +1,91 @@ +# deploy clamav daemon +class clamav::daemon { + +  $domain_hash           = hiera('domain') +  $domain                = $domain_hash['full_suffix'] + +  package { [ 'clamav-daemon', 'arj' ]: +    ensure => installed; +  } + +  service { +    'clamav-daemon': +      ensure     => running, +      name       => clamav-daemon, +      pattern    => '/usr/sbin/clamd', +      enable     => true, +      hasrestart => true, +      subscribe  => File['/etc/default/clamav-daemon'], +      require    => Package['clamav-daemon']; +  } + +  file { +    '/var/run/clamav': +      ensure  => directory, +      mode    => '0750', +      owner   => clamav, +      group   => postfix, +      require => [Package['postfix'], Package['clamav-daemon']]; + +    '/var/lib/clamav': +      mode    => '0755', +      owner   => clamav, +      group   => clamav, +      require => Package['clamav-daemon']; + +    '/etc/default/clamav-daemon': +      source => 'puppet:///modules/clamav/clamav-daemon_default', +      mode   => '0644', +      owner  => root, +      group  => root; + +    # this file contains additional domains that we want the clamav +    # phishing process to look for (our domain) +    '/var/lib/clamav/local.pdb': +      content => template('clamav/local.pdb.erb'), +      mode    => '0644', +      owner   => clamav, +      group   => clamav, +      require => Package['clamav-daemon']; +  } + +  file_line { +    'clamav_daemon_tmp': +      path    => '/etc/clamav/clamd.conf', +      line    => 'TemporaryDirectory /var/tmp', +      require => Package['clamav-daemon'], +      notify  => Service['clamav-daemon']; + +    'enable_phishscanurls': +      path    => '/etc/clamav/clamd.conf', +      match   => 'PhishingScanURLs no', +      line    => 'PhishingScanURLs yes', +      require => Package['clamav-daemon'], +      notify  => Service['clamav-daemon']; + +    'clamav_LogSyslog_true': +      path    => '/etc/clamav/clamd.conf', +      match   => '^LogSyslog false', +      line    => 'LogSyslog true', +      require => Package['clamav-daemon'], +      notify  => Service['clamav-daemon']; + +    'clamav_MaxThreads': +      path    => '/etc/clamav/clamd.conf', +      match   => 'MaxThreads 20', +      line    => 'MaxThreads 100', +      require => Package['clamav-daemon'], +      notify  => Service['clamav-daemon']; +  } + +  # remove LogFile line +  file_line { +    'clamav_LogFile': +      path    => '/etc/clamav/clamd.conf', +      match   => '^LogFile .*', +      line    => '', +      require => Package['clamav-daemon'], +      notify  => Service['clamav-daemon']; +  } + +} diff --git a/puppet/modules/clamav/manifests/freshclam.pp b/puppet/modules/clamav/manifests/freshclam.pp new file mode 100644 index 00000000..80c822a4 --- /dev/null +++ b/puppet/modules/clamav/manifests/freshclam.pp @@ -0,0 +1,23 @@ +class clamav::freshclam { + +  package { 'clamav-freshclam': ensure => installed } + +  service { +    'freshclam': +      ensure     => running, +      enable     => true, +      name       => clamav-freshclam, +      pattern    => '/usr/bin/freshclam', +      hasrestart => true, +      require    => Package['clamav-freshclam']; +  } + +  file_line { +    'freshclam_notify': +      path    => '/etc/clamav/freshclam.conf', +      line    => 'NotifyClamd /etc/clamav/clamd.conf', +      require => Package['clamav-freshclam'], +      notify  => Service['freshclam']; +  } + +} diff --git a/puppet/modules/clamav/manifests/init.pp b/puppet/modules/clamav/manifests/init.pp new file mode 100644 index 00000000..de8fb4dc --- /dev/null +++ b/puppet/modules/clamav/manifests/init.pp @@ -0,0 +1,8 @@ +class clamav { + +  include clamav::daemon +  include clamav::milter +  include clamav::unofficial_sigs +  include clamav::freshclam + +} diff --git a/puppet/modules/clamav/manifests/milter.pp b/puppet/modules/clamav/manifests/milter.pp new file mode 100644 index 00000000..e8a85e3f --- /dev/null +++ b/puppet/modules/clamav/manifests/milter.pp @@ -0,0 +1,50 @@ +class clamav::milter { + +  $clamav                = hiera('clamav') +  $whitelisted_addresses = $clamav['whitelisted_addresses'] +  $domain_hash           = hiera('domain') +  $domain                = $domain_hash['full_suffix'] + +  package { 'clamav-milter': ensure => installed } + +  service { +    'clamav-milter': +      ensure     => running, +      enable     => true, +      name       => clamav-milter, +      pattern    => '/usr/sbin/clamav-milter', +      hasrestart => true, +      require    => Package['clamav-milter'], +      subscribe  => File['/etc/default/clamav-milter']; +  } + +  file { +    '/run/clamav/milter.ctl': +      mode    => '0666', +      owner   => clamav, +      group   => postfix, +      require => Class['clamav::daemon']; + +    '/etc/clamav/clamav-milter.conf': +      content   => template('clamav/clamav-milter.conf.erb'), +      mode      => '0644', +      owner     => root, +      group     => root, +      require   => Package['clamav-milter'], +      subscribe => Service['clamav-milter']; + +    '/etc/default/clamav-milter': +      source => 'puppet:///modules/clamav/clamav-milter_default', +      mode   => '0644', +      owner  => root, +      group  => root; + +    '/etc/clamav/whitelisted_addresses': +      content => template('clamav/whitelisted_addresses.erb'), +      mode    => '0644', +      owner   => root, +      group   => root, +      require => Package['clamav-milter']; +  } + +} diff --git a/puppet/modules/clamav/manifests/unofficial_sigs.pp b/puppet/modules/clamav/manifests/unofficial_sigs.pp new file mode 100644 index 00000000..2d849585 --- /dev/null +++ b/puppet/modules/clamav/manifests/unofficial_sigs.pp @@ -0,0 +1,23 @@ +class clamav::unofficial_sigs { + +  package { 'clamav-unofficial-sigs': +    ensure => installed +  } + +  ensure_packages(['wget', 'gnupg', 'socat', 'rsync', 'curl']) + +  file { +    '/var/log/clamav-unofficial-sigs.log': +      ensure  => file, +      owner   => clamav, +      group   => clamav, +      require => Package['clamav-unofficial-sigs']; + +    '/etc/clamav-unofficial-sigs.conf.d/01-leap.conf': +      source  => 'puppet:///modules/clamav/01-leap.conf', +      mode    => '0755', +      owner   => root, +      group   => root, +      require => Package['clamav-unofficial-sigs']; +    } +} diff --git a/puppet/modules/clamav/templates/clamav-milter.conf.erb b/puppet/modules/clamav/templates/clamav-milter.conf.erb new file mode 100644 index 00000000..9bf7099e --- /dev/null +++ b/puppet/modules/clamav/templates/clamav-milter.conf.erb @@ -0,0 +1,28 @@ +# THIS FILE MANAGED BY PUPPET +MilterSocket /var/run/clamav/milter.ctl +FixStaleSocket true +User clamav +MilterSocketGroup clamav +MilterSocketMode 666 +AllowSupplementaryGroups true +ReadTimeout 120 +Foreground false +PidFile /var/run/clamav/clamav-milter.pid +ClamdSocket unix:/var/run/clamav/clamd.ctl +OnClean Accept +OnInfected Reject +OnFail Defer +AddHeader Replace +LogSyslog true +LogFacility LOG_LOCAL6 +LogVerbose yes +LogInfected Basic +LogTime true +LogFileUnlock false +LogClean Off +LogRotate true +SupportMultipleRecipients false +MaxFileSize 10M +TemporaryDirectory /var/tmp +RejectMsg "Message refused due to content violation: %v - contact https://<%= @domain %>/tickets/new if this is in error" +Whitelist /etc/clamav/whitelisted_addresses diff --git a/puppet/modules/clamav/templates/local.pdb.erb b/puppet/modules/clamav/templates/local.pdb.erb new file mode 100644 index 00000000..9ea0584a --- /dev/null +++ b/puppet/modules/clamav/templates/local.pdb.erb @@ -0,0 +1 @@ +H:<%= @domain %> diff --git a/puppet/modules/clamav/templates/whitelisted_addresses.erb b/puppet/modules/clamav/templates/whitelisted_addresses.erb new file mode 100644 index 00000000..9e068ec5 --- /dev/null +++ b/puppet/modules/clamav/templates/whitelisted_addresses.erb @@ -0,0 +1,5 @@ +<%- if @whitelisted_addresses then -%> +<%   @whitelisted_addresses.each do |name| -%> +From::<%= name %> +<%   end -%> +<% end -%> diff --git a/puppet/modules/couchdb b/puppet/modules/couchdb -Subproject 3c20a3169e77e5a5f9abc06788c3a7730d5530c +Subproject 40d2289f8e10625cd45fdccdf492b5fb6490e66 diff --git a/puppet/modules/haproxy b/puppet/modules/haproxy -Subproject b398f3cb0a67d1170d0564a3f03977f9a08c2b6 +Subproject af322a73c013f80a958ab7d5d31d0c75cf6d052 diff --git a/puppet/modules/journald/manifests/init.pp b/puppet/modules/journald/manifests/init.pp new file mode 100644 index 00000000..879baba4 --- /dev/null +++ b/puppet/modules/journald/manifests/init.pp @@ -0,0 +1,7 @@ +class journald { + +    service { 'systemd-journald': +      ensure => running, +      enable => true, +    } +} diff --git a/puppet/modules/leap/manifests/cli/install.pp b/puppet/modules/leap/manifests/cli/install.pp new file mode 100644 index 00000000..25e87033 --- /dev/null +++ b/puppet/modules/leap/manifests/cli/install.pp @@ -0,0 +1,46 @@ +# installs leap_cli on node +class leap::cli::install ( $source = false ) { +  if $source { +    # needed for building leap_cli from source +    include ::git +    include ::rubygems + +    class { '::ruby': +      install_dev => true +    } + +    class { 'bundler::install': install_method => 'package' } + +    Class[Ruby] -> +      Class[rubygems] -> +      Class[bundler::install] + + +    vcsrepo { '/srv/leap/cli': +      ensure   => present, +      force    => true, +      revision => 'develop', +      provider => 'git', +      source   => 'https://leap.se/git/leap_cli.git', +      owner    => 'root', +      group    => 'root', +      notify   => Exec['install_leap_cli'], +      require  => Package['git'] +    } + +    exec { 'install_leap_cli': +      command     => '/usr/bin/rake build && /usr/bin/rake install', +      cwd         => '/srv/leap/cli', +      user        => 'root', +      environment => 'USER=root', +      refreshonly => true, +      require     => [ Class[bundler::install] ] +    } +  } +  else { +    package { 'leap_cli': +      ensure   => installed, +      provider => gem +    } +  } +} diff --git a/puppet/modules/leap/manifests/logfile.pp b/puppet/modules/leap/manifests/logfile.pp index 63dbd16b..adb3ca8a 100644 --- a/puppet/modules/leap/manifests/logfile.pp +++ b/puppet/modules/leap/manifests/logfile.pp @@ -1,9 +1,18 @@  #  # make syslog log to a particular file for a particular process.  # - -define leap::logfile($process=$name) { -  $logfile = "/var/log/leap/${name}.log" +# arguments: +# +#   * name: what config files are named as (eg.  /etc/rsyslog.d/50-$name.conf) +#   * log: the full path of the log file (defaults to /var/log/leap/$name.log +#   * process: the syslog tag to filter on (defaults to name) +# +define leap::logfile($process = $name, $log = undef) { +  if $log { +    $logfile = $log +  } else { +    $logfile = "/var/log/leap/${name}.log" +  }    rsyslog::snippet { "50-${name}":      content => template('leap/rsyslog.erb') diff --git a/puppet/modules/leap_mx/manifests/init.pp b/puppet/modules/leap_mx/manifests/init.pp index 284662d2..d758e3ab 100644 --- a/puppet/modules/leap_mx/manifests/init.pp +++ b/puppet/modules/leap_mx/manifests/init.pp @@ -1,3 +1,4 @@ +# deploy leap mx service  class leap_mx {    $leap_mx          = hiera('couchdb_leap_mx_user') @@ -10,23 +11,66 @@ class leap_mx {    $sources          = hiera('sources')    include soledad::common -  include site_apt::preferences::twisted    #    # USER AND GROUP    # +  # Make the user for leap-mx. This user is where all legitimate, non-system +  # mail is delivered so leap-mx can process it. Previously, we let the system +  # pick a uid/gid, but we need to know what they are set to in order to set the +  # virtual_uid_maps and virtual_gid_maps. Its a bit overkill write a fact just +  # for this, so instead we pick arbitrary numbers that seem unlikely to be used +  # and then use them in the postfix configuration    group { 'leap-mx':      ensure    => present, +    gid       => 42424,      allowdupe => false;    }    user { 'leap-mx': -    ensure    => present, -    allowdupe => false, -    gid       => 'leap-mx', -    home      => '/etc/leap', -    require   => Group['leap-mx']; +    ensure     => present, +    comment    => 'Leap Mail', +    allowdupe  => false, +    uid        => 42424, +    gid        => 'leap-mx', +    home       => '/var/mail/leap-mx', +    shell      => '/bin/false', +    managehome => true, +    require    => Group['leap-mx']; +  } + +  file { +    '/var/mail/leap-mx': +      ensure  => directory, +      owner   => 'leap-mx', +      group   => 'leap-mx', +      mode    => '0755', +      require => User['leap-mx']; + +    '/var/mail/leap-mx/Maildir': +      ensure => directory, +      owner  => 'leap-mx', +      group  => 'leap-mx', +      mode   => '0700'; + +    '/var/mail/leap-mx/Maildir/new': +      ensure => directory, +      owner  => 'leap-mx', +      group  => 'leap-mx', +      mode   => '0700'; + +    '/var/mail/leap-mx/Maildir/cur': +      ensure => directory, +      owner  => 'leap-mx', +      group  => 'leap-mx', +      mode   => '0700'; + +    '/var/mail/leap-mx/Maildir/tmp': +      ensure => directory, +      owner  => 'leap-mx', +      group  => 'leap-mx', +      mode   => '0700';    }    # @@ -41,12 +85,9 @@ class leap_mx {      notify  => Service['leap-mx'];    } -  file { '/etc/default/leap_mx': -    content => 'LOGFILE=/var/log/leap/mx.log', -    owner   => 'root', -    group   => 'root', -    mode    => '0644', -    notify  => Service['leap-mx']; +  leap::logfile { 'leap-mx': +    log     => '/var/log/leap/mx.log', +    process => 'leap-mx'    }    # @@ -57,8 +98,8 @@ class leap_mx {      $sources['leap-mx']['package']:        ensure  => $sources['leap-mx']['revision'],        require => [ -        Class['site_apt::preferences::twisted'], -        Class['site_apt::leap_repo'] ]; +        Class['site_apt::leap_repo'], +        User['leap-mx'] ];      'leap-keymanager':        ensure => latest; @@ -75,20 +116,4 @@ class leap_mx {      hasrestart => true,      require    => [ Package['leap-mx'] ];    } - -  augeas { -    'logrotate_mx': -      context => '/files/etc/logrotate.d/leap-mx/rule', -      changes => [ -                  'set file /var/log/leap/mx.log', -                  'set rotate 5', -                  'set schedule daily', -                  'clear nocreate', -                  'rm create', -                  'rm ifempty', -                  'set compress compress', -                  'set missingok missingok', -                  'set copytruncate copytruncate' -                  ] -  }  } diff --git a/puppet/modules/leap_mx/templates/mx.conf.erb b/puppet/modules/leap_mx/templates/mx.conf.erb index e05bc150..b54b3a86 100644 --- a/puppet/modules/leap_mx/templates/mx.conf.erb +++ b/puppet/modules/leap_mx/templates/mx.conf.erb @@ -1,5 +1,5 @@  [mail1] -path=/var/mail/vmail/Maildir +path=/var/mail/leap-mx/Maildir  recursive=True  [couchdb] @@ -13,3 +13,6 @@ port=4242  [check recipient]  port=2244 + +[fingerprint map] +port=2424 diff --git a/puppet/modules/nagios b/puppet/modules/nagios -Subproject b55f23d4d90c97cec08251544aa9700df86ad0b +Subproject 68dab01a85996e14efcccf856b623a2caf25782 diff --git a/puppet/modules/obfsproxy/manifests/init.pp b/puppet/modules/obfsproxy/manifests/init.pp index 61714fdf..6a3d2c72 100644 --- a/puppet/modules/obfsproxy/manifests/init.pp +++ b/puppet/modules/obfsproxy/manifests/init.pp @@ -1,3 +1,4 @@ +# deploy obfsproxy service  class obfsproxy (    $transport,    $bind_address, @@ -23,18 +24,18 @@ class obfsproxy (    }    file { '/etc/init.d/obfsproxy': -    path      => '/etc/init.d/obfsproxy', -    ensure    => present, -    source    => 'puppet:///modules/obfsproxy/obfsproxy_init', -    owner     => 'root', -    group     => 'root', -    mode      => '0750', -    require   => File[$conf], +    ensure  => present, +    path    => '/etc/init.d/obfsproxy', +    source  => 'puppet:///modules/obfsproxy/obfsproxy_init', +    owner   => 'root', +    group   => 'root', +    mode    => '0750', +    require => File[$conf],    }    file { $conf : -    path    => $conf,      ensure  => present, +    path    => $conf,      owner   => 'root',      group   => 'root',      mode    => '0600', @@ -67,8 +68,7 @@ class obfsproxy (    }    package { 'obfsproxy': -    ensure  => present, -    require => Class['site_apt::preferences::obfsproxy'], +    ensure  => present    }    service { 'obfsproxy': diff --git a/puppet/modules/opendkim/manifests/init.pp b/puppet/modules/opendkim/manifests/init.pp new file mode 100644 index 00000000..4d4c5312 --- /dev/null +++ b/puppet/modules/opendkim/manifests/init.pp @@ -0,0 +1,67 @@ +# +# I am not sure about what issues might arise with DKIM key sizes +# larger than 2048. It might or might not be supported. See: +# http://dkim.org/specs/rfc4871-dkimbase.html#rfc.section.3.3.3 +# +class opendkim { + +  $domain_hash = hiera('domain') +  $domain      = $domain_hash['full_suffix'] +  $mx          = hiera('mx') +  $dkim        = $mx['dkim'] +  $selector    = $dkim['selector'] +  $dkim_cert   = $dkim['public_key'] +  $dkim_key    = $dkim['private_key'] + +  ensure_packages(['opendkim', 'libvbr2']) + +  # postfix user needs to be in the opendkim group +  # in order to access the opendkim socket located at: +  # local:/var/run/opendkim/opendkim.sock +  user { 'postfix': +    groups  => 'opendkim', +    require => Package['opendkim']; +  } + +  service { 'opendkim': +    ensure     => running, +    enable     => true, +    hasstatus  => true, +    hasrestart => true, +    subscribe  => File[$dkim_key]; +  } + +  file { +    '/etc/opendkim.conf': +      ensure  => file, +      content => template('opendkim/opendkim.conf'), +      mode    => '0644', +      owner   => root, +      group   => root, +      notify  => Service['opendkim'], +      require => Package['opendkim']; + +    '/etc/default/opendkim.conf': +      ensure  => file, +      content => 'SOCKET="inet:8891@localhost" # listen on loopback on port 8891', +      mode    => '0644', +      owner   => root, +      group   => root, +      notify  => Service['opendkim'], +      require => Package['opendkim']; + +    $dkim_key: +      ensure  => file, +      mode    => '0600', +      owner   => 'opendkim', +      group   => 'opendkim', +      require => Package['opendkim']; + +    $dkim_cert: +      ensure  => file, +      mode    => '0600', +      owner   => 'opendkim', +      group   => 'opendkim', +      require => Package['opendkim']; +  } +} diff --git a/puppet/modules/opendkim/templates/opendkim.conf b/puppet/modules/opendkim/templates/opendkim.conf new file mode 100644 index 00000000..5a948229 --- /dev/null +++ b/puppet/modules/opendkim/templates/opendkim.conf @@ -0,0 +1,45 @@ +# This is a basic configuration that can easily be adapted to suit a standard +# installation. For more advanced options, see opendkim.conf(5) and/or +# /usr/share/doc/opendkim/examples/opendkim.conf.sample. + +# Log to syslog +Syslog                  yes +SyslogSuccess           yes +LogWhy                  no +# Required to use local socket with MTAs that access the socket as a non- +# privileged user (e.g. Postfix) +UMask                   002 + +Domain                  <%= @domain %> +SubDomains              yes + +# set internal hosts to all the known hosts, like mydomains? + +# can we generate a larger key and get it in dns? +KeyFile                 <%= @dkim_key %> + +Selector                <%= @selector %> + +# Commonly-used options; the commented-out versions show the defaults. +Canonicalization        relaxed +#Mode                   sv +#ADSPDiscard            no + +SignatureAlgorithm      rsa-sha256 + +# Always oversign From (sign using actual From and a null From to prevent +# malicious signatures header fields (From and/or others) between the signer +# and the verifier.  From is oversigned by default in the Debian pacakge +# because it is often the identity key used by reputation systems and thus +# somewhat security sensitive. +OversignHeaders         From + +# List domains to use for RFC 6541 DKIM Authorized Third-Party Signatures +# (ATPS) (experimental) + +#ATPSDomains            example.com + +RemoveOldSignatures     yes + +Mode                    sv +BaseDirectory           /var/tmp diff --git a/puppet/modules/postfix b/puppet/modules/postfix -Subproject f09cd0eff2bcab7e12c09ec67be3c918bc83fac +Subproject cce918f784ebf8a8875f43c79bc3a1f39ab9456 diff --git a/puppet/modules/postfwd/files/postfwd_default b/puppet/modules/postfwd/files/postfwd_default new file mode 100644 index 00000000..83742e40 --- /dev/null +++ b/puppet/modules/postfwd/files/postfwd_default @@ -0,0 +1,19 @@ +### This file managed by Puppet +# Global options for postfwd(8). + +# Set to '1' to enable startup (daemon mode) +STARTUP=1 + +# Config file +CONF=/etc/postfix/postfwd.cf +# IP where listen to +INET=127.0.0.1 +# Port where listen to +PORT=10040 +# run as user postfwd +RUNAS="postfw" +# Arguments passed on start (--daemon implied) +# disable summary and cache-no-size +#ARGS="--summary=600 --cache=600 --cache-rdomain-only --cache-no-size" +ARGS="--cache=600 --cache-rdomain-only --no-rulestats" + diff --git a/puppet/modules/postfwd/manifests/init.pp b/puppet/modules/postfwd/manifests/init.pp new file mode 100644 index 00000000..6db3fa52 --- /dev/null +++ b/puppet/modules/postfwd/manifests/init.pp @@ -0,0 +1,43 @@ +# This class provides rate-limiting for outgoing SMTP, using postfwd +# it is configured with some limits that seem reasonable for a generic +# use-case. Each of the following applies to sasl_authenticated users: +# +# . 150 recipients at a time +# . no more than 50 messages in 60 minutes +# . no more than 250 recipients in 60 minutes. +# +# This class could be easily extended to add overrides to these rules, +# maximum sizes per client, or additional rules +class postfwd { + +  ensure_packages(['libnet-server-perl', 'libnet-dns-perl', 'postfwd']) + +  file { +    '/etc/default/postfwd': +      source  => 'puppet:///modules/postfwd/postfwd_default', +      mode    => '0644', +      owner   => root, +      group   => root, +      before  => Package['postfwd']; + +    '/etc/postfix/postfwd.cf': +      content => template('postfwd/postfwd.cf.erb'), +      mode    => '0644', +      owner   => root, +      group   => root, +      require => Package['postfix'], +      before  => Package['postfwd']; +  } + +  service { +    'postfwd': +      ensure     => running, +      name       => postfwd, +      pattern    => '/usr/sbin/postfwd', +      enable     => true, +      hasrestart => true, +      hasstatus  => false, +      require    => [ File['/etc/default/postfwd'], +                      File['/etc/postfix/postfwd.cf']]; +  } +} diff --git a/puppet/modules/postfwd/templates/postfwd.cf.erb b/puppet/modules/postfwd/templates/postfwd.cf.erb new file mode 100644 index 00000000..1c45dd03 --- /dev/null +++ b/puppet/modules/postfwd/templates/postfwd.cf.erb @@ -0,0 +1,28 @@ +### This file managed by Puppet +# Before deploying a rule +# 1. test with an additional "sender==test@domain.org;" in the rule so it +#   only applies to your test account +# 2. then when ready to test for all users, use WARN and watch the logs +#   for a few days and make sure it working the way you like +# 3. Then when ready to deploy for real set a proper error code + +## Overrides - make like the following example +# id=exampleuser; sasl_username==exampleuser; action=dunno + +## Rules that apply to all senders +# Recipient Per Message Limit +# We only receive mail via smtp from sasl authenticated users +# directly. We want to limit to a lower amount to prevent phished accounts +# spamming +id=RCPTSENDER; recipient_count=150; action=REJECT Too many recipients, please try again. Contact http://<%= @domain %>/tickets/new if this is in error. ERROR:RCPTSENDER  + +# Message Rate Limit +# This limits sasl authenticated users to no more than 50/60mins +# NOTE: sasl_username needs to be set to something or this check will fail +id=MSGRATE ; sasl_username=!!(^$); action==rate($$sasl_username/100/3600/450 4.7.1 exceeded message rate. Contact Contact http://<%= @domain %>/tickets/new if this is in error. ERROR:MSGRATE) + +# Total Recipient Rate Limit +# This adds up the recipients for all the sasl authenticated users messages +# and can't exceed more than 250/60min +# NOTE: sasl_username needs to be set to something or this check will fail +id=RCPTRATE ; sasl_username=!!(^$); action==rcpt($$sasl_username/500/3600/450 4.7.1 exceeded message rate. Contact http://<%= @domain %>/tickets/new if this is in error. ERROR:RCPTRATE) diff --git a/puppet/modules/ruby b/puppet/modules/ruby -Subproject e4de25d78eefc7df70a35dee22a3e0dc1b7e1d0 +Subproject 9ccd853c49af7d0b57ebd9c2ea7673b193fce24 diff --git a/puppet/modules/rubygems b/puppet/modules/rubygems -Subproject ef820cfec3321d17be99ef814318adb4e3cc1e9 +Subproject e704c9fe1c40fea5b10fe3ca2b4f5de825341cc diff --git a/puppet/modules/site_apache/manifests/common.pp b/puppet/modules/site_apache/manifests/common.pp index 2b83ffa5..8a11759a 100644 --- a/puppet/modules/site_apache/manifests/common.pp +++ b/puppet/modules/site_apache/manifests/common.pp @@ -1,27 +1,30 @@ +# install basic apache modules needed for all services (nagios, webapp)  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 apache::module::rewrite +  include apache::module::env -  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, +    ssl_cipher_suite => 'HIGH:MEDIUM:!aNULL:!MD5' +  } -  class { '::apache': no_default_site => true, ssl => true } +  # needed for the mod_ssl config +  include apache::module::mime -  apache::vhost::file { -    'common': -      content => template('site_apache/vhosts.d/common.conf.erb') +  # load mods depending on apache version +  if ( $::lsbdistcodename == 'jessie' ) { +    # apache >= 2.4, debian jessie +    # needed for mod_ssl config +    include apache::module::socache_shmcb +    # generally needed +    include apache::module::mpm_prefork +  } else { +    # apache < 2.4, debian wheezy +    # for "Order" directive, i.e. main apache2.conf +    include apache::module::authz_host    } -  apache::config::include{ 'ssl_common.inc': } +  include site_apache::common::tls  } diff --git a/puppet/modules/site_apache/manifests/common/tls.pp b/puppet/modules/site_apache/manifests/common/tls.pp new file mode 100644 index 00000000..040868bf --- /dev/null +++ b/puppet/modules/site_apache/manifests/common/tls.pp @@ -0,0 +1,6 @@ +class site_apache::common::tls { +  # class to setup common SSL configurations + +  apache::config::include{ 'ssl_common.inc': } + +} diff --git a/puppet/modules/site_apache/manifests/module/alias.pp b/puppet/modules/site_apache/manifests/module/alias.pp deleted file mode 100644 index c1f5e185..00000000 --- a/puppet/modules/site_apache/manifests/module/alias.pp +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index f73a5607..00000000 --- a/puppet/modules/site_apache/manifests/module/expires.pp +++ /dev/null @@ -1,4 +0,0 @@ -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 deleted file mode 100644 index f7caa28c..00000000 --- a/puppet/modules/site_apache/manifests/module/headers.pp +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index f106167a..00000000 --- a/puppet/modules/site_apache/manifests/module/removeip.pp +++ /dev/null @@ -1,5 +0,0 @@ -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 deleted file mode 100644 index 7ad00a0c..00000000 --- a/puppet/modules/site_apache/manifests/module/rewrite.pp +++ /dev/null @@ -1,5 +0,0 @@ -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 0396f54b..bfa5d04d 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/api.conf.erb @@ -1,18 +1,17 @@  <VirtualHost *:80> -  ServerName <%= api_domain %> +  ServerName <%= @api_domain %>    RewriteEngine On -  RewriteRule ^.*$ https://<%= api_domain -%>:<%= api_port -%>%{REQUEST_URI} [R=permanent,L] +  RewriteRule ^.*$ https://<%= @api_domain -%>:<%= @api_port -%>%{REQUEST_URI} [R=permanent,L]    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common  </VirtualHost> -Listen 0.0.0.0:<%= api_port %> +Listen 0.0.0.0:<%= @api_port %> -<VirtualHost *:<%= api_port -%>> -  ServerName <%= api_domain %> +<VirtualHost *:<%= @api_port -%>> +  ServerName <%= @api_domain %>    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common    SSLCACertificatePath /etc/ssl/certs -  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 @@ -27,6 +26,12 @@ Listen 0.0.0.0:<%= api_port %>    </IfModule>    DocumentRoot /srv/leap/webapp/public +  <% if scope.function_guess_apache_version([]) == '2.4' %> +  <Directory /srv/leap/webapp/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %>    # Check for maintenance file and redirect all requests    RewriteEngine On diff --git a/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb index ee5cd707..bf60e794 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/common.conf.erb @@ -1,22 +1,21 @@  <VirtualHost *:80> -  ServerName <%= webapp_domain %> -  ServerAlias <%= domain_name %> -  ServerAlias <%= domain %> -  ServerAlias www.<%= domain %> +  ServerName <%= @webapp_domain %> +  ServerAlias <%= @domain_name %> +  ServerAlias <%= @domain %> +  ServerAlias www.<%= @domain %>    RewriteEngine On -  RewriteRule ^.*$ https://<%= domain -%>%{REQUEST_URI} [R=permanent,L] +  RewriteRule ^.*$ https://<%= @webapp_domain -%>%{REQUEST_URI} [R=permanent,L]    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common  </VirtualHost>  <VirtualHost *:443> -  ServerName <%= webapp_domain %> -  ServerAlias <%= domain_name %> -  ServerAlias <%= domain %> -  ServerAlias www.<%= domain %> +  ServerName <%= @webapp_domain %> +  ServerAlias <%= @domain_name %> +  ServerAlias <%= @domain %> +  ServerAlias www.<%= @domain %>    CustomLog ${APACHE_LOG_DIR}/other_vhosts_access.log common    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 @@ -32,6 +31,12 @@  <% if (defined? @services) and (@services.include? 'webapp') -%>    DocumentRoot /srv/leap/webapp/public +  <% if scope.function_guess_apache_version([]) == '2.4' %> +  <Directory /srv/leap/webapp/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %>    RewriteEngine On    # Check for maintenance file and redirect all requests @@ -69,4 +74,3 @@    </DirectoryMatch>  <% end -%>  </VirtualHost> - diff --git a/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb b/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb index 0c6f3b8e..232b1577 100644 --- a/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb +++ b/puppet/modules/site_apache/templates/vhosts.d/hidden_service.conf.erb @@ -1,5 +1,5 @@  <VirtualHost 127.0.0.1:80> -  ServerName <%= tor_domain %> +  ServerName <%= @tor_domain %>    <IfModule mod_headers.c>      Header always unset X-Powered-By @@ -8,6 +8,12 @@  <% if (defined? @services) and (@services.include? 'webapp') -%>    DocumentRoot /srv/leap/webapp/public +  <% if scope.function_guess_apache_version([]) == '2.4' %> +  <Directory /srv/leap/webapp/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %>    RewriteEngine On    # Check for maintenance file and redirect all requests @@ -30,4 +36,20 @@      ExpiresDefault "access plus 1 year"    </Location>  <% end -%> + +<% if (defined? @services) and (@services.include? 'static') -%> +  DocumentRoot "/srv/static/root/public" +  <% if scope.function_guess_apache_version([]) == '2.4' %> +  <Directory /srv/static/root/public> +    AllowOverride None +    Require all granted +  </Directory> +  <% end %> +  AccessFileName .htaccess + +  Alias /provider.json /srv/leap/provider.json +  <Location /provider.json> +    Header set X-Minimum-Client-Version 0.5 +  </Location> +<% end -%>  </VirtualHost> diff --git a/puppet/modules/site_apt/files/Debian/51unattended-upgrades-leap b/puppet/modules/site_apt/files/Debian/51unattended-upgrades-leap new file mode 100644 index 00000000..bbaac6a2 --- /dev/null +++ b/puppet/modules/site_apt/files/Debian/51unattended-upgrades-leap @@ -0,0 +1,6 @@ +// this file is managed by puppet ! + +Unattended-Upgrade::Allowed-Origins { +  "leap.se:stable"; +} + diff --git a/puppet/modules/site_apt/files/keys/leap-archive.gpg b/puppet/modules/site_apt/files/keys/leap-archive.gpgBinary files differ new file mode 100644 index 00000000..dd7f3be6 --- /dev/null +++ b/puppet/modules/site_apt/files/keys/leap-archive.gpg diff --git a/puppet/modules/site_apt/files/keys/leap-experimental-archive.gpg b/puppet/modules/site_apt/files/keys/leap-experimental-archive.gpgBinary files differ new file mode 100644 index 00000000..5cc9064b --- /dev/null +++ b/puppet/modules/site_apt/files/keys/leap-experimental-archive.gpg diff --git a/puppet/modules/site_apt/files/keys/leap_key.asc b/puppet/modules/site_apt/files/keys/leap_key.asc deleted file mode 100644 index 5d9fb310..00000000 --- a/puppet/modules/site_apt/files/keys/leap_key.asc +++ /dev/null @@ -1,443 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- - -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 -FTL4yta7 -=DRTl ------END PGP PUBLIC KEY BLOCK----- diff --git a/puppet/modules/site_apt/manifests/dist_upgrade.pp b/puppet/modules/site_apt/manifests/dist_upgrade.pp index 08de31bb..0eb98cea 100644 --- a/puppet/modules/site_apt/manifests/dist_upgrade.pp +++ b/puppet/modules/site_apt/manifests/dist_upgrade.pp @@ -1,17 +1,17 @@ +# upgrade all packages  class site_apt::dist_upgrade { +  # facter returns 'true' as string +  # lint:ignore:quoted_booleans    if $::apt_running == 'true' { +  # lint:endignore      fail ('apt-get is running in background - Please wait until it finishes. Exiting.')    } else { -    exec{'initial_apt_update': -      command     => '/usr/bin/apt-get update', -      refreshonly => false, -      timeout     => 360, -    }      exec{'initial_apt_dist_upgrade':        command     => "/usr/bin/apt-get -q -y -o 'DPkg::Options::=--force-confold'  dist-upgrade",        refreshonly => false,        timeout     => 1200, +      require     => Exec['apt_updated']      }    }  } diff --git a/puppet/modules/site_apt/manifests/init.pp b/puppet/modules/site_apt/manifests/init.pp index cf49f870..455425c1 100644 --- a/puppet/modules/site_apt/manifests/init.pp +++ b/puppet/modules/site_apt/manifests/init.pp @@ -3,15 +3,29 @@ class site_apt {    $sources           = hiera('sources')    $apt_config        = $sources['apt'] + +  # debian repo urls    $apt_url_basic     = $apt_config['basic']    $apt_url_security  = $apt_config['security']    $apt_url_backports = $apt_config['backports'] +  # leap repo url +  $platform_sources       = $sources['platform'] +  $apt_url_platform_basic = $platform_sources['apt']['basic'] + +  # needed on jessie hosts for getting pnp4nagios from testing +  if ( $::operatingsystemmajrelease == '8' ) { +    $use_next_release = true +  } else { +    $use_next_release = false +  } +    class { 'apt': -    custom_key_dir => 'puppet:///modules/site_apt/keys', -    debian_url     => $apt_url_basic, -    security_url   => $apt_url_security, -    backports_url  => $apt_url_backports +    custom_key_dir   => 'puppet:///modules/site_apt/keys', +    debian_url       => $apt_url_basic, +    security_url     => $apt_url_security, +    backports_url    => $apt_url_backports, +    use_next_release => $use_next_release    }    # enable http://deb.leap.se debian package repository @@ -23,14 +37,10 @@ class site_apt {    include ::site_apt::unattended_upgrades -  apt::sources_list { 'secondary.list.disabled': -    content => template('site_apt/secondary.list'); -  } - -  apt::preferences_snippet { 'facter': -    release  => "${::lsbdistcodename}-backports", -    priority => 999 -  } +  # not currently used +  #apt::sources_list { 'secondary.list': +  #  content => template('site_apt/secondary.list'); +  #}    apt::preferences_snippet { 'leap':      priority => 999, @@ -38,13 +48,8 @@ class site_apt {      pin      => 'origin "deb.leap.se"'    } -  # All packages should be installed _after_ refresh_apt is called, -  # which does an apt-get update. -  # There is one exception: -  # The creation of sources.list depends on the lsb package +  # All packages should be installed after 'update_apt' is called, +  # which does an 'apt-get update'. +  Exec['update_apt'] -> Package <||> -  File['/etc/apt/preferences'] -> -    Apt::Preferences_snippet <| |> -> -    Exec['refresh_apt'] -> -    Package <| ( title != 'lsb' ) |>  } diff --git a/puppet/modules/site_apt/manifests/leap_repo.pp b/puppet/modules/site_apt/manifests/leap_repo.pp index 2d4ba0e1..5eedce45 100644 --- a/puppet/modules/site_apt/manifests/leap_repo.pp +++ b/puppet/modules/site_apt/manifests/leap_repo.pp @@ -1,17 +1,16 @@ +# install leap deb repo together with leap-keyring package +# containing the apt signing key  class site_apt::leap_repo {    $platform = hiera_hash('platform')    $major_version = $platform['major_version']    apt::sources_list { 'leap.list': -    content => "deb http://deb.leap.se/${major_version} wheezy main\n", +    content => "deb ${::site_apt::apt_url_platform_basic} ${::lsbdistcodename} main\n",      before  => Exec[refresh_apt]    } -  package { 'leap-keyring': +  package { 'leap-archive-keyring':      ensure => latest    } -  # We wont be able to install the leap-keyring package unless the leap apt -  # source has been added and apt has been refreshed -  Exec['refresh_apt'] -> Package['leap-keyring']  } diff --git a/puppet/modules/site_apt/manifests/preferences/obfsproxy.pp b/puppet/modules/site_apt/manifests/preferences/obfsproxy.pp deleted file mode 100644 index 75b01956..00000000 --- a/puppet/modules/site_apt/manifests/preferences/obfsproxy.pp +++ /dev/null @@ -1,9 +0,0 @@ -class site_apt::preferences::obfsproxy { - -  apt::preferences_snippet { 'obfsproxy': -    package  => 'obfsproxy', -    release  => 'wheezy-backports', -    priority => 999; -  } - -} diff --git a/puppet/modules/site_apt/manifests/preferences/openvpn.pp b/puppet/modules/site_apt/manifests/preferences/openvpn.pp deleted file mode 100644 index c7ddae25..00000000 --- a/puppet/modules/site_apt/manifests/preferences/openvpn.pp +++ /dev/null @@ -1,9 +0,0 @@ -class site_apt::preferences::openvpn { - -  apt::preferences_snippet { 'openvpn': -    package  => 'openvpn', -    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 deleted file mode 100644 index abff6838..00000000 --- a/puppet/modules/site_apt/manifests/preferences/twisted.pp +++ /dev/null @@ -1,9 +0,0 @@ -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/manifests/preferences/unbound.pp b/puppet/modules/site_apt/manifests/preferences/unbound.pp deleted file mode 100644 index 6da964f9..00000000 --- a/puppet/modules/site_apt/manifests/preferences/unbound.pp +++ /dev/null @@ -1,10 +0,0 @@ -class site_apt::preferences::unbound { - -  apt::preferences_snippet { 'unbound': -    package  => 'libunbound* unbound*', -    release  => "${::lsbdistcodename}-backports", -    priority => 999, -    before   => Class['unbound::package']; -  } - -} diff --git a/puppet/modules/site_apt/manifests/unattended_upgrades.pp b/puppet/modules/site_apt/manifests/unattended_upgrades.pp index 40111deb..42f1f4c6 100644 --- a/puppet/modules/site_apt/manifests/unattended_upgrades.pp +++ b/puppet/modules/site_apt/manifests/unattended_upgrades.pp @@ -1,9 +1,20 @@ +# configute unattended upgrades so packages from both Debian and LEAP +# repos get upgraded unattended  class site_apt::unattended_upgrades {    # override unattended-upgrades package resource to make sure    # that it is upgraded on every deploy (#6245) +  # configure upgrades for Debian    class { 'apt::unattended_upgrades': -    config_content => template('site_apt/50unattended-upgrades'),      ensure_version => latest    } + +  # configure LEAP upgrades +  apt::apt_conf { '51unattended-upgrades-leap': +    source      => [ +      "puppet:///modules/site_apt/${::lsbdistid}/51unattended-upgrades-leap"], +    require     => Package['unattended-upgrades'], +    refresh_apt => false, +  } +  } diff --git a/puppet/modules/site_apt/templates/50unattended-upgrades b/puppet/modules/site_apt/templates/50unattended-upgrades deleted file mode 100644 index 9ae3ab84..00000000 --- a/puppet/modules/site_apt/templates/50unattended-upgrades +++ /dev/null @@ -1,16 +0,0 @@ -// this file is managed by puppet ! - -Unattended-Upgrade::Allowed-Origins { -        "${distro_id}:oldstable"; -        "${distro_id}:${distro_codename}-security"; -        "${distro_id}:${distro_codename}-updates"; -        "${distro_id} Backports:${distro_codename}-backports"; -        "leap.se:stable"; -}; - -APT::Periodic::Update-Package-Lists "1"; -APT::Periodic::Download-Upgradeable-Packages "1"; -APT::Periodic::Unattended-Upgrade "1"; - -Unattended-Upgrade::Mail "root"; -Unattended-Upgrade::MailOnlyOnError "true"; diff --git a/puppet/modules/site_apt/templates/jessie/postfix.seeds b/puppet/modules/site_apt/templates/jessie/postfix.seeds new file mode 100644 index 00000000..1a878ccc --- /dev/null +++ b/puppet/modules/site_apt/templates/jessie/postfix.seeds @@ -0,0 +1 @@ +postfix	postfix/main_mailer_type	select	No configuration diff --git a/puppet/modules/site_apt/templates/secondary.list b/puppet/modules/site_apt/templates/secondary.list index 41334b0b..0c024549 100644 --- a/puppet/modules/site_apt/templates/secondary.list +++ b/puppet/modules/site_apt/templates/secondary.list @@ -1,3 +1,3 @@  # basic -deb http://ftp.debian.org/debian/ <%= lsbdistcodename %> main contrib non-free +deb http://ftp.debian.org/debian/ <%= @lsbdistcodename %> main contrib non-free diff --git a/puppet/modules/site_check_mk/files/agent/local_checks/couchdb/leap_couch_stats.sh b/puppet/modules/site_check_mk/files/agent/local_checks/couchdb/leap_couch_stats.sh index 83b407e0..c7477b18 100755 --- a/puppet/modules/site_check_mk/files/agent/local_checks/couchdb/leap_couch_stats.sh +++ b/puppet/modules/site_check_mk/files/agent/local_checks/couchdb/leap_couch_stats.sh @@ -11,7 +11,7 @@ start_time=$(date +%s.%N)  CURL='curl -s --netrc-file /etc/couchdb/couchdb.netrc'  URL='http://127.0.0.1:5984'  TMPFILE=$(mktemp) -DBLIST_EXCLUDE='(user-|sessions_|tokens_)' +DBLIST_EXCLUDE='(user-|sessions_|tokens_|_replicator|_users)'  PREFIX='Couchdb_' @@ -104,7 +104,7 @@ do  done  # special handling for rotated dbs -suffix=$(($(date +'%s') / (60*60*24*30) + 1)) +suffix=$(($(date +'%s') / (60*60*24*30)))  db_stats "sessions_${suffix}" "sessions"  db_stats "tokens_${suffix}" "tokens" 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 index b8687c9a..4711e247 100755 --- 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 @@ -12,7 +12,7 @@ STATUS[1]='Warning'  STATUS[2]='Critical'  CHECKNAME='Leap_MX_Queue' -WATCHDIR='/var/mail/vmail/Maildir/new/' +WATCHDIR='/var/mail/leap-mx/Maildir/new/'  total=`find $WATCHDIR -type f -mmin +$MAXAGE | wc -l` diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg index 95ddd2ca..0f378a5a 100644 --- a/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg +++ b/puppet/modules/site_check_mk/files/agent/logwatch/bigcouch.cfg @@ -6,7 +6,7 @@   I 127.0.0.1 localhost:5984 .* ok   # https://leap.se/code/issues/5246   I Shutting down group server - # ignore bigcouch conflict errors, mainly coming from tapicero creating new users + # ignore bigcouch conflict errors   I Error in process.*{{nocatch,conflict}   # ignore "Uncaught error in HTTP request: {exit, normal}" error   # it's suppressed in later versions of bigcouch anhow diff --git a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/bigcouch.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/bigcouch.cfg new file mode 100644 index 00000000..f53f0780 --- /dev/null +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/bigcouch.cfg @@ -0,0 +1,5 @@ +# 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/couchdb.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg index f546135a..5f8d5b95 100644 --- a/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg +++ b/puppet/modules/site_check_mk/files/agent/logwatch/syslog/couchdb.cfg @@ -1,7 +1,2 @@   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/tapicero.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/tapicero.cfg deleted file mode 100644 index d98f5094..00000000 --- a/puppet/modules/site_check_mk/files/agent/logwatch/tapicero.cfg +++ /dev/null @@ -1,11 +0,0 @@ -/var/log/leap/tapicero.log -# Ignore transient Tapicero errors when creating a db (#6511) - I tapicero.*(Creating database|Checking security of|Writing security to|Uploading design doc to) user-.* failed (\(trying again soon\)|(twice )?due to): (RestClient::ResourceNotFound|RestClient::InternalServerError): (404 Resource Not Found|500 Internal Server Error) - 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/webapp.cfg b/puppet/modules/site_check_mk/files/agent/logwatch/webapp.cfg index 008e9e09..337d9ec6 100644 --- a/puppet/modules/site_check_mk/files/agent/logwatch/webapp.cfg +++ b/puppet/modules/site_check_mk/files/agent/logwatch/webapp.cfg @@ -1,5 +1,7 @@  /var/log/leap/webapp.log  # check for webapp errors + C Completed 500 +# couch connection issues   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 diff --git a/puppet/modules/site_check_mk/files/extra_host_conf.mk b/puppet/modules/site_check_mk/files/extra_host_conf.mk deleted file mode 100644 index 2c96f97a..00000000 --- a/puppet/modules/site_check_mk/files/extra_host_conf.mk +++ /dev/null @@ -1,6 +0,0 @@ -# retry 3 times before setting a host into a hard state -# and send out notification -extra_host_conf["max_check_attempts"] = [  -  ("4", ALL_HOSTS )  -] - diff --git a/puppet/modules/site_check_mk/manifests/agent.pp b/puppet/modules/site_check_mk/manifests/agent.pp index 589041eb..b95d5d64 100644 --- a/puppet/modules/site_check_mk/manifests/agent.pp +++ b/puppet/modules/site_check_mk/manifests/agent.pp @@ -1,17 +1,24 @@ +# installs check-mk agent  class site_check_mk::agent {    $ssh_hash = hiera('ssh')    $pubkey   = $ssh_hash['authorized_keys']['monitor']['key']    $type     = $ssh_hash['authorized_keys']['monitor']['type'] + +  # /usr/bin/mk-job depends on /usr/bin/time +  ensure_packages('time') +    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 +    authdir                     => '/root/.ssh', +    authfile                    => 'authorized_keys', +    register_agent              => false, +    require                     => Package['time']    } ->    class { 'site_check_mk::agent::mrpe': } -> diff --git a/puppet/modules/site_check_mk/manifests/agent/couchdb.pp b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp index abfc7ad0..1554fd3c 100644 --- a/puppet/modules/site_check_mk/manifests/agent/couchdb.pp +++ b/puppet/modules/site_check_mk/manifests/agent/couchdb.pp @@ -1,32 +1,18 @@ +# configure logwatch and nagios checks for couchdb (both bigcouch and plain +# couchdb installations)  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 -  augeas { -    'Bigcouch_epmd_procs': -      incl    => '/etc/check_mk/mrpe.cfg', -      lens    => 'Spacevars.lns', -      changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_epmd_procs', -        'set Bigcouch_epmd_procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/epmd\'' ], -      require => File['/etc/check_mk/mrpe.cfg']; -    'Bigcouch_beam_procs': -      incl    => '/etc/check_mk/mrpe.cfg', -      lens    => 'Spacevars.lns', -      changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_beam_procs', -        'set Bigcouch_beam_procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/beam\'' ], -      require => File['/etc/check_mk/mrpe.cfg']; +  # check different couchdb stats +  file { '/usr/lib/check_mk_agent/local/leap_couch_stats.sh': +    source  => 'puppet:///modules/site_check_mk/agent/local_checks/couchdb/leap_couch_stats.sh', +    mode    => '0755', +    require => Package['check_mk-agent']    }    # check open files for bigcouch proc @@ -36,20 +22,13 @@ class site_check_mk::agent::couchdb {      mode   => '0755'    }    augeas { -    'Bigcouch_open_files': +    'Couchdb_open_files':        incl    => '/etc/check_mk/mrpe.cfg',        lens    => 'Spacevars.lns',        changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_open_files', -        'set Bigcouch_open_files \'/srv/leap/nagios/plugins/check_unix_open_fds.pl -a beam -w 28672,28672 -c 30720,30720\'' ], +        'rm /files/etc/check_mk/mrpe.cfg/Couchdb_open_files', +        'set Couchdb_open_files \'/srv/leap/nagios/plugins/check_unix_open_fds.pl -a beam -w 28672,28672 -c 30720,30720\'' ],        require => File['/etc/check_mk/mrpe.cfg'];    } - -  # check different couchdb stats -  file { '/usr/lib/check_mk_agent/local/leap_couch_stats.sh': -    source  => 'puppet:///modules/site_check_mk/agent/local_checks/couchdb/leap_couch_stats.sh', -    mode    => '0755', -    require => Package['check_mk-agent'] -  }  } diff --git a/puppet/modules/site_check_mk/manifests/agent/couchdb/bigcouch.pp b/puppet/modules/site_check_mk/manifests/agent/couchdb/bigcouch.pp new file mode 100644 index 00000000..82c3ac72 --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/couchdb/bigcouch.pp @@ -0,0 +1,49 @@ +# configure logwatch and nagios checks for bigcouch +class site_check_mk::agent::couchdb::bigcouch { + +  # watch bigcouch logs +  # currently disabled because bigcouch is too noisy +  # see https://leap.se/code/issues/7375 for more details +  # and site_config::remove_files for removing leftovers +  #file { '/etc/check_mk/logwatch.d/bigcouch.cfg': +  #  source => 'puppet:///modules/site_check_mk/agent/logwatch/bigcouch.cfg', +  #} + +  # check syslog msg from: +  # - empd +  # - /usr/local/bin/couch-doc-update +  concat::fragment { 'syslog_bigcouch': +    source  => 'puppet:///modules/site_check_mk/agent/logwatch/syslog/bigcouch.cfg', +    target  => '/etc/check_mk/logwatch.d/syslog.cfg', +    order   => '02'; +  } + +  # check bigcouch processes +  augeas { +    'Bigcouch_epmd_procs': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => [ +        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_epmd_procs', +        'set Bigcouch_epmd_procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/epmd\'' ], +      require => File['/etc/check_mk/mrpe.cfg']; +    'Bigcouch_beam_procs': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => [ +        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_beam_procs', +        'set Bigcouch_beam_procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a /opt/bigcouch/erts-5.9.1/bin/beam\'' ], +      require => File['/etc/check_mk/mrpe.cfg']; +  } + +  augeas { +    'Bigcouch_open_files': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => [ +        'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_open_files', +        'set Bigcouch_open_files \'/srv/leap/nagios/plugins/check_unix_open_fds.pl -a beam -w 28672,28672 -c 30720,30720\'' ], +      require => File['/etc/check_mk/mrpe.cfg']; +  } + +} diff --git a/puppet/modules/site_check_mk/manifests/agent/couchdb/plain.pp b/puppet/modules/site_check_mk/manifests/agent/couchdb/plain.pp new file mode 100644 index 00000000..3ec2267b --- /dev/null +++ b/puppet/modules/site_check_mk/manifests/agent/couchdb/plain.pp @@ -0,0 +1,23 @@ +# configure logwatch and nagios checks for plain single couchdb master +class site_check_mk::agent::couchdb::plain { + +  # remove bigcouch leftovers +  augeas { +    'Bigcouch_epmd_procs': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_epmd_procs', +      require => File['/etc/check_mk/mrpe.cfg']; +    'Bigcouch_beam_procs': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_beam_procs', +      require => File['/etc/check_mk/mrpe.cfg']; +    'Bigcouch_open_files': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Bigcouch_open_files', +      require => File['/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 index 98757b59..20cbcade 100644 --- a/puppet/modules/site_check_mk/manifests/agent/mx.pp +++ b/puppet/modules/site_check_mk/manifests/agent/mx.pp @@ -1,3 +1,4 @@ +# check check_mk agent checks for mx service  class site_check_mk::agent::mx {    # watch logs @@ -6,13 +7,13 @@ class site_check_mk::agent::mx {    }    # local nagios plugin checks via mrpe +  # removed because leap_cli integrates a check for running mx procs already, +  # which is also integrated into nagios (called "Mx/Are_MX_daemons_running")    augeas {      'Leap_MX_Procs':        incl    => '/etc/check_mk/mrpe.cfg',        lens    => 'Spacevars.lns', -      changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Leap_MX_Procs', -        'set Leap_MX_Procs \'/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 -a "/usr/bin/python /usr/bin/twistd --pidfile=/var/run/leap_mx.pid --rundir=/var/lib/leap_mx/ --python=/usr/share/app/leap_mx.tac --logfile=/var/log/leap/mx.log"\'' ], +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Leap_MX_Procs',        require => File['/etc/check_mk/mrpe.cfg'];    } diff --git a/puppet/modules/site_check_mk/manifests/agent/tapicero.pp b/puppet/modules/site_check_mk/manifests/agent/tapicero.pp deleted file mode 100644 index 8505b34a..00000000 --- a/puppet/modules/site_check_mk/manifests/agent/tapicero.pp +++ /dev/null @@ -1,26 +0,0 @@ -# sets up tapicero monitoring -class site_check_mk::agent::tapicero { - -  include ::site_nagios::plugins - -  # watch logs -  file { '/etc/check_mk/logwatch.d/tapicero.cfg': -    source => 'puppet:///modules/site_check_mk/agent/logwatch/tapicero.cfg', -  } - -  # local nagios plugin checks via mrpe -  augeas { -    'Tapicero_Procs': -      incl    => '/etc/check_mk/mrpe.cfg', -      lens    => 'Spacevars.lns', -      changes => [ -        'rm /files/etc/check_mk/mrpe.cfg/Tapicero_Procs', -        "set Tapicero_Procs \"/usr/lib/nagios/plugins/check_procs -w 1:1 -c 1:1 --ereg-argument-array='^tapicero$'\"" ], -      require => File['/etc/check_mk/mrpe.cfg']; -    'Tapicero_Heartbeat': -      incl    => '/etc/check_mk/mrpe.cfg', -      lens    => 'Spacevars.lns', -      changes => 'set Tapicero_Heartbeat \'/usr/local/lib/nagios/plugins/check_last_regex_in_log -f /var/log/leap/tapicero.log -r "tapicero" -w 1200 -c 2400\'', -      require => File['/etc/check_mk/mrpe.cfg']; -  } -} diff --git a/puppet/modules/site_check_mk/manifests/server.pp b/puppet/modules/site_check_mk/manifests/server.pp index 67519513..7ff9eb4a 100644 --- a/puppet/modules/site_check_mk/manifests/server.pp +++ b/puppet/modules/site_check_mk/manifests/server.pp @@ -17,20 +17,35 @@ class site_check_mk::server {      ensure => installed,    } +  # we don't use check-mk-multisite, and the jessie version +  # of this config file breaks with apache 2.4 +  # until https://gitlab.com/shared-puppet-modules-group/apache/issues/11 +  # is not fixed, we need to use a generic file type here +  #apache::config::global { 'check-mk-multisite.conf': +  #  ensure => absent +  #} + +  file { '/etc/apache2/conf-enabled/check-mk-multisite.conf': +    ensure  => absent, +    require => Package['check-mk-server']; +  } +    # 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'] +    site                      => '', +    etc_dir                   => '/etc', +    nagios_subdir             => 'nagios3', +    bin_dir                   => '/usr/bin', +    host_groups               => undef, +    use_storedconfigs         => false, +    inventory_only_on_changes => false, +    require                   => Package['check-mk-server']    } -  Exec['check_mk-reload'] -> +  Exec['check_mk-refresh'] ->      Exec['check_mk-refresh-inventory-daily'] -> -    Service['nagios'] +      Exec['check_mk-reload'] -> +        Service['nagios']    file {      '/etc/check_mk/conf.d/use_ssh.mk': @@ -54,7 +69,7 @@ class site_check_mk::server {        notify  => Exec['check_mk-refresh'],        require => Package['check-mk-server'];      '/etc/check_mk/conf.d/extra_host_conf.mk': -      source  => 'puppet:///modules/site_check_mk/extra_host_conf.mk', +      content => template('site_check_mk/extra_host_conf.mk'),        notify  => Exec['check_mk-refresh'],        require => Package['check-mk-server']; diff --git a/puppet/modules/site_check_mk/templates/extra_host_conf.mk b/puppet/modules/site_check_mk/templates/extra_host_conf.mk new file mode 100644 index 00000000..bc27b514 --- /dev/null +++ b/puppet/modules/site_check_mk/templates/extra_host_conf.mk @@ -0,0 +1,13 @@ +# retry 3 times before setting a host into a hard state +# and send out notification +extra_host_conf["max_check_attempts"] = [ +  ("4", ALL_HOSTS ) +] + +# Use hostnames as alias so notification mail subjects +# are more readable and not so long. Alias defaults to +# the fqdn of a host is not changed. +extra_host_conf["alias"] = [ +<% @hosts.keys.sort.each do |key| -%>  ( "<%= key.strip %>", ["<%= @hosts[key]['domain_internal']%>"]), +<% end -%> +] diff --git a/puppet/modules/site_check_mk/templates/use_ssh.mk b/puppet/modules/site_check_mk/templates/use_ssh.mk index 0bebebcf..55269536 100644 --- a/puppet/modules/site_check_mk/templates/use_ssh.mk +++ b/puppet/modules/site_check_mk/templates/use_ssh.mk @@ -1,6 +1,6 @@  # http://mathias-kettner.de/checkmk_datasource_programs.html  datasource_programs = [ -<% nagios_hosts.sort.each do |name,config| %> +<% @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 cdebbad0..8bf465c1 100644 --- a/puppet/modules/site_config/manifests/caching_resolver.pp +++ b/puppet/modules/site_config/manifests/caching_resolver.pp @@ -1,14 +1,13 @@ +# deploy local caching resolver  class site_config::caching_resolver {    tag 'leap_base' -  include site_apt::preferences::unbound -    class { 'unbound':      root_hints => false,      anchor     => false,      ssl        => false,      settings   => { -      server       => { +      server => {          verbosity      => '1',          interface      => [ '127.0.0.1', '::1' ],          port           => '53', diff --git a/puppet/modules/site_config/manifests/default.pp b/puppet/modules/site_config/manifests/default.pp index e69e4b7b..256de1a1 100644 --- a/puppet/modules/site_config/manifests/default.pp +++ b/puppet/modules/site_config/manifests/default.pp @@ -1,19 +1,11 @@ +# common things to set up on every node  class site_config::default {    tag 'leap_base' -  # the logoutput exec parameter defaults to "on_error" in puppet 3, -  # but to "false" in puppet 2.7, so we need to set this globally here -  Exec<||> { logoutput => on_failure } -    $services    = hiera('services', [])    $domain_hash = hiera('domain')    include site_config::params - -  # make sure apt is updated before any packages are installed -  include apt::update -  Package { require => Exec['apt_updated'] } - -  include site_config::slow +  include site_config::setup    # default class, used by all hosts @@ -29,7 +21,10 @@ class site_config::default {    # i.e. openstack/aws nodes, vagrant nodes    # fix dhclient from changing resolver information -   if $::dhcp_enabled == 'true' { +  # facter returns 'true' as string +  # lint:ignore:quoted_booleans +  if $::dhcp_enabled == 'true' { +  # lint:endignore      include site_config::dhclient    } @@ -46,7 +41,7 @@ class site_config::default {    include haveged    # install/remove base packages -  include site_config::packages::base +  include site_config::packages    # include basic shorewall config    include site_shorewall::defaults @@ -58,7 +53,9 @@ class site_config::default {    # set up core leap files and directories    include site_config::files -  include site_config::remove_files + +  # remove leftovers from previous deploys +  include site_config::remove    if ! member($services, 'mx') {      include site_postfix::satellite diff --git a/puppet/modules/site_config/manifests/dhclient.pp b/puppet/modules/site_config/manifests/dhclient.pp index 7755413b..a1f87d41 100644 --- a/puppet/modules/site_config/manifests/dhclient.pp +++ b/puppet/modules/site_config/manifests/dhclient.pp @@ -1,10 +1,10 @@ +# Unfortunately, there does not seem to be a way to reload the dhclient.conf +# config file, or a convenient way to disable the modifications to +# /etc/resolv.conf. So the following makes the functions involved noops and +# ships a script to kill and restart dhclient. See the debian bugs: +# #681698, #712796  class site_config::dhclient { -  # Unfortunately, there does not seem to be a way to reload the dhclient.conf -  # config file, or a convenient way to disable the modifications to -  # /etc/resolv.conf. So the following makes the functions involved noops and -  # ships a script to kill and restart dhclient. See the debian bugs: -  # #681698, #712796    include site_config::params @@ -23,10 +23,10 @@ class site_config::dhclient {    }    file { '/etc/dhcp/dhclient-enter-hooks.d': -    ensure  => directory, -    mode    => '0755', -    owner   => 'root', -    group   => 'root', +    ensure => directory, +    mode   => '0755', +    owner  => 'root', +    group  => 'root',    }    file { '/etc/dhcp/dhclient-enter-hooks.d/disable_resolvconf': diff --git a/puppet/modules/site_config/manifests/files.pp b/puppet/modules/site_config/manifests/files.pp index 684d3ad0..d2ef8a98 100644 --- a/puppet/modules/site_config/manifests/files.pp +++ b/puppet/modules/site_config/manifests/files.pp @@ -1,3 +1,4 @@ +# set up core leap files and directories  class site_config::files {    file { @@ -7,15 +8,15 @@ class site_config::files {        group   => 'root',        mode    => '0711'; -    '/var/lib/leap': +    [ '/etc/leap', '/var/lib/leap']:        ensure => directory, -      owner  => root, +      owner  => 'root',        group  => 'root',        mode   => '0755';      '/var/log/leap':        ensure => directory, -      owner  => root, +      owner  => 'root',        group  => 'adm',        mode   => '0750';    } diff --git a/puppet/modules/site_config/manifests/packages.pp b/puppet/modules/site_config/manifests/packages.pp new file mode 100644 index 00000000..140189a4 --- /dev/null +++ b/puppet/modules/site_config/manifests/packages.pp @@ -0,0 +1,32 @@ +# install default packages and remove unwanted packages +class site_config::packages { + + +  # base set of packages that we want to have installed everywhere +  package { [ 'etckeeper', 'screen', 'less', 'ntp' ]: +    ensure => installed, +  } + +  # base set of packages that we want to remove everywhere +  package { [ +    'acpi', 'build-essential', +    'cpp', 'cpp-4.6', 'cpp-4.7', 'cpp-4.8', 'cpp-4.9', +    'eject', 'ftp', +    'g++', 'g++-4.6', 'g++-4.7', 'g++-4.8', 'g++-4.9', +    'gcc', 'gcc-4.6', 'gcc-4.7', 'gcc-4.8', 'gcc-4.9', +    'laptop-detect', 'libc6-dev', 'libssl-dev', 'lpr', 'make', +    'pppconfig', 'pppoe', 'pump', 'qstat', +    'samba-common', 'samba-common-bin', 'smbclient', +    'tcl8.5', 'tk8.5', 'os-prober', 'unzip', 'xauth', 'x11-common', +    'x11-utils', 'xterm' ]: +      ensure => purged; +  } + +  # leave a few packages installed on local environments +  # vagrant i.e. needs them for mounting shared folders +    if $::site_config::params::environment != 'local' { +    package { [ 'nfs-common', 'nfs-kernel-server', 'rpcbind', 'portmap' ]: +      ensure => purged; +    } +  } +} diff --git a/puppet/modules/site_config/manifests/packages/base.pp b/puppet/modules/site_config/manifests/packages/base.pp deleted file mode 100644 index c23495fc..00000000 --- a/puppet/modules/site_config/manifests/packages/base.pp +++ /dev/null @@ -1,19 +0,0 @@ -# install default packages and remove unwanted packages -class site_config::packages::base { - - -  # base set of packages that we want to have installed everywhere -  package { [ 'etckeeper', 'screen', 'less', 'ntp' ]: -    ensure => installed, -  } - -  # base set of packages that we want to remove everywhere -  package { [ 'acpi', 'eject', 'ftp', -              'laptop-detect', 'lpr', 'nfs-common', 'nfs-kernel-server', -              'portmap', 'pppconfig', 'pppoe', 'pump', 'qstat', 'rpcbind', -              'samba-common', 'samba-common-bin', 'smbclient', 'tcl8.5', -              'tk8.5', 'os-prober', 'unzip', 'xauth', 'x11-common', -              'x11-utils', 'xterm' ]: -    ensure => absent; -  } -} diff --git a/puppet/modules/site_config/manifests/packages/build_essential.pp b/puppet/modules/site_config/manifests/packages/build_essential.pp index 7dfb8b03..2b3e13b9 100644 --- a/puppet/modules/site_config/manifests/packages/build_essential.pp +++ b/puppet/modules/site_config/manifests/packages/build_essential.pp @@ -1,11 +1,28 @@  #  # 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']: +class site_config::packages::build_essential inherits ::site_config::packages { + +  # NICKSERVER CODE NOTE: in order to support TLS, libssl-dev must be installed +  # before EventMachine gem is built/installed. +  Package[ 'gcc', 'make', 'g++', 'cpp', 'libssl-dev', 'libc6-dev' ] { +    ensure => present +  } + +  case $::operatingsystemrelease { +    /^8.*/: { +      Package[ 'gcc-4.9','g++-4.9', 'cpp-4.9' ] { +        ensure => present +      } +    } + +    /^7.*/: { +      Package[ 'gcc-4.7','g++-4.7', 'cpp-4.7' ] {          ensure => present +      }      } + +    default:  { }    } -}
\ No newline at end of file + +} diff --git a/puppet/modules/site_config/manifests/packages/uninstall.pp b/puppet/modules/site_config/manifests/packages/uninstall.pp deleted file mode 100644 index 12f527d9..00000000 --- a/puppet/modules/site_config/manifests/packages/uninstall.pp +++ /dev/null @@ -1,16 +0,0 @@ -# -# 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/remove.pp b/puppet/modules/site_config/manifests/remove.pp new file mode 100644 index 00000000..443df9c2 --- /dev/null +++ b/puppet/modules/site_config/manifests/remove.pp @@ -0,0 +1,11 @@ +# remove leftovers from previous deploys +class site_config::remove { +  include site_config::remove::files + +  case $::operatingsystemrelease { +    /^8.*/: { +      include site_config::remove::jessie +    } +    default:  { } +  } +} diff --git a/puppet/modules/site_config/manifests/remove/bigcouch.pp b/puppet/modules/site_config/manifests/remove/bigcouch.pp new file mode 100644 index 00000000..3535c3c1 --- /dev/null +++ b/puppet/modules/site_config/manifests/remove/bigcouch.pp @@ -0,0 +1,42 @@ +# remove bigcouch leftovers from previous installations +class site_config::remove::bigcouch { + +  # Don't use check_mk logwatch to watch bigcouch logs anymore +  # see https://leap.se/code/issues/7375 for more details +  file { '/etc/check_mk/logwatch.d/bigcouch.cfg': +    ensure => absent, +    notify => [ +      Exec['remove_bigcouch_logwatch_stateline'] +    ] +  } + +  exec { 'remove_bigcouch_logwatch_stateline': +    command     => "sed -i '/bigcouch.log/d' /etc/check_mk/logwatch.state", +    refreshonly => true, +  } + +  cron { 'compact_all_shards': +    ensure => absent +  } + + +  exec { 'kill_bigcouch_stunnel_procs': +    refreshonly => true, +    command     => '/usr/bin/pkill -f "/usr/bin/stunnel4 /etc/stunnel/(ednp|epmd)_server.conf"' +  } + +  # 'tidy' doesn't notify other resources, so we need to use file here instead +  # see https://tickets.puppetlabs.com/browse/PUP-6021 +  file { +    [ '/etc/stunnel/ednp_server.conf', '/etc/stunnel/epmd_server.conf']: +      ensure => absent, +      # notifying Service[stunnel] doesn't work here because the config +      # files contain the pid of the procs to stop/start. +      # If we remove the config, and restart stunnel then it will only +      # stop/start the procs for which config files are found and the stale +      # service will continue to run. +      # So we simply kill them. +      notify => Exec['kill_bigcouch_stunnel_procs'] +  } + +} diff --git a/puppet/modules/site_config/manifests/remove_files.pp b/puppet/modules/site_config/manifests/remove/files.pp index b339e6af..41d6462e 100644 --- a/puppet/modules/site_config/manifests/remove_files.pp +++ b/puppet/modules/site_config/manifests/remove/files.pp @@ -9,7 +9,16 @@  # release.  # -class site_config::remove_files { +class site_config::remove::files { + +  # Platform 0.8 removals +  tidy { +    '/etc/default/leap_mx':; +    '/etc/logrotate.d/mx':; +    '/etc/rsyslog.d/50-mx.conf':; +    '/etc/apt/preferences.d/openvpn':; +    '/etc/apt/sources.list.d/secondary.list.disabled.list':; +  }    #    # Platform 0.7 removals @@ -17,24 +26,22 @@ class site_config::remove_files {    tidy {      '/etc/rsyslog.d/99-tapicero.conf':; -    '/etc/rsyslog.d/99-leap-mx.conf':;      '/etc/rsyslog.d/01-webapp.conf':;      '/etc/rsyslog.d/50-stunnel.conf':; -    '/etc/logrotate.d/mx':;      '/etc/logrotate.d/stunnel':;      '/var/log/stunnel4/stunnel.log':;      'leap_mx':        path => '/var/log/',        recurse => true, -      matches => 'leap_mx*'; -    'leap_mx_rotate': -      path => '/var/log/leap/', -      recurse => true, -      matches => [ 'mx.log.[0-9]', 'mx.log.[0-9]?', 'mx.log.[6-9]?gz']; +      matches => ['leap_mx*', 'mx.log.[1-5]', 'mx.log.[6-9](.gz)?', +                  'mx.log.[0-9][0-9](.gz)?'];      '/srv/leap/webapp/public/provider.json':;      '/srv/leap/couchdb/designs/tmp_users':        recurse => true,        rmdirs => true; +    '/etc/leap/soledad-server.conf':; +    '/var/log/leap/openvpn.log':; +    '/etc/rsyslog.d/50-openvpn.conf':;    }    # leax-mx logged to /var/log/leap_mx.log in the past @@ -46,5 +53,4 @@ class site_config::remove_files {        onlyif  => "/bin/grep -qe 'leap_mx.log' /etc/check_mk/logwatch.state"    } -  } diff --git a/puppet/modules/site_config/manifests/remove/jessie.pp b/puppet/modules/site_config/manifests/remove/jessie.pp new file mode 100644 index 00000000..e9497baf --- /dev/null +++ b/puppet/modules/site_config/manifests/remove/jessie.pp @@ -0,0 +1,14 @@ +# remove possible leftovers after upgrading from wheezy to jessie +class site_config::remove::jessie { + +  tidy { +    '/etc/apt/preferences.d/rsyslog_anon_depends': +      notify => Exec['apt_updated']; +  } + +  apt::preferences_snippet { +    [ 'facter', 'obfsproxy', 'python-twisted', 'unbound' ]: +      ensure => absent; +  } + +} diff --git a/puppet/modules/site_config/manifests/remove/monitoring.pp b/puppet/modules/site_config/manifests/remove/monitoring.pp new file mode 100644 index 00000000..18e2949b --- /dev/null +++ b/puppet/modules/site_config/manifests/remove/monitoring.pp @@ -0,0 +1,13 @@ +# remove leftovers on monitoring nodes +class site_config::remove::monitoring { + +  # Remove check_mk loggwatch spoolfiles for +  # tapicero and bigcouch +  tidy { +    'remove_logwatch_spoolfiles': +      path    => '/var/lib/check_mk/logwatch', +      recurse => true, +      matches => [ '*tapicero.log', '*bigcouch.log']; +  } + +} diff --git a/puppet/modules/site_config/manifests/remove/tapicero.pp b/puppet/modules/site_config/manifests/remove/tapicero.pp new file mode 100644 index 00000000..07c3c6c6 --- /dev/null +++ b/puppet/modules/site_config/manifests/remove/tapicero.pp @@ -0,0 +1,72 @@ +# remove tapicero leftovers from previous deploys on couchdb nodes +class site_config::remove::tapicero { + +  ensure_packages('curl') + +  # remove tapicero couchdb user +  $couchdb_config = hiera('couch') +  $couchdb_mode   = $couchdb_config['mode'] + +  if $couchdb_mode == 'multimaster' +  { +    $port = 5986 +  } else { +    $port = 5984 +  } + +  exec { 'remove_couchdb_user': +    onlyif  => "/usr/bin/curl -s 127.0.0.1:${port}/_users/org.couchdb.user:tapicero | grep -qv 'not_found'", +    command => "/usr/local/bin/couch-doc-update --host 127.0.0.1:${port} --db _users --id org.couchdb.user:tapicero --delete", +    require => Package['curl'] +  } + + +  exec { 'kill_tapicero': +    onlyif  => '/usr/bin/test -s /var/run/tapicero.pid', +    command => '/usr/bin/pkill --pidfile /var/run/tapicero.pid' +  } + +  user { 'tapicero': +    ensure  => absent; +  } + +  group { 'tapicero': +    ensure => absent, +    require => User['tapicero']; +  } + +  tidy { +    '/srv/leap/tapicero': +      recurse => true, +      require   => [ Exec['kill_tapicero'] ]; +    '/var/lib/leap/tapicero': +      require   => [ Exec['kill_tapicero'] ]; +    '/var/run/tapicero': +      require   => [ Exec['kill_tapicero'] ]; +    '/etc/leap/tapicero.yaml': +      require   => [ Exec['kill_tapicero'] ]; +    '/etc/init.d/tapicero': +      require   => [ Exec['kill_tapicero'] ]; +    'tapicero_logs': +      path    => '/var/log/leap', +      recurse => true, +      matches => 'tapicero*', +      require   => [ Exec['kill_tapicero'] ]; +    '/etc/check_mk/logwatch.d/tapicero.cfg':; +  } + +  # remove local nagios plugin checks via mrpe +  augeas { +    'Tapicero_Procs': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => 'rm /files/etc/check_mk/mrpe.cfg/Tapicero_Procs', +      require => File['/etc/check_mk/mrpe.cfg']; +    'Tapicero_Heartbeat': +      incl    => '/etc/check_mk/mrpe.cfg', +      lens    => 'Spacevars.lns', +      changes => 'rm Tapicero_Heartbeat', +      require => File['/etc/check_mk/mrpe.cfg']; +  } + +} diff --git a/puppet/modules/site_config/manifests/remove/webapp.pp b/puppet/modules/site_config/manifests/remove/webapp.pp new file mode 100644 index 00000000..58f59815 --- /dev/null +++ b/puppet/modules/site_config/manifests/remove/webapp.pp @@ -0,0 +1,7 @@ +# remove leftovers on webapp nodes +class site_config::remove::webapp { +  tidy { +    '/etc/apache/sites-enabled/leap_webapp.conf': +      notify => Service['apache']; +  } +} diff --git a/puppet/modules/site_config/manifests/resolvconf.pp b/puppet/modules/site_config/manifests/resolvconf.pp index 05990c67..09f0b405 100644 --- a/puppet/modules/site_config/manifests/resolvconf.pp +++ b/puppet/modules/site_config/manifests/resolvconf.pp @@ -8,7 +8,7 @@ class site_config::resolvconf {      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)' +      '172.81.176.146 # OpenNIC (https://servers.opennicproject.org/edit.php?srv=ns1.tor.ca.dns.opennic.glue)'      ]    }  } diff --git a/puppet/modules/site_config/manifests/ruby.pp b/puppet/modules/site_config/manifests/ruby.pp index 2a720114..5c13233d 100644 --- a/puppet/modules/site_config/manifests/ruby.pp +++ b/puppet/modules/site_config/manifests/ruby.pp @@ -1,14 +1,8 @@ +# install ruby, rubygems and bundler +# configure ruby settings common to all servers  class site_config::ruby {    Class[Ruby] -> Class[rubygems] -> Class[bundler::install] -  class { '::ruby': ruby_version => '1.9.3' } +  class { '::ruby': }    class { 'bundler::install': install_method => 'package' }    include rubygems  } - - -# -# Ruby settings common to all servers -# -# Why this way? So that other classes can do 'include site_ruby' without creating redeclaration errors. -# See https://puppetlabs.com/blog/modeling-class-composition-with-parameterized-classes/ -# diff --git a/puppet/modules/site_config/manifests/ruby/dev.pp b/puppet/modules/site_config/manifests/ruby/dev.pp index 3ea6ca96..2b0b106d 100644 --- a/puppet/modules/site_config/manifests/ruby/dev.pp +++ b/puppet/modules/site_config/manifests/ruby/dev.pp @@ -1,8 +1,8 @@ -class site_config::ruby::dev inherits site_config::ruby { -  Class['::ruby'] { -    ruby_version => '1.9.3', -    install_dev  => true -  } +# install ruby dev packages needed for building some gems +class site_config::ruby::dev { +  include site_config::ruby +  include ::ruby::devel +    # 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 index b09d0413..82dfe76d 100644 --- a/puppet/modules/site_config/manifests/setup.pp +++ b/puppet/modules/site_config/manifests/setup.pp @@ -1,3 +1,7 @@ +# common things to set up on every node +# leftover from the past, where we did two puppetruns +# after another. We should consolidate this into site_config::default +# in the future.  class site_config::setup {    tag 'leap_base' @@ -13,17 +17,14 @@ class site_config::setup {    include stdlib    # configure /etc/hosts -  class { 'site_config::hosts': -    stage => setup, -  } +  class { 'site_config::hosts': }    include site_config::initial_firewall    include site_apt    package { 'facter': -    ensure  => latest, -    require => Exec['refresh_apt'] +    ensure  => latest    }    # if squid_deb_proxy_client is set to true, install and configure diff --git a/puppet/modules/site_config/manifests/slow.pp b/puppet/modules/site_config/manifests/slow.pp index 94bac88d..8e9b7035 100644 --- a/puppet/modules/site_config/manifests/slow.pp +++ b/puppet/modules/site_config/manifests/slow.pp @@ -1,6 +1,10 @@ +# this class is run by default, but can be excluded +# for testing purposes by calling "leap deploy" with +# the "--fast" parameter  class site_config::slow {    tag 'leap_slow' -  class { 'site_apt::dist_upgrade': -    stage => setup, -  } + +  include site_config::default +  include apt::update +  class { 'site_apt::dist_upgrade': }  } diff --git a/puppet/modules/site_config/manifests/syslog.pp b/puppet/modules/site_config/manifests/syslog.pp index 83b49c8e..591e0601 100644 --- a/puppet/modules/site_config/manifests/syslog.pp +++ b/puppet/modules/site_config/manifests/syslog.pp @@ -1,10 +1,31 @@ +# configure rsyslog on all nodes  class site_config::syslog { -  include site_apt::preferences::rsyslog +  # only pin rsyslog packages to backports on wheezy +  case $::operatingsystemrelease { +    /^7.*/: { +      include ::site_apt::preferences::rsyslog +    } +    # on jessie+ systems, systemd and journald are enabled, +    # and journald logs IP addresses, so we need to disable +    # it until a solution is found, (#7863): +    # https://github.com/systemd/systemd/issues/2447 +    default: { +      include ::journald +      augeas { +        'disable_journald': +          incl    => '/etc/systemd/journald.conf', +          lens    => 'Puppet.lns', +          changes => 'set /files/etc/systemd/journald.conf/Journal/Storage \'none\'', +          notify  => Service['systemd-journald']; +      } +    } +  } -  class { 'rsyslog::client': -    log_remote => false, -    log_local  => true +  class { '::rsyslog::client': +    log_remote    => false, +    log_local     => true, +    custom_config => 'site_rsyslog/client.conf.erb'    }    rsyslog::snippet { '00-anonymize_logs': @@ -15,12 +36,13 @@ action(type="mmanon" ipv4.bits="32" mode="rewrite")'    augeas {      'logrotate_leap_deploy':        context => '/files/etc/logrotate.d/leap_deploy/rule', -      changes => [ 'set file /var/log/leap/deploy.log', -                   'set rotate 5', -                   'set size 1M', -                   'set compress compress', -                   'set missingok missingok', -                   'set copytruncate copytruncate' ]; +      changes => [ +        'set file /var/log/leap/deploy.log', +        'set rotate 5', +        'set size 1M', +        'set compress compress', +        'set missingok missingok', +        'set copytruncate copytruncate' ];      # NOTE:      # the puppet_command script requires the option delaycompress @@ -28,12 +50,13 @@ action(type="mmanon" ipv4.bits="32" mode="rewrite")'      'logrotate_leap_deploy_summary':        context => '/files/etc/logrotate.d/leap_deploy_summary/rule', -      changes => [ 'set file /var/log/leap/deploy-summary.log', -                   'set rotate 5', -                   'set size 100k', -                   'set delaycompress delaycompress', -                   'set compress compress', -                   'set missingok missingok', -                   'set copytruncate copytruncate' ] +      changes => [ +        'set file /var/log/leap/deploy-summary.log', +        'set rotate 5', +        'set size 100k', +        'set delaycompress delaycompress', +        'set compress compress', +        'set missingok missingok', +        'set copytruncate copytruncate' ]    }  } diff --git a/puppet/modules/site_config/manifests/x509/ca.pp b/puppet/modules/site_config/manifests/x509/ca.pp index b16d0eeb..2880ecaf 100644 --- a/puppet/modules/site_config/manifests/x509/ca.pp +++ b/puppet/modules/site_config/manifests/x509/ca.pp @@ -1,5 +1,7 @@  class site_config::x509::ca { +  include ::site_config::params +    $x509      = hiera('x509')    $ca        = $x509['ca_cert'] diff --git a/puppet/modules/site_config/manifests/x509/ca_bundle.pp b/puppet/modules/site_config/manifests/x509/ca_bundle.pp index 4cbe574a..5808e29e 100644 --- a/puppet/modules/site_config/manifests/x509/ca_bundle.pp +++ b/puppet/modules/site_config/manifests/x509/ca_bundle.pp @@ -5,6 +5,7 @@ class site_config::x509::ca_bundle {    # 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. +  include ::site_config::params    $x509      = hiera('x509')    $ca        = $x509['ca_cert'] diff --git a/puppet/modules/site_config/manifests/x509/cert.pp b/puppet/modules/site_config/manifests/x509/cert.pp index 7ed42959..7e5a36b9 100644 --- a/puppet/modules/site_config/manifests/x509/cert.pp +++ b/puppet/modules/site_config/manifests/x509/cert.pp @@ -1,5 +1,7 @@  class site_config::x509::cert { +  include ::site_config::params +    $x509      = hiera('x509')    $cert      = $x509['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 index 0f313898..3fbafa98 100644 --- a/puppet/modules/site_config/manifests/x509/client_ca/ca.pp +++ b/puppet/modules/site_config/manifests/x509/client_ca/ca.pp @@ -5,6 +5,8 @@ class site_config::x509::client_ca::ca {    ## client certificates by the webapp.    ## +  include ::site_config::params +    $x509 = hiera('x509')    $cert = $x509['client_ca_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 index f9ef3f52..0b537e76 100644 --- a/puppet/modules/site_config/manifests/x509/client_ca/key.pp +++ b/puppet/modules/site_config/manifests/x509/client_ca/key.pp @@ -5,6 +5,8 @@ class site_config::x509::client_ca::key {    ## client certificates by the webapp.    ## +  include ::site_config::params +    $x509 = hiera('x509')    $key  = $x509['client_ca_key'] diff --git a/puppet/modules/site_config/manifests/x509/commercial/ca.pp b/puppet/modules/site_config/manifests/x509/commercial/ca.pp index 8f35759f..c76a9dbb 100644 --- a/puppet/modules/site_config/manifests/x509/commercial/ca.pp +++ b/puppet/modules/site_config/manifests/x509/commercial/ca.pp @@ -1,5 +1,7 @@  class site_config::x509::commercial::ca { +  include ::site_config::params +    $x509      = hiera('x509')    $ca        = $x509['commercial_ca_cert'] diff --git a/puppet/modules/site_config/manifests/x509/commercial/cert.pp b/puppet/modules/site_config/manifests/x509/commercial/cert.pp index 0c71a705..9dd6ffcd 100644 --- a/puppet/modules/site_config/manifests/x509/commercial/cert.pp +++ b/puppet/modules/site_config/manifests/x509/commercial/cert.pp @@ -1,10 +1,15 @@  class site_config::x509::commercial::cert { +  include ::site_config::params +    $x509      = hiera('x509')    $cert      = $x509['commercial_cert'] +  $ca        = $x509['commercial_ca_cert'] + +  $cafile = "${cert}\n${ca}"    x509::cert { $site_config::params::commercial_cert_name: -    content => $cert +    content => $cafile    }  } diff --git a/puppet/modules/site_config/manifests/x509/commercial/key.pp b/puppet/modules/site_config/manifests/x509/commercial/key.pp index d32e85ef..2be439fd 100644 --- a/puppet/modules/site_config/manifests/x509/commercial/key.pp +++ b/puppet/modules/site_config/manifests/x509/commercial/key.pp @@ -1,5 +1,7 @@  class site_config::x509::commercial::key { +  include ::site_config::params +    $x509      = hiera('x509')    $key       = $x509['commercial_key'] diff --git a/puppet/modules/site_config/manifests/x509/key.pp b/puppet/modules/site_config/manifests/x509/key.pp index 32b59726..448dc6a6 100644 --- a/puppet/modules/site_config/manifests/x509/key.pp +++ b/puppet/modules/site_config/manifests/x509/key.pp @@ -1,5 +1,7 @@  class site_config::x509::key { +  include ::site_config::params +    $x509      = hiera('x509')    $key       = $x509['key'] diff --git a/puppet/modules/site_config/templates/hosts b/puppet/modules/site_config/templates/hosts index d557f730..d62cbc3f 100644 --- a/puppet/modules/site_config/templates/hosts +++ b/puppet/modules/site_config/templates/hosts @@ -6,7 +6,8 @@  <%- if @hosts then -%>  <%   @hosts.keys.sort.each do |name| -%>  <%-     props = @hosts[name] -%> -<%=     props["ip_address"] %> <%= props["domain_full"] %> <%= props["domain_internal"] %> <%= name %> +<%-     aliases = props["aliases"] ? props["aliases"].join(' ') : nil -%> +<%=     [props["ip_address"], props["domain_full"], props["domain_internal"], aliases, name].compact.uniq.join(' ') %>  <%   end -%>  <% end -%> diff --git a/puppet/modules/site_couchdb/files/designs/identities/Identity.json b/puppet/modules/site_couchdb/files/designs/identities/Identity.json index 2ac092ab..b1c567c1 100644 --- a/puppet/modules/site_couchdb/files/designs/identities/Identity.json +++ b/puppet/modules/site_couchdb/files/designs/identities/Identity.json @@ -2,27 +2,33 @@    "_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" +    "all": { +      "map": "                function(doc) {\n                  if (doc['type'] == 'Identity') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }, -    "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" +    "cert_fingerprints_by_expiry": { +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.cert_fingerprints === \"object\") {\n    for (fp in doc.cert_fingerprints) {\n      if (doc.cert_fingerprints.hasOwnProperty(fp)) {\n        emit(doc.cert_fingerprints[fp], fp);\n      }\n    }\n  }\n}\n" +    }, +    "cert_expiry_by_fingerprint": { +      "map": "function(doc) {\n  if (doc.type != 'Identity') {\n    return;\n  }\n  if (typeof doc.cert_fingerprints === \"object\") {\n    for (fp in doc.cert_fingerprints) {\n      if (doc.cert_fingerprints.hasOwnProperty(fp)) {\n        emit(fp, doc.cert_fingerprints[fp]);\n      }\n    }\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" +      "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" +    "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" +    }, +    "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": { +      "map": "                function(doc) {\n                  if ((doc['type'] == 'Identity') && (doc['address'] != null)) {\n                    emit(doc['address'], 1);\n                  }\n                }\n", +      "reduce": "_sum"      }    }, -  "couchrest-hash": "e9004d70e26770c621a9667536429a68" +  "couchrest-hash": "4a774c3f56122b655a314670403b27e2"  }
\ No newline at end of file diff --git a/puppet/modules/site_couchdb/files/designs/invite_codes/InviteCode.json b/puppet/modules/site_couchdb/files/designs/invite_codes/InviteCode.json new file mode 100644 index 00000000..006c1ea1 --- /dev/null +++ b/puppet/modules/site_couchdb/files/designs/invite_codes/InviteCode.json @@ -0,0 +1,22 @@ +{ +   "_id": "_design/InviteCode", +   "language": "javascript", +   "views": { +       "by__id": { +           "map": "                function(doc) {\n                  if ((doc['type'] == 'InviteCode') && (doc['_id'] != null)) {\n                    emit(doc['_id'], 1);\n                  }\n                }\n", +           "reduce": "_sum" +       }, +       "by_invite_code": { +           "map": "                function(doc) {\n                  if ((doc['type'] == 'InviteCode') && (doc['invite_code'] != null)) {\n                    emit(doc['invite_code'], 1);\n                  }\n                }\n", +           "reduce": "_sum" +       }, +       "by_invite_count": { +           "map": "                function(doc) {\n                  if ((doc['type'] == 'InviteCode') && (doc['invite_count'] != null)) {\n                    emit(doc['invite_count'], 1);\n                  }\n                }\n", +           "reduce": "_sum" +       }, +       "all": { +           "map": "                function(doc) {\n                  if (doc['type'] == 'InviteCode') {\n                    emit(doc._id, null);\n                  }\n                }\n" +       } +   }, +   "couchrest-hash": "83fb8f504520b4a9c7ddbb7928cd0ce3" +}
\ 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 index 7bcd74c7..6a48fc4d 100644 --- a/puppet/modules/site_couchdb/files/designs/messages/Message.json +++ b/puppet/modules/site_couchdb/files/designs/messages/Message.json @@ -2,17 +2,17 @@    "_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); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "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) {\n            return sum(values);\n          }\n"      },      "all": {        "map": "                function(doc) {\n                  if (doc['type'] == 'Message') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }    }, -  "couchrest-hash": "0967e7cc5bb1e61edc1c085f6f0cecbf" +  "couchrest-hash": "ba80168e51015d2678cad88fc6c5b986"  }
\ 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 index 2c9408b8..578f632b 100644 --- a/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json +++ b/puppet/modules/site_couchdb/files/designs/tickets/Ticket.json @@ -24,27 +24,27 @@      },      "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); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "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); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "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) {\n            return sum(values);\n          }\n"      },      "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); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n" +    }, +    "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) {\n            return sum(values);\n          }\n"      },      "all": {        "map": "                function(doc) {\n                  if (doc['type'] == 'Ticket') {\n                    emit(doc._id, null);\n                  }\n                }\n"      }    }, -  "couchrest-hash": "9978e2cbeacbe8622c2a7f103bf8130f" +  "couchrest-hash": "b21eaeea8ea66bfda65581b1b7ce06af"  }
\ 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 index 4089ad97..8a82cf4a 100644 --- a/puppet/modules/site_couchdb/files/designs/users/User.json +++ b/puppet/modules/site_couchdb/files/designs/users/User.json @@ -11,12 +11,12 @@      },      "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); }" +      "reduce": "          function(key, values, rereduce) {\n            return sum(values);\n          }\n"      },      "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" +  "couchrest-hash": "d854607d299887a347e554176cb79e20"  }
\ 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 index 2f734ed4..c905316b 100644 --- a/puppet/modules/site_couchdb/manifests/add_users.pp +++ b/puppet/modules/site_couchdb/manifests/add_users.pp @@ -1,3 +1,4 @@ +# add couchdb users for all services  class site_couchdb::add_users {    Class['site_couchdb::create_dbs'] @@ -35,16 +36,6 @@ class site_couchdb::add_users {      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: diff --git a/puppet/modules/site_couchdb/manifests/bigcouch.pp b/puppet/modules/site_couchdb/manifests/bigcouch.pp index 469a2783..2de3d4d0 100644 --- a/puppet/modules/site_couchdb/manifests/bigcouch.pp +++ b/puppet/modules/site_couchdb/manifests/bigcouch.pp @@ -44,4 +44,7 @@ class site_couchdb::bigcouch {      require => Package['couchdb'],      notify  => Service['couchdb']    } + +  include site_check_mk::agent::couchdb::bigcouch +  } diff --git a/puppet/modules/site_couchdb/manifests/create_dbs.pp b/puppet/modules/site_couchdb/manifests/create_dbs.pp index eea4bbf5..a2d1c655 100644 --- a/puppet/modules/site_couchdb/manifests/create_dbs.pp +++ b/puppet/modules/site_couchdb/manifests/create_dbs.pp @@ -90,4 +90,13 @@ class site_couchdb::create_dbs {      members => "{ \"names\": [\"${site_couchdb::couchdb_webapp_user}\"], \"roles\": [\"replication\"] }",      require => Couchdb::Query::Setup['localhost']    } + +  ## invite_codes db +  ## store invite codes for new signups +  ## r/w: webapp +  couchdb::create_db { 'invite_codes': +    members => "{ \"names\": [\"${site_couchdb::couchdb_webapp_user}\"], \"roles\": [\"replication\"] }", +    require => Couchdb::Query::Setup['localhost'] +  } +  } diff --git a/puppet/modules/site_couchdb/manifests/designs.pp b/puppet/modules/site_couchdb/manifests/designs.pp index 1ab1c6a1..e5fd94c6 100644 --- a/puppet/modules/site_couchdb/manifests/designs.pp +++ b/puppet/modules/site_couchdb/manifests/designs.pp @@ -12,12 +12,13 @@ class site_couchdb::designs {    }    site_couchdb::upload_design { -    'customers':   design => 'customers/Customer.json'; -    'identities':  design => 'identities/Identity.json'; -    'tickets':     design => 'tickets/Ticket.json'; -    'messages':    design => 'messages/Message.json'; -    'users':       design => 'users/User.json'; -    'tmp_users':   design => 'users/User.json'; +    'customers':    design => 'customers/Customer.json'; +    'identities':   design => 'identities/Identity.json'; +    'tickets':      design => 'tickets/Ticket.json'; +    'messages':     design => 'messages/Message.json'; +    'users':        design => 'users/User.json'; +    'tmp_users':    design => 'users/User.json'; +    'invite_codes': design => 'invite_codes/InviteCode.json';      'shared_docs':        db => 'shared',        design => 'shared/docs.json'; diff --git a/puppet/modules/site_couchdb/manifests/init.pp b/puppet/modules/site_couchdb/manifests/init.pp index 6b6ddd3a..c4fe6277 100644 --- a/puppet/modules/site_couchdb/manifests/init.pp +++ b/puppet/modules/site_couchdb/manifests/init.pp @@ -26,11 +26,6 @@ class site_couchdb {    $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'] @@ -43,11 +38,14 @@ class site_couchdb {    $couchdb_backup           = $couchdb_config['backup']    $couchdb_mode             = $couchdb_config['mode'] -  $couchdb_pwhash_alg       = $couchdb_config['pwhash_alg'] -  if $couchdb_mode == 'multimaster' { include site_couchdb::bigcouch } -  if $couchdb_mode == 'master'      { include site_couchdb::master } -  if $couchdb_mode == 'mirror'      { include site_couchdb::mirror } +  # ensure bigcouch has been purged from the system: +  # TODO: remove this check in 0.9 release +  if file('/opt/bigcouch/bin/bigcouch', '/dev/null') != '' { +    fail 'ERROR: BigCouch appears to be installed. Make sure you have migrated to CouchDB before proceeding. See https://leap.se/upgrade-0-8' +  } + +  include site_couchdb::plain    Class['site_config::default']      -> Service['shorewall'] @@ -55,6 +53,7 @@ class site_couchdb {      -> Class['couchdb']      -> Class['site_couchdb::setup'] +  include ::site_config::default    include site_stunnel    include site_couchdb::setup @@ -66,6 +65,17 @@ class site_couchdb {    if $couchdb_backup   { include site_couchdb::backup }    include site_check_mk::agent::couchdb -  include site_check_mk::agent::tapicero + +  # remove tapicero leftovers on couchdb nodes +  include site_config::remove::tapicero + +  # Destroy every per-user storage database +  # where the corresponding user record does not exist. +  cron { 'cleanup_stale_userdbs': +    command => '(/bin/date; /srv/leap/couchdb/scripts/cleanup-user-dbs) >> /var/log/leap/couchdb-cleanup.log', +    user    => 'root', +    hour    => 4, +    minute  => 7; +  }  } diff --git a/puppet/modules/site_couchdb/manifests/logrotate.pp b/puppet/modules/site_couchdb/manifests/logrotate.pp index e1039d49..bb8843bb 100644 --- a/puppet/modules/site_couchdb/manifests/logrotate.pp +++ b/puppet/modules/site_couchdb/manifests/logrotate.pp @@ -1,12 +1,14 @@ +# configure couchdb logrotation  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' ] +      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/master.pp b/puppet/modules/site_couchdb/manifests/master.pp deleted file mode 100644 index c28eee7d..00000000 --- a/puppet/modules/site_couchdb/manifests/master.pp +++ /dev/null @@ -1,9 +0,0 @@ -# this class sets up a single, plain couchdb node -class site_couchdb::master { -  class { 'couchdb': -    admin_pw            => $site_couchdb::couchdb_admin_pw, -    admin_salt          => $site_couchdb::couchdb_admin_salt, -    chttpd_bind_address => '127.0.0.1', -    pwhash_alg          => $site_couchdb::couchdb_pwhash_alg -  } -} diff --git a/puppet/modules/site_couchdb/manifests/mirror.pp b/puppet/modules/site_couchdb/manifests/mirror.pp index abe35c4c..fb82b897 100644 --- a/puppet/modules/site_couchdb/manifests/mirror.pp +++ b/puppet/modules/site_couchdb/manifests/mirror.pp @@ -1,3 +1,4 @@ +# configure mirroring of couch nodes  class site_couchdb::mirror {    Class['site_couchdb::add_users'] @@ -22,55 +23,55 @@ class site_couchdb::mirror {    ### customer database    couchdb::mirror_db { 'customers': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## identities database    couchdb::mirror_db { 'identities': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## keycache database    couchdb::mirror_db { 'keycache': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## sessions database    couchdb::mirror_db { 'sessions': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## shared database    couchdb::mirror_db { 'shared': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## tickets database    couchdb::mirror_db { 'tickets': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## tokens database    couchdb::mirror_db { 'tokens': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## users database    couchdb::mirror_db { 'users': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    }    ## messages db    couchdb::mirror_db { 'messages': -    from => $from, +    from    => $from,      require => Couchdb::Query::Setup['localhost']    } diff --git a/puppet/modules/site_couchdb/manifests/plain.pp b/puppet/modules/site_couchdb/manifests/plain.pp new file mode 100644 index 00000000..b40fc100 --- /dev/null +++ b/puppet/modules/site_couchdb/manifests/plain.pp @@ -0,0 +1,14 @@ +# this class sets up a single, plain couchdb node +class site_couchdb::plain { +  class { 'couchdb': +    admin_pw            => $site_couchdb::couchdb_admin_pw, +    admin_salt          => $site_couchdb::couchdb_admin_salt, +    chttpd_bind_address => '127.0.0.1' +  } + +  include site_check_mk::agent::couchdb::plain + +  # remove bigcouch leftovers from previous installations +  include ::site_config::remove::bigcouch + +} diff --git a/puppet/modules/site_couchdb/manifests/setup.pp b/puppet/modules/site_couchdb/manifests/setup.pp index 69bd1c6a..710d3c1c 100644 --- a/puppet/modules/site_couchdb/manifests/setup.pp +++ b/puppet/modules/site_couchdb/manifests/setup.pp @@ -12,27 +12,42 @@ class site_couchdb::setup {    $user = $site_couchdb::couchdb_admin_user -  # /etc/couchdb/couchdb-admin.netrc is deployed by couchdb::query::setup -  # we symlink to couchdb.netrc for puppet commands. -  # 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) +  # setup /etc/couchdb/couchdb-admin.netrc for couchdb admin access +  couchdb::query::setup { 'localhost': +    user => $user, +    pw   => $site_couchdb::couchdb_admin_pw +  } + +  # We symlink /etc/couchdb/couchdb-admin.netrc to /etc/couchdb/couchdb.netrc +  # for puppet commands, and to to /root/.netrc for couchdb_scripts +  # (eg. backup) and to makes life easier for the admin on the command line +  # (i.e. using curl/wget without passing credentials)    file {      '/etc/couchdb/couchdb.netrc':        ensure  => link,        target  => "/etc/couchdb/couchdb-${user}.netrc"; -      '/root/.netrc':        ensure  => link,        target  => '/etc/couchdb/couchdb.netrc'; +  } -    '/srv/leap/couchdb': -      ensure => directory +  # setup /etc/couchdb/couchdb-soledad-admin.netrc file for couchdb admin +  # access, accessible only for the soledad-admin user to create soledad +  # userdbs +  if member(hiera('services', []), 'soledad') { +    file { '/etc/couchdb/couchdb-soledad-admin.netrc': +      content => "machine localhost login ${user} password ${site_couchdb::couchdb_admin_pw}", +      mode    => '0400', +      owner   => 'soledad-admin', +      group   => 'root', +      require => [ Package['couchdb'], User['soledad-admin'] ]; +    }    } -  couchdb::query::setup { 'localhost': -    user  => $user, -    pw    => $site_couchdb::couchdb_admin_pw, +  # Checkout couchdb_scripts repo +  file { +    '/srv/leap/couchdb': +      ensure => directory    }    vcsrepo { '/srv/leap/couchdb/scripts': diff --git a/puppet/modules/site_couchdb/manifests/upload_design.pp b/puppet/modules/site_couchdb/manifests/upload_design.pp index 7b0cabd7..bd73ebf2 100644 --- a/puppet/modules/site_couchdb/manifests/upload_design.pp +++ b/puppet/modules/site_couchdb/manifests/upload_design.pp @@ -1,4 +1,5 @@ -define site_couchdb::upload_design($db = $title, $design) { +# upload a design doc to a db +define site_couchdb::upload_design($design, $db = $title) {    $design_name = regsubst($design, '^.*\/(.*)\.json$', '\1')    $id = "_design/${design_name}"    $file = "/srv/leap/couchdb/designs/${design}" diff --git a/puppet/modules/site_mx/manifests/init.pp b/puppet/modules/site_mx/manifests/init.pp index 91014ed6..a9b0198b 100644 --- a/puppet/modules/site_mx/manifests/init.pp +++ b/puppet/modules/site_mx/manifests/init.pp @@ -2,6 +2,7 @@ class site_mx {    tag 'leap_service'    Class['site_config::default'] -> Class['site_mx'] +  include site_config::default    include site_config::x509::cert    include site_config::x509::key    include site_config::x509::ca diff --git a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg index 0d729b8c..62f26f2c 100644 --- a/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg +++ b/puppet/modules/site_nagios/files/configs/Debian/nagios.cfg @@ -22,18 +22,33 @@ log_file=/var/log/nagios3/nagios.log  # if you wish (as shown below), or keep them all in a single config file.  #cfg_file=/etc/nagios3/commands.cfg -# Puppet-managed configuration files -cfg_dir=/etc/nagios3/conf.d - -# check-mk managed configuration files +# Check_mk configuration files +cfg_dir=/etc/nagios3/conf.d/check_mk  cfg_dir=/etc/nagios3/local +# Puppet-managed configuration files +cfg_file=/etc/nagios3/nagios_templates.cfg +cfg_file=/etc/nagios3/nagios_command.cfg +cfg_file=/etc/nagios3/nagios_contact.cfg +cfg_file=/etc/nagios3/nagios_contactgroup.cfg +cfg_file=/etc/nagios3/nagios_host.cfg +cfg_file=/etc/nagios3/nagios_hostdependency.cfg +cfg_file=/etc/nagios3/nagios_hostescalation.cfg +cfg_file=/etc/nagios3/nagios_hostextinfo.cfg +cfg_file=/etc/nagios3/nagios_hostgroup.cfg +cfg_file=/etc/nagios3/nagios_hostgroupescalation.cfg +cfg_file=/etc/nagios3/nagios_service.cfg +cfg_file=/etc/nagios3/nagios_servicedependency.cfg +cfg_file=/etc/nagios3/nagios_serviceescalation.cfg +cfg_file=/etc/nagios3/nagios_serviceextinfo.cfg +cfg_file=/etc/nagios3/nagios_servicegroup.cfg +cfg_file=/etc/nagios3/nagios_timeperiod.cfg +  # Debian also defaults to using the check commands defined by the debian  # nagios-plugins package  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 @@ -70,7 +85,7 @@ precached_object_file=/var/lib/nagios3/objects.precache  # defined as macros in this file and restrictive permissions (600)  # can be placed on this file. -resource_file=/etc/nagios3/private/resource.cfg +resource_file=/etc/nagios3/resource.cfg diff --git a/puppet/modules/site_nagios/manifests/init.pp b/puppet/modules/site_nagios/manifests/init.pp index eb08cdcb..f91bfc26 100644 --- a/puppet/modules/site_nagios/manifests/init.pp +++ b/puppet/modules/site_nagios/manifests/init.pp @@ -1,6 +1,13 @@ +# setup nagios on monitoring node  class site_nagios  {    tag 'leap_service' + +  include site_config::default +    Class['site_config::default'] -> Class['site_nagios']    include site_nagios::server + +  # remove leftovers on monitoring nodes +  include site_config::remove::monitoring  } diff --git a/puppet/modules/site_nagios/manifests/server.pp b/puppet/modules/site_nagios/manifests/server.pp index cb6c8d95..aa9b956e 100644 --- a/puppet/modules/site_nagios/manifests/server.pp +++ b/puppet/modules/site_nagios/manifests/server.pp @@ -1,8 +1,7 @@  # configures nagios on monitoring node +# lint:ignore:inherits_across_namespaces  class site_nagios::server inherits nagios::base { - -  # First, purge old nagios config (see #1467) -  class { 'site_nagios::server::purge': } +# lint:endignore    $nagios_hiera     = hiera('nagios')    $nagiosadmin_pw   = htpasswd_sha1($nagios_hiera['nagiosadmin_pw']) @@ -22,17 +21,43 @@ class site_nagios::server inherits nagios::base {      # it in site_apache::common      httpd              => 'absent',      allow_external_cmd => true, -    stored_config      => false, +    storeconfigs       => false, +  } + +  # Delete nagios config files provided by packages +  # These don't get parsed by nagios.conf, but are +  # still irritating duplicates to the real config +  # files deployed by puppet in /etc/nagios3/ +  file { [ +    '/etc/nagios3/conf.d/contacts_nagios2.cfg', +    '/etc/nagios3/conf.d/extinfo_nagios2.cfg', +    '/etc/nagios3/conf.d/generic-host_nagios2.cfg', +    '/etc/nagios3/conf.d/generic-service_nagios2.cfg', +    '/etc/nagios3/conf.d/hostgroups_nagios2.cfg', +    '/etc/nagios3/conf.d/localhost_nagios2.cfg', +    '/etc/nagios3/conf.d/pnp4nagios.cfg', +    '/etc/nagios3/conf.d/services_nagios2.cfg', +    '/etc/nagios3/conf.d/timeperiods_nagios2.cfg' ]: +      ensure => absent;    } -  file { '/etc/apache2/conf.d/nagios3.conf': -    ensure => link, -    target => '/usr/share/doc/nagios3-common/examples/apache2.conf', -    notify => Service['apache'] +  # deploy apache nagios3 config +  # until https://gitlab.com/shared-puppet-modules-group/apache/issues/11 +  # is not fixed, we need to manually deploy the config file +  file { +    '/etc/apache2/conf-available/nagios3.conf': +      ensure  => present, +      source  => 'puppet:///modules/nagios/configs/apache2.conf', +      require => [ Package['nagios3'], Package['apache2'] ]; +    '/etc/apache2/conf-enabled/nagios3.conf': +      ensure  => link, +      target  => '/etc/apache2/conf-available/nagios3.conf', +      require => [ Package['nagios3'], Package['apache2'] ];    }    include site_apache::common -  include site_apache::module::headers +  include site_webapp::common_vhost +  include apache::module::headers    File ['nagios_htpasswd'] {      source  => undef, diff --git a/puppet/modules/site_nagios/manifests/server/add_contacts.pp b/puppet/modules/site_nagios/manifests/server/add_contacts.pp index db507abf..b5c6f0a5 100644 --- a/puppet/modules/site_nagios/manifests/server/add_contacts.pp +++ b/puppet/modules/site_nagios/manifests/server/add_contacts.pp @@ -1,3 +1,4 @@ +# configure a nagios_contact  define site_nagios::server::add_contacts ($contact_emails) {    $environment = $name @@ -11,6 +12,7 @@ define site_nagios::server::add_contacts ($contact_emails) {        host_notification_options     => 'd,r',        service_notification_commands => 'notify-service-by-email',        host_notification_commands    => 'notify-host-by-email', -      email                         => join($contact_emails, ', ') +      email                         => join($contact_emails, ', '), +      require                       => Package['nagios']    }  } diff --git a/puppet/modules/site_nagios/manifests/server/apache.pp b/puppet/modules/site_nagios/manifests/server/apache.pp index 8dbc7e9b..82962e89 100644 --- a/puppet/modules/site_nagios/manifests/server/apache.pp +++ b/puppet/modules/site_nagios/manifests/server/apache.pp @@ -1,7 +1,25 @@ +# set up apache for nagios  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 +  include apache::module::authn_file +  # "AuthUserFile" +  include apache::module::authz_user +  # "AuthType Basic" +  include apache::module::auth_basic +  # "DirectoryIndex" +  include apache::module::dir +  include apache::module::php5 +  include apache::module::cgi + +  # apache >= 2.4, debian jessie +  if ( $::lsbdistcodename == 'jessie' ) { +    include apache::module::authn_core +  } +  } diff --git a/puppet/modules/site_nagios/manifests/server/contactgroup.pp b/puppet/modules/site_nagios/manifests/server/contactgroup.pp index 188c54f1..5e60dd06 100644 --- a/puppet/modules/site_nagios/manifests/server/contactgroup.pp +++ b/puppet/modules/site_nagios/manifests/server/contactgroup.pp @@ -1,6 +1,8 @@ +# configure a contactgroup  define site_nagios::server::contactgroup ($contact_emails) {    nagios_contactgroup { $name: -    members => $name +    members => $name, +    require => Package['nagios']    }  } diff --git a/puppet/modules/site_nagios/manifests/server/hostgroup.pp b/puppet/modules/site_nagios/manifests/server/hostgroup.pp index 6f85ca6d..0692fced 100644 --- a/puppet/modules/site_nagios/manifests/server/hostgroup.pp +++ b/puppet/modules/site_nagios/manifests/server/hostgroup.pp @@ -1,3 +1,7 @@ +# create a nagios hostsgroup  define site_nagios::server::hostgroup ($contact_emails) { -  nagios_hostgroup { $name: } +  nagios_hostgroup { $name: +    ensure  => present, +    require => Package['nagios'] +  }  } diff --git a/puppet/modules/site_nagios/manifests/server/purge.pp b/puppet/modules/site_nagios/manifests/server/purge.pp deleted file mode 100644 index 6815a703..00000000 --- a/puppet/modules/site_nagios/manifests/server/purge.pp +++ /dev/null @@ -1,19 +0,0 @@ -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_nagios/templates/icli_aliases.erb b/puppet/modules/site_nagios/templates/icli_aliases.erb index f1428f9e..bcb2abb0 100644 --- a/puppet/modules/site_nagios/templates/icli_aliases.erb +++ b/puppet/modules/site_nagios/templates/icli_aliases.erb @@ -3,5 +3,5 @@ alias ncli_problems='ncli -z '!o,!A''  <% @environments.keys.sort.each do |env_name| %>  alias ncli_<%= env_name %>='ncli -z '!o,!A' -g <%= env_name %>' -alias ncli_<%= env_name %>_recheck='ncli -s Check_MK -g <%= env_name %> -r' -<% end -%>
\ No newline at end of file +alias ncli_<%= env_name %>_recheck='ncli -s Check_MK -g <%= env_name %> -a R' +<% end -%> diff --git a/puppet/modules/site_nickserver/manifests/init.pp b/puppet/modules/site_nickserver/manifests/init.pp index c2deab0f..eb4415e7 100644 --- a/puppet/modules/site_nickserver/manifests/init.pp +++ b/puppet/modules/site_nickserver/manifests/init.pp @@ -61,13 +61,6 @@ class site_nickserver {      require   => Group['nickserver'];    } -  # -  # NICKSERVER CODE NOTE: in order to support TLS, libssl-dev must be installed -  # before EventMachine gem is built/installed. -  # - -  package { 'libssl-dev': ensure => installed } -    vcsrepo { '/srv/leap/nickserver':      ensure   => present,      revision => $sources['nickserver']['revision'], @@ -122,6 +115,20 @@ class site_nickserver {        require => Vcsrepo['/srv/leap/nickserver'];    } +  # register initscript at systemd on nodes newer than wheezy +  # see https://leap.se/code/issues/7614 +  case $::operatingsystemrelease { +    /^7.*/: { } +    default:  { +      exec { 'register_systemd_nickserver': +        refreshonly => true, +        command     => '/bin/systemctl enable nickserver', +        subscribe   => File['/etc/init.d/nickserver'], +        before      => Service['nickserver']; +      } +    } +  } +    service { 'nickserver':      ensure     => running,      enable     => true, @@ -129,6 +136,7 @@ class site_nickserver {      hasstatus  => true,      require    => [        File['/etc/init.d/nickserver'], +      File['/usr/bin/nickserver'],        Class['Site_config::X509::Key'],        Class['Site_config::X509::Cert'],        Class['Site_config::X509::Ca'] ]; diff --git a/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb b/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb index d4e734c3..8f59fe38 100644 --- a/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb +++ b/puppet/modules/site_nickserver/templates/nickserver-proxy.conf.erb @@ -9,7 +9,6 @@ Listen 0.0.0.0:<%= @nickserver_port -%>    ServerAlias <%= @address_domain %>    SSLCACertificatePath /etc/ssl/certs -  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 diff --git a/puppet/modules/site_obfsproxy/manifests/init.pp b/puppet/modules/site_obfsproxy/manifests/init.pp index 6275ebee..2ed5ec9e 100644 --- a/puppet/modules/site_obfsproxy/manifests/init.pp +++ b/puppet/modules/site_obfsproxy/manifests/init.pp @@ -19,8 +19,7 @@ class site_obfsproxy {      $bind_address = hiera('ip_address')    } -  include site_apt::preferences::twisted -  include site_apt::preferences::obfsproxy +  include site_config::default    class { 'obfsproxy':      transport    => $transport, diff --git a/puppet/modules/site_openvpn/manifests/init.pp b/puppet/modules/site_openvpn/manifests/init.pp index e2a3124e..f1ecefb9 100644 --- a/puppet/modules/site_openvpn/manifests/init.pp +++ b/puppet/modules/site_openvpn/manifests/init.pp @@ -24,9 +24,11 @@ class site_openvpn {    include site_config::x509::key    include site_config::x509::ca_bundle - +  include site_config::default    Class['site_config::default'] -> Class['site_openvpn'] +  include ::site_obfsproxy +    $openvpn          = hiera('openvpn')    $openvpn_ports    = $openvpn['ports']    $openvpn_config   = $openvpn['configuration'] @@ -67,7 +69,7 @@ class site_openvpn {    # 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) %>') +  $primary_netmask = inline_template('<%= scope.lookupvar(@factname_primary_netmask) %>')    # deploy dh keys    include site_openvpn::dh_key @@ -85,24 +87,24 @@ class site_openvpn {    if $openvpn_allow_unlimited {      site_openvpn::server_config { 'tcp_config': -      port        => '1194', -      proto       => 'tcp', -      local       => $unlimited_gateway_address, -      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', -      config      => $openvpn_config +      port       => '1194', +      proto      => 'tcp', +      local      => $unlimited_gateway_address, +      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', +      config     => $openvpn_config      }      site_openvpn::server_config { 'udp_config': -      port        => '1194', -      proto       => 'udp', -      local       => $unlimited_gateway_address, -      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', -      config      => $openvpn_config +      port       => '1194', +      proto      => 'udp', +      local      => $unlimited_gateway_address, +      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', +      config     => $openvpn_config      }    } else {      tidy { '/etc/openvpn/tcp_config.conf': } @@ -111,24 +113,24 @@ class site_openvpn {    if $openvpn_allow_limited {      site_openvpn::server_config { 'limited_tcp_config': -      port        => '1194', -      proto       => 'tcp', -      local       => $limited_gateway_address, -      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', -      config      => $openvpn_config +      port       => '1194', +      proto      => 'tcp', +      local      => $limited_gateway_address, +      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', +      config     => $openvpn_config      }      site_openvpn::server_config { 'limited_udp_config': -      port        => '1194', -      proto       => 'udp', -      local       => $limited_gateway_address, -      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', -      config      => $openvpn_config +      port       => '1194', +      proto      => 'udp', +      local      => $limited_gateway_address, +      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', +      config     => $openvpn_config      }    } else {      tidy { '/etc/openvpn/limited_tcp_config.conf': } @@ -172,14 +174,8 @@ class site_openvpn {    include site_shorewall::eip -  # In wheezy, we need the openvpn backport to get the 2.3 version of -  # openvpn which has proper ipv6 support -  include site_apt::preferences::openvpn -    package { -    'openvpn': -      ensure  => latest, -      require => Class['site_apt::preferences::openvpn']; +    'openvpn': ensure => latest    }    service { @@ -228,7 +224,15 @@ class site_openvpn {        order   => 10;    } -  leap::logfile { 'openvpn': } +  leap::logfile { 'openvpn_tcp': } +  leap::logfile { 'openvpn_udp': } + +  # Because we currently do not support ipv6 and instead block it (so no leaks +  # happen), we get a large number of these messages, so we ignore them (#6540) +  rsyslog::snippet { '01-ignore_icmpv6_send': +    content => ':msg, contains, "icmpv6_send: no reply to icmp error" ~' +  } +    include site_check_mk::agent::openvpn  } diff --git a/puppet/modules/site_openvpn/manifests/server_config.pp b/puppet/modules/site_openvpn/manifests/server_config.pp index 221c79a7..6decc665 100644 --- a/puppet/modules/site_openvpn/manifests/server_config.pp +++ b/puppet/modules/site_openvpn/manifests/server_config.pp @@ -109,7 +109,7 @@ define site_openvpn::server_config(      "cert ${openvpn_configname}":        key     => 'cert',        value   => "${x509::variables::certs}/${site_config::params::cert_name}.crt", -        server  => $openvpn_configname; +      server  => $openvpn_configname;      "key ${openvpn_configname}":        key     => 'key',        value   => "${x509::variables::keys}/${site_config::params::cert_name}.key", @@ -203,5 +203,26 @@ define site_openvpn::server_config(        key    => 'verb',        value  => '3',        server => $openvpn_configname; +    "log-append /var/log/leap/openvpn_${proto}.log": +      key    => 'log-append', +      value  => "/var/log/leap/openvpn_${proto}.log", +      server => $openvpn_configname; +  } + +  # register openvpn services at systemd on nodes newer than wheezy +  # see https://leap.se/code/issues/7798 +  case $::operatingsystemrelease { +    /^7.*/: { } +    default:  { +      exec { "enable_systemd_${openvpn_configname}": +        refreshonly => true, +        command     => "/bin/systemctl enable openvpn@${openvpn_configname}", +        subscribe   => File["/etc/openvpn/${openvpn_configname}.conf"], +        notify      => Service["openvpn@${openvpn_configname}"]; +      } +      service { "openvpn@${openvpn_configname}": +        ensure  => running +      } +    }    }  } diff --git a/puppet/modules/site_postfix/files/checks/received_anon b/puppet/modules/site_postfix/files/checks/received_anon index 2822973e..9de25e63 100644 --- a/puppet/modules/site_postfix/files/checks/received_anon +++ b/puppet/modules/site_postfix/files/checks/received_anon @@ -1,2 +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:]]+).*/ +/^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/mx.pp b/puppet/modules/site_postfix/manifests/mx.pp index 49692d24..c269946b 100644 --- a/puppet/modules/site_postfix/manifests/mx.pp +++ b/puppet/modules/site_postfix/manifests/mx.pp @@ -7,10 +7,12 @@ class site_postfix::mx {    $domain              = $domain_hash['full_suffix']    $host_domain         = $domain_hash['full']    $cert_name           = hiera('name') -  $mynetworks          = join(hiera('mynetworks'), ' ') +  $mynetworks          = join(hiera('mynetworks', ''), ' ') +  $rbls                = suffix(prefix(hiera('rbls', []), 'reject_rbl_client '), ',') -  $root_mail_recipient = hiera('contacts') -  $postfix_smtp_listen = 'all' +  $root_mail_recipient    = hiera('contacts') +  $postfix_smtp_listen    = 'all' +  $postfix_use_postscreen = 'yes'    include site_config::x509::cert    include site_config::x509::key @@ -20,20 +22,41 @@ class site_postfix::mx {    postfix::config {      'mynetworks':        value => "127.0.0.0/8 [::1]/128 [fe80::]/64 ${mynetworks}"; +    # Note: mydestination should not include @domain, because this is +    # used in virtual alias maps.      'mydestination': -      value => "\$myorigin, localhost, localhost.\$mydomain, ${domain}"; +      value => "\$myorigin, localhost, localhost.\$mydomain";      'myhostname':        value => $host_domain;      'mailbox_size_limit':        value => '0';      'home_mailbox': -      value => 'Maildir/'; +      value => ''; +    'virtual_mailbox_domains': +      value => 'deliver.local'; +    'virtual_mailbox_base': +      value => '/var/mail/leap-mx'; +    'virtual_mailbox_maps': +      value => 'static:Maildir/'; +    # Note: virtual-aliases map will take precedence over leap-mx +    # lookup (tcp:localhost)      'virtual_alias_maps': -      value => 'tcp:localhost:4242'; +      value => 'hash:/etc/postfix/virtual-aliases tcp:localhost:4242';      'luser_relay': -      value => 'vmail'; -    'smtpd_tls_received_header': -      value => 'yes'; +      value => ''; +    # uid and gid are set to an arbitrary hard-coded value here, this +    # must match the 'leap-mx' user/group +    'virtual_uid_maps': +      value => 'static:42424'; +    'virtual_gid_maps': +      value => 'static:42424'; +    # the two following configs are needed for matching user's client cert +    # fingerprints to enable relaying (#3634). Satellites do not have +    # these configured. +    'smtpd_tls_fingerprint_digest': +      value => 'sha1'; +    'relay_clientcerts': +      value => 'tcp:localhost:2424';      # 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': @@ -44,40 +67,86 @@ class site_postfix::mx {      # alias map      'local_recipient_maps':        value => '$alias_maps'; +    # setup clamav and opendkim on smtpd +    'smtpd_milters': +      value => 'unix:/run/clamav/milter.ctl,inet:localhost:8891'; +    # setup opendkim for smtp (non-smtpd) outgoing mail +    'non_smtpd_milters': +      value => 'inet:localhost:8891'; +    'milter_default_action': +      value => 'accept'; +    # Make sure that the right values are set, these could be set to different +    # things on install, depending on preseed or debconf options +    # selected (see #7478) +    'relay_transport': +      value => 'relay'; +    'default_transport': +      value => 'smtp'; +    'mailbox_command': +      value => ''; +    'header_checks': +      value => ''; +    'postscreen_access_list': +      value => 'permit_mynetworks'; +    'postscreen_greet_action': +      value => 'enforce';    } -  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 +  # Make sure that the cleanup serivce is not chrooted, otherwise it cannot +  # access the opendkim milter socket (#8020) +  exec { 'unset_cleanup_chroot': +    command => '/usr/sbin/postconf -F "cleanup/unix/chroot=n"', +    onlyif  => '/usr/sbin/postconf -h -F "cleanup/unix/chroot" | egrep -q ^n', +    notify  => Service['postfix'], +    require => File['/etc/postfix/master.cf'] +  } + +  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::static_aliases +  include ::site_postfix::mx::rewrite_openpgp_header +  include ::site_postfix::mx::received_anon +  include ::clamav +  include ::opendkim +  include ::postfwd    # 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, +  case $::operatingsystemrelease { +    /^7.*/: { +      $smtpd_relay_restrictions='' +    } +    default:  { +      $smtpd_relay_restrictions="  -o smtpd_relay_restrictions=\$smtps_relay_restrictions\n" +    }    } +  $mastercf_tail = " +smtps     inet  n       -       -       -       -       smtpd +  -o smtpd_tls_wrappermode=yes +  -o smtpd_tls_security_level=encrypt +  -o tls_preempt_cipherlist=yes +${smtpd_relay_restrictions}  -o smtpd_recipient_restrictions=\$smtps_recipient_restrictions +  -o smtpd_helo_restrictions=\$smtps_helo_restrictions +  -o smtpd_client_restrictions= +  -o cleanup_service_name=clean_smtps +clean_smtps   unix  n - n - 0 cleanup +  -o header_checks=pcre:/etc/postfix/checks/rewrite_openpgp_headers,pcre:/etc/postfix/checks/received_anon" +    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", +    mastercf_tail       => $mastercf_tail, +    use_postscreen      => 'yes',      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'] ] +      User['leap-mx'] ]    }  } diff --git a/puppet/modules/site_postfix/manifests/mx/checks.pp b/puppet/modules/site_postfix/manifests/mx/checks.pp index 5d75a5e5..f406ad34 100644 --- a/puppet/modules/site_postfix/manifests/mx/checks.pp +++ b/puppet/modules/site_postfix/manifests/mx/checks.pp @@ -20,22 +20,4 @@ class site_postfix::mx::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/received_anon.pp b/puppet/modules/site_postfix/manifests/mx/received_anon.pp new file mode 100644 index 00000000..51ba3faa --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/received_anon.pp @@ -0,0 +1,13 @@ +# Anonymize the user's home IP from the email headers (Feature #3866)  +class site_postfix::mx::received_anon { + +  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'] +  } +} diff --git a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp b/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp deleted file mode 100644 index 83e27376..00000000 --- a/puppet/modules/site_postfix/manifests/mx/reserved_aliases.pp +++ /dev/null @@ -1,15 +0,0 @@ -# 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/rewrite_openpgp_header.pp b/puppet/modules/site_postfix/manifests/mx/rewrite_openpgp_header.pp new file mode 100644 index 00000000..71f945b8 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/rewrite_openpgp_header.pp @@ -0,0 +1,11 @@ +class site_postfix::mx::rewrite_openpgp_header { +  $mx             = hiera('mx') +  $correct_domain = $mx['key_lookup_domain'] + +  file { '/etc/postfix/checks/rewrite_openpgp_headers': +    content => template('site_postfix/checks/rewrite_openpgp_headers.erb'), +    mode    => '0644', +    owner   => root, +    group   => root; +  } +} diff --git a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp index d56f6b54..c93c3ba2 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtp_tls.pp @@ -1,11 +1,16 @@ +# configure smtp tls  class site_postfix::mx::smtp_tls {    include site_config::x509::ca    include x509::variables +  $cert_name = hiera('name')    $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_config::x509::cert +  include site_config::x509::key +    # smtp TLS    postfix::config {      'smtp_use_tls':        value  => 'yes'; @@ -20,9 +25,19 @@ class site_postfix::mx::smtp_tls {      'smtp_tls_fingerprint_digest':        value => 'sha1';      'smtp_tls_session_cache_database': -      value => 'btree:${data_directory}/smtp_cache'; +      value => "btree:\${data_directory}/smtp_cache";      # see issue #4011      'smtp_tls_protocols':        value => '!SSLv2, !SSLv3'; +    'smtp_tls_mandatory_protocols': +      value => '!SSLv2, !SSLv3'; +    'tls_ssl_options': +      value => 'NO_COMPRESSION'; +    # We can switch between the different postfix internal list of ciphers by +    # using smtpd_tls_ciphers.  For server-to-server connections we leave this +    # at its default because of opportunistic encryption combined with many mail +    # servers only support outdated protocols and ciphers and if we are too +    # strict with required ciphers, then connections *will* fall-back to +    # plain-text. Bad ciphers are still better than plain text transmission.    }  } diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp index 0ec40277..291d7ee4 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_checks.pp @@ -1,3 +1,5 @@ +# smtpd checks for incoming mail on smtp port 25 and +# mail sent via the bitmask client using smtps port 465  class site_postfix::mx::smtpd_checks {    postfix::config { @@ -6,7 +8,7 @@ class site_postfix::mx::smtpd_checks {      'checks_dir':        value => '$config_directory/checks';      'smtpd_client_restrictions': -      value => 'permit_mynetworks,permit'; +      value => "permit_mynetworks,${site_postfix::mx::rbls},permit";      'smtpd_data_restrictions':        value => 'permit_mynetworks, reject_unauth_pipelining, permit';      'smtpd_delay_reject': @@ -15,13 +17,16 @@ class site_postfix::mx::smtpd_checks {        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 + +    # permit_tls_clientcerts will lookup client cert fingerprints from the tcp +    # lookup on port 2424 (based on what is configured in relay_clientcerts +    # paramter, see site_postfix::mx postfix::config resource) to determine +    # if a client is allowed to relay mail through us. This enables us to +    # disable a user by removing their valid client cert (#3634)      'smtps_recipient_restrictions': -      value => 'permit_tls_all_clientcerts, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; +      value => 'permit_tls_clientcerts, check_recipient_access tcp:localhost:2244, reject_unauth_destination, permit'; +    'smtps_relay_restrictions': +      value => 'permit_mynetworks, permit_tls_clientcerts, defer_unauth_destination';      'smtps_helo_restrictions':        value => 'permit_mynetworks, check_helo_access hash:$checks_dir/helo_checks, permit';      'smtpd_sender_restrictions': diff --git a/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp index 0809c75f..66297f55 100644 --- a/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp +++ b/puppet/modules/site_postfix/manifests/mx/smtpd_tls.pp @@ -1,3 +1,4 @@ +# configure smtpd tls  class site_postfix::mx::smtpd_tls {    include x509::variables @@ -12,12 +13,25 @@ class site_postfix::mx::smtpd_tls {      'smtpd_tls_cert_file':  value  => $cert_path;      'smtpd_tls_key_file':   value  => $key_path;      'smtpd_tls_ask_ccert':  value  => 'yes'; +    'smtpd_tls_received_header': +      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'; +      value => "btree:\${data_directory}/smtpd_scache"; +    # see issue #4011 +    'smtpd_tls_mandatory_protocols': +      value => '!SSLv2, !SSLv3'; +    'smtpd_tls_protocols': +      value => '!SSLv2, !SSLv3'; +    # For connections to MUAs, TLS is mandatory and the ciphersuite is modified. +    # MX and SMTP client configuration +    'smtpd_tls_mandatory_ciphers': +      value => 'high'; +    'tls_high_cipherlist': +      value => '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:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!RC4:!MD5:!PSK!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';    }    # Setup DH parameters diff --git a/puppet/modules/site_postfix/manifests/mx/static_aliases.pp b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp new file mode 100644 index 00000000..9cd7ca02 --- /dev/null +++ b/puppet/modules/site_postfix/manifests/mx/static_aliases.pp @@ -0,0 +1,88 @@ +# +# Defines static, hard coded aliases that are not in the database. +# These aliases take precedence over the database aliases. +# +# There are three classes of reserved names: +# +# (1) forbidden_usernames: +#     Some usernames are forbidden and cannot be registered. +#     this is defined in node property webapp.forbidden_usernames +#     This is enforced by the webapp. +# +# (2) public aliases: +#     Some aliases for root, and are publicly exposed so that anyone +#     can deliver mail to them. For example, postmaster. +#     These are implemented in the virtual alias map, which takes +#     precedence over the local alias map. +# +# (3) local aliases: +#     Some aliases are only available locally: mail can be delivered +#     to the alias if the mail originates from the local host, or is +#     hostname qualified, but otherwise it will be rejected. +#     These are implemented in the local alias map. +# +# The alias for local 'root' is defined elsewhere. In this file, we +# define the virtual 'root@domain' (which can be overwritten by +# defining an entry for root in node property mx.aliases). +# + +class site_postfix::mx::static_aliases { + +  $mx = hiera('mx') +  $root_recipients = hiera('contacts') + +  # +  # LOCAL ALIASES +  # + +  # NOTE: if you remove one of these, they will still appear in the +  # /etc/aliases file +  $local_aliases = [ +    'admin', 'administrator', 'bin', 'cron', 'games', 'ftp', 'lp', 'maildrop', +    'mysql', 'news', 'nobody', 'noc', 'postgresql', 'ssladmin', 'sys', +    'usenet', 'uucp', 'www', 'www-data', 'leap-mx' +  ] + +  postfix::mailalias { +    $local_aliases: +      ensure    => present, +      recipient => 'root' +  } + +  # +  # PUBLIC ALIASES +  # + +  $public_aliases = $mx['aliases'] + +  $default_public_aliases = { +    'root'          => $root_recipients, +    'abuse'         => 'postmaster', +    'arin-admin'    => 'root', +    'certmaster'    => 'hostmaster', +    'domainadmin'   => 'hostmaster', +    'hostmaster'    => 'root', +    'mailer-daemon' => 'postmaster', +    'postmaster'    => 'root', +    'security'      => 'root', +    'webmaster'     => 'hostmaster', +  } + +  $aliases = merge($default_public_aliases, $public_aliases) + +  exec { 'postmap_virtual_aliases': +    command     => '/usr/sbin/postmap /etc/postfix/virtual-aliases', +    refreshonly => true, +    user        => root, +    group       => root, +    require     => Package['postfix'], +    subscribe   => File['/etc/postfix/virtual-aliases'] +  } +  file { '/etc/postfix/virtual-aliases': +    content => template('site_postfix/virtual-aliases.erb'), +    owner   => root, +    group   => root, +    mode    => '0600', +    require => Package['postfix'] +  } +} diff --git a/puppet/modules/site_postfix/templates/checks/helo_access.erb b/puppet/modules/site_postfix/templates/checks/helo_access.erb index bef3c11d..bac2c45a 100644 --- a/puppet/modules/site_postfix/templates/checks/helo_access.erb +++ b/puppet/modules/site_postfix/templates/checks/helo_access.erb @@ -18,4 +18,4 @@  # 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 %> +<%= @domain %> 554 You are not in domain <%= @domain %> diff --git a/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb b/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb new file mode 100644 index 00000000..7af14f7d --- /dev/null +++ b/puppet/modules/site_postfix/templates/checks/rewrite_openpgp_headers.erb @@ -0,0 +1,13 @@ +# THIS FILE IS MANAGED BY PUPPET +# +# This will replace the OpenPGP header that the client adds, because it is +# sometimes incorrect (due to the client not always knowing what the proper URL +# is for the webapp). +# e.g. This will rewrite this header: +# OpenPGP: id=4C0E01CD50E2F653; url="https://leap.se/key/elijah"; preference="signencrypt +# with this replacement: +# OpenPGP: id=4C0E01CD50E2F653; url="https://user.leap.se/key/elijah"; preference="signencrypt +# +# Note: whitespace in the pattern is represented by [[:space:]] to avoid these warnings from postmap: +# "record is in "key: value" format; is this an alias file?" and "duplicate entry" +/^(OpenPGP:[[:space:]]id=[[:alnum:]]+;[[:space:]]url="https:\/\/)<%= @domain %>(\/key\/[[:alpha:]]+";.*)/i REPLACE ${1}<%= @correct_domain %>${2} diff --git a/puppet/modules/site_postfix/templates/virtual-aliases.erb b/puppet/modules/site_postfix/templates/virtual-aliases.erb new file mode 100644 index 00000000..8373de97 --- /dev/null +++ b/puppet/modules/site_postfix/templates/virtual-aliases.erb @@ -0,0 +1,21 @@ +# +# This file is managed by puppet. +# +# These virtual aliases take precedence over all other aliases. +# + +# +# enable these virtual domains: +# +<%= @domain %> enabled +<%- @aliases.keys.map {|addr| addr.split('@')[1] }.compact.sort.uniq.each do |virt_domain| -%> +<%= virt_domain %> enabled +<%- end %> + +# +# virtual aliases: +# +<%- @aliases.keys.sort.each do |from| -%> +<%-   full_address = from =~ /@/ ? from : from + "@" + @domain -%> +<%= full_address %> <%= [@aliases[from]].flatten.map{|a| a =~ /@/ ? a : a + "@" + @domain}.join(', ') %> +<%- end -%> diff --git a/puppet/modules/site_rsyslog/templates/client.conf.erb b/puppet/modules/site_rsyslog/templates/client.conf.erb new file mode 100644 index 00000000..7f94759d --- /dev/null +++ b/puppet/modules/site_rsyslog/templates/client.conf.erb @@ -0,0 +1,134 @@ + +# An "In-Memory Queue" is created for remote logging. +$WorkDirectory <%= scope.lookupvar('rsyslog::spool_dir') -%>    # where to place spool files +$ActionQueueFileName queue      # unique name prefix for spool files +$ActionQueueMaxDiskSpace <%= scope.lookupvar('rsyslog::client::spool_size') -%>     # spool space limit (use as much as possible) +$ActionQueueSaveOnShutdown on   # save messages to disk on shutdown +$ActionQueueType LinkedList     # run asynchronously +$ActionResumeRetryCount -1      # infinety retries if host is down +<% if scope.lookupvar('rsyslog::client::log_templates') and ! scope.lookupvar('rsyslog::client::log_templates').empty?-%> + +# Define custom logging templates +<% scope.lookupvar('rsyslog::client::log_templates').flatten.compact.each do |log_template| -%> +$template <%= log_template['name'] %>,"<%= log_template['template'] %>" +<% end -%> +<% end -%> +<% if scope.lookupvar('rsyslog::client::actionfiletemplate') -%> + +# Using specified format for default logging format: +$ActionFileDefaultTemplate <%= scope.lookupvar('rsyslog::client::actionfiletemplate') %> +<% else -%> + +#Using default format for default logging format: +$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat +<% end -%> +<% if scope.lookupvar('rsyslog::client::ssl') -%> + +# Setup SSL connection. +# CA/Cert +$DefaultNetStreamDriverCAFile <%= scope.lookupvar('rsyslog::client::ssl_ca') %> + +# Connection settings. +$DefaultNetstreamDriver gtls +$ActionSendStreamDriverMode 1 +$ActionSendStreamDriverAuthMode anon +<% end -%> +<% if scope.lookupvar('rsyslog::client::remote_servers')  -%> + +<% scope.lookupvar('rsyslog::client::remote_servers').flatten.compact.each do |server| -%> +<% if server['pattern'] and server['pattern'] != ''-%> +<% pattern = server['pattern'] -%> +<% else -%> +<% pattern = '*.*' -%> +<% end -%> +<% if server['protocol'] == 'TCP' or server['protocol'] == 'tcp'-%> +<% protocol = '@@' -%> +<% protocol_type = 'TCP' -%> +<% else -%> +<% protocol = '@' -%> +<% protocol_type = 'UDP' -%> +<% end -%> +<% if server['host'] and server['host'] != ''-%> +<% host = server['host'] -%> +<% else -%> +<% host = 'localhost' -%> +<% end -%> +<% if server['port'] and server['port'] != ''-%> +<% port = server['port'] -%> +<% else -%> +<% port = '514' -%> +<% end -%> +<% if server['format'] -%> +<% format = ";#{server['format']}" -%> +<% format_type = server['format'] -%> +<% else -%> +<% format = '' -%> +<% format_type = 'the default' -%> +<% end -%> +# Sending logs that match <%= pattern %> to <%= host %> via <%= protocol_type %> on <%= port %> using <%=format_type %> format. +<%= pattern %> <%= protocol %><%= host %>:<%= port %><%= format %> +<% end -%> +<% elsif scope.lookupvar('rsyslog::client::log_remote') -%> + +# Log to remote syslog server using <%= scope.lookupvar('rsyslog::client::remote_type') %> +<% if scope.lookupvar('rsyslog::client::remote_type') == 'tcp' -%> +*.* @@<%= scope.lookupvar('rsyslog::client::server') -%>:<%= scope.lookupvar('rsyslog::client::port') -%>;<%= scope.lookupvar('remote_forward_format') -%> +<% else -%> +*.* @<%= scope.lookupvar('rsyslog::client::server') -%>:<%= scope.lookupvar('rsyslog::client::port') -%>;<%= scope.lookupvar('remote_forward_format') -%> +<% end -%> +<% end -%> +<% if scope.lookupvar('rsyslog::client::log_auth_local') or scope.lookupvar('rsyslog::client::log_local') -%> + +# Logging locally. + +<% if scope.lookupvar('rsyslog::log_style') == 'debian' -%> +# Log auth messages locally +.*;auth,authpriv.none;mail.none -/var/log/syslog +<% elsif scope.lookupvar('rsyslog::log_style') == 'redhat' -%> +# Log auth messages locally +auth,authpriv.*                 /var/log/secure +<% end -%> +<% end -%> +<% if scope.lookupvar('rsyslog::client::log_local') -%> +<% if scope.lookupvar('rsyslog::log_style') == 'debian' -%> +# First some standard log files.  Log by facility. +# +*.*;auth,authpriv.none         -/var/log/syslog +cron.*                          /var/log/cron.log +daemon.*                       -/var/log/daemon.log +kern.*                         -/var/log/kern.log +mail.*                         -/var/log/mail.log +user.*                         -/var/log/user.log + +# +# Some "catch-all" log files. +# +*.=debug;\ +       auth,authpriv.none;\ +       news.none;mail.none     -/var/log/debug +*.=info;*.=notice;*.=warn;\ +       auth,authpriv.none;\ +       cron,daemon.none;\ +       mail,news.none          -/var/log/messages + +# Log anything (except mail) of level info or higher. +# Don't log private authentication messages! +*.info;mail.none;authpriv.none;cron.none                /var/log/messages + +# Log cron stuff +cron.*                         /var/log/cron + +# Everybody gets emergency messages +<% if @rsyslog_version and @rsyslog_version.split('.')[0].to_i >= 8 -%> +*.emerg       :omusrmsg:* +<% else -%> +*.emerg				* +<% end -%> + +# Save boot messages also to boot.log +local7.*                       -/var/log/boot.log +<% end -%> +<% end -%> + + + diff --git a/puppet/modules/site_shorewall/files/Debian/shorewall.service b/puppet/modules/site_shorewall/files/Debian/shorewall.service new file mode 100644 index 00000000..ec250ef1 --- /dev/null +++ b/puppet/modules/site_shorewall/files/Debian/shorewall.service @@ -0,0 +1,23 @@ +# +#     The Shoreline Firewall (Shorewall) Packet Filtering Firewall +# +#     Copyright 2011 Jonathan Underwood <jonathan.underwood@gmail.com> +#     Copyright 2015 Tom Eastep <teastep@shorewall.net> +# +[Unit] +Description=Shorewall IPv4 firewall +Wants=network-online.target +After=network-online.target +Conflicts=iptables.service firewalld.service + +[Service] +Type=oneshot +RemainAfterExit=yes +EnvironmentFile=-/etc/default/shorewall +StandardOutput=syslog +ExecStart=/sbin/shorewall $OPTIONS start $STARTOPTIONS +ExecStop=/sbin/shorewall $OPTIONS stop +ExecReload=/sbin/shorewall $OPTIONS reload $RELOADOPTIONS + +[Install] +WantedBy=basic.target diff --git a/puppet/modules/site_shorewall/manifests/defaults.pp b/puppet/modules/site_shorewall/manifests/defaults.pp index 8f56ac42..ceb17868 100644 --- a/puppet/modules/site_shorewall/manifests/defaults.pp +++ b/puppet/modules/site_shorewall/manifests/defaults.pp @@ -47,6 +47,18 @@ class site_shorewall::defaults {      ensure => installed    } +  include ::systemd +  file { '/etc/systemd/system/shorewall.service': +    ensure  => file, +    owner   => 'root', +    group   => 'root', +    mode    => '0644', +    source  => 'puppet:///modules/site_shorewall/Debian/shorewall.service', +    require => Package['shorewall'], +    notify  => Service['shorewall'], +    } ~> +    Exec['systemctl-daemon-reload'] +    augeas {      # stop instead of clear firewall on shutdown      'shorewall_SAFESTOP': @@ -54,14 +66,14 @@ class site_shorewall::defaults {        lens    => 'Shellvars.lns',        incl    => '/etc/shorewall/shorewall.conf',        require => Package['shorewall'], -      notify  => Service[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]; +      notify  => Service['shorewall'];      # configure shorewall-init      'shorewall-init':        changes => 'set /files/etc/default/shorewall-init/PRODUCTS shorewall', diff --git a/puppet/modules/site_shorewall/manifests/obfsproxy.pp b/puppet/modules/site_shorewall/manifests/obfsproxy.pp index 68fb9b9f..75846705 100644 --- a/puppet/modules/site_shorewall/manifests/obfsproxy.pp +++ b/puppet/modules/site_shorewall/manifests/obfsproxy.pp @@ -1,3 +1,4 @@ +# configure shorewell for obfsproxy  class site_shorewall::obfsproxy {    include site_shorewall::defaults @@ -8,7 +9,7 @@ class site_shorewall::obfsproxy {    # define macro for incoming services    file { '/etc/shorewall/macro.leap_obfsproxy': -    content => "PARAM   -       -       tcp    $scram_port ", +    content => "PARAM   -       -       tcp    ${scram_port} ",      notify  => Service['shorewall'],      require => Package['shorewall']    } diff --git a/puppet/modules/site_shorewall/manifests/service/webapp_api.pp b/puppet/modules/site_shorewall/manifests/service/webapp_api.pp index 0c6c824d..d3a1aeed 100644 --- a/puppet/modules/site_shorewall/manifests/service/webapp_api.pp +++ b/puppet/modules/site_shorewall/manifests/service/webapp_api.pp @@ -1,3 +1,4 @@ +# configure shorewall for webapp api  class site_shorewall::service::webapp_api {    $api = hiera('api') @@ -5,7 +6,7 @@ class site_shorewall::service::webapp_api {    # define macro for incoming services    file { '/etc/shorewall/macro.leap_webapp_api': -    content => "PARAM   -       -       tcp    $api_port ", +    content => "PARAM   -       -       tcp    ${api_port} ",      notify  => Service['shorewall'],      require => Package['shorewall']    } diff --git a/puppet/modules/site_shorewall/manifests/sshd.pp b/puppet/modules/site_shorewall/manifests/sshd.pp index 88b4102c..e2332592 100644 --- a/puppet/modules/site_shorewall/manifests/sshd.pp +++ b/puppet/modules/site_shorewall/manifests/sshd.pp @@ -1,3 +1,4 @@ +# configure shorewall for sshd  class site_shorewall::sshd {    $ssh_config     = hiera('ssh') @@ -7,7 +8,7 @@ class site_shorewall::sshd {    # define macro for incoming sshd    file { '/etc/shorewall/macro.leap_sshd': -    content => "PARAM   -       -       tcp    $ssh_port", +    content => "PARAM   -       -       tcp    ${ssh_port}",      notify  => Service['shorewall'],      require => Package['shorewall']    } diff --git a/puppet/modules/site_shorewall/manifests/tor.pp b/puppet/modules/site_shorewall/manifests/tor.pp index f35af985..324b4844 100644 --- a/puppet/modules/site_shorewall/manifests/tor.pp +++ b/puppet/modules/site_shorewall/manifests/tor.pp @@ -1,3 +1,4 @@ +# configure shorewall for tor  class site_shorewall::tor {    include site_shorewall::defaults @@ -7,7 +8,7 @@ class site_shorewall::tor {    # define macro for incoming services    file { '/etc/shorewall/macro.leap_tor': -    content => "PARAM   -       -       tcp    $tor_port ", +    content => "PARAM   -       -       tcp    ${tor_port} ",      notify  => Service['shorewall'],      require => Package['shorewall']    } diff --git a/puppet/modules/site_sshd/manifests/authorized_keys.pp b/puppet/modules/site_sshd/manifests/authorized_keys.pp index 90a33d8d..a1fde3f6 100644 --- a/puppet/modules/site_sshd/manifests/authorized_keys.pp +++ b/puppet/modules/site_sshd/manifests/authorized_keys.pp @@ -1,20 +1,22 @@ +# We want to purge unmanaged keys from the authorized_keys file so that only +# keys added in the provider are valid. Any manually added keys will be +# overridden. +# +# In order to do this, we have to use a custom define to deploy the +# authorized_keys file because puppet's internal resource doesn't allow +# purging before populating this file. +# +# See the following for more information: +# https://tickets.puppetlabs.com/browse/PUP-1174 +# https://leap.se/code/issues/2990 +# https://leap.se/code/issues/3010 +#  define site_sshd::authorized_keys ($keys, $ensure = 'present', $home = '') { -  # We want to purge unmanaged keys from the authorized_keys file so that only -  # keys added in the provider are valid. Any manually added keys will be -  # overridden. -  # -  # In order to do this, we have to use a custom define to deploy the -  # authorized_keys file because puppet's internal resource doesn't allow -  # purging before populating this file. -  # -  # See the following for more information: -  # https://tickets.puppetlabs.com/browse/PUP-1174 -  # https://leap.se/code/issues/2990 -  # https://leap.se/code/issues/3010 -  #    # This line allows default homedir based on $title variable.    # If $home is empty, the default is used.    $homedir = $home ? {'' => "/home/${title}", default => $home} +  $owner   = $ensure ? {'present' => $title, default => undef } +  $group   = $ensure ? {'present' => $title, default => undef }    file {      "${homedir}/.ssh":        ensure  => 'directory', @@ -23,8 +25,8 @@ define site_sshd::authorized_keys ($keys, $ensure = 'present', $home = '') {        mode    => '0700';      "${homedir}/.ssh/authorized_keys":        ensure  => $ensure, -      owner   => $ensure ? {'present' => $title, default => undef }, -      group   => $ensure ? {'present' => $title, default => undef }, +      owner   => $owner, +      group   => $group,        mode    => '0600',        require => File["${homedir}/.ssh"],        content => template('site_sshd/authorized_keys.erb'); diff --git a/puppet/modules/site_sshd/manifests/init.pp b/puppet/modules/site_sshd/manifests/init.pp index 1da2f1d5..a9202da4 100644 --- a/puppet/modules/site_sshd/manifests/init.pp +++ b/puppet/modules/site_sshd/manifests/init.pp @@ -1,6 +1,8 @@ +# configures sshd, mosh, authorized keys and known hosts  class site_sshd { -  $ssh   = hiera_hash('ssh') -  $hosts = hiera('hosts', '') +  $ssh        = hiera_hash('ssh') +  $ssh_config = $ssh['config'] +  $hosts      = hiera('hosts', '')    ##    ## SETUP AUTHORIZED KEYS @@ -48,15 +50,33 @@ class site_sshd {      }    } +  # we cannot use the 'hardened' parameter because leap_cli uses an +  # old net-ssh gem that is incompatible with the included +  # "KexAlgorithms curve25519-sha256@libssh.org", +  # see https://leap.se/code/issues/7591 +  # therefore we don't use it here, but include all other options +  # that would be applied by the 'hardened' parameter +  # not all options are available on wheezy +  if ( $::lsbdistcodename == 'wheezy' ) { +    $tail_additional_options = 'Ciphers aes256-ctr +MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160' +  } else { +    $tail_additional_options = 'Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes256-ctr +MACs hmac-sha2-512,hmac-sha2-256,hmac-ripemd160' +  } +    ##    ## SSHD SERVER CONFIGURATION    ##    class { '::sshd': -    manage_nagios => false, -    ports         => [ $ssh['port'] ], -    use_pam       => 'yes', -    hardened_ssl  => 'yes', -    print_motd    => 'no', -    manage_client => false +    manage_nagios           => false, +    ports                   => [ $ssh['port'] ], +    use_pam                 => 'yes', +    print_motd              => 'no', +    tcp_forwarding          => $ssh_config['AllowTcpForwarding'], +    manage_client           => false, +    use_storedconfigs       => false, +    tail_additional_options => $tail_additional_options, +    hostkey_type            => [ 'rsa', 'dsa', 'ecdsa' ]    }  } diff --git a/puppet/modules/site_sshd/templates/authorized_keys.erb b/puppet/modules/site_sshd/templates/authorized_keys.erb index 69f4d8e6..51bdc5b3 100644 --- a/puppet/modules/site_sshd/templates/authorized_keys.erb +++ b/puppet/modules/site_sshd/templates/authorized_keys.erb @@ -1,7 +1,7 @@  # NOTICE: This file is autogenerated by Puppet  # all manually added keys will be overridden -<% keys.sort.each do |user, hash| -%> +<% @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 -%> diff --git a/puppet/modules/site_static/manifests/domain.pp b/puppet/modules/site_static/manifests/domain.pp index b9177f25..b26cc9e3 100644 --- a/puppet/modules/site_static/manifests/domain.pp +++ b/puppet/modules/site_static/manifests/domain.pp @@ -1,3 +1,4 @@ +# configure static service for domain  define site_static::domain (    $ca_cert,    $key, @@ -10,19 +11,19 @@ define site_static::domain (    $domain = $name    $base_dir = '/srv/static' -  create_resources(site_static::location, $locations) +  $cafile = "${cert}\n${ca_cert}" + +  if is_hash($locations) { +    create_resources(site_static::location, $locations) +  }    x509::cert { $domain: -    content => $cert, -    notify => Service[apache] +    content => $cafile, +    notify  => Service[apache]    }    x509::key { $domain:      content => $key, -    notify => Service[apache] -  } -  x509::ca { "${domain}_ca": -    content => $ca_cert, -    notify => Service[apache] +    notify  => Service[apache]    }    apache::vhost::file { $domain: diff --git a/puppet/modules/site_static/manifests/init.pp b/puppet/modules/site_static/manifests/init.pp index 1efc510b..4a722d62 100644 --- a/puppet/modules/site_static/manifests/init.pp +++ b/puppet/modules/site_static/manifests/init.pp @@ -1,6 +1,8 @@ +# deploy static service  class site_static {    tag 'leap_service' +  include site_config::default    include site_config::x509::cert    include site_config::x509::key    include site_config::x509::ca_bundle @@ -9,6 +11,7 @@ class site_static {    $domains       = $static['domains']    $formats       = $static['formats']    $bootstrap     = $static['bootstrap_files'] +  $tor           = hiera('tor', false)    if $bootstrap['enabled'] {      $bootstrap_domain  = $bootstrap['domain'] @@ -27,14 +30,13 @@ class site_static {      }    } -  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::config::include{ 'ssl_common.inc': } - +  include apache::module::headers +  include apache::module::alias +  include apache::module::expires +  include apache::module::removeip +  include apache::module::dir +  include apache::module::negotiation +  include site_apache::common    include site_config::ruby::dev    if (member($formats, 'rack')) { @@ -46,9 +48,9 @@ class site_static {    }    if (member($formats, 'amber')) { -    rubygems::gem{'amber-0.3.7':   -       require =>  Package['zlib1g-dev'] -     } +    rubygems::gem{'amber-0.3.8': +      require =>  Package['zlib1g-dev'] +    }      package { 'zlib1g-dev':          ensure => installed @@ -57,6 +59,13 @@ class site_static {    create_resources(site_static::domain, $domains) +  if $tor { +    $hidden_service = $tor['hidden_service'] +    if $hidden_service['active'] { +      include site_webapp::hidden_service +    } +  } +    include site_shorewall::defaults    include site_shorewall::service::http    include site_shorewall::service::https diff --git a/puppet/modules/site_static/manifests/location.pp b/puppet/modules/site_static/manifests/location.pp index ce2af9af..d116de2f 100644 --- a/puppet/modules/site_static/manifests/location.pp +++ b/puppet/modules/site_static/manifests/location.pp @@ -1,3 +1,4 @@ +# configure static service for location  define site_static::location($path, $format, $source) {    $file_path = "/srv/static/${name}" @@ -14,10 +15,10 @@ define site_static::location($path, $format, $source) {    if ($format == 'amber') {      exec {"amber_build_${name}": -      cwd     => $file_path, -      command => 'amber rebuild', -      user    => 'www-data', -      timeout => 600, +      cwd       => $file_path, +      command   => 'amber rebuild', +      user      => 'www-data', +      timeout   => 600,        subscribe => Vcsrepo[$file_path]      }    } diff --git a/puppet/modules/site_static/templates/amber.erb b/puppet/modules/site_static/templates/amber.erb index 17dc2ad6..694f1136 100644 --- a/puppet/modules/site_static/templates/amber.erb +++ b/puppet/modules/site_static/templates/amber.erb @@ -1,15 +1,13 @@ -<%- if @location_path == '' -%> -  <Directory "<%= @directory %>/"> -    AllowOverride FileInfo Indexes Options=All,MultiViews -    Order deny,allow -    Allow from all -  </Directory> -<%- else -%> +<%- if @location_path != '' -%>    AliasMatch ^/[a-z]{2}/<%=@location_path%>(/.+|/|)$ "<%=@directory%>/$1"    Alias /<%=@location_path%> "<%=@directory%>/" +<%- end -%>    <Directory "<%=@directory%>/">      AllowOverride FileInfo Indexes Options=All,MultiViews +<% if scope.function_guess_apache_version([]) == '2.4' %> +    Require all granted +<% else %>      Order deny,allow      Allow from all +<% end %>    </Directory> -<%- end -%> diff --git a/puppet/modules/site_static/templates/apache.conf.erb b/puppet/modules/site_static/templates/apache.conf.erb index 4d61cc08..6b969d1c 100644 --- a/puppet/modules/site_static/templates/apache.conf.erb +++ b/puppet/modules/site_static/templates/apache.conf.erb @@ -48,7 +48,7 @@    Include include.d/ssl_common.inc  <%- if @tls_only -%> -  Header add Strict-Transport-Security: "max-age=15768000;includeSubdomains" +  Header always set Strict-Transport-Security: "max-age=15768000;includeSubdomains"  <%- end -%>    Header set X-Frame-Options "deny"    Header always unset X-Powered-By @@ -56,7 +56,6 @@    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' diff --git a/puppet/modules/site_static/templates/rack.erb b/puppet/modules/site_static/templates/rack.erb index aae91f1c..431778bb 100644 --- a/puppet/modules/site_static/templates/rack.erb +++ b/puppet/modules/site_static/templates/rack.erb @@ -1,21 +1,19 @@    #PassengerLogLevel 1    #PassengerAppEnv production    #PassengerFriendlyErrorPages on -<%- if @location_path == '' -%> -  <Directory "<%=@directory%>"> -    Order deny,allow -    Allow from all -    Options -MultiViews -  </Directory> -<%- else -%> +<%- if @location_path != '' -%>    Alias /<%=@location_path%> "<%=@directory%>"    <Location /<%=@location_path%>>      PassengerBaseURI /<%=@location_path%>      PassengerAppRoot "<%=File.dirname(@directory)%>"    </Location> +<%- end -%>    <Directory "<%=@directory%>"> +    Options -MultiViews +<% if scope.function_guess_apache_version([]) == '2.4' %> +    Require all granted +<% else %>      Order deny,allow      Allow from all -    Options -MultiViews +<% end %>    </Directory> -<%- end -%> diff --git a/puppet/modules/site_stunnel/manifests/init.pp b/puppet/modules/site_stunnel/manifests/init.pp index d919a072..a874721f 100644 --- a/puppet/modules/site_stunnel/manifests/init.pp +++ b/puppet/modules/site_stunnel/manifests/init.pp @@ -36,8 +36,8 @@ class site_stunnel {    # the default is to keep 356 log files for each stunnel.    # here we set a more reasonable number.    augeas { -    "logrotate_stunnel": -      context => "/files/etc/logrotate.d/stunnel4/rule", +    'logrotate_stunnel': +      context => '/files/etc/logrotate.d/stunnel4/rule',        changes => [          'set rotate 5',        ] diff --git a/puppet/modules/site_stunnel/manifests/override_service.pp b/puppet/modules/site_stunnel/manifests/override_service.pp index 96187048..435b9aa0 100644 --- a/puppet/modules/site_stunnel/manifests/override_service.pp +++ b/puppet/modules/site_stunnel/manifests/override_service.pp @@ -1,4 +1,9 @@ +# override stunnel::debian defaults +# +# ignore puppet lint error about inheriting from different namespace +# lint:ignore:inherits_across_namespaces  class site_stunnel::override_service inherits stunnel::debian { +# lint:endignore    include site_config::x509::cert    include site_config::x509::key diff --git a/puppet/modules/site_stunnel/manifests/servers.pp b/puppet/modules/site_stunnel/manifests/servers.pp index b6fac319..e76d1e9d 100644 --- a/puppet/modules/site_stunnel/manifests/servers.pp +++ b/puppet/modules/site_stunnel/manifests/servers.pp @@ -16,6 +16,8 @@ define site_stunnel::servers (    $rndfile    = '/var/lib/stunnel4/.rnd',    $debuglevel = '4' ) { +  $logfile = "/var/log/stunnel4/${name}.log" +    include site_config::x509::cert    include site_config::x509::key    include site_config::x509::ca @@ -35,7 +37,9 @@ define site_stunnel::servers (      pid        => "/var/run/stunnel4/${pid}.pid",      rndfile    => '/var/lib/stunnel4/.rnd',      debuglevel => $debuglevel, -    sslversion => 'TLSv1'; +    sslversion => 'TLSv1', +    syslog     => 'no', +    output     => $logfile;    }    # allow incoming connections on $accept_port diff --git a/puppet/modules/site_tor/manifests/disable_exit.pp b/puppet/modules/site_tor/manifests/disable_exit.pp index 73016646..078f80ae 100644 --- a/puppet/modules/site_tor/manifests/disable_exit.pp +++ b/puppet/modules/site_tor/manifests/disable_exit.pp @@ -1,7 +1,7 @@  class site_tor::disable_exit {    tor::daemon::exit_policy {      'no_exit_at_all': -      reject => '*:*'; +      reject => [ '*:*' ];    }  } diff --git a/puppet/modules/site_tor/manifests/init.pp b/puppet/modules/site_tor/manifests/init.pp index 80ccc5d3..2207a5a9 100644 --- a/puppet/modules/site_tor/manifests/init.pp +++ b/puppet/modules/site_tor/manifests/init.pp @@ -19,6 +19,7 @@ class site_tor {      $openvpn_ports = []    } +  include site_config::default    include tor::daemon    tor::daemon::relay { $nickname:      port           => 9001, diff --git a/puppet/modules/site_webapp/files/server-status.conf b/puppet/modules/site_webapp/files/server-status.conf new file mode 100644 index 00000000..10b2d4ed --- /dev/null +++ b/puppet/modules/site_webapp/files/server-status.conf @@ -0,0 +1,26 @@ +# Keep track of extended status information for each request +ExtendedStatus On + +# Determine if mod_status displays the first 63 characters of a request or +# the last 63, assuming the request itself is greater than 63 chars. +# Default: Off +#SeeRequestTail On + +Listen 127.0.0.1:8162 + +<VirtualHost 127.0.0.1:8162> + +<Location /server-status> +    SetHandler server-status +    Require all granted +    Allow from 127.0.0.1 +</Location> + +</VirtualHost> + + +<IfModule mod_proxy.c> +    # Show Proxy LoadBalancer status in mod_status +    ProxyStatus On +</IfModule> + diff --git a/puppet/modules/site_webapp/manifests/apache.pp b/puppet/modules/site_webapp/manifests/apache.pp index 93e172a0..80c7b29b 100644 --- a/puppet/modules/site_webapp/manifests/apache.pp +++ b/puppet/modules/site_webapp/manifests/apache.pp @@ -1,3 +1,4 @@ +# configure apache and passenger to serve the webapp  class site_webapp::apache {    $web_api          = hiera('api') @@ -11,16 +12,17 @@ class site_webapp::apache {    $webapp_domain    = $webapp['domain']    include site_apache::common -  include site_apache::module::headers -  include site_apache::module::alias -  include site_apache::module::expires -  include site_apache::module::removeip +  include apache::module::headers +  include apache::module::alias +  include apache::module::expires +  include apache::module::removeip +  include site_webapp::common_vhost    class { 'passenger': use_munin => false }    apache::vhost::file {      'api': -      content => template('site_apache/vhosts.d/api.conf.erb') +      content => template('site_apache/vhosts.d/api.conf.erb');    }  } diff --git a/puppet/modules/site_webapp/manifests/common_vhost.pp b/puppet/modules/site_webapp/manifests/common_vhost.pp new file mode 100644 index 00000000..c57aad57 --- /dev/null +++ b/puppet/modules/site_webapp/manifests/common_vhost.pp @@ -0,0 +1,18 @@ +class site_webapp::common_vhost { +  # installs x509 cert + key and common config +  # that both nagios + leap webapp use + +  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] + +  apache::vhost::file { +  'common': +    content => template('site_apache/vhosts.d/common.conf.erb') +  } +} diff --git a/puppet/modules/site_webapp/manifests/couchdb.pp b/puppet/modules/site_webapp/manifests/couchdb.pp index 1dbc745d..71450370 100644 --- a/puppet/modules/site_webapp/manifests/couchdb.pp +++ b/puppet/modules/site_webapp/manifests/couchdb.pp @@ -14,29 +14,36 @@ class site_webapp::couchdb {    file {      '/srv/leap/webapp/config/couchdb.yml':        content => template('site_webapp/couchdb.yml.erb'), -      owner   => leap-webapp, -      group   => leap-webapp, +      owner   => 'leap-webapp', +      group   => 'leap-webapp',        mode    => '0600',        require => Vcsrepo['/srv/leap/webapp']; +    # couchdb.admin.yml is a symlink to prevent the vcsrepo resource +    # from changing its user permissions every time.      '/srv/leap/webapp/config/couchdb.admin.yml': +      ensure => 'link', +      target => '/etc/leap/couchdb.admin.yml', +      require => Vcsrepo['/srv/leap/webapp']; + +    '/etc/leap/couchdb.admin.yml':        content => template('site_webapp/couchdb.admin.yml.erb'), -      owner   => leap-webapp, -      group   => leap-webapp, +      owner   => 'root', +      group   => 'root',        mode    => '0600', -      require => Vcsrepo['/srv/leap/webapp']; +      require => File['/etc/leap'];      '/srv/leap/webapp/log':        ensure  => directory, -      owner   => leap-webapp, -      group   => leap-webapp, +      owner   => 'leap-webapp', +      group   => 'leap-webapp',        mode    => '0755',        require => Vcsrepo['/srv/leap/webapp'];      '/srv/leap/webapp/log/production.log':        ensure  => present, -      owner   => leap-webapp, -      group   => leap-webapp, +      owner   => 'leap-webapp', +      group   => 'leap-webapp',        mode    => '0666',        require => Vcsrepo['/srv/leap/webapp'];    } diff --git a/puppet/modules/site_webapp/manifests/cron.pp b/puppet/modules/site_webapp/manifests/cron.pp index d26ee312..70b9da04 100644 --- a/puppet/modules/site_webapp/manifests/cron.pp +++ b/puppet/modules/site_webapp/manifests/cron.pp @@ -1,3 +1,4 @@ +# setup webapp cronjobs  class site_webapp::cron {    # cron tasks that need to be performed to cleanup the database @@ -5,27 +6,31 @@ class site_webapp::cron {      'rotate_databases':        command     => 'cd /srv/leap/webapp && bundle exec rake db:rotate',        environment => 'RAILS_ENV=production', +      user        => 'root',        hour        => [0,6,12,18],        minute      => 0;      'delete_tmp_databases':        command     => 'cd /srv/leap/webapp && bundle exec rake db:deletetmp',        environment => 'RAILS_ENV=production', +      user        => 'root',        hour        => 1,        minute      => 1;      # there is no longer a need to remove expired sessions, since the database      # will get destroyed.      'remove_expired_sessions': +      ensure      => absent,        command     => 'cd /srv/leap/webapp && bundle exec rake cleanup:sessions',        environment => 'RAILS_ENV=production', +      user        => 'leap-webapp',        hour        => 2, -      minute      => 30, -      ensure      => absent; +      minute      => 30;      'remove_expired_tokens':        command     => 'cd /srv/leap/webapp && bundle exec rake cleanup:tokens',        environment => 'RAILS_ENV=production', +      user        => 'leap-webapp',        hour        => 3,        minute      => 0;    } diff --git a/puppet/modules/site_webapp/manifests/hidden_service.pp b/puppet/modules/site_webapp/manifests/hidden_service.pp index 16b6e2e7..72a2ce95 100644 --- a/puppet/modules/site_webapp/manifests/hidden_service.pp +++ b/puppet/modules/site_webapp/manifests/hidden_service.pp @@ -4,13 +4,13 @@ class site_webapp::hidden_service {    $tor_domain       = "${hidden_service['address']}.onion"    include site_apache::common -  include site_apache::module::headers -  include site_apache::module::alias -  include site_apache::module::expires -  include site_apache::module::removeip - +  include apache::module::headers +  include apache::module::alias +  include apache::module::expires +  include apache::module::removeip +      include tor::daemon -  tor::daemon::hidden_service { 'webapp': ports => '80 127.0.0.1:80' } +  tor::daemon::hidden_service { 'webapp': ports => [ '80 127.0.0.1:80'] }    file {      '/var/lib/tor/webapp/': @@ -34,10 +34,19 @@ class site_webapp::hidden_service {        mode    => '0600';    } +  # it is necessary to zero out the config of the status module +  # because we are configuring our own version that is unavailable +  # over the hidden service (see: #7456 and #7776) +  apache::module { 'status': ensure => present, conf_content => ' ' } +  # the access_compat module is required to enable Allow directives +  apache::module { 'access_compat': ensure => present } +      apache::vhost::file {      'hidden_service': -      content => template('site_apache/vhosts.d/hidden_service.conf.erb') +      content => template('site_apache/vhosts.d/hidden_service.conf.erb'); +    'server_status': +      vhost_source => 'modules/site_webapp/server-status.conf';    }    include site_shorewall::tor -}
\ No newline at end of file +} diff --git a/puppet/modules/site_webapp/manifests/init.pp b/puppet/modules/site_webapp/manifests/init.pp index ec94c090..15925aba 100644 --- a/puppet/modules/site_webapp/manifests/init.pp +++ b/puppet/modules/site_webapp/manifests/init.pp @@ -1,3 +1,4 @@ +# configure webapp service  class site_webapp {    tag 'leap_service'    $definition_files = hiera('definition_files') @@ -20,11 +21,16 @@ class site_webapp {    include site_webapp::couchdb    include site_haproxy    include site_webapp::cron +  include site_config::default    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_nickserver + +  # remove leftovers from previous installations on webapp nodes +  include site_config::remove::webapp    group { 'leap-webapp':      ensure    => present, @@ -54,7 +60,7 @@ class site_webapp {    exec { 'bundler_update':      cwd     => '/srv/leap/webapp', -    command => '/bin/bash -c "/usr/bin/bundle check --path vendor/bundle || /usr/bin/bundle install --path vendor/bundle --without test development"', +    command => '/bin/bash -c "/usr/bin/bundle check --path vendor/bundle || /usr/bin/bundle install --path vendor/bundle --without test development debug"',      unless  => '/usr/bin/bundle check --path vendor/bundle',      user    => 'leap-webapp',      timeout => 600, @@ -163,10 +169,8 @@ class site_webapp {    # needed for the soledad-sync check which is run on the -  # webapp node (#6520) -  package { 'python-u1db': -    ensure => latest, -  } +  # webapp node +  include soledad::client    leap::logfile { 'webapp': } diff --git a/puppet/modules/site_webapp/templates/config.yml.erb b/puppet/modules/site_webapp/templates/config.yml.erb index ccde2d2e..dd55d3e9 100644 --- a/puppet/modules/site_webapp/templates/config.yml.erb +++ b/puppet/modules/site_webapp/templates/config.yml.erb @@ -1,28 +1,36 @@ -<%- require 'json' -%> -<%- cert_options = @webapp['client_certificates'] -%> -production: -  admins: <%= @webapp['admins'].inspect %> -  domain: <%= @provider_domain %> -  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'] %> -  client_cert_bit_size: <%= cert_options['bit_size'].to_i %> -  client_cert_hash: <%= cert_options['digest'] %> -  allow_limited_certs: <%= @webapp['allow_limited_certs'].inspect %> -  allow_unlimited_certs: <%= @webapp['allow_unlimited_certs'].inspect %> -  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'] %>" -  default_service_level: "<%= @webapp['default_service_level'] %>" -  service_levels: <%= scope.function_sorted_json([@webapp['service_levels']]) %> -  allow_registration: <%= @webapp['allow_registration'].inspect %> -  handle_blacklist: <%= @webapp['forbidden_usernames'].inspect %> -<%- if @webapp['engines'] && @webapp['engines'].any? -%> -  engines: -<%-   @webapp['engines'].each do |engine| -%> -    - <%= engine %> -<%-   end -%> -<%- end -%> +<% +cert_options = @webapp['client_certificates'] +production = { +  "admins" => @webapp['admins'], +  "default_locale" => @webapp['default_locale'], +  "available_locales" => @webapp['locales'], +  "domain" => @provider_domain, +  "force_ssl" => @webapp['secure'], +  "client_ca_key" => "%s/%s.key" % [scope.lookupvar('x509::variables::keys'), scope.lookupvar('site_config::params::client_ca_name')], +  "client_ca_cert" => "%s/%s.crt" % [scope.lookupvar('x509::variables::local_CAs'), scope.lookupvar('site_config::params::client_ca_name')], +  "secret_token" => @secret_token, +  "client_cert_lifespan" => cert_options['life_span'], +  "client_cert_bit_size" => cert_options['bit_size'].to_i, +  "client_cert_hash" => cert_options['digest'], +  "allow_limited_certs" => @webapp['allow_limited_certs'], +  "allow_unlimited_certs" => @webapp['allow_unlimited_certs'], +  "allow_anonymous_certs" => @webapp['allow_anonymous_certs'], +  "limited_cert_prefix" => cert_options['limited_prefix'], +  "unlimited_cert_prefix" => cert_options['unlimited_prefix'], +  "minimum_client_version" => @webapp['client_version']['min'], +  "default_service_level" => @webapp['default_service_level'], +  "service_levels" => @webapp['service_levels'], +  "allow_registration" => @webapp['allow_registration'], +  "handle_blacklist" => @webapp['forbidden_usernames'], +  "invite_required" => @webapp['invite_required'], +  "api_tokens" => @webapp['api_tokens'] +} + +if @webapp['engines'] && @webapp['engines'].any? +  production["engines"] = @webapp['engines'] +end +-%> +# +# This file is generated by puppet. This file inherits from defaults.yml. +# +<%= scope.function_sorted_yaml([{"production" => production}]) %> diff --git a/puppet/modules/soledad/manifests/client.pp b/puppet/modules/soledad/manifests/client.pp new file mode 100644 index 00000000..e470adeb --- /dev/null +++ b/puppet/modules/soledad/manifests/client.pp @@ -0,0 +1,16 @@ +# setup soledad-client +# currently needed on webapp node to run the soledad-sync test +class soledad::client { + +  tag 'leap_service' +  include soledad::common + +  package { +    'soledad-client': +      ensure  => latest, +      require => Class['site_apt::leap_repo']; +    'python-u1db': +      ensure => latest; +  } + +} diff --git a/puppet/modules/soledad/manifests/common.pp b/puppet/modules/soledad/manifests/common.pp index 8a1d664a..8d8339d4 100644 --- a/puppet/modules/soledad/manifests/common.pp +++ b/puppet/modules/soledad/manifests/common.pp @@ -1,10 +1,8 @@ +# install soledad-common, both needed both soledad-client and soledad-server  class soledad::common { -  include soledad -    package { 'soledad-common': -    ensure  => latest, -    require => User['soledad'] +    ensure  => latest;    }  } diff --git a/puppet/modules/soledad/manifests/init.pp b/puppet/modules/soledad/manifests/init.pp deleted file mode 100644 index 7cf0b729..00000000 --- a/puppet/modules/soledad/manifests/init.pp +++ /dev/null @@ -1,29 +0,0 @@ -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 index b71fab69..8674f421 100644 --- a/puppet/modules/soledad/manifests/server.pp +++ b/puppet/modules/soledad/manifests/server.pp @@ -1,11 +1,14 @@ +# setup soledad-server  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'] +  include site_config::default +  include soledad::common + +  $soledad              = hiera('soledad') +  $couchdb_user         = $soledad['couchdb_soledad_user']['username'] +  $couchdb_password     = $soledad['couchdb_soledad_user']['password'] +  $couchdb_leap_mx_user = $soledad['couchdb_leap_mx_user']['username']    $couchdb_host = 'localhost'    $couchdb_port = '5984' @@ -22,20 +25,34 @@ class soledad::server {    # 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']; +  file { +    '/etc/soledad': +      ensure => directory, +      owner  => 'root', +      group  => 'root', +      mode   => '0755'; +    '/etc/soledad/soledad-server.conf': +      content => template('soledad/soledad-server.conf.erb'), +      owner   => 'soledad', +      group   => 'soledad', +      mode    => '0640', +      notify  => Service['soledad-server'], +      require => [ User['soledad'], Group['soledad'] ]; +    '/srv/leap/soledad': +      ensure  => directory, +      owner   => 'soledad', +      group   => 'soledad', +      require => [ User['soledad'], Group['soledad'] ]; +    '/var/lib/soledad': +      ensure  => directory, +      owner   => 'soledad', +      group   => 'soledad', +      require => [ User['soledad'], Group['soledad'] ];    }    package { $sources['soledad']['package']:      ensure  => $sources['soledad']['revision'], -    require => [ -      Class['site_apt::preferences::twisted'], -      Class['site_apt::leap_repo'] ]; +    require => Class['site_apt::leap_repo'];    }    file { '/etc/default/soledad': @@ -44,7 +61,7 @@ class soledad::server {      group   => 'soledad',      mode    => '0600',      notify  => Service['soledad-server'], -    require => Class['soledad']; +    require => [ User['soledad'], Group['soledad'] ];    }    service { 'soledad-server': @@ -52,7 +69,7 @@ class soledad::server {      enable     => true,      hasstatus  => true,      hasrestart => true, -    require    => Class['soledad'], +    require    => [ User['soledad'], Group['soledad'] ],      subscribe  => [        Package['soledad-server'],        Class['Site_config::X509::Key'], @@ -62,4 +79,26 @@ class soledad::server {    include site_shorewall::soledad    include site_check_mk::agent::soledad + +  # set up users, group and directories for soledad-server +  # although the soledad users are already created by the +  # soledad-server package +  group { 'soledad': +    ensure => present, +    system => true, +  } +  user { +    'soledad': +      ensure    => present, +      system    => true, +      gid       => 'soledad', +      home      => '/srv/leap/soledad', +      require   => Group['soledad']; +    'soledad-admin': +      ensure  => present, +      system  => true, +      gid     => 'soledad', +      home    => '/srv/leap/soledad', +      require => Group['soledad']; +  }  } diff --git a/puppet/modules/soledad/templates/soledad-server.conf.erb b/puppet/modules/soledad/templates/soledad-server.conf.erb index 47d1f6e4..1c6a0d19 100644 --- a/puppet/modules/soledad/templates/soledad-server.conf.erb +++ b/puppet/modules/soledad/templates/soledad-server.conf.erb @@ -1,3 +1,12 @@  [soledad-server] -couch_url = http://<%= @couchdb_user %>:<%= @couchdb_password %>@<%= @couchdb_host %>:<%= @couchdb_port %> +couch_url   = http://<%= @couchdb_user %>:<%= @couchdb_password %>@<%= @couchdb_host %>:<%= @couchdb_port %> +create_cmd  = sudo -u soledad-admin /usr/bin/create-user-db +admin_netrc = /etc/couchdb/couchdb-soledad-admin.netrc + +[database-security] +members = <%= @couchdb_user %>, <%= @couchdb_leap_mx_user %> +# not needed, but for documentation: +# members_roles = replication +# admins = admin +# admins_roles = replication diff --git a/puppet/modules/sshd b/puppet/modules/sshd -Subproject 750a497758d94c2f5a6cad23cecc3dbde2d2f92 +Subproject 76f4f872f81209a52df2205fd88b5619df58f00 diff --git a/puppet/modules/stunnel b/puppet/modules/stunnel -Subproject b0dc7c84b5f55aec12d7d65da812037913d9dbe +Subproject 79e874c1a86ad5c48c4e726a5d4c68bd879ce45 diff --git a/puppet/modules/systemd b/puppet/modules/systemd new file mode 160000 +Subproject 6d47fd4999fe03eba6fb11c4490dcbb90d93790 diff --git a/puppet/modules/tapicero/files/tapicero.init b/puppet/modules/tapicero/files/tapicero.init deleted file mode 100755 index 7a9af45f..00000000 --- a/puppet/modules/tapicero/files/tapicero.init +++ /dev/null @@ -1,60 +0,0 @@ -#!/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 deleted file mode 100644 index ca8488c8..00000000 --- a/puppet/modules/tapicero/manifests/init.pp +++ /dev/null @@ -1,137 +0,0 @@ -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'] - -  $couchdb_mode            = $couchdb['mode'] -  $couchdb_replication     = $couchdb['replication'] - -  $sources                 = hiera('sources') - -  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']; - -    # for pid file -    '/var/run/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 => $sources['tapicero']['revision'], -    provider => $sources['tapicero']['type'], -    source   => $sources['tapicero']['source'], -    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  => false, -    hasrestart => true, -    require    => [ File['/etc/init.d/tapicero'], -                    File['/var/run/tapicero'], -                    Couchdb::Add_user[$::site_couchdb::couchdb_tapicero_user] ]; -  } - -  leap::logfile { 'tapicero': } -} diff --git a/puppet/modules/tapicero/templates/tapicero.yaml.erb b/puppet/modules/tapicero/templates/tapicero.yaml.erb deleted file mode 100644 index 8b08b49c..00000000 --- a/puppet/modules/tapicero/templates/tapicero.yaml.erb +++ /dev/null @@ -1,52 +0,0 @@ -<%- require 'json' -%> - -# -# 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 : "" -  netrc: "/etc/couchdb/couchdb.netrc" - -# file to store the last processed user record in so we can resume after -# a restart: -seq_dir: "/var/lib/leap/tapicero/" - -# Configure log_file like this if you want to log to a file instead of syslog: -#log_file: "/var/log/leap/tapicero.log" -#log_level: debug -log_level: info - -# tapicero specific options -options: -  # prefix for per user databases: -  db_prefix: "user-" -  mode: <%= @couchdb_mode %> -<%- if @couchdb_replication %> -  replication: <%= @couchdb_replication.to_json %> -<%- end -%> - -  # 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: [] -    members: -      names: -        - <%= @couchdb_soledad_user %> -        - <%= @couchdb_leap_mx_user %> -      roles: -        - replication - - diff --git a/puppet/modules/tor b/puppet/modules/tor -Subproject dcb6e748864e7dfd3c14f4f2aba4c9120f12b78 +Subproject 8c936c166b6da1ebd0e8d95e56ceee5167357d6 diff --git a/puppet/modules/try/manifests/file.pp b/puppet/modules/try/manifests/file.pp index cd1bb035..2493d343 100644 --- a/puppet/modules/try/manifests/file.pp +++ b/puppet/modules/try/manifests/file.pp @@ -32,17 +32,17 @@ define try::file (    exec {      "chmod_${name}":        command => "/bin/chmod -R ${mode} '${name}'", -      onlyif => "/usr/bin/test $mode", +      onlyif => "/usr/bin/test ${mode}",        refreshonly => true,        loglevel => debug;      "chown_${name}":        command => "/bin/chown -R ${owner} '${name}'", -      onlyif => "/usr/bin/test $owner", +      onlyif => "/usr/bin/test ${owner}",        refreshonly => true,        loglevel => debug;      "chgrp_${name}":        command => "/bin/chgrp -R ${group} '${name}'", -      onlyif => "/usr/bin/test $group", +      onlyif => "/usr/bin/test ${group}",        refreshonly => true,        loglevel => debug;    } @@ -50,31 +50,31 @@ define try::file (    if $target {      exec { "symlink_${name}":        command => "/bin/ln -s ${target} ${name}", -      onlyif => "/usr/bin/test -d '${target}'", +      onlyif  => "/usr/bin/test -d '${target}'",      }    } 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}"]] +          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}"]] +          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}"]] +        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}"]]        }      }    } diff --git a/puppet/modules/unbound b/puppet/modules/unbound -Subproject 00646b0ffc71a86981b05f983c86ace0979d1b6 +Subproject a26b91dfea3189e6777629fa00d54f51dc41f4d diff --git a/puppet/modules/vcsrepo b/puppet/modules/vcsrepo -Subproject f92d09226cfddb0c7e5e342dd199d8ea05b497c +Subproject 4e23209eaccf1ab504d35158f4141b3053327c2 | 
