├── .fixtures.yml ├── .gitignore ├── CHANGELOG.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── files ├── actionpolicy-auth │ ├── README.md │ └── util │ │ ├── actionpolicy.ddl │ │ └── actionpolicy.rb ├── policies │ ├── README.policy-format │ ├── allow_psk_root.policy_example │ ├── puppet.policy_example │ └── service.policy_example └── ssl │ ├── clients │ ├── fireagate.example.net.pem │ ├── geode.netconsonance.com.pem │ ├── heliotrope.example.net.pem │ ├── jorhett.pem │ └── sunstone.example.net.pem │ └── server │ ├── private.pem │ └── public.pem ├── lib └── facter │ └── ssldir.rb ├── manifests ├── client.pp ├── facts.pp ├── facts │ └── cronjob.pp ├── init.pp ├── middleware.pp ├── params.pp ├── plugin │ ├── actionpolicy.pp │ ├── agent.pp │ └── client.pp ├── server.pp └── userconfig.pp ├── metadata.json ├── spec ├── classes │ ├── client_spec.rb │ ├── facts │ │ └── cronjob_spec.rb │ ├── init_spec.rb │ ├── middleware_spec.rb │ └── server_spec.rb └── spec_helper.rb ├── templates ├── activemq.sysconfig.erb ├── activemq.xml.erb ├── agent.policy.erb ├── client.cfg.erb ├── jetty-realm.properties.erb ├── logrotate-auditlog.erb ├── rabbitmq.config.erb ├── server.cfg.erb └── userconfig.erb └── tests └── init.pp /.fixtures.yml: -------------------------------------------------------------------------------- 1 | fixtures: 2 | symlinks: 3 | mcollective: "#{source_dir}" 4 | 5 | forge_modules: 6 | stdlib: 7 | repo: "puppetlabs/stdlib" 8 | ref: 3.2.1 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /pkg/ 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2015-11-26 - Release 1.0.3 2 | ### Bugfix 3 | - Ensure that facts cronjob is moved into place without confirmation prompt 4 | 5 | ##2015-11-26 - Release 1.0.2 6 | ###Bugfix release 7 | 8 | ####Bugfixes 9 | - Fixed jetty password template variable reference (reported by devoncustard) 10 | 11 | ##2015-11-22 - Release 1.0.1 12 | ###Stable release 13 | 14 | This release is in use in many production sites and is stable. 15 | Only non-breaking bugfixes will be applied to 1.0.X versions going forward. 16 | 17 | Release 2.0 and above will only support Puppet 4 / future parser, 18 | and will drop support for Puppet 3 and below. 19 | 20 | ####Bugfixes 21 | - Fixed an error about referencing qualified variable in an optional class 22 | - Added/improved docs in both README and facts::cronjobs class 23 | - Fix for trailing comma on collectives (provided by Vadym Chepkov) 24 | - Fix for wrong variable name on client plugin loglevel (provided by Vadym Chepkov) 25 | - Fix for actionpolicy default name (reported by Taejon Moon) 26 | 27 | ##2015-09-08 - Release 0.1.7 28 | ###Puppet 4 Compatibility 29 | 30 | ####Features 31 | - Adjusted configuration to work with Puppet 4 32 | - Added new `mcollective::facts::cronjob::run_every` parameter to control facts updates 33 | 34 | ####Obsoletes 35 | The Hiera parameter 'mcollective::facts::cronjob::run_every' is now preferred 36 | and the only working method for Puppet 4. Use of the 'mcollective::facts' class 37 | is deprecated and will be removed in v1.0 38 | 39 | ##2015-05-27 - Release 0.1.6 40 | ###Added $logrotate_directory parameter 41 | 42 | ####Features 43 | - Added rspec tests for platform defaults 44 | - Added new $logrotate_directory variable 45 | 46 | The new variable defaults to backwards compatible changes, 47 | but allows it to be set to undef/nil to disable logrotate file installation. 48 | 49 | ##2015-05-26 - Release 0.1.5 50 | ###Added rspec tests 51 | 52 | ####Features 53 | - Added rspec tests for every class 54 | 55 | ####Bugfixes 56 | - Fix mistype in error message 57 | - Remove extra spaces that puppet-lint didn't like 58 | - Removed a set of double quotes without a variable inside 59 | - Fixed dependency resolution problem 60 | 61 | ##2015-05-25 - Release 0.1.4 62 | ###Changed to BSD 3-Clause License 63 | 64 | The module has been changed to the BSD 3-clause license. 65 | 66 | ####Features 67 | - Added CHANGELOG in Markdown format 68 | 69 | ##2015-05-19 - Release 0.1.3 70 | ###Fixed problem with ActiveMQ config file template 71 | 72 | ####Bugfixes 73 | - activemq won't replace variables inside the xml configuration without config.PropertyPlaceholderConfigurer 74 | 75 | ##2015-04-01 - Release 0.1.2 76 | ###Puppetlabs ActiveMQ 5.9 package, Improved facts.yaml generation 77 | 78 | ####Features 79 | - Use ActiveMQ 5.9 package from Puppet Labs dependency repo 80 | - Added module tests 81 | - More complete metadata 82 | 83 | ####Bugfixes 84 | - Revised facts.yaml generation to work properly regardless of Puppet stringify settings 85 | 86 | ##2014-09-10 - Release 0.1.1 87 | ###Improved documentation 88 | 89 | ##2014-07-14 - Release 0.0.1 90 | ###Original release 91 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 3.3'] 4 | gem 'puppet', puppetversion 5 | gem 'puppetlabs_spec_helper', '>= 0.1.0' 6 | gem 'puppet-lint', '>= 0.3.2' 7 | gem 'facter', '>= 1.7.0' 8 | gem 'rspec-puppet', '~> 2.1.0' 9 | 10 | # rspec must be v3.1.0 for ruby 1.8.7 11 | if RUBY_VERSION >= '1.8.7' and RUBY_VERSION < '1.9' 12 | gem 'rspec', '~> 3.1.0' 13 | end 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015, Jo Rhett 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of jorhett-mcollective nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mcollective 2 | 3 | ## Overview 4 | 5 |
6 | Cover of Learning MCollective 7 |
8 | 9 | This is an MCollective module for Puppet. It configures MCollective brokers, 10 | servers, and clients without any other dependency classes, as documented in 11 | [Learning MCollective](http://shop.oreilly.com/product/0636920032472.do). 12 | 13 | O'Reilly Media, Inc. 14 | http://shop.oreilly.com/product/0636920032472.do 15 | ISBN: [978-1-4919-4567-4](http://shop.oreilly.com/product/0636920032472.do) 16 |
17 | 18 | ## Deprecated 19 | 20 | This module is deprecated in favour of [choria](https://forge.puppet.com/choria/choria), 21 | which greatly simplifies what used to be the more complex bespoke Mcollective installations this module could create. 22 | 23 | ## Description 24 | 25 | This module can configure MCollective middleware brokers, 26 | servers, and clients. It can automatically configure complex configurations, 27 | such as networks of brokers, subcollectives, and TLS security options. 28 | 29 | With just a hostname and passwords it can create a fully working 30 | MCollective setup. With just a few more lines of input it can create 31 | TLS-validated, globally distributed MCollective environments. 32 | 33 | The module can also create authorization policies from Hiera input. 34 | 35 | ## Supported Operating Systems 36 | 37 | The module has been validated for full functionality on: 38 | 39 | * CentOS 6.4 and higher 40 | * Ubuntu 13.10 41 | * FreeBSD 9.2 and higher 42 | 43 | Updates for Solaris, MacOS, and Windows coming soon. 44 | 45 | ## Simple Setup 46 | 47 | The easiest setup is to put the passwords in Hiera and then simply 48 | include the modules in site or nodes manifest. 49 | 50 | ```YAML 51 | Hiera: common.yaml 52 | classes: 53 | - mcollective::server 54 | 55 | mcollective::hosts: 56 | - 'activemq.example.net' 57 | mcollective::client_password: 'Client Password' 58 | mcollective::server_password: 'Server Password' 59 | mcollective::psk_key : 'Salt Value' 60 | 61 | Hiera: fqdn/activemq.example.net.yaml 62 | classes: 63 | - mcollective::middleware 64 | 65 | Hiera: fqdn/admin.example.net.yaml 66 | classes: 67 | - mcollective::client 68 | ``` 69 | 70 | Or if using in profiles with declarative style assignment: 71 | 72 | ```puppet 73 | node default { 74 | include mcollective::server 75 | } 76 | node 'activemq.example.net' { 77 | include mcollective::middleware 78 | } 79 | node 'admin.example.net' { 80 | include mcollective::client 81 | } 82 | ``` 83 | 84 | This module is a companion intended for use with the Learning MCollective book. 85 | 86 | ## Facts 87 | 88 | The older version of the book refers to including the `facts` class to have facts 89 | from Facter and Puppet placed in /etc/mcollective/facts.yaml. 90 | 91 | ``` 92 | include mcollective::facts 93 | ``` 94 | 95 | While this still works, it is deprecated and will be removed in a future version. 96 | Instead, add this variable to define how many minutes between updates. 97 | 98 | ```YAML 99 | Hiera: common.yaml 100 | mcollective::facts::cronjob::run_every: 10 101 | ``` 102 | 103 | ## Bugs 104 | 105 | If you report it, and I can replicate it I'll fix it. 106 | 107 | If you have an idea for improvement I might do it. If you create a Pull request 108 | it will happen faster. If you send me changes to support more operating systems, 109 | I'll owe you beer. 110 | 111 | I'm human and prone to overwork so response times vary. YMMV. 112 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'puppetlabs_spec_helper/rake_tasks' 3 | require 'puppet-lint/tasks/puppet-lint' 4 | PuppetLint.configuration.send('disable_80chars') 5 | PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] 6 | 7 | desc "Validate manifests, templates, and ruby files" 8 | task :validate do 9 | Dir['manifests/**/*.pp'].each do |manifest| 10 | sh "puppet parser validate --noop #{manifest}" 11 | end 12 | Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| 13 | sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ 14 | end 15 | Dir['templates/**/*.erb'].each do |template| 16 | sh "erb -P -x -T '-' #{template} | ruby -c" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /files/actionpolicy-auth/README.md: -------------------------------------------------------------------------------- 1 | Action Policy Authorization Plugin 2 | ============================= 3 | 4 | This is a plugin that provides fine grained action level authorization for agents. Any MCollective agent plugins based on SimpleRPC can be restricted with authorization plugins like this one. 5 | 6 | Installation 7 | ============ 8 | 9 | * [Follow the plugin deployment guide](http://docs.puppetlabs.com/mcollective/deploy/plugins.html#method-2-copying-plugins-into-the-libdir), using the libdir copy method and placing the `actionpolicy.rb` and `actionpolicy.ddl` files in the `util` directory. 10 | 11 | Note that it is not currently possible to use the 'mco plugin package' command to package this plugin. 12 | 13 | Configuration 14 | ============= 15 | 16 | There are three settings available for the actionpolicy plugin: 17 | 18 | * `allow_unconfigured` -- whether to allow requests to agents that do not have policy files configured. Boolean, with allowed values of `0`, `1`, `y`, `n`; values of `true` or `false` are not allowed. Defaults to `0`. 19 | * `enable_default` -- whether to use a default policy file. Boolean, with allowed values of `0`, `1`, `y`, `n`; values of `true` or `false` are not allowed. Defaults to `0`. 20 | * `default_name` -- the name of the default policy file, if `enable_default` is set to `1` or `y`. 21 | 22 | General authentication configuration options can be set in the server config file. 23 | 24 | # Enables system wide rpc authorization 25 | rpcauthorization = 1 26 | # Sets the authorization provider to use the actionpolicy plugin 27 | rpcauthprovider = action_policy 28 | # Allow requests to agents without policies 29 | plugin.actionpolicy.allow_unconfigured = 1 30 | 31 | ## Default Policy Files 32 | 33 | You can optionally have a default policy file that applies in the absence of an agent-specific policy file. 34 | 35 | plugin.actionpolicy.enable_default = 1 36 | plugin.actionpolicy.default_name = default 37 | 38 | This allows you to create a policy file called default.policy which will be used unless a specific policy file exists. Note that if both 39 | `allow_unconfigured` and `enable_default` are configured, all requests will go through the default policy, as `enable_default` takes precedence 40 | over `allow_unconfigured`. 41 | 42 | Usage 43 | ===== 44 | 45 | Policies are defined in files like `/policies/.policy` 46 | 47 | Example: Puppet agent policy file 48 | 49 | # /etc/mcollective/policies/puppet.policy 50 | policy default deny 51 | allow cert=admin * * * 52 | allow cert=acme-devs * customer=acme acme::devserver 53 | allow cert=acme-devs enable disable status customer=acme * 54 | 55 | # /etc/mcollective/policies/service.policy 56 | policy default deny 57 | allow cert=puppet-admins restart (puppet().enabled=false and environment=production) or environment=development 58 | 59 | The above policy can be described as: 60 | 61 | * Allow the `admin` user to invoke all Puppet actions on all servers. 62 | * Allow the `acme-devs` user to invoke _all_ Puppet actions on machines with the fact _customer=acme_ and the config class _acme::devserver_ 63 | * Allow the `acme-devs` user to invoke the _enable, disable and status_ actions on all other machines with fact _customer=acme_ 64 | * Allow the `puppet-admins` user to restart services at any time in development but in production only when Puppet has been disabled 65 | * All other commands get denied 66 | 67 | Policy File Format 68 | ----- 69 | 70 | Policy files must have the following format: 71 | 72 | * Any lines starting with `#` are comments. 73 | * A single `policy default deny` or `policy default allow` line is permitted; it can go anywhere in the file. This default policy will apply to any commands that don't match a specific rule. If you don't specify a default policy, the value of the `plugin.actionpolicy.allow_unconfigured` setting will be used as the default. 74 | * Any number of _policy lines_ are permitted. These must be **tab delimited** lines with either four or five fields (the final field is optional) in the following order: 75 | 1. `allow` or `deny` 76 | 2. Caller ID --- must be either `*` (always matches) or **one** caller ID string (see below) 77 | 3. Actions --- must be either `*` (always matches) or a space-separated list of actions 78 | 4. Facts --- may be either `*` (always matches), a space-separated list of `fact=value` pairs (matches if _every_ listed fact matches), or any valid [compound filter string][compound] 79 | 5. Classes --- may be completely absent (always matches), `*` (always matches), a space-separated list of class names (matches if _every_ listed class is present), or any valid [compound filter string][compound] 80 | 81 | ### Notes 82 | 83 | * Like firewall rules, policy lines are processed **in order** --- ActionPolicy will allow or deny each request using the _first_ rule that matches it. A policy line matches a request if **every** field after the allow/deny field matches. 84 | * Policy lines **must** use hard tabs; editor features that convert tabs to spaces (like Vim's `expandtab`) will result in non-functional policy lines. 85 | * Compound filter strings may match on facts, classes, and data plugins (MCollective 2.2.x or later). When using data plugins in action policies, you should avoid using slow ones, as this will impact the response times of agents, the client waiting time, etc. 86 | 87 | [compound]: http://docs.puppetlabs.com/mcollective/reference/basic/basic_cli_usage.html#complex-compound-or-select-queries 88 | 89 | 90 | ### Caller ID 91 | 92 | Caller ID strings are always of the form `=`, but both the kind and the value of the ID will depend on your security plugin. See your security plugin's documentation or code for details. 93 | 94 | * The recommended SSL security plugin sets caller IDs of `cert=`, where `` is the filename of the client's public key file (minus the `.pem` extension). So a request validated with the `puppet-admins.pem` public key file would be given a caller ID of `cert=puppet-admins`. This kind of caller ID is cryptographically authenticated. 95 | * The PSK security plugin defaults to caller IDs of `uid=`, where `` is the local UID of the client process. [There are several other options available](https://github.com/puppetlabs/marionette-collective/blob/master/plugins/mcollective/security/psk.rb#L79), which can be configured with the `plugin.psk.callertype` setting. **None of PSK's caller IDs are authenticated,** and you should generally not be relying on authorization at all if you are using the PSK security plugin. 96 | 97 | 98 | Hardcoding ActionPolicy Into a Specific Agent 99 | ============================ 100 | 101 | Instead of using the site-wide authorization settings (as described above), you can also hardcode authorization plugins in your agents: 102 | 103 | module MCollective::Agent 104 | class Service "actionpolicy", 2 | :description => "Action Policy simplerpc authorization plugin", 3 | :author => "P.Loubser ", 4 | :license => "ASL 2.0", 5 | :version => "2.0.0", 6 | :url => "https://github.com/puppetlabs/mcollective-actionpolicy-authorization", 7 | :timeout => 1 8 | 9 | requires :mcollective => "2.2.1" 10 | -------------------------------------------------------------------------------- /files/actionpolicy-auth/util/actionpolicy.rb: -------------------------------------------------------------------------------- 1 | module MCollective 2 | module Util 3 | class ActionPolicy 4 | attr_accessor :config, :allow_unconfigured, :configdir, :agent, :caller, :action 5 | 6 | def self.authorize(request) 7 | ActionPolicy.new(request).authorize_request 8 | end 9 | 10 | def initialize(request) 11 | @config = Config.instance 12 | @agent = request.agent 13 | @caller = request.caller 14 | @action = request.action 15 | @allow_unconfigured = !!(config.pluginconf.fetch('actionpolicy.allow_unconfigured', 'n') =~ /^1|y/i) 16 | @configdir = @config.configdir 17 | end 18 | 19 | def authorize_request 20 | # Lookup the policy file. If none exists and @allow_unconfigured 21 | # is false the request gets denied. 22 | policy_file = lookup_policy_file 23 | 24 | # No policy file exists and allow_unconfigured is false 25 | if !policy_file && !@allow_unconfigured 26 | deny('Could not load any valid policy files. Denying based on allow_unconfigured: %s' % @allow_unconfigured) 27 | # No policy exists but allow_unconfigured is true 28 | elsif !(policy_file) && @allow_unconfigured 29 | Log.debug('Could not load any valid policy files. Allowing based on allow_unconfigured: %s' % @allow_unconfigured) 30 | return true 31 | end 32 | 33 | # A policy file exists 34 | parse_policy_file(policy_file) 35 | end 36 | 37 | def parse_policy_file(policy_file) 38 | Log.debug('Parsing policyfile for %s: %s' % [@agent, policy_file]) 39 | allow = @allow_unconfigured 40 | 41 | File.read(policy_file).each_line do |line| 42 | next if line =~ /^(#.*|\s*)$/ 43 | 44 | if line =~ /^policy\s+default\s+(\w+)/ 45 | if $1 == 'allow' 46 | allow = true 47 | else 48 | allow = false 49 | end 50 | elsif line =~ /^(allow|deny)\t+(.+?)\t+(.+?)\t+(.+?)(\t+(.+?))*$/ 51 | if check_policy($2, $3, $4, $6) 52 | if $1 == 'allow' 53 | return true 54 | else 55 | deny("Denying based on explicit 'deny' policy rule in policyfile: %s" % File.basename(policy_file)) 56 | end 57 | end 58 | else 59 | Log.debug("Cannot parse policy line: %s" % line) 60 | end 61 | end 62 | 63 | allow || deny("Denying based on default policy in %s" % File.basename(policy_file)) 64 | end 65 | 66 | # Check if a request made by a caller matches the state defined in the policy 67 | def check_policy(rpccaller, actions, facts, classes) 68 | # If we have a wildcard caller or the caller matches our policy line 69 | # then continue else skip this policy line\ 70 | if (rpccaller != '*') && (rpccaller != @caller) 71 | return false 72 | end 73 | 74 | # If we have a wildcard actions list or the request action is in the list 75 | # of actions in the policy line continue, else skip this policy line 76 | if (actions != '*') && !(actions.split.include?(@action)) 77 | return false 78 | end 79 | 80 | unless classes 81 | return parse_compound(facts) 82 | else 83 | return parse_facts(facts) && parse_classes(classes) 84 | end 85 | end 86 | 87 | def parse_facts(facts) 88 | return true if facts == '*' 89 | 90 | if is_compound?(facts) 91 | return parse_compound(facts) 92 | else 93 | facts.split.each do |fact| 94 | return false unless lookup_fact(fact) 95 | end 96 | end 97 | 98 | true 99 | end 100 | 101 | def parse_classes(classes) 102 | return true if classes == '*' 103 | 104 | if is_compound?(classes) 105 | return parse_compound(classes) 106 | else 107 | classes.split.each do |klass| 108 | return false unless lookup_class(klass) 109 | end 110 | end 111 | 112 | true 113 | end 114 | 115 | def lookup_fact(fact) 116 | if fact =~ /(.+)(<|>|=|<=|>=)(.+)/ 117 | lv = $1 118 | sym = $2 119 | rv = $3 120 | 121 | sym = '==' if sym == '=' 122 | return eval("'#{Util.get_fact(lv)}'#{sym}'#{rv}'") 123 | else 124 | Log.warn("Class found where fact was expected") 125 | return false 126 | end 127 | end 128 | 129 | def lookup_class(klass) 130 | if klass =~ /(.+)(<|>|=|<=|>=)(.+)/ 131 | Log.warn("Fact found where class was expected") 132 | return false 133 | else 134 | return Util.has_cf_class?(klass) 135 | end 136 | end 137 | 138 | def lookup(token) 139 | if token =~ /(.+)(<|>|=|<=|>=)(.+)/ 140 | return lookup_fact(token) 141 | else 142 | return lookup_class(token) 143 | end 144 | end 145 | 146 | # Here we lookup the full path of the policy file. If the policyfile 147 | # does not exist, we check to see if a default file was set and 148 | # determine its full path. If no default file exists, or default was 149 | # not specified, we return false. 150 | def lookup_policy_file 151 | policy_file = File.join(@configdir, "policies", "#{@agent}.policy") 152 | 153 | Log.debug("Looking for policy in #{policy_file}") 154 | 155 | return policy_file if File.exist?(policy_file) 156 | 157 | if @config.pluginconf.fetch('actionpolicy.enable_default', 'n') =~ /^1|y/i 158 | defaultname = @config.pluginconf.fetch('actionpolicy.default_name', 'default') 159 | default_file = File.join(@configdir, "policies", "#{defaultname}.policy") 160 | 161 | Log.debug("Initial lookup failed: looking for policy in #{default_file}") 162 | 163 | return default_file if File.exist?(default_file) 164 | end 165 | 166 | Log.debug('Could not find any policy files.') 167 | nil 168 | end 169 | 170 | # Evalute a compound statement and return its truth value 171 | def eval_statement(statement) 172 | token_type = statement.keys.first 173 | token_value = statement.values.first 174 | 175 | return token_value if (token_type != 'statement' && token_type != 'fstatement') 176 | 177 | if token_type == 'statement' 178 | return lookup(token_value) 179 | elsif token_type == 'fstatement' 180 | begin 181 | return Matcher.eval_compound_fstatement(token_value) 182 | rescue => e 183 | Log.warn("Could not call Data function in policy file: #{e}") 184 | return false 185 | end 186 | end 187 | end 188 | 189 | def is_compound?(list) 190 | list.split.each do |token| 191 | if token =~ /^!|^not$|^or$|^and$|\(.+\)/ 192 | return true 193 | end 194 | end 195 | 196 | false 197 | end 198 | 199 | def parse_compound(list) 200 | stack = Matcher.create_compound_callstack(list) 201 | 202 | begin 203 | stack.map!{ |item| eval_statement(item) } 204 | rescue => e 205 | Log.debug(e.to_s) 206 | return false 207 | end 208 | 209 | eval(stack.join(' ')) 210 | end 211 | 212 | def deny(logline) 213 | Log.debug(logline) 214 | 215 | raise(RPCAborted, 'You are not authorized to call this agent or action.') 216 | end 217 | end 218 | end 219 | end 220 | -------------------------------------------------------------------------------- /files/policies/README.policy-format: -------------------------------------------------------------------------------- 1 | All of this content is derrived from the plug's github page at 2 | https://github.com/puppetlabs/mcollective-actionpolicy-auth 3 | 4 | Policies are defined in files like /policies/.policy 5 | 6 | Any lines starting with # are comments. 7 | 8 | A single policy default deny or policy default allow line is permitted; 9 | it can go anywhere in the file. This default policy will apply to any 10 | commands that don't match a specific rule. If you don't specify a 11 | default policy, the value of the plugin.actionpolicy.allow_unconfigured 12 | setting will be used as the default. 13 | 14 | Any number of policy lines are permitted. These must be tab delimited 15 | lines with either four or five fields (the final field is optional) 16 | in the following order: 17 | 18 | allow or deny 19 | 20 | Caller ID --- must be either * (always matches) or one caller ID string 21 | 22 | Actions --- must be either * (always matches) or a space-separated list 23 | 24 | Facts --- may be either * (always matches), 25 | a space-separated list of fact=value pairs (matches if every fact matches), 26 | or any valid compound filter string 27 | 28 | Classes --- may be completely absent (always matches), 29 | * (always matches), 30 | a space-separated list of class names (matches if every class is present), 31 | or any valid compound filter string 32 | -------------------------------------------------------------------------------- /files/policies/allow_psk_root.policy_example: -------------------------------------------------------------------------------- 1 | # /etc/mcollective/policies/allow_psk_root.policy 2 | # This is insecure unless we can trust root on every client machine 3 | policy default deny 4 | allow uid=0 * * * 5 | allow gid=0 * * * 6 | -------------------------------------------------------------------------------- /files/policies/puppet.policy_example: -------------------------------------------------------------------------------- 1 | # /etc/mcollective/policies/puppet.policy 2 | policy default deny 3 | 4 | # Get out of jail free if you push out a policy that breaks authorization 5 | allow * runonce runall * * 6 | 7 | # Admins can do anything 8 | #allow cert=admin * * * 9 | 10 | # if Wile E Coyote had a dev team... 11 | 12 | # acme-devs can run puppet once or get puppet summary on any server 13 | #allow cert=acme-devs runonce summary customer=acme * 14 | 15 | # acme-devs can enable/disable puppet or run puppet on all devservers 16 | #allow cert=acme-devs enable disable runall customer=acme acme::devserver 17 | -------------------------------------------------------------------------------- /files/policies/service.policy_example: -------------------------------------------------------------------------------- 1 | # /etc/mcollective/policies/service.policy 2 | # Admins can do anything 3 | # acme-devs can do anything to acme devservers 4 | # acme-devs can do status and restart on any acme box 5 | policy default deny 6 | allow cert=admin * * * 7 | allow cert=acme-devs * customer=acme acme::devserver 8 | allow cert=acme-devs restart status customer=acme * 9 | -------------------------------------------------------------------------------- /files/ssl/clients/fireagate.example.net.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv6VEev1VADrSCgyebIut 3 | lV4FKZ9nOSwUgU/nVauisLdLcKcT9uWThVNd8sbyebqOt+fm6qaO5VuPP4rNGuuu 4 | nKhS7Cnl6oMSdkX+Fk6D/xVvIcNUljJjaR/87gy04ZwBK0UjH8/KRbC1dg9Dn/tC 5 | YHCJ2LszAzU5fSi32C9bmFqIfQg7RwxEqOODkjP/+TemVBoYa8GhxQzoWuVViW7G 6 | pSvA4FO0pjaCWBPh7OAGFyHKazyyM3zGc5VBRCYece+0YqzQUBBBgwkx7tUxlGQN 7 | BW/D85Zgwm1F5zIJe+qhCMgb0sgeSA71QTiCQtIb3/5k/pQA+kQ+seDgkp4FrTOt 8 | 2DI8SCSMH9px/SrjfAYL3vYalFHa1GvF7t85Z7CcyvfXgZ3wHHRmN473PrDsmxk1 9 | h3qzOFxstebgaEEi0Y9TF2fpYY9q0BS9DWEsKiaL3yhPmya7vhw4tgHSYX4KAkdV 10 | ZsqACcI3+yaiwzdQdrG5XuERYbNfcRT+PZgdMGkhQILlqm4iZOBXQw0/tp9C2gxu 11 | /UMeNrfaXLyuTHE30LTrN8D0WHtBJRIFETmmGoIP63+EicOr9PWW/yEyWEKz7Wyh 12 | zw1/JfSiGGGFcLv4lOUdvJjbm9Ukr3gD2LAXGcCQNz24bvVI/NG9rkaxy2TgZ/Fo 13 | F4tiTn8AgO+Xv/cRFjWKy0UCAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /files/ssl/clients/geode.netconsonance.com.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIICCgKCAgEAru8dpnUg69FVIMXrXjPrfHb8XoYlhMda05ceuOKQlG667veoQHHO 3 | K3rWtwjEhtW/kQsZGtxqiKjADJoZQ2jZ5QRHFsG1gmY8LsKhwM3oinBqyLbdav4J 4 | qTSm/z7SHOgZd6k2b+ATDpC73gbu3iFKJu5klLqJkBakvXDHchgu2YDqFnsf5Ivy 5 | Cc8yWPNxSLnJIf+9QMh+FtfkNOcFbn5SLuBTgikIEnVCWwKmxeyN5KLY8s1EhsHm 6 | ahcoPbygdmnG2n7mNeU7pTQe5PlGxu9y/ImLwypmVc6CJ0UpDupyLvIcbBkUtXE3 7 | nKkbf7109N2VxeRR/4XAjVKaGT0fpzqAzbBs02JhETuStsR2kPYRffhwz1tv4IsN 8 | TMR8BnJ6R1/POIQYfdTOmU2SeT0PCYJS/6NMXO4l5BxXmaLKGAiXJKgTXqawLS+k 9 | 8xj2Xoomr5zDAG9tVegJvCerN3KYQDvec0jRbisE16ZytwqKQJEH80Ywuv4rjDkK 10 | nKAbg8PYr48n7+l+Tj8g7vnyHSkXaRRYl2XvlIR+52mtXZrd4YWTXrp2+EIv0CWm 11 | PyzKFVJSLBwuC0dHSiZw7qOnbrthX8eVttdiVresb1AE6i+KkazAj/rb6zSYVZuH 12 | n+mLymdCGNVLmMtInQHqi42+MtkqkR/QSk1/xJk4KiXEybiVpS0K1BECAwEAAQ== 13 | -----END RSA PUBLIC KEY----- 14 | -------------------------------------------------------------------------------- /files/ssl/clients/heliotrope.example.net.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIICCgKCAgEAvwNw9s+mxC1eo1guOvlpyzPpnFUwfkCYhw8HFDBlaRHcmSZOq0jC 3 | bKbLekCG0FaTC8HuPc5cURBBsMsjx1d7Ct1F3QyGwtvWESGjwZoi2C4QUwTXaXUP 4 | +z/ILLs0pCUfsl+LQqXbc9xACjhmU+sr0JOeJE87IUQbTQxQ/HGh91LobhyJ+/32 5 | 8nI4wxjAuAtv1lxiyLTxdNca6qO4jPvkRZTyCb0L0NPOdim16MnxDUniakI0CXE5 6 | tAe6Bc4cu04ujp2m1TEiZS4foAf3QqkCiyfh2O17N58tq6Dua6oX4x4qpo+kCnXc 7 | IqyPa8pwycI9UpCqZ7KhOUQcQjpGXqE8/tZ6YkEkuc5/IMBhlfyQF+NMcv2GLFMJ 8 | 6Zdkjf8C24+uZKW0M2K5/XvjPoNUXiEx37v7LR8x4ioFs8Ei39bbTuVl9BfIHfCt 9 | fsQCKQ6kDLWfdSHP5aPYN+WnqK1ehPbekZ8ORo3y5B0zZ1VnBry2aWGN1bcjPV87 10 | RmhkcMTBS3LxtkXSZIY+zTm1D5J9WI27FRQt0+H/MpeqjbCc/44y6fwPuto8dZha 11 | PfQGRjdBOAKRVNUgoghWgwe7HO90p7TrfBjWHNs9JypUoIGnN/K5umdmbNQ7BLdm 12 | ycctTDAiyuYzZc4x0BFahHIuHXf6j4ht/hwv6LelcSt6m7KFvNHxZVUCAwEAAQ== 13 | -----END RSA PUBLIC KEY----- 14 | -------------------------------------------------------------------------------- /files/ssl/clients/jorhett.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PUBLIC KEY----- 2 | MIICCgKCAgEA5qNcK2CIiE9JVCYbv2PCYTEsQB1SgtAOIK75jXwHwtuxyWE7K5Yb 3 | NaB7TF3Ji5K+tY1Qo+GI+HgrHdX/WQiFYUjWyHYHf1MFoCDPUtIPIdtH8fgof7Tq 4 | NAHsp/+RD3YT9gVGLzutA4GBIax6ruqP4Eixttyppkf3hLs5+rlXu0XD2+nU3LMc 5 | Tlv32vAoGBTCK7eIOwJUtux5EYrPqL8HgrVehaIhtD+lL48odgtvRmZJ/wz3UZ8R 6 | 7kch6g3CPA/MoYK249SslJDK08ljW7d5lhIfjnUeYfJo043rwpgBD8Qu9dQ6jAQ6 7 | JjI4ioM+2RRe5bCo9TiB1PQQdbl7F8YGm6hLB72QZvF4k8KVtEku6teJGkkzNniV 8 | XNqyclxwTvGnMJ8PxSdX9//8sOwauMMdZ60NOpeB/izIQjXjDV6krecErQWdEhAf 9 | pZHv2jGTUjDtp5FOhsjbvRwbidVfY/6847vMeX7UVOuA6YwOFN4NS7h8bTDCLDLn 10 | r63oFspIMMDk1L4cdJseSB61m4HItkk08jO/+bpuxE2b93VjSYaz1Yd1G1VOvU7f 11 | VV+wBNgNjCubpHoVzG5atUPmCCQuf8c/GNmEcKCNX4xYYNkyfkq0B5pY1QnoRRA6 12 | 7zdNN8xoQLgQIsBabX5ek/CtjB3OdYMvFiYP60E9JKbtk9hC3RI5qFUCAwEAAQ== 13 | -----END RSA PUBLIC KEY----- 14 | -------------------------------------------------------------------------------- /files/ssl/clients/sunstone.example.net.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoUM6EhGzuua/x0ibTcNi 3 | zIXRKQHZXDWjFZyqX0wEeWSt2tWiEo99768GnxcNyOLPb/tKMCZzobgYB82XlVxm 4 | EWjjTBpmCZpBF/FkJ1rv4nIldT1ur2ScWy6sin9umMuXTldPNJweHWB+27p3gxwq 5 | dwB+uvZuUmsjGD331wsR0fgg/VGfFY9d2/eyIit6URcBENxc2ROgKQvRBZ7lNnJI 6 | i530hMAaiRCkOs8QlXmcq52TOU+yXOduzfeviBR7FRiM+1Yx88OZkCGXYvMenamv 7 | fxyR2WDMviH4t3Ie9CJTfRiJT3q282nzRraeovuxpbUHIC9deQH5pHz/orSa9xbQ 8 | 9YNKB8yXU+BdAGaOEbuYdDYC+EEvIAHdi1xBsl01//Z/yTpoH/+daC1+x06cvF5E 9 | z2Y26Eeeb/O2ofYAknSPQDU2lrSrVweSV1JD1N7yAgtmQRa4NbzhVHYNjPOBa1g1 10 | aycA7LSi+U/7W3RINkvLoNfAFBb3A3ZFvsapo2hrEclQmjdoMuEcdafbqohIoRkh 11 | ThjbhHeDmB19cnVCLGA1SMTwYcHt1hp5uJoRlxPh8RO6yTmChGuqDxk9CtK7mu0B 12 | P7DV7QEFKQCipffeYdxOQBAJjNh6L0l1Ja3lvZpdKv5isVMSzqjsffxpRgxjvzKP 13 | uTrvO0WbmbBGr/OX4AZFHr0CAwEAAQ== 14 | -----END PUBLIC KEY----- 15 | -------------------------------------------------------------------------------- /files/ssl/server/private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAotUs39Xh+D3zpp96ynmsxXOr+3sL2PQgjeseSFZ7cfux9q0w 3 | O2rb0LB2cRFPvcsE90elGuKMFDsHkt28huc+KR5s0V6Gz0nm0xo4PcPLbk+p7XyY 4 | fFMiXWAhUAXdOKppg+BnjttBcAFxmKCNOvvQcAPlbb7R/WWy89LnUSBDT3aN8ouV 5 | vYxgYrComcvZ/xzGcp1GBD3oINsmiF0bR9t1gV0c+alMgCWdthc1ZeEzpP7x8FVe 6 | KeazVCPaf98UpH5+1EC7UU2Ub85cMGYO4Qq7ZircZ8VtC7O609d6KdkvQ4gWdI7t 7 | vYBL9kBkjp+NoEWOfdF3opAkAgSZq5wHux3NewIDAQABAoIBAGra18LfuZVNGlpK 8 | p6q9ZCqC+OZj3ed2dPKMy2ePER1AnY2SI2eqfSua0W7rfFfBJbYcVvWom2IfRp4T 9 | Usd4cmtLYv+WN4NKLOZ1e1jU5uex8YI+VFapu5BpKBM6dezcr7dyCKNPsMaOu/v7 10 | yBJf822+sM1u/qB6H5Av48pyEJnQ14QYwPAdZdXcq8SyJOMTaJb/pKsJm4iLsB6p 11 | iBOallwDeHz0eARwJf5UnbFhHERe68KS0MGYSCUXXdFwh+zisPaF83Umtrhav6xp 12 | 03onTb8SP0plTQGE5CsE8gLhxavDGWzESIhBHjAQSMi6z7VCvZ1bOHgKlAzJynnV 13 | kh948wECgYEA14Os0uoEmM/nQwzMpX9v1eDB6Etf4Bo3K1vcjLa3BtuPbyG/sztE 14 | YfufEoOnPcCHp5eT2MLqP/fvRxIXNH6cr4EjsQYmwl+iwI3x6Gzx7COjTZdKpfs9 15 | zaThFNkXzW0stH8s1ewn9qNnakTJhT/l0SHIbFqMdP5kAJx4i5NwF/sCgYEAwWv7 16 | SQnc7Lo7JURvqyMYIPSSdKc0XQDRUs+JrX7VmOapwKy1mQBy2/AGw7JtyQaDZaXh 17 | GmvRwTeHY0xEGLZYlluXIGH8B1Z6jNLhZDkRLFHACgcXJ2IR/1nfnwm+Pe21xsh5 18 | IKRjQ/P9yfpJ/DWGa35ypI6fdeXGwgbPjgGfqIECgYBmLn9lrSEq1wA+UTZCja6X 19 | yK4Hlp1JowRfYXmrmgIjlTxno6fBsisVDfl5DMThyYRIGN03nAr283YWy2QHNrTR 20 | nbgvecwswq1nAKYe3nDB1o/Z/Q6ergW6mB9EBD593vKgTeATOZolHYqt3xlxPT+Y 21 | rZzaiwAnhGojxAx/mRM/uwKBgFEvdcXuceCbOoAl/YkjrdkHTwHPvNbcpP/RRMSh 22 | 3B3Vk6Lf20lhOtS+Jti1aAdcyII94gIpB13GZPl05ZBJ2V0jDIf3GMYrsjyxtxFO 23 | MrsbhTOwTjOlolA/9PDYMhXkVMwfEVh2J4Q6QWgpuiw2ezlbVdtkUeI2k/qUyUGd 24 | xNoBAoGBAJ51gN3TgEgk7jEGTX1sI1Cl0uenq43PwqoSb4UHjKDt9n0Tur4ns32N 25 | hoCKFjUmG0mxanrZYGTYkcmk3DNCVHPwBDy1Ww6PsOMnGzVlFQKN2pJS0zKbnpyB 26 | BfITdS8VjosySYeDn8znqlQ6L8r2QwSHudkj9+dvgKqTJ09Mo657 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /files/ssl/server/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAotUs39Xh+D3zpp96ynms 3 | xXOr+3sL2PQgjeseSFZ7cfux9q0wO2rb0LB2cRFPvcsE90elGuKMFDsHkt28huc+ 4 | KR5s0V6Gz0nm0xo4PcPLbk+p7XyYfFMiXWAhUAXdOKppg+BnjttBcAFxmKCNOvvQ 5 | cAPlbb7R/WWy89LnUSBDT3aN8ouVvYxgYrComcvZ/xzGcp1GBD3oINsmiF0bR9t1 6 | gV0c+alMgCWdthc1ZeEzpP7x8FVeKeazVCPaf98UpH5+1EC7UU2Ub85cMGYO4Qq7 7 | ZircZ8VtC7O609d6KdkvQ4gWdI7tvYBL9kBkjp+NoEWOfdF3opAkAgSZq5wHux3N 8 | ewIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /lib/facter/ssldir.rb: -------------------------------------------------------------------------------- 1 | # == Fact: ssldir 2 | # 3 | # A custom fact that gets the puppet client's SSLdir 4 | # 5 | Facter.add("ssldir") do 6 | setcode do 7 | Puppet[:ssldir] 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /manifests/client.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::client 2 | # 3 | # This module manages the MCollective client application 4 | # 5 | # === Parameters 6 | # 7 | # [*etcdir*] 8 | # Location of mcollective configuration files. 9 | # Defaults to $mcollective::etcdir which defaults to os-dependent location 10 | # 11 | # [*hosts*] 12 | # An array of middleware brokers for the client to connect 13 | # Defaults to $mcollective::hosts 14 | # 15 | # [*collectives*] 16 | # An array of collectives for the client to subscribe to 17 | # Defaults to $mcollective::collectives 18 | # 19 | # [*package*] 20 | # The name of the package to install or remove 21 | # Defaults to os-dependent value from mcollective::params 22 | # 23 | # [*version*] 24 | # The version or state of the package 25 | # Values: latest (default), present, absent, or specific version number 26 | # 27 | # [*unix_group*] 28 | # The unix group that will be allowed to read the client.cfg file. 29 | # This is security for the pre-shared-key when PSK is used. 30 | # Default: wheel 31 | # 32 | # [*logger_type*] 33 | # Where to send log messages. You usually want the user to see them. 34 | # Values: console (default), syslog, file 35 | # 36 | # [*log_level*] 37 | # How verbose should logging be? 38 | # Values: fatal, error, warn (default), info, debug 39 | # 40 | # [*logfacility*] 41 | # If logger_type is syslog, which log facility to use? Default: user 42 | # 43 | # [*logfile*] 44 | # If logger_type is file, what file should the logs be put in? 45 | # Default is os-dependent, often /var/log/mcollective.log 46 | # 47 | # [*keeplogs*] 48 | # Any positive value will enable log rotation retaining that many files. 49 | # A blank or 0 value will disable log rotation. 50 | # Default: 5 51 | # 52 | # [*max_log_size*] 53 | # Max size in bytes for log files before rotation happens. 54 | # Default: 2097152 (2mb) 55 | # 56 | # [*sshkey_known_hosts*] 57 | # Defines a known hosts file for use instead of ~/.ssh/known_hosts 58 | # Default: undefined (only matters if security_provider is sshkey) 59 | # 60 | # [*disc_method*] 61 | # Defines the default discovery method to use 62 | # Default: mc 63 | # 64 | # [*disc_options*] 65 | # Defines the default discovery options to use 66 | # Default: undefined 67 | # 68 | # [*da_threshold*] 69 | # Defines the threshold used to determine when to use direct addressing 70 | # Default: 10 71 | # 72 | # === Variables 73 | # 74 | # This class makes use of these variables from base mcollective class 75 | # 76 | # [*client_user*] 77 | # The username clients will use to authenticate. Default: client 78 | # 79 | # [*client_password*] 80 | # Required: The password clients will use to authenticate 81 | # 82 | # [*connector*] 83 | # Which middleware connector to use. Values: 'activemq' (default) or 'rabbitmq' 84 | # 85 | # [*port*] 86 | # Which port to connect to. Default: 61613 87 | # 88 | # [*connector_ssl*] 89 | # Use SSL service? Values: false (default), true 90 | # 91 | # [*connector_ssl_type*] 92 | # Which type of SSL encryption should be used? (ActiveMQ only) Values: anonymous (default), trusted 93 | # 94 | # [*security_provider*] 95 | # Values: psk (default), sshkey, ssl, aes_security 96 | # 97 | # [*psk_key*] 98 | # Pre-shared key if provider is psk 99 | # 100 | # [*psk_callertype*] 101 | # Valid to put in the 'caller' field of each request. 102 | # Values: uid (default), gid, user, group, identity 103 | # 104 | # === Examples 105 | # 106 | # class { 'mcollective::client': 107 | # hosts => ['activemq.example.net'], 108 | # collectives => ['mcollective'], 109 | # } 110 | # 111 | # Hiera 112 | # mcollective::hosts : 113 | # - 'activemq.example.net' 114 | # mcollective::collectives : 115 | # - 'mcollective' 116 | # 117 | class mcollective::client( 118 | # This value can be overridden in Hiera or through class parameters 119 | $unix_group = 'wheel', 120 | $etcdir = $mcollective::etcdir, 121 | $hosts = $mcollective::hosts, 122 | $collectives = $mcollective::collectives, 123 | $package = $mcollective::params::client_package_name, 124 | 125 | # Package update? 126 | $version = 'latest', 127 | $sshkey_known_hosts = undef, 128 | 129 | # Logging 130 | $logfile = $mcollective::params::logfile, 131 | $logger_type = 'console', 132 | $log_level = 'warn', 133 | $logfacility = 'user', 134 | $keeplogs = '5', 135 | $max_log_size = '2097152', 136 | $disc_method = 'mc', 137 | $disc_options = undef, 138 | $da_threshold = '10', 139 | ) 140 | inherits mcollective { 141 | 142 | validate_array( $hosts ) 143 | validate_array( $collectives ) 144 | validate_re( $version, '^present$|^latest$|^[._0-9a-zA-Z:-]+$' ) 145 | validate_re( $unix_group, '^[._0-9a-zA-Z-]+$' ) 146 | validate_re( $da_threshold, '^[0-9]+$' ) 147 | 148 | # Validate that client username and password were supplied 149 | validate_re( $client_user, '^.{5}', 'Please provide a client username' ) 150 | validate_re( $client_password, '^.{12}', 'Please provide at last twelve characters in client password' ) 151 | 152 | package { $package: 153 | ensure => $version, 154 | } 155 | 156 | file { "${etcdir}/client.cfg": 157 | ensure => file, 158 | owner => root, 159 | group => $unix_group, 160 | mode => '0440', 161 | content => template( 'mcollective/client.cfg.erb' ), 162 | require => Package[ $package ], 163 | } 164 | 165 | # Handle all per-user configurations 166 | $userdefaults = { group => 'wheel' } 167 | $userlist = hiera_hash( 'mcollective::userconfigs', false ) 168 | if is_hash( $userlist ) { 169 | create_resources( mcollective::userconfig, $userlist, $userdefaults ) 170 | } 171 | 172 | # Load in all the appropriate mcollective client plugins 173 | $defaults = { version => 'present' } 174 | $clients = hiera_hash( 'mcollective::plugin::clients', false ) 175 | if is_hash( $clients ) { 176 | create_resources( mcollective::plugin::client, $clients, $defaults ) 177 | } 178 | 179 | # Management of SSL keys 180 | if( $mcollective::security_provider == 'ssl' ) { 181 | # Ensure the package is installed before we create this directory 182 | Package[$package] -> File["${etcdir}/ssl"] 183 | 184 | # copy the server public keys to all servers 185 | realize File["${etcdir}/ssl/server/public.pem"] 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /manifests/facts.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::facts 2 | # 3 | # This module sets a positive value read by facts::cronjob 4 | # 5 | # === Example 6 | # 7 | # include mcollective::facts 8 | # 9 | # === DEPRECATED 10 | # use hiera value mcollective::facts::cronjob::run_every instead 11 | # 12 | 13 | # This looks weird, huh? Going away soon. 14 | class mcollective::facts inherits mcollective::facts::cronjob { 15 | 16 | # Just in case they define the variable and include the class both 17 | if( ! $mcollective::facts::cronjob::run_every ) { 18 | # Override to enable and set minutes 19 | Cron['mcollective-facts'] { 20 | ensure => present, 21 | minute => '*/10', 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /manifests/facts/cronjob.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::facts 2 | # 3 | # This module installs a cron script that puts Puppet facts in a file for MCollective to use 4 | # 5 | # === Example 6 | # 7 | # Hiera: 8 | # mcollective::facts::cronjob::run_every: 15 # every quarter hour 9 | # 10 | class mcollective::facts::cronjob( 11 | $run_every = 'unknown', 12 | ) 13 | inherits mcollective { 14 | 15 | # if they passed in Hiera value use that. 16 | $enable = $run_every ? { 17 | 'unknown' => 'absent', 18 | undef => 'absent', 19 | '' => 'absent', 20 | default => 'present', 21 | } 22 | 23 | # Define the minute to be all if runevery wasn't defined 24 | $minute = $enable ? { 25 | 'absent' => '*', 26 | 'present' => "*/${run_every}", 27 | } 28 | 29 | # shorten for ease of use 30 | $yamlfile = "${mcollective::etcdir}/facts.yaml" 31 | 32 | cron { 'mcollective-facts': 33 | ensure => $enable, 34 | command => "facter --puppet --yaml > ${yamlfile}.new && ! diff -q ${yamlfile}.new ${yamlfile} > /dev/null && mv -f ${yamlfile}.new ${yamlfile}", 35 | minute => $minute, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /manifests/init.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective 2 | # 3 | # This module manages the MCollective ecosystem 4 | # 5 | # === Parameters: 6 | # 7 | # [*client_user*] 8 | # The username clients will use to authenticate. Default: client 9 | # 10 | # [*client_password*] 11 | # The password clients will use to authenticate 12 | # Required for mcollective::client and mcollective::middleware classes 13 | # 14 | # [*server_user*] 15 | # The username servers will use to authenticate. Default: server 16 | # 17 | # [*server_password*] 18 | # The password servers will use to authenticate. 19 | # Required for mcollective::server and mcollective::middleware classes 20 | # 21 | # [*broker_user*] 22 | # The username brokers will use to authenticate. Default: admin 23 | # 24 | # [*broker_password*] 25 | # The password brokers will use to authenticate to each other 26 | # Required if hosts > 1 27 | # 28 | # [*connector*] 29 | # Which middleware connector to use. Values: 'activemq' (default) or 'rabbitmq' 30 | # 31 | # [*hosts*] 32 | # An array of middleware brokers to connect 33 | # 34 | # [*port*] 35 | # Which port to connect to. Default: 61613 36 | # 37 | # [*connector_ssl*] 38 | # Use SSL for connection? (ActiveMQ only) Values: false (default), true 39 | # Should change port to 61614 if this is enabled 40 | # 41 | # [*connector_ssl_type*] 42 | # Which type of SSL encryption should be used? (ActiveMQ only) Values: anonymous (default), trusted 43 | # 44 | # [*collectives*] 45 | # An array of collectives to support. Default ['mcollective'] 46 | # 47 | # [*security_provider*] 48 | # Values: psk (default), sshkey, ssl, aes_security 49 | # 50 | # [*psk_key*] 51 | # Pre-shared key if provider is psk 52 | # 53 | # [*psk_callertype*] 54 | # Valid to put in the 'caller' field of each request. 55 | # Values: uid (default), gid, user, group, identity 56 | # 57 | # [*registerinterval*] 58 | # How often to resend registration information in seconds. Default 600 59 | # 60 | # === Examples 61 | # 62 | # node default { 63 | # class { 'mcollective': 64 | # client_password => 'changeme', 65 | # server_password => 'changeme', 66 | # security_password => 'changeme', 67 | # } 68 | # } 69 | # 70 | # Hiera 71 | # mcollective::client_password : 'changeme', 72 | # mcollective::server_password : 'changeme', 73 | # mcollective::security_password : 'changeme', 74 | # 75 | class mcollective( 76 | # Puppet v3 will look for values in Hiera before falling back to defaults defined in params class 77 | # These values tend to be common based on operating system 78 | $etcdir = $mcollective::params::etcdir, 79 | $libdir = $mcollective::params::libdir, 80 | $logfile = $mcollective::params::logfile, 81 | $stomp_package = $mcollective::params::stomp_package, 82 | $stomp_version = 'latest', 83 | 84 | # Puppet v3 will look for values in Hiera before falling back to defaults defined here 85 | $server_user = 'server', 86 | $server_password = undef, 87 | $client_user = 'client', 88 | $client_password = undef, 89 | $broker_user = 'admin', 90 | $broker_password = undef, 91 | $connector = 'activemq', 92 | $connector_ssl = false, 93 | $connector_ssl_type = 'anonymous', 94 | $port = undef, 95 | $hosts, # array required - no default value 96 | $collectives = ['mcollective'], 97 | $registerinterval = 600, 98 | $security_provider = 'psk', 99 | $psk_key = undef, # will be checked if provider = psk 100 | $psk_callertype = 'uid', 101 | ) 102 | inherits mcollective::params { 103 | 104 | # Ensure that someone can order against this main class 105 | #contain 'mcollective::client' 106 | #contain 'mcollective::server' 107 | #contain 'mcollective::facts' 108 | #contain 'mcollective::middleware' 109 | 110 | # The main module just presets variables used in client classes. 111 | validate_array( $hosts ) 112 | validate_re( $connector, [ '^activemq$', '^rabbitmq$' ] ) 113 | validate_re( $security_provider, [ '^psk$', '^sshkey$', '^ssl', '^aes_security' ] ) 114 | validate_bool( $connector_ssl ) 115 | 116 | if( $security_provider == 'psk' ) { 117 | validate_re( $psk_key, '^\S{20}', 'Please use a longer string of non-whitespace characters for the pre-shared key' ) 118 | } 119 | 120 | # Set the appropriate default port based on whether SSL is enabled 121 | if( $port != undef ) { 122 | $_port = $port 123 | } 124 | else { 125 | $_port = $connector_ssl ? { true => 61614, default => 61613 } 126 | } 127 | 128 | # Ensure that the common dependency is up to date 129 | package { $stomp_package: 130 | ensure => $stomp_version, 131 | } 132 | 133 | # ensure the ssl directory exists for the lient and server modules 134 | if( ( $mcollective::security_provider == 'aes_security' ) or ( $mcollective::security_provider == 'ssl' ) ) { 135 | file { "${etcdir}/ssl": 136 | ensure => directory, 137 | owner => 0, 138 | group => 0, 139 | mode => '0555', 140 | } 141 | if( $mcollective::security_provider == 'ssl' ) { 142 | file { "${etcdir}/ssl/server": 143 | ensure => directory, 144 | owner => 0, 145 | group => 0, 146 | mode => '0555', 147 | } 148 | @file { "${etcdir}/ssl/server/public.pem": 149 | ensure => file, 150 | owner => 0, 151 | group => 0, 152 | mode => '0444', 153 | links => follow, 154 | replace => true, 155 | source => 'puppet:///modules/mcollective/ssl/server/public.pem', 156 | } 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /manifests/middleware.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::middleware 2 | # 3 | # This module manages the MCollective middleware transport 4 | # 5 | # === Parameters 6 | # 7 | # [*directory*] 8 | # Location of activemq/rabbitmq configuration files 9 | # Defaults to $mcollective::params::activemq_directory which defaults to os-dependent location 10 | # 11 | # [*user*] 12 | # Owner of the middleware configuration files 13 | # Defaults to $mcollective::params::activemq_user_name which defaults to os-dependent value 14 | # 15 | # [*config_file*] 16 | # The middleware configuration file 17 | # Defaults to $mcollective::params::activemq_config_file which defaults to os-dependent value 18 | # 19 | # [*defaults_file*] 20 | # The middleware init defaults file 21 | # Defaults to $mcollective::params::activemq_defaults_file which defaults to os-dependent value 22 | # 23 | # [*package*] 24 | # The name of the package to install or remove 25 | # Defaults to os-dependent value from mcollective::params::activemq_package_name 26 | # 27 | # [*version*] 28 | # The version or state of the package: latest, present (default), absent, or specific version number 29 | # 30 | # [*max_connections*] 31 | # The maximum number of connections: default 1000 32 | # 33 | # [*service*] 34 | # The name of the service to manage 35 | # Defaults to os-dependent value from mcollective::params::activemq_service_name 36 | # 37 | # [*java_memory_size*] 38 | # The memory size allowed for JVM heap 39 | # Defaults to '512m' 40 | # 41 | # [*ensure*] 42 | # Should the service be running? 43 | # Values: running (default), stopped 44 | # 45 | # [*enable*] 46 | # Should the service start at boot? 47 | # Values: true (default), false 48 | # 49 | # [*truststore_password*] 50 | # Password for the TLS Truststore 51 | # 52 | # [*keystore_password*] 53 | # Password for the TLS Keystore 54 | # 55 | # [*jetty_password*] 56 | # admin password for (and enable) the ActiveMQ Jetty Web Admin 57 | # Default: null (disabled) 58 | # 59 | # [*use_jmx*] 60 | # Whether to enable the ActiveMQ JMX MBeans console 61 | # Values: true, false (default) 62 | # 63 | # === Variables 64 | # 65 | # This class makes use of these variables from base mcollective class 66 | # 67 | # [*connector*] 68 | # Which middleware connector to use. Values: 'activemq' (default) or 'rabbitmq' 69 | # 70 | # [*hosts*] 71 | # An array of middleware brokers for the client to connect 72 | # Defaults to $mcollective::hosts 73 | # 74 | # [*collectives*] 75 | # An array of collectives for the client to subscribe to 76 | # Defaults to $mcollective::collectives 77 | # 78 | # [*client_user*] 79 | # The username clients will use to authenticate. Default: client 80 | # 81 | # [*client_password*] 82 | # Required: The password clients will use to authenticate 83 | # 84 | # [*server_user*] 85 | # The username servers will use to authenticate. Default: server 86 | # 87 | # [*server_password*] 88 | # The password servers will use to authenticate. 89 | # Required: The password servers will use to authenticate 90 | # 91 | # [*broker_user*] 92 | # The username brokers will use to authenticate. Default: admin 93 | # 94 | # [*broker_password*] 95 | # The password brokers will use to authenticate to each other 96 | # Required if hosts > 1 97 | # 98 | # [*port*] 99 | # Which port to connect to. Default: 61613 100 | # 101 | # [*connector_ssl*] 102 | # Use SSL service? Values: false (default), true 103 | # 104 | # [*connector_ssl_type*] 105 | # Which type of SSL encryption should be used? (ActiveMQ only) 106 | # Values: anonymous (default), trusted 107 | # 108 | # [*registerinterval*] 109 | # How often to resend registration information in seconds. Default 600 110 | # 111 | # === Examples 112 | # 113 | # class { 'mcollective::middleware': 114 | # hosts => ['activemq.1.example.net','activemq.2.example.net'], 115 | # } 116 | # 117 | # Hiera 118 | # mcollective::middleware::hosts : 119 | # - activemq.1.example.net 120 | # - activemq.2.example.net 121 | # 122 | class mcollective::middleware( 123 | $version = 'present', 124 | $max_connections = '1000', 125 | $ensure = 'running', 126 | $enable = true, 127 | $use_jmx = false, 128 | $jetty_password = undef, 129 | $java_memory_size = '512m', 130 | 131 | # This allows override for just this class 132 | $hosts = $mcollective::hosts, 133 | 134 | # These are OS-specific 135 | $package = $mcollective::params::activemq_package_name, 136 | $service = $mcollective::params::activemq_service_name, 137 | $user = $mcollective::params::activemq_user_name, 138 | $directory = $mcollective::params::activemq_directory, 139 | $config_file = $mcollective::params::activemq_config_file, 140 | $defaults_file = $mcollective::params::activemq_defaults_file, 141 | 142 | # Truststore and Keystore passwords 143 | $keystore_password = undef, # will be checked if security_provider is either tls option 144 | $truststore_password = undef, # will be checked if security_provider is 'trusted' 145 | ) 146 | inherits mcollective { 147 | 148 | # Make an array of hosts not including self 149 | validate_absolute_path( $directory ) 150 | validate_array( $hosts ) 151 | if( size($hosts) > 1 ) { 152 | $remotehostsF = reject($hosts, $::fqdn) 153 | $remotehostsH = reject($remotehostsF, $::hostname) 154 | $remotehosts = reject($remotehostsH, $::clientcert) 155 | if( size($remotehosts) > 0 ) { 156 | $brokernetwork = true 157 | validate_string( $mcollective::broker_user ) 158 | validate_string( $mcollective::broker_password ) 159 | if( $mcollective::broker_password == undef ) { 160 | validate_re( $mcollective::broker_password, '^\S{6,}+', 'Broker password must be at least 6 characters when multiple brokers are listed.' ) 161 | } 162 | } 163 | } 164 | else { 165 | $remotehosts = [] 166 | } 167 | 168 | # The main module just presets variables used in client classes. 169 | validate_re( $mcollective::connector, [ '^activemq$', '^rabbitmq$' ] ) 170 | validate_bool( $mcollective::connector_ssl ) 171 | validate_bool( $use_jmx ) 172 | 173 | # Validate that client and server username and password were supplied 174 | validate_re( $client_user, '^.{5}', 'Please provide a client username' ) 175 | validate_re( $client_password, '^.{12}', 'Please provide at last twelve characters in client password' ) 176 | validate_re( $server_user, '^.{5}', 'Please provide a server username' ) 177 | validate_re( $server_password, '^.{12}', 'Please provide at last twelve characters in server password' ) 178 | 179 | 180 | # Main menu 181 | package { $package: 182 | ensure => $version, 183 | notify => Service[ $service ], 184 | } 185 | 186 | # If Jetty is enabled, store the password in the jetty realm properties file 187 | if( ( $mcollective::connector == 'activemq' ) and ( $jetty_password != '' ) and ( $jetty_password != undef ) ) { 188 | $use_jetty = true 189 | 190 | file { "${directory}/jetty-realm.properties": 191 | ensure => file, 192 | owner => $user, 193 | group => 'nobody', 194 | mode => '0440', 195 | content => template('mcollective/jetty-realm.properties.erb'), 196 | require => Package[ $package ], 197 | before => File["${directory}/${config_file}"], 198 | } 199 | } 200 | 201 | # Now build the main file 202 | file { "${directory}/${config_file}": 203 | ensure => file, 204 | owner => $user, 205 | group => 0, 206 | mode => '0400', 207 | require => Package[ $package ], 208 | content => template( "mcollective/${config_file}.erb" ), 209 | notify => Service[ $service ], 210 | } 211 | 212 | if( ( $mcollective::connector == 'activemq' ) and ( $defaults_file != '' ) ) { 213 | file { '/etc/sysconfig/activemq': 214 | ensure => file, 215 | owner => $user, 216 | group => 0, 217 | mode => '0444', 218 | require => Package[ $package ], 219 | content => template( 'mcollective/activemq.sysconfig.erb' ), 220 | notify => Service[ $service ], 221 | } 222 | } 223 | 224 | service { $service: 225 | ensure => $ensure, 226 | enable => $enable, 227 | require => Package[ $package ], 228 | } 229 | 230 | # Set up keystore and truststore if necessary 231 | if( $mcollective::connector_ssl == true ) { 232 | validate_re( $keystore_password, '^\S{6,}$', 'Keystore password must be at least 6 characters' ) 233 | file { "${directory}/ssl": 234 | ensure => directory, 235 | owner => $user, 236 | group => 0, 237 | mode => '0500', 238 | require => Package[ $package ], 239 | } 240 | # Keystore 241 | Exec { 242 | path => ['/bin:/usr/bin:/usr/local/bin'], 243 | timeout => 20, 244 | } 245 | # I don't like it, but there's no easy way to build a template of local files. 246 | # These operations are protected by the directory being unreadable except by activemq user and root 247 | exec { 'mcollective-create-pem': 248 | cwd => "${directory}/ssl", 249 | command => "cat ${::ssldir}/certs/${clientcert}.pem ${::ssldir}/private_keys/${clientcert}.pem > ${directory}/ssl/combined.pem", 250 | creates => "${directory}/ssl/combined.pem", 251 | returns => [0], 252 | require => File["${directory}/ssl"], 253 | before => Exec['mcollective-create-p12'], 254 | } 255 | file { "${directory}/ssl/combined.pem": 256 | ensure => file, 257 | owner => 0, 258 | group => 0, 259 | mode => '0400', 260 | require => Exec['mcollective-create-pem'], 261 | } 262 | exec { 'mcollective-create-p12': 263 | cwd => "${directory}/ssl", 264 | command => "openssl pkcs12 -export -in combined.pem -out combined.p12 -name ${::clientcert} -passout pass:${keystore_password}", 265 | creates => "${directory}/ssl/combined.p12", 266 | returns => [0], 267 | require => File["${directory}/ssl/combined.pem"], 268 | before => Exec['mcollective-create-keystore'], 269 | } 270 | file { "${directory}/ssl/combined.p12": 271 | ensure => file, 272 | owner => 0, 273 | group => 0, 274 | mode => '0400', 275 | require => Exec['mcollective-create-p12'], 276 | } 277 | exec { 'mcollective-create-keystore': 278 | cwd => "${directory}/ssl", 279 | command => "keytool -noprompt -importkeystore -destkeystore keystore.jks -srcstoretype PKCS12 -srckeystore combined.p12 -alias '${::clientcert}' -storetype JKS -srcstorepass '${keystore_password}' -deststorepass '${keystore_password}'", 280 | creates => "${directory}/ssl/keystore.jks", 281 | returns => [0], 282 | require => File["${directory}/ssl"], 283 | before => File["${directory}/ssl/keystore.jks"], 284 | } 285 | file { "${directory}/ssl/keystore.jks": 286 | ensure => file, 287 | owner => $user, 288 | group => 0, 289 | mode => '0400', 290 | before => Service[ $service ], 291 | } 292 | 293 | # Truststore 294 | if( $brokernetwork or ( $mcollective::connector_ssl_type == 'trusted' ) ) { 295 | validate_re( $truststore_password, '^\S{6,}$', 'Truststore password must be at least 6 characters' ) 296 | exec { 'mcollective-create-truststore': 297 | cwd => "${directory}/ssl", 298 | command => "keytool -noprompt -importcert -alias '${::clientcert}' -file ${::ssldir}/certs/ca.pem -keystore ${directory}/ssl/truststore.jks -storetype JKS -storepass '${truststore_password}'", 299 | creates => "${directory}/ssl/truststore.jks", 300 | returns => [0], 301 | require => File["${directory}/ssl"], 302 | before => File["${directory}/ssl/truststore.jks"], 303 | } 304 | file { "${directory}/ssl/truststore.jks": 305 | ensure => file, 306 | owner => $user, 307 | group => 0, 308 | mode => '0400', 309 | before => Service[ $service ], 310 | } 311 | } 312 | 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /manifests/params.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::params 2 | # 3 | # OS-specific parameter defaults 4 | # 5 | class mcollective::params { 6 | # Default locations for certain os combinations 7 | $etcdir = $::clientversion ? { 8 | /(?:4\.)/ => '/etc/puppetlabs/mcollective', 9 | default => $::osfamily ? { 10 | /(?i-mx:redhat)/ => '/etc/mcollective', 11 | /(?i-mx:debian)/ => '/etc/mcollective', 12 | /(?i-mx:freebsd)/ => '/usr/local/etc/mcollective', 13 | default => '/etc/puppetlabs/mcollective', 14 | } 15 | } 16 | 17 | $logrotate_directory = $::osfamily ? { 18 | /(?i-mx:freebsd)/ => '/usr/local/etc/logrotate.d', 19 | default => '/etc/logrotate.d', 20 | } 21 | 22 | $libdir = $::osfamily ? { 23 | /(?i-mx:redhat)/ => '/usr/libexec/mcollective', 24 | /(?i-mx:debian)/ => '/usr/share/mcollective/plugins', 25 | /(?i-mx:freebsd)/ => '/usr/local/share', 26 | default => '/usr/libexec/mcollective', 27 | } 28 | 29 | # Stomp Package 30 | $stomp_package = $::osfamily ? { 31 | /(?i-mx:redhat)/ => 'rubygem-stomp', 32 | /(?i-mx:debian)/ => 'ruby-stomp', 33 | /(?i-mx:freebsd)/ => 'devel/rubygem-stomp', 34 | default => 'rubygem-stomp', 35 | } 36 | 37 | # Package and service names 38 | $package_name = $::osfamily ? { 39 | /(?i-mx:redhat)/ => 'mcollective', 40 | /(?i-mx:debian)/ => 'mcollective', 41 | /(?i-mx:freebsd)/ => 'sysutils/mcollective', 42 | default => 'mcollective', 43 | } 44 | 45 | $client_package_name = $::osfamily ? { 46 | /(?i-mx:redhat)/ => 'mcollective-client', 47 | /(?i-mx:debian)/ => 'mcollective-client', 48 | /(?i-mx:freebsd)/ => 'sysutils/mcollective-client', 49 | default => 'mcollective-client', 50 | } 51 | 52 | $service_name = $::osfamily ? { 53 | /(?i-mx:redhat)/ => 'mcollective', 54 | /(?i-mx:debian)/ => 'mcollective', 55 | /(?i-mx:freebsd)/ => 'mcollectived', 56 | default => 'mcollective-client', 57 | } 58 | 59 | # Logfile locations (all platforms seem identical for this for now) 60 | $logfile = '/var/log/mcollective.log' 61 | 62 | # These appear to be the same for all platforms 63 | $activemq_config_file = 'activemq.xml' 64 | $activemq_service_name = 'activemq' 65 | $activemq_user_name = 'activemq' 66 | 67 | $activemq_package_name = $::osfamily ? { 68 | /(?i-mx:redhat)/ => 'activemq', 69 | /(?i-mx:debian)/ => 'activemq', 70 | /(?i-mx:freebsd)/ => 'net/activemq', 71 | default => 'activemq', 72 | } 73 | 74 | $activemq_directory = $::osfamily ? { 75 | /(?i-mx:redhat)/ => '/etc/activemq', 76 | /(?i-mx:debian)/ => '/etc/activemq', 77 | /(?i-mx:freebsd)/ => '/usr/local/etc/activemq', 78 | default => '/etc/activemq', 79 | } 80 | 81 | $activemq_defaults_file = $::osfamily ? { 82 | /(?i-mx:redhat)/ => '/etc/sysconfig/activemq', 83 | /(?i-mx:debian)/ => '/etc/default/activemq', 84 | /(?i-mx:freebsd)/ => undef, 85 | default => undef, 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /manifests/plugin/actionpolicy.pp: -------------------------------------------------------------------------------- 1 | # == Type: mcollective::plugin::actionpolicy 2 | # 3 | # This defined type creates an actionpolicy file for one agent 4 | # 5 | # === Parameters 6 | # 7 | # [*agent*] 8 | # Name of the agent 9 | # 10 | # [*default*] 11 | # Allow (default) or Deny 12 | # 13 | # [*rules*] 14 | # A hash of rules to implement 15 | # 16 | # === Examples 17 | # 18 | # mcollective::plugin::actionpolicy { 'puppet': 19 | # default => 'deny', 20 | # } 21 | # 22 | # Hiera 23 | # puppet: 24 | # default: deny 25 | # rules: 26 | # 'get out of jail free': 27 | # policy : allow 28 | # caller : * 29 | # actions: * 30 | # facts : * 31 | # classes: * 32 | # 33 | define mcollective::plugin::actionpolicy( 34 | $agent = $name, 35 | $default = 'allow', 36 | $rules = {}, 37 | ) { 38 | 39 | # The template iterates through the rules 40 | file { "${mcollective::etcdir}/policies/${agent}.policy": 41 | ensure => present, 42 | owner => 0, 43 | group => 0, 44 | mode => '0440', 45 | replace => true, 46 | content => template( 'mcollective/agent.policy.erb' ), 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /manifests/plugin/agent.pp: -------------------------------------------------------------------------------- 1 | # == Type: mcollective::plugin::agent 2 | # 3 | # This defined type loads one agent 4 | # 5 | # === Parameters 6 | # 7 | # [*version*] 8 | # 'latest' (default) or a specific version of an agent 9 | # 10 | # [*dependencies*] 11 | # Other packages this agent depends on 12 | # 13 | # === Examples 14 | # 15 | # mcollective::plugin::agent { 'puppet': 16 | # version => 'latest', 17 | # } 18 | # 19 | # Hiera (plural version implemented in mcollective::server) 20 | # 21 | # mcollective::plugin::agents: 22 | # puppet: 23 | # version: latest 24 | # 25 | define mcollective::plugin::agent( 26 | $version = 'latest', 27 | $dependencies = [], 28 | ) { 29 | package { "mcollective-${name}-agent": 30 | ensure => $version, 31 | require => [ Package[$mcollective::server::package], $dependencies], 32 | notify => Service[ $mcollective::service_name ], 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /manifests/plugin/client.pp: -------------------------------------------------------------------------------- 1 | # == Type: mcollective::plugin::client 2 | # 3 | # This defined type loads one client application 4 | # 5 | # === Parameters 6 | # 7 | # [*version*] 8 | # 'latest' (default) or a specific version of an client 9 | # 10 | # [*dependencies*] 11 | # Other packages this client depends on 12 | # 13 | # === Examples 14 | # 15 | # mcollective::plugin::client: { 'puppet': 16 | # version => 'latest', 17 | # } 18 | # 19 | # Hiera (plural version implemented in mcollective::client) 20 | # 21 | # mcollective::plugin::clients: 22 | # puppet: 23 | # version: latest 24 | # 25 | define mcollective::plugin::client ( 26 | $version = 'latest', 27 | $dependencies = [], 28 | ) { 29 | package { "mcollective-${name}-client": 30 | ensure => $version, 31 | require => [ Package[$mcollective::client::package], $dependencies], 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /manifests/server.pp: -------------------------------------------------------------------------------- 1 | # == Class: mcollective::server 2 | # 3 | # This module manages the MCollective server agent 4 | # 5 | # === Parameters 6 | # 7 | # [*etcdir*] 8 | # Location of mcollective configuration files. 9 | # Defaults to $mcollective::etcdir which defaults to os-dependent location 10 | # 11 | # [*libdir*] 12 | # Location of mcollective ruby lib directory. 13 | # Defaults to an os-dependent location in mcollective::params 14 | # 15 | # [*hosts*] 16 | # An array of middleware brokers for the server to connect 17 | # Defaults to $mcollective::hosts 18 | # 19 | # [*collectives*] 20 | # An array of collectives for the server to subscribe to 21 | # Defaults to $mcollective::collectives 22 | # 23 | # [*package*] 24 | # The name of the package to install or remove 25 | # Defaults to os-dependent value from mcollective::params 26 | # 27 | # [*version*] 28 | # The version or state of the package 29 | # Values: latest (default) , present, absent, or specific version number 30 | # 31 | # [*service*] 32 | # The name of the service to manage 33 | # Defaults to os-dependent value from mcollective::params 34 | # 35 | # [*ensure*] 36 | # Should the service be running? 37 | # Values: running (default), stopped 38 | # 39 | # [*enable*] 40 | # Should the service start at boot? 41 | # Values: true (default), false 42 | # 43 | # [*allow_managed_resources*] 44 | # Allow management of Puppet RAL-style resources? 45 | # Values: true (default), false 46 | # 47 | # [*resource_type_whitelist*] 48 | # Which resources are allowed to be managed? 49 | # Default: none 50 | # 51 | # [*resource_type_blacklist*] 52 | # If whitelist is empty, which resources should be blocked? 53 | # Default: null 54 | # 55 | # [*audit_logfile*] 56 | # If this logfile is specified then auditing is enabled. 57 | # 58 | # [*authorization_enable*] 59 | # Where or not to enable authorization 60 | # Values: false (default), true 61 | # 62 | # [*authorization_default_policy*] 63 | # What authorization policy should be applied to agents with a specific policy? 64 | # 65 | # [*logger_type*] 66 | # Where to send log messages. You usually want the user to see them. 67 | # Values: syslog (default), file, console 68 | # 69 | # [*log_level*] 70 | # How verbose should logging be? 71 | # Values: fatal, error, warn, info (default), debug 72 | # 73 | # [*logfacility*] 74 | # If logger_type is syslog, which log facility to use? Default: user 75 | # 76 | # [*logfile*] 77 | # If logger_type is file, what file should the logs be put in? 78 | # Default is os-dependent, often /var/log/mcollective.log 79 | # 80 | # [*keeplogs*] 81 | # Any positive value will enable log rotation retaining that many files. 82 | # A blank or 0 value will disable log rotation. 83 | # Default: 5 84 | # 85 | # [*max_log_size*] 86 | # Max size in bytes for log files before rotation happens. 87 | # Default: 2097152 (2mb) 88 | # 89 | # [*logrotate_directory*] 90 | # Directory where logrotate files are stored. 91 | # Default: /etc/logrotate.d 92 | # Nil or Undef value will disable logrotate installation 93 | # 94 | # [*sshkey_authorized_keys*] 95 | # Defines a authorized keys file for use instead of ~/.ssh/authorized_keys 96 | # Default: undefined (only matters if security_provider is sshkey) 97 | # 98 | # === Variables 99 | # 100 | # This class makes use of these variables from base mcollective class 101 | # 102 | # [*server_user*] 103 | # The username servers will use to authenticate. Default: server 104 | # 105 | # [*server_password*] 106 | # The password servers will use to authenticate. 107 | # Required: The password servers will use to authenticate 108 | # 109 | # [*connector*] 110 | # Which middleware connector to use. Values: 'activemq' (default) or 'rabbitmq' 111 | # 112 | # [*port*] 113 | # Which port to connect to. Default: 61613 114 | # 115 | # [*connector_ssl*] 116 | # Use SSL connection to the service? Values: false (default), true 117 | # 118 | # [*connector_ssl_type*] 119 | # Which type of SSL encryption should be used? (ActiveMQ only) 120 | # Values: anonymous (default), trusted 121 | # 122 | # [*security_provider*] 123 | # Values: psk (default), ssl, aes_security, sshkey 124 | # 125 | # [*psk_key*] 126 | # Pre-shared key if provider is psk 127 | # 128 | # [*registerinterval*] 129 | # How often to resend registration information in seconds. Default 600 130 | # 131 | # === Examples 132 | # 133 | # class { 'mcollective::server': 134 | # authorization_enable => true, 135 | # } 136 | # 137 | # Hiera 138 | # mcollective::server::authorization_enable : true, 139 | # 140 | class mcollective::server( 141 | # Package and Service defaults that are OS-specific, can override in Hiera 142 | $package = $mcollective::params::package_name, 143 | $service = $mcollective::params::service_name, 144 | $libdir = $mcollective::params::libdir, 145 | $etcdir = $mcollective::etcdir, 146 | 147 | # Connector settings 148 | # These values can be overridden for a given server in Hiera 149 | $version = 'latest', 150 | $ensure = 'running', 151 | $enable = true, 152 | $hosts = $mcollective::hosts, 153 | $collectives = $mcollective::collectives, 154 | 155 | # Authorization 156 | $allow_managed_resources = true, 157 | $resource_type_whitelist = 'none', 158 | $resource_type_blacklist = undef, 159 | $audit_logfile = undef, 160 | $authorization_enable = undef, 161 | $authorization_default_policy = undef, 162 | $ssh_authorized_keys = undef, 163 | 164 | # Logging 165 | $logrotate_directory = $mcollective::params::logrotate_directory, 166 | $logfile = $mcollective::params::logfile, 167 | $logger_type = 'syslog', 168 | $log_level = 'info', 169 | $logfacility = 'user', 170 | $keeplogs = '5', 171 | $max_log_size = '2097152', 172 | ) 173 | inherits mcollective { 174 | 175 | validate_array( $hosts ) 176 | validate_array( $collectives ) 177 | validate_re( $version, '^present$|^latest$|^[._0-9a-zA-Z:-]+$' ) 178 | validate_re( $ensure, '^running$|^stopped$' ) 179 | validate_bool( $enable ) 180 | 181 | # Validate that server username and password were supplied 182 | validate_re( $server_user, '^.{5}', 'Please provide a server username' ) 183 | validate_re( $server_password, '^.{12}', 'Please provide at last twelve characters in server password' ) 184 | 185 | # Ensure the facts cronjob is set up or removed 186 | include mcollective::facts::cronjob 187 | 188 | # Now install the packages 189 | package { $package: 190 | ensure => $version, 191 | notify => Service[ $service ], 192 | } 193 | 194 | file { "${etcdir}/server.cfg": 195 | ensure => file, 196 | owner => 0, 197 | group => 0, 198 | mode => '0400', 199 | content => template( 'mcollective/server.cfg.erb' ), 200 | require => Package[ $package ], 201 | notify => Service[ $service ], 202 | } 203 | 204 | # Management of SSL keys 205 | if( ( $mcollective::security_provider == 'aes_security' ) or ( $mcollective::security_provider == 'ssl' ) ) { 206 | Package[$package] -> File["${etcdir}/ssl"] 207 | 208 | # copy client public keys to all servers 209 | file { "${etcdir}/ssl/clients": 210 | ensure => directory, 211 | owner => 0, 212 | group => 0, 213 | mode => '0644', 214 | links => follow, 215 | purge => true, 216 | force => true, 217 | recurse => true, 218 | source => 'puppet:///modules/mcollective/ssl/clients', 219 | require => Package[ $package ], 220 | before => Service[ $service ], 221 | } 222 | 223 | # For SSL module One keypair is shared across all servers 224 | if( $mcollective::security_provider == 'ssl' ) { 225 | # Get the public key 226 | realize File["${etcdir}/ssl/server/public.pem"] 227 | 228 | # ...and the private key 229 | file { "${etcdir}/ssl/server/private.pem": 230 | ensure => file, 231 | owner => 0, 232 | group => 0, 233 | mode => '0400', 234 | links => follow, 235 | replace => true, 236 | source => 'puppet:///modules/mcollective/ssl/server/private.pem', 237 | require => [ Package[ $package ], File["${etcdir}/ssl/server/public.pem"] ], 238 | before => Service[ $service ], 239 | } 240 | } 241 | } 242 | 243 | # Policies used by the authorization plugins 244 | if( $authorization_enable ) { 245 | # Copy any files from the policies directory 246 | file { "${etcdir}/policies": 247 | ensure => directory, 248 | owner => 0, 249 | group => 0, 250 | mode => '0444', 251 | links => follow, 252 | recurse => true, 253 | replace => true, 254 | force => true, 255 | purge => false, 256 | source => 'puppet:///modules/mcollective/policies', 257 | require => Package[ $package ], 258 | before => Service[ $service ], 259 | } 260 | 261 | file { "${libdir}/mcollective/util": 262 | ensure => directory, 263 | owner => 0, 264 | group => 0, 265 | mode => '0755', 266 | require => Package[ $package ], 267 | before => Service[ $service ], 268 | } 269 | 270 | file { "${libdir}/mcollective/util/actionpolicy.rb": 271 | ensure => file, 272 | owner => 0, 273 | group => 0, 274 | mode => '0444', 275 | source => 'puppet:///modules/mcollective/actionpolicy-auth/util/actionpolicy.rb', 276 | require => File["${etcdir}/server.cfg"], 277 | before => Service[ $service ], 278 | } 279 | 280 | file { "${libdir}/mcollective/util/actionpolicy.ddl": 281 | ensure => file, 282 | owner => 0, 283 | group => 0, 284 | mode => '0444', 285 | source => 'puppet:///modules/mcollective/actionpolicy-auth/util/actionpolicy.ddl', 286 | require => File["${etcdir}/server.cfg"], 287 | before => Service[ $service ], 288 | } 289 | 290 | # Create rules from YAML for the ActionPolicy module 291 | $actionpolicies = hiera_hash( 'mcollective::plugin::actionpolicies', false ) 292 | if is_hash( $actionpolicies ) { 293 | create_resources( mcollective::plugin::actionpolicy, $actionpolicies ) 294 | } 295 | } 296 | 297 | # Now start the daemon 298 | service { $service: 299 | ensure => $ensure, 300 | enable => $enable, 301 | require => Package[ $package ], 302 | } 303 | 304 | # Load in all the appropriate mcollective agents 305 | $defaults = { version => 'present' } 306 | $agents = hiera_hash( 'mcollective::plugin::agents', false ) 307 | if is_hash( $agents ) { 308 | create_resources( mcollective::plugin::agent, $agents, $defaults ) 309 | } 310 | 311 | # Create or remove a logrotate config for the audit log 312 | if( $audit_logfile == undef ) { 313 | $auditlog_ensure = absent 314 | } 315 | else { 316 | $auditlog_ensure = file 317 | } 318 | 319 | # Only install logrotate if the logrotate directory is installed 320 | if( $logrotate_directory ) { 321 | file { 'logrotate-directory': 322 | ensure => directory, 323 | path => $logrotate_directory, 324 | owner => 0, 325 | group => 0, 326 | mode => '0755', 327 | } 328 | file { 'logrotate-auditlog': 329 | ensure => $auditlog_ensure, 330 | path => "${logrotate_directory}/mcollective-auditlog", 331 | owner => 0, 332 | group => 0, 333 | mode => '0444', 334 | content => template( 'mcollective/logrotate-auditlog.erb' ), 335 | } 336 | } 337 | } 338 | -------------------------------------------------------------------------------- /manifests/userconfig.pp: -------------------------------------------------------------------------------- 1 | # == Type: mcollective::userconfig 2 | # 3 | # This module manages the MCollective client application 4 | # 5 | # === Parameters 6 | # 7 | # [*user*] 8 | # The user who should own the file to be created. 9 | # Default: $title 10 | # 11 | # [*group*] 12 | # The group who should own the file to be created. 13 | # Default: wheel 14 | # 15 | # [*homedir*] 16 | # The home directory of the user 17 | # Defaults to /home/$user 18 | # 19 | # [*filename*] 20 | # The name of the file to be created, relative to $homedir 21 | # Defaults to .mcollective 22 | # 23 | # [*hosts*] 24 | # An array of middleware brokers for the client to connect 25 | # Defaults to $mcollective::hosts 26 | # 27 | # [*collectives*] 28 | # An array of collectives for the client to subscribe to 29 | # Defaults to $mcollective::collectives 30 | # 31 | # [*logger_type*] 32 | # Where to send log messages. You usually want the user to see them. 33 | # Values: console (default), syslog, file 34 | # 35 | # [*log_level*] 36 | # How verbose should logging be? 37 | # Values: fatal, error, warn (default), info, debug 38 | # 39 | # === Variables 40 | # 41 | # This class makes use of these variables from base mcollective class 42 | # 43 | # [*client_user*] 44 | # The username clients will use to authenticate. 45 | # Default: client 46 | # 47 | # [*client_password*] 48 | # Required: The password clients will use to authenticate 49 | # 50 | # [*connector*] 51 | # Which middleware connector to use. Values: 'activemq' (default) or 'rabbitmq' 52 | # 53 | # [*port*] 54 | # Which port to connect to. 55 | # 56 | # [*connector_ssl*] 57 | # Use SSL service? Values: false, true 58 | # 59 | # [*connector_ssl_type*] 60 | # Which type of SSL encryption should be used? (ActiveMQ only) 61 | # 62 | # [*security_provider*] 63 | # Values: psk, sshkey, ssl, aes_security 64 | # 65 | # [*psk_key*] 66 | # Pre-shared key if provider is psk 67 | # 68 | # [*psk_callertype*] 69 | # Valid to put in the 'caller' field of each request. 70 | # Values: uid (default), gid, user, group, identity 71 | # 72 | # === Examples 73 | # 74 | # mcollective::userconfig { 'jorhett': 75 | # group => 'staff', 76 | # } 77 | # 78 | # Hiera 79 | # mcollective::userconfigs: 80 | # jill: 81 | # group: staff 82 | # jack: {} 83 | # 84 | define mcollective::userconfig( 85 | $user = $title, 86 | $group = 'wheel', 87 | $homedir = 'unknown', 88 | $filename = '.mcollective', 89 | 90 | # This value can be overridden in Hiera or through class parameters 91 | $etcdir = $mcollective::etcdir, 92 | $hosts = $mcollective::hosts, 93 | $collectives = $mcollective::collectives, 94 | 95 | # Logging 96 | $logger_type = $mcollective::client::logger_type, 97 | $log_level = $mcollective::client::log_level, 98 | ) { 99 | 100 | validate_array( $hosts ) 101 | validate_array( $collectives ) 102 | validate_re( $user, '^[._0-9a-zA-Z-]+$' ) 103 | validate_re( $group, '^[._0-9a-zA-Z-]+$' ) 104 | 105 | if( $homedir == 'unknown' ) { 106 | $homepath = "/home/${user}" 107 | } 108 | else { 109 | $homepath = $homedir 110 | } 111 | $private_key = "${homepath}/.mcollective.d/private_keys/${user}.pem" 112 | $public_key = "${homepath}/.mcollective.d/public_keys/${user}.pem" 113 | 114 | # Stubs for SSL trusted, must be created by user 115 | $ssl_private = "${homepath}/.puppet/ssl/private_keys/${user}.pem" 116 | $ssl_cert = "${homepath}/.puppet/ssl/certs/${user}.pem" 117 | $ca_cert = "${homepath}/.puppet/ssl/certs/ca.pem" 118 | 119 | file {[ 120 | "${homepath}/.mcollective.d", 121 | "${homepath}/.mcollective.d/private_keys", 122 | "${homepath}/.mcollective.d/public_keys", 123 | "${homepath}/.mcollective.d/certs", 124 | ]: 125 | ensure => 'directory', 126 | owner => $user, 127 | group => $group, 128 | } 129 | 130 | exec { "create-private-${user}": 131 | path => '/usr/bin:/usr/local/bin', 132 | command => "openssl genrsa -out ${private_key} 2048", 133 | unless => "/usr/bin/test -e ${private_key}", 134 | } 135 | 136 | exec { "create-public-${user}": 137 | path => '/usr/bin:/usr/local/bin', 138 | command => "openssl rsa -in ${private_key} -out ${public_key}", 139 | unless => "/usr/bin/test -e ${public_key}", 140 | require => Exec["create-private-${user}"], 141 | } 142 | 143 | file { "${homepath}/${filename}": 144 | ensure => file, 145 | owner => $user, 146 | group => $group, 147 | mode => '0440', 148 | content => template( 'mcollective/userconfig.erb' ), 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jorhett-mcollective", 3 | "version": "1.0.4", 4 | "author": "Jo Rhett", 5 | "license": "BSD-3-Clause", 6 | "summary": "Configures MCollective servers, clients, and middleware brokers; handles networks of brokers, subcollectives, and TLS security options", 7 | "source": "https://github.com/jorhett/puppet-mcollective", 8 | "project_page": "https://github.com/jorhett/puppet-mcollective", 9 | "issues_url": "https://github.com/jorhett/puppet-mcollective/issues", 10 | "tags": [ 11 | "mcollective", 12 | "activemq", 13 | "deprecated" 14 | ], 15 | "operatingsystem_support": [ 16 | { 17 | "operatingsystem":"RedHat", 18 | "operatingsystemrelease":[ "6","7" ] 19 | }, 20 | { 21 | "operatingsystem":"CentOS", 22 | "operatingsystemrelease":[ "6","7" ] 23 | }, 24 | { 25 | "operatingsystem":"OracleLinux", 26 | "operatingsystemrelease":[ "6","7" ] 27 | }, 28 | { 29 | "operatingsystem":"Scientific", 30 | "operatingsystemrelease":[ "6","7" ] 31 | }, 32 | { 33 | "operatingsystem":"Debian", 34 | "operatingsystemrelease":[ "6","7" ] 35 | }, 36 | { 37 | "operatingsystem": "Ubuntu", 38 | "operatingsystemrelease": [ "15.04", "14.10", "14.04", "13.10", "13.04", "12.10", "12.04" ] 39 | }, 40 | { 41 | "operatingsystem": "FreeBSD", 42 | "operatingsystemrelease": [ "10.1", "10.0", "9.3" ] 43 | } 44 | ], 45 | "requirements": [ 46 | { "name": "pe", "version_requirement": ">= 3.3.0 <= 5.0.0" }, 47 | { "name": "puppet", "version_requirement": ">= 3.5.0 <= 5.0.0" } 48 | ], 49 | "dependencies": [ 50 | { "name": "puppetlabs/stdlib", "version_requirement": ">= 3.2.0 <= 5.0.0" } 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /spec/classes/client_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'mcollective::client' do 4 | let(:pre_condition) do 5 | 'class { "mcollective": 6 | hosts => ["middleware.example.net"], 7 | client_password => "fakeTestingClientPassword", 8 | server_password => "fakeTestingServerPassword", 9 | psk_key => "fakeTestingPreSharedKey", 10 | }' 11 | end 12 | 13 | context 'with defaults for all parameters' do 14 | it do 15 | should contain_package('mcollective-client') 16 | end 17 | 18 | it do 19 | should compile.with_all_deps 20 | end 21 | end 22 | 23 | context "With a package name specified" do 24 | let :params do 25 | { 26 | :package => 'mcollective-client' 27 | } 28 | end 29 | 30 | it do 31 | should contain_package('mcollective-client').with( { 'name' => 'mcollective-client' } ) 32 | end 33 | end 34 | 35 | context "On a RedHat OS with no package name specified" do 36 | let :facts do 37 | { 38 | :osfamily => 'RedHat', 39 | } 40 | end 41 | 42 | it do 43 | should contain_package('mcollective-client').with({ 44 | 'name' => 'mcollective-client', 45 | 'ensure' => 'latest', 46 | }) 47 | end 48 | end 49 | 50 | context "On a Debian OS with no package name specified" do 51 | let :facts do 52 | { 53 | :osfamily => 'Debian' 54 | } 55 | end 56 | 57 | it do 58 | should contain_package('mcollective-client').with({ 59 | 'name' => 'mcollective-client', 60 | 'ensure' => 'latest', 61 | }) 62 | end 63 | end 64 | 65 | context "On a FreeBSD OS with no package name specified" do 66 | let :facts do 67 | { 68 | :osfamily => 'FreeBSD' 69 | } 70 | end 71 | 72 | it do 73 | should contain_package('sysutils/mcollective-client').with({ 74 | 'name' => 'sysutils/mcollective-client' 75 | }) 76 | end 77 | end 78 | 79 | context "On an unknown OS with no stomp package name specified" do 80 | let :facts do 81 | { 82 | :osfamily => 'Darwin' 83 | } 84 | end 85 | 86 | it do 87 | should contain_package('rubygem-stomp').with({ 'name' => 'rubygem-stomp' }) 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /spec/classes/facts/cronjob_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'mcollective::facts::cronjob' do 4 | let(:pre_condition) do 5 | 'class { "mcollective": 6 | hosts => ["middleware.example.net"], 7 | client_password => "fakeTestingClientPassword", 8 | server_password => "fakeTestingServerPassword", 9 | psk_key => "fakeTestingPreSharedKey", 10 | }' 11 | end 12 | 13 | context 'with defaults for all parameters' do 14 | it do 15 | should contain_cron('mcollective-facts') 16 | end 17 | 18 | it do 19 | should compile.with_all_deps 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /spec/classes/init_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'mcollective' do 4 | let(:params) do 5 | { 6 | :hosts => ['middleware.example.net'], 7 | :client_password => 'fakeTestingClientPassword', 8 | :server_password => 'fakeTestingServerPassword', 9 | :psk_key => 'fakeTestingPreSharedKey', 10 | } 11 | end 12 | 13 | context 'with defaults for all parameters' do 14 | it do 15 | should contain_class('mcollective') 16 | should contain_class('mcollective::params') 17 | end 18 | 19 | it do 20 | should compile.with_all_deps 21 | end 22 | end 23 | 24 | # Now test for failures 25 | context "Without a list of hosts" do 26 | let(:params) do { 27 | :hosts => nil, 28 | :client_password => 'fakeTestingClientPassword', 29 | :server_password => 'fakeTestingServerPassword', 30 | :psk_key => 'fakeTestingPreSharedKey', 31 | } end 32 | 33 | it do 34 | expect { should raise_error(Puppet::Error) } 35 | end 36 | end 37 | 38 | context "Without a client password" do 39 | let(:params) do { 40 | :hosts => ['middleware.example.net'], 41 | :client_password => nil, 42 | :server_password => 'fakeTestingServerPassword', 43 | :psk_key => 'fakeTestingPreSharedKey', 44 | } end 45 | 46 | it do 47 | expect { should raise_error(Puppet::Error) } 48 | end 49 | end 50 | 51 | context "Without a server password" do 52 | let(:params) do { 53 | :hosts => ['middleware.example.net'], 54 | :client_password => 'fakeTestingClientPassword', 55 | :server_password => nil, 56 | :psk_key => 'fakeTestingPreSharedKey', 57 | } end 58 | 59 | it do 60 | expect { should raise_error(Puppet::Error) } 61 | end 62 | end 63 | 64 | context "Without a pre-shared key" do 65 | let(:params) do { 66 | :hosts => ['middleware.example.net'], 67 | :client_password => 'fakeTestingClientPassword', 68 | :server_password => 'fakeTestingServerPassword', 69 | :psk_key => nil, 70 | } end 71 | 72 | it do 73 | expect { should raise_error(Puppet::Error) } 74 | end 75 | end 76 | 77 | #at_exit { RSpec::Puppet::Coverage.report! } 78 | end 79 | -------------------------------------------------------------------------------- /spec/classes/middleware_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'mcollective::middleware' do 4 | let(:pre_condition) do 5 | 'class { "mcollective": 6 | hosts => ["middleware.example.net"], 7 | client_password => "fakeTestingClientPassword", 8 | server_password => "fakeTestingServerPassword", 9 | psk_key => "fakeTestingPreSharedKey", 10 | }' 11 | end 12 | 13 | let(:params) do 14 | { 15 | } 16 | end 17 | 18 | context 'with defaults for all parameters' do 19 | it do 20 | should compile.with_all_deps 21 | end 22 | end 23 | 24 | # Now test for failures 25 | context "Without a list of hosts" do 26 | let(:params) do { 27 | :hosts => nil, 28 | :client_password => 'fakeTestingClientPassword', 29 | :server_password => 'fakeTestingServerPassword', 30 | :psk_key => 'fakeTestingPreSharedKey', 31 | } end 32 | 33 | it do 34 | expect { should raise_error(Puppet::Error) } 35 | end 36 | end 37 | 38 | context 'with defaults for all parameters' do 39 | it do 40 | should contain_package('activemq') 41 | end 42 | 43 | it do 44 | should compile.with_all_deps 45 | end 46 | end 47 | 48 | context "With the rabbitmq package name specified" do 49 | let :params do 50 | { 51 | :package => 'rabbitmq' 52 | } 53 | end 54 | 55 | it do 56 | should contain_package('rabbitmq').with( { 'name' => 'rabbitmq' } ) 57 | end 58 | end 59 | end 60 | -------------------------------------------------------------------------------- /spec/classes/server_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'mcollective::server' do 4 | let(:pre_condition) { 5 | 'class { "mcollective": 6 | hosts => ["middleware.example.net"], 7 | client_password => "fakeTestingClientPassword", 8 | server_password => "fakeTestingServerPassword", 9 | psk_key => "fakeTestingPreSharedKey", 10 | }' 11 | } 12 | 13 | context 'with defaults for all parameters' do 14 | it do 15 | should contain_package('mcollective') 16 | end 17 | 18 | it do 19 | should compile.with_all_deps 20 | end 21 | end 22 | 23 | context "With a package name specified" do 24 | let :params do 25 | { 26 | :package => 'mcollectived' 27 | } 28 | end 29 | 30 | it do 31 | should contain_package('mcollectived').with({ 32 | 'name' => 'mcollectived' 33 | }) 34 | end 35 | end 36 | 37 | context "With an undefined logrotate directory" do 38 | let :params do 39 | { 40 | :logrotate_directory => '', 41 | } 42 | end 43 | 44 | it do 45 | should_not contain_file('logrotate-directory') 46 | end 47 | end 48 | 49 | context "On a RedHat OS with no package name specified" do 50 | let :facts do 51 | { 52 | :osfamily => 'RedHat', 53 | } 54 | end 55 | 56 | it do 57 | should contain_package('mcollective').with({ 58 | 'name' => 'mcollective', 59 | 'ensure' => 'latest', 60 | }) 61 | should contain_service('mcollective').with({ 62 | 'name' => 'mcollective', 63 | 'ensure' => 'running', 64 | }) 65 | should contain_file('logrotate-directory').with({ 66 | 'path' => '/etc/logrotate.d', 67 | }) 68 | end 69 | end 70 | 71 | context "On a Debian OS with no package name specified" do 72 | let :facts do 73 | { 74 | :osfamily => 'Debian' 75 | } 76 | end 77 | 78 | it do 79 | should contain_package('mcollective').with({ 80 | 'name' => 'mcollective', 81 | 'ensure' => 'latest', 82 | }) 83 | should contain_service('mcollective').with({ 84 | 'name' => 'mcollective', 85 | 'ensure' => 'running', 86 | }) 87 | end 88 | end 89 | 90 | context "On a FreeBSD OS with no package name specified" do 91 | let :facts do 92 | { 93 | :osfamily => 'FreeBSD' 94 | } 95 | end 96 | 97 | it do 98 | should contain_package('sysutils/mcollective').with({ 99 | 'name' => 'sysutils/mcollective', 100 | }) 101 | should contain_service('mcollectived').with({ 102 | 'name' => 'mcollectived', 103 | 'ensure' => 'running', 104 | }) 105 | end 106 | end 107 | 108 | context "On an unknown OS with no stomp package name specified" do 109 | let :facts do 110 | { 111 | :osfamily => 'Darwin' 112 | } 113 | end 114 | 115 | it do 116 | should contain_package('rubygem-stomp').with({ 'name' => 'rubygem-stomp' }) 117 | end 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'puppetlabs_spec_helper/module_spec_helper' 3 | -------------------------------------------------------------------------------- /templates/activemq.sysconfig.erb: -------------------------------------------------------------------------------- 1 | ACTIVEMQ_OPTS_MEMORY="-Xms<%= @java_memory_size -%> -Xmx<%= @java_memory_size -%>" 2 | -------------------------------------------------------------------------------- /templates/activemq.xml.erb: -------------------------------------------------------------------------------- 1 | 17 | 22 | 23 | 24 | 25 | 26 | 32 | useJmx="true" 33 | populateJMSXUserID="true" 34 | <% end -%> 35 | > 36 | 37 | 38 | 39 | 40 | 47 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 85 | 86 | 88 | createConnector="true" 89 | connectorHost="localhost" 90 | rmiServerPort="1098" 91 | connectorPort="1099" 92 | <% else -%> 93 | createConnector="false" 94 | <% end -%> 95 | /> 96 | 97 | 98 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | <% if( @brokernetwork == true ) then -%> 112 | 113 | <% end -%> 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | <% if( @brokernetwork == true ) then -%> 124 | 125 | 126 | <% end -%> 127 | <%- @collectives.each do |collective| -%> 128 | 129 | 130 | 131 | 132 | 133 | 134 | <%- end -%> 135 | 136 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | <%- 168 | # DoS protection, limit concurrent connections (default 1000) and frame size to 100MB 169 | dos_params = 'maximumConnections=' + @max_connections 170 | dos_params += '&wireFormat.maxFrameSize=104857600' 171 | ssl_connector_params = dos_params 172 | if( scope.lookupvar('mcollective::connector_ssl_type') == 'trusted' ) then 173 | ssl_connector_params = 'needClientAuth=true&' + dos_params 174 | end 175 | -%> 176 | <% if( scope.lookupvar('mcollective::connector_ssl') ) then -%> 177 | 178 | 182 | 183 | <% if( @brokernetwork == true ) then -%> 184 | 188 | <% end -%> 189 | 190 | 191 | 192 | 195 | trustStore="ssl/truststore.jks" trustStorePassword="<%= @truststore_password -%>" 196 | <% end -%> 197 | /> 198 | 199 | <% else -%> 200 | 201 | 202 | 206 | <% if( @brokernetwork == true ) then -%> 207 | 211 | <% end -%> 212 | 213 | <% end # brokernetwork -%> 214 | 215 | 216 | <%- @remotehosts.each do |remotehost| -%> 217 | 220 | uri="static:(ssl://<%= remotehost -%>:61617?wireFormat.tightEncodingEnabled=false&wireFormat.maxInactivityDuration=0)" 221 | <% else -%> 222 | uri="static:(tcp://<%= remotehost -%>:61616?wireFormat.tightEncodingEnabled=false&wireFormat.maxInactivityDuration=0)" 223 | <% end -%> 224 | userName="<%= scope.lookupvar('mcollective::broker_user') -%>" 225 | password="<%= scope.lookupvar('mcollective::broker_password') -%>" 226 | duplex="false" 227 | decreaseNetworkConsumerPriority="true" 228 | suppressDuplicateTopicSubscriptions="true" 229 | networkTTL="2" 230 | dynamicOnly="true" 231 | conduitSubscriptions="true" 232 | > 233 | 234 | 235 | 236 | 237 | 240 | uri="static:(ssl://<%= remotehost -%>:61617?wireFormat.tightEncodingEnabled=false&wireFormat.maxInactivityDuration=0)" 241 | <% else -%> 242 | uri="static:(tcp://<%= remotehost -%>:61616?wireFormat.tightEncodingEnabled=false&wireFormat.maxInactivityDuration=0)" 243 | <% end -%> 244 | userName="<%= scope.lookupvar('mcollective::broker_user') -%>" 245 | password="<%= scope.lookupvar('mcollective::broker_password') -%>" 246 | duplex="false" 247 | decreaseNetworkConsumerPriority="true" 248 | suppressDuplicateTopicSubscriptions="true" 249 | networkTTL="2" 250 | dynamicOnly="true" 251 | conduitSubscriptions="false" 252 | > 253 | 254 | 255 | 256 | 257 | <% end -%> 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | <% if( @use_jetty ) then -%> 266 | 270 | 271 | <% end -%> 272 | 273 | -------------------------------------------------------------------------------- /templates/agent.policy.erb: -------------------------------------------------------------------------------- 1 | # /etc/mcollective/policies/<%= @agent -%>.policy 2 | <% if( @default ) then -%> 3 | policy default <%= @default %> 4 | <% end -%> 5 | <% @rules.sort.map do |comment, rule| -%> 6 | # <%= comment %> 7 | <%= rule['policy'] %> <%= rule['caller'] %> <%= rule['actions'] %> <%= rule['facts'] %> <%= rule['classes'] %> 8 | <% end -%> 9 | -------------------------------------------------------------------------------- /templates/client.cfg.erb: -------------------------------------------------------------------------------- 1 | # Connector 2 | libdir = <%= scope.lookupvar('mcollective::libdir') %> 3 | <% if( scope.lookupvar('::clientversion').to_f >= 4.0 ) then -%> 4 | libdir = /opt/puppetlabs/mcollective/plugins 5 | <% end -%> 6 | direct_addressing = 1 7 | <% if( @collectives ) then -%> 8 | main_collective = <%= @collectives[0] %> 9 | collectives = <%= @collectives.join(',') %> 10 | <% end -%> 11 | 12 | connector = <%= scope.lookupvar('mcollective::connector') %> 13 | <% if( scope.lookupvar('mcollective::connector') == 'rabbitmq' ) then -%> 14 | plugin.rabbitmq.vhost = /mcollective 15 | <% elsif( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 16 | plugin.activemq.heartbeat_interval = 30 17 | <% end -%> 18 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.size = <%= @hosts.length %> 19 | <% @hosts.each_with_index do |mqhost, index| -%> 20 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.host = <%= mqhost %> 21 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.port = <%= scope.lookupvar('mcollective::_port') %> 22 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.user = <%= scope.lookupvar('mcollective::client_user') %> 23 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.password = <%= scope.lookupvar('mcollective::client_password') %> 24 | <% if( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 25 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl = <%= scope.lookupvar('mcollective::connector_ssl') %> 26 | <% if( scope.lookupvar('mcollective::connector_ssl_type') != 'trusted' ) then -%> 27 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.fallback = true 28 | <% end -%> 29 | <% end -%> 30 | <% end -%> 31 | 32 | # Security provider 33 | <% if( scope.lookupvar('mcollective::security_provider') == 'psk' ) then -%> 34 | securityprovider = psk 35 | plugin.psk = <%= scope.lookupvar('mcollective::psk_key') %> 36 | plugin.psk.callertype = <%= scope.lookupvar('mcollective::psk_callertype') %> 37 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'sshkey' ) then -%> 38 | securityprovider = sshkey 39 | <% if( @sshkey_known_hosts ) then -%> 40 | plugin.sshkey.client.known_hosts = <%= @sshkey_known_hosts %> 41 | <% end -%> 42 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'ssl' ) then -%> 43 | securityprovider = ssl 44 | plugin.ssl_server_public = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/server/public.pem 45 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'aes_security' ) then -%> 46 | securityprovider = aes_security 47 | <% end -%> 48 | 49 | # Discovery 50 | default_discovery_method = <%= scope.lookupvar('disc_method') %> 51 | <% if( scope.lookupvar('da_threshold') != '' ) then -%> 52 | direct_addressing_threshold = <%= scope.lookupvar('da_threshold') %> 53 | <% end -%> 54 | <% if( scope.lookupvar('disc_options') != '' ) then -%> 55 | default_discovery_options = <%= scope.lookupvar('disc_options') %> 56 | <% end -%> 57 | 58 | # Miscellaneous settings 59 | color = 1 60 | rpclimitmethod = first 61 | 62 | # Performance settings 63 | direct_addressing_threshold = 10 64 | ttl = 60 65 | 66 | # Logging 67 | logger_type = <%= @logger_type %> 68 | loglevel = <%= @log_level %> 69 | <% if( @logger_type == 'syslog' ) then -%> 70 | logfacility = <%= @logfacility %> 71 | <% end -%> 72 | <% if( @logger_type == 'file' ) then -%> 73 | logfile = <%= @logfile %> 74 | <% if( @keeplogs ) then -%> 75 | keeplogs = <%= @keeplogs %> 76 | <% end -%> 77 | <% if( @max_log_size ) then -%> 78 | max_log_size = <%= @max_log_size %> 79 | <% end -%> 80 | <% end -%> 81 | -------------------------------------------------------------------------------- /templates/jetty-realm.properties.erb: -------------------------------------------------------------------------------- 1 | ## --------------------------------------------------------------------------- 2 | ## Licensed to the Apache Software Foundation (ASF) under one or more 3 | ## contributor license agreements. See the NOTICE file distributed with 4 | ## this work for additional information regarding copyright ownership. 5 | ## The ASF licenses this file to You under the Apache License, Version 2.0 6 | ## (the "License"); you may not use this file except in compliance with 7 | ## the License. You may obtain a copy of the License at 8 | ## 9 | ## http://www.apache.org/licenses/LICENSE-2.0 10 | ## 11 | ## Unless required by applicable law or agreed to in writing, software 12 | ## distributed under the License is distributed on an "AS IS" BASIS, 13 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | ## See the License for the specific language governing permissions and 15 | ## limitations under the License. 16 | ## --------------------------------------------------------------------------- 17 | 18 | # Defines users that can access the web (console, demo, etc.) 19 | # username: password [,rolename ...] 20 | admin: <%= @jetty_password -%>, admin 21 | # user: user, user 22 | -------------------------------------------------------------------------------- /templates/logrotate-auditlog.erb: -------------------------------------------------------------------------------- 1 | # This doesn't specify a time interval or a size, so as to inherit any site-specific policy 2 | <%= @audit_logfile -%> { 3 | missingok 4 | notifempty 5 | delaycompress 6 | create 0600 root 7 | } 8 | -------------------------------------------------------------------------------- /templates/rabbitmq.config.erb: -------------------------------------------------------------------------------- 1 | [ 2 | {rabbit, [ 3 | <% if( scope.lookupvar('mcollective::connector_ssl') == 'true' ) then -%> 4 | {ssl_options, [ 5 | {cacertfile,"<%= scope.lookupvar('::ssldir') -%>/ca/ca.pem"}, 6 | {certfile,"<%= scope.lookupvar('::ssldir') -%>/certs/<%= scope.lookupvar('::clientcert') -%>.pem"}, 7 | {keyfile,"<%= scope.lookupvar('::ssldir') -%>/private_keys/<%= scope.lookupvar('::clientcert') -%>.pem"}, 8 | {verify,verify_peer}, 9 | {fail_if_no_peer_cert,false} 10 | ]} 11 | <% end -%> 12 | ]}, 13 | {rabbitmq_stomp, [ 14 | <% if( @connector_ssl ) then -%> 15 | {ssl_listeners, [<%= @_port -%>]} 16 | <% else -%> 17 | {tcp_listeners, [<%= @_port -%>]} 18 | <% end -%> 19 | ]} 20 | ]. 21 | -------------------------------------------------------------------------------- /templates/server.cfg.erb: -------------------------------------------------------------------------------- 1 | # /etc/mcollective/server.cfg 2 | libdir = <%= scope.lookupvar('mcollective::libdir') %> 3 | <% if( scope.lookupvar('::clientversion').to_f >= 4.0 ) then -%> 4 | libdir = /opt/puppetlabs/mcollective/plugins 5 | classesfile = /opt/puppetlabs/puppet/cache/state/classes.txt 6 | <% end -%> 7 | daemonize = 1 8 | direct_addressing = 1 9 | <% if( @collectives ) then -%> 10 | main_collective = <%= @collectives[0] %> 11 | collectives = <%= @collectives.join(',') %> 12 | <% end -%> 13 | 14 | # ActiveMQ connector settings: 15 | connector = <%= scope.lookupvar('mcollective::connector') %> 16 | <% if( scope.lookupvar('mcollective::connector') == 'rabbitmq' ) then -%> 17 | plugin.rabbitmq.vhost = /mcollective 18 | <% elsif( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 19 | plugin.activemq.heartbeat_interval = 30 20 | <% end -%> 21 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.size = <%= @hosts.length %> 22 | <% @hosts.each_with_index do |mqhost, index| -%> 23 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.host = <%= mqhost %> 24 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.port = <%= scope.lookupvar('mcollective::_port') %> 25 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.user = <%= scope.lookupvar('mcollective::server_user') %> 26 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.password = <%= scope.lookupvar('mcollective::server_password') %> 27 | <% if( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 28 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl = <%= scope.lookupvar('mcollective::connector_ssl') %> 29 | <% if( scope.lookupvar('mcollective::connector_ssl_type') == 'trusted' ) then -%> 30 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.key = <%= scope.lookupvar('::ssldir') -%>/private_keys/<%= scope.lookupvar('clientcert') -%>.pem 31 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.cert = <%= scope.lookupvar('::ssldir') -%>/certs/<%= scope.lookupvar('clientcert') -%>.pem 32 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.ca = <%= scope.lookupvar('::ssldir') -%>/certs/ca.pem 33 | <% else -%> 34 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.fallback = true 35 | <% end -%> 36 | <% end -%> 37 | <% end -%> 38 | 39 | # Send these messages to keep the Stomp connection alive. 40 | # This solves NAT and firewall timeout problems. 41 | registerinterval = <%= scope.lookupvar('mcollective::registerinterval') %> 42 | 43 | # Security provider 44 | <% if( scope.lookupvar('mcollective::security_provider') == 'psk' ) then -%> 45 | securityprovider = psk 46 | plugin.psk = <%= scope.lookupvar('mcollective::psk_key') %> 47 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'sshkey' ) then -%> 48 | securityprovider = sshkey 49 | <% if( @sshkey_authorized_keys ) then -%> 50 | plugin.sshkey.server.known_hosts = <%= @sshkey_authorized_keys %> 51 | <% end -%> 52 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'ssl' ) then -%> 53 | securityprovider = ssl 54 | plugin.ssl_server_private = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/server/private.pem 55 | plugin.ssl_server_public = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/server/public.pem 56 | plugin.ssl_client_cert_dir = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/clients 57 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'aes_security' ) then -%> 58 | securityprovider = aes_security 59 | plugin.aes.server_public = <%= scope.lookupvar('::ssldir') -%>/public_keys/<%= scope.lookupvar('clientcert') -%>.pem 60 | plugin.aes.server_private = <%= scope.lookupvar('::ssldir') -%>/private_keys/<%= scope.lookupvar('clientcert') -%>.pem 61 | plugin.aes.client_cert_dir = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/clients 62 | plugin.aes.enforce_ttl = true 63 | <% end -%> 64 | 65 | # Facts 66 | factsource = yaml 67 | plugin.yaml = <%= scope.lookupvar('mcollective::etcdir') %>/facts.yaml 68 | 69 | # Puppet resource control 70 | plugin.puppet.resource_allow_managed_resources = <%= @allow_managed_resources %> 71 | <% if( @resource_type_whitelist ) then -%> 72 | plugin.puppet.resource_type_whitelist = <%= @resource_type_whitelist %> 73 | <% else -%> 74 | plugin.puppet.resource_type_blacklist = <%= @resource_type_blacklist %> 75 | <% end -%> 76 | 77 | <% if( @audit_logfile ) then -%> 78 | # Auditing 79 | rpcaudit = 1 80 | rpcauditprovider = Logfile 81 | plugin.rpcaudit.logfile = <%= @audit_logfile %> 82 | <% end -%> 83 | 84 | <% if( @authorization_enable ) then -%> 85 | # Authorization policy 86 | rpcauthorization = 1 87 | rpcauthprovider = action_policy 88 | <% if( @authorization_default_policy ) then -%> 89 | plugin.actionpolicy.enable_default = 1 90 | plugin.actionpolicy.default_name = <%= @authorization_default_policy -%> 91 | <% else -%> 92 | plugin.actionpolicy.allow_unconfigured = 1 93 | <% end -%> 94 | <% end -%> 95 | 96 | # Logging 97 | logger_type = <%= @logger_type %> 98 | loglevel = <%= @log_level %> 99 | <% if( @logger_type == 'syslog' ) then -%> 100 | logfacility = <%= @logfacility %> 101 | <% end -%> 102 | <% if( @logger_type == 'file' ) then -%> 103 | logfile = <%= @logfile %> 104 | <% if( @keeplogs ) then -%> 105 | keeplogs = <%= @keeplogs %> 106 | <% end -%> 107 | <% if( @max_log_size ) then -%> 108 | max_log_size = <%= @max_log_size %> 109 | <% end -%> 110 | <% end -%> 111 | -------------------------------------------------------------------------------- /templates/userconfig.erb: -------------------------------------------------------------------------------- 1 | # Connector 2 | libdir = <%= scope.lookupvar('mcollective::libdir') %> 3 | direct_addressing = 1 4 | <% if( @collectives ) then -%> 5 | main_collective = <%= @collectives[0] %> 6 | collectives = <%- @collectives.each do |collective| -%><%= collective -%>,<% end -%> 7 | <% end -%> 8 | 9 | connector = <%= scope.lookupvar('mcollective::connector') %> 10 | <% if( scope.lookupvar('mcollective::connector') == 'rabbitmq' ) then -%> 11 | plugin.rabbitmq.vhost = /mcollective 12 | <% elsif( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 13 | plugin.activemq.heartbeat_interval = 30 14 | <% end -%> 15 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.size = <%= @hosts.length %> 16 | <% @hosts.each_with_index do |mqhost, index| -%> 17 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.host = <%= mqhost %> 18 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.port = <%= scope.lookupvar('mcollective::_port') %> 19 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.user = <%= scope.lookupvar('mcollective::client_user') %> 20 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.password = <%= scope.lookupvar('mcollective::client_password') %> 21 | <% if( scope.lookupvar('mcollective::connector') == 'activemq' ) then -%> 22 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl = <%= scope.lookupvar('mcollective::connector_ssl') %> 23 | <% if( scope.lookupvar('mcollective::connector_ssl_type') == 'trusted' ) then -%> 24 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.key = <%= scope.lookupvar('ssl_private') %> 25 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.cert = <%= scope.lookupvar('ssl_cert') %> 26 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.ca = <%= scope.lookupvar('ca_cert') %> 27 | <% else -%> 28 | plugin.<%= scope.lookupvar('mcollective::connector') -%>.pool.<%= index+1 -%>.ssl.fallback = true 29 | <% end -%> 30 | <% end -%> 31 | <% end -%> 32 | 33 | # Security provider 34 | <% if( scope.lookupvar('mcollective::security_provider') == 'psk' ) then -%> 35 | securityprovider = psk 36 | plugin.psk = <%= scope.lookupvar('mcollective::psk_key') %> 37 | plugin.psk.callertype = <%= scope.lookupvar('mcollective::psk_callertype') %> 38 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'sshkey' ) then -%> 39 | securityprovider = sshkey 40 | <% if( @sshkey_known_hosts ) then -%> 41 | plugin.sshkey.client.known_hosts = <%= @sshkey_known_hosts %> 42 | <% end -%> 43 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'ssl' ) then -%> 44 | securityprovider = ssl 45 | plugin.ssl_server_public = <%= scope.lookupvar('mcollective::etcdir') -%>/ssl/server/public.pem 46 | plugin.ssl_client_private = <%= scope.lookupvar('private_key') %> 47 | plugin.ssl_client_public = <%= scope.lookupvar('public_key') %> 48 | <% elsif( scope.lookupvar('mcollective::security_provider') == 'aes_security' ) then -%> 49 | securityprovider = aes_security 50 | plugin.aes_client_private = <%= scope.lookupvar('private_key') %> 51 | plugin.aes_client_public = <%= scope.lookupvar('public_key') %> 52 | <% end -%> 53 | 54 | # Discovery 55 | default_discovery_method = <%= scope.lookupvar('disc_method') %> 56 | <% if( scope.lookupvar('da_threshold') != '' ) then -%> 57 | direct_addressing_threshold = <%= scope.lookupvar('da_threshold') %> 58 | <% end -%> 59 | <% if( scope.lookupvar('disc_options') != '' ) then -%> 60 | default_discovery_options = <%= scope.lookupvar('disc_options') %> 61 | <% end -%> 62 | 63 | # Miscellaneous settings 64 | color = 1 65 | rpclimitmethod = first 66 | 67 | # Performance settings 68 | direct_addressing_threshold = 10 69 | ttl = 60 70 | 71 | # Logging 72 | logger_type = <%= @logger_type %> 73 | loglevel = <%= @log_level %> 74 | <% if( @logger_type == 'syslog' ) then -%> 75 | logfacility = <%= @logfacility %> 76 | <% end -%> 77 | <% if( @logger_type == 'file' ) then -%> 78 | logfile = <%= @logfile %> 79 | <% if( @keeplogs ) then -%> 80 | keeplogs = <%= @keeplogs %> 81 | <% end -%> 82 | <% if( @max_log_size ) then -%> 83 | max_log_size = <%= @max_log_size %> 84 | <% end -%> 85 | <% end -%> 86 | -------------------------------------------------------------------------------- /tests/init.pp: -------------------------------------------------------------------------------- 1 | # The baseline for module testing used by Puppet Labs is that each manifest 2 | # should have a corresponding test manifest that declares that class or defined 3 | # type. 4 | # 5 | # Tests are then run by using puppet apply --noop (to check for compilation 6 | # errors and view a log of events) or by fully applying the test in a virtual 7 | # environment (to compare the resulting system state to the desired state). 8 | # 9 | # Learn more about module testing here: 10 | # http://docs.puppetlabs.com/guides/tests_smoke.html 11 | # 12 | include mcollective 13 | --------------------------------------------------------------------------------