dtk-node-agent 0.7.7 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. checksums.yaml +5 -13
  2. data/README.md +21 -4
  3. data/bin/dtk-node-agent +17 -0
  4. data/lib/config/install.config +2 -2
  5. data/lib/dtk-node-agent/installer.rb +30 -25
  6. data/lib/dtk-node-agent/version.rb +18 -1
  7. metadata +23 -110
  8. data/mcollective_additions/debian.mcollective.init +0 -92
  9. data/mcollective_additions/plugins/README.md +0 -1
  10. data/mcollective_additions/plugins/v1.2/agent/discovery.rb +0 -39
  11. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.ddl +0 -15
  12. data/mcollective_additions/plugins/v1.2/agent/get_log_fragment.rb +0 -79
  13. data/mcollective_additions/plugins/v1.2/agent/git_access.ddl +0 -9
  14. data/mcollective_additions/plugins/v1.2/agent/git_access.rb +0 -79
  15. data/mcollective_additions/plugins/v1.2/agent/netstat.ddl +0 -9
  16. data/mcollective_additions/plugins/v1.2/agent/netstat.rb +0 -34
  17. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.ddl +0 -9
  18. data/mcollective_additions/plugins/v1.2/agent/puppet_apply.rb +0 -630
  19. data/mcollective_additions/plugins/v1.2/agent/rpcutil.ddl +0 -204
  20. data/mcollective_additions/plugins/v1.2/agent/rpcutil.rb +0 -101
  21. data/mcollective_additions/plugins/v1.2/facts/pbuilder_facts.rb +0 -35
  22. data/mcollective_additions/plugins/v2.2/agent/action_agent.ddl +0 -9
  23. data/mcollective_additions/plugins/v2.2/agent/action_agent.rb +0 -47
  24. data/mcollective_additions/plugins/v2.2/agent/dev_manager.ddl +0 -9
  25. data/mcollective_additions/plugins/v2.2/agent/dev_manager.rb +0 -111
  26. data/mcollective_additions/plugins/v2.2/agent/discovery.rb +0 -39
  27. data/mcollective_additions/plugins/v2.2/agent/dtk_node_agent_git_client.rb +0 -94
  28. data/mcollective_additions/plugins/v2.2/agent/execute_tests.ddl +0 -9
  29. data/mcollective_additions/plugins/v2.2/agent/execute_tests.rb +0 -111
  30. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.ddl +0 -9
  31. data/mcollective_additions/plugins/v2.2/agent/execute_tests_v2.rb +0 -131
  32. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.ddl +0 -15
  33. data/mcollective_additions/plugins/v2.2/agent/get_log_fragment.rb +0 -79
  34. data/mcollective_additions/plugins/v2.2/agent/git_access.ddl +0 -9
  35. data/mcollective_additions/plugins/v2.2/agent/git_access.rb +0 -61
  36. data/mcollective_additions/plugins/v2.2/agent/netstat.ddl +0 -9
  37. data/mcollective_additions/plugins/v2.2/agent/netstat.rb +0 -34
  38. data/mcollective_additions/plugins/v2.2/agent/ps.ddl +0 -9
  39. data/mcollective_additions/plugins/v2.2/agent/ps.rb +0 -37
  40. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.ddl +0 -9
  41. data/mcollective_additions/plugins/v2.2/agent/puppet_apply.rb +0 -818
  42. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.ddl +0 -10
  43. data/mcollective_additions/plugins/v2.2/agent/puppet_cancel.rb +0 -78
  44. data/mcollective_additions/plugins/v2.2/agent/rpcutil.ddl +0 -204
  45. data/mcollective_additions/plugins/v2.2/agent/rpcutil.rb +0 -101
  46. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.ddl +0 -13
  47. data/mcollective_additions/plugins/v2.2/agent/ssh_agent.rb +0 -97
  48. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.ddl +0 -10
  49. data/mcollective_additions/plugins/v2.2/agent/sync_agent_code.rb +0 -85
  50. data/mcollective_additions/plugins/v2.2/agent/tail.ddl +0 -11
  51. data/mcollective_additions/plugins/v2.2/agent/tail.rb +0 -67
  52. data/mcollective_additions/plugins/v2.2/audit/logfile.rb +0 -26
  53. data/mcollective_additions/plugins/v2.2/connector/r8stomp.rb +0 -238
  54. data/mcollective_additions/plugins/v2.2/connector/stomp.rb +0 -349
  55. data/mcollective_additions/plugins/v2.2/connector/stomp_em.rb +0 -191
  56. data/mcollective_additions/plugins/v2.2/data/agent_data.ddl +0 -22
  57. data/mcollective_additions/plugins/v2.2/data/agent_data.rb +0 -17
  58. data/mcollective_additions/plugins/v2.2/data/collective_data.ddl +0 -20
  59. data/mcollective_additions/plugins/v2.2/data/collective_data.rb +0 -9
  60. data/mcollective_additions/plugins/v2.2/data/fact_data.ddl +0 -28
  61. data/mcollective_additions/plugins/v2.2/data/fact_data.rb +0 -55
  62. data/mcollective_additions/plugins/v2.2/data/fstat_data.ddl +0 -89
  63. data/mcollective_additions/plugins/v2.2/data/fstat_data.rb +0 -56
  64. data/mcollective_additions/plugins/v2.2/discovery/flatfile.ddl +0 -11
  65. data/mcollective_additions/plugins/v2.2/discovery/flatfile.rb +0 -48
  66. data/mcollective_additions/plugins/v2.2/discovery/mc.ddl +0 -11
  67. data/mcollective_additions/plugins/v2.2/discovery/mc.rb +0 -30
  68. data/mcollective_additions/plugins/v2.2/discovery/stdin.ddl +0 -11
  69. data/mcollective_additions/plugins/v2.2/discovery/stdin.rb +0 -66
  70. data/mcollective_additions/plugins/v2.2/facts/pbuilder_facts.rb +0 -37
  71. data/mcollective_additions/plugins/v2.2/facts/yaml_facts.rb +0 -61
  72. data/mcollective_additions/plugins/v2.2/registration/agentlist.rb +0 -10
  73. data/mcollective_additions/plugins/v2.2/security/sshkey.ddl +0 -9
  74. data/mcollective_additions/plugins/v2.2/security/sshkey.rb +0 -362
  75. data/mcollective_additions/plugins/v2.2/util/puppetrunner.rb +0 -36
  76. data/mcollective_additions/plugins/v2.2/validator/array_validator.ddl +0 -7
  77. data/mcollective_additions/plugins/v2.2/validator/array_validator.rb +0 -9
  78. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.ddl +0 -7
  79. data/mcollective_additions/plugins/v2.2/validator/ipv4address_validator.rb +0 -16
  80. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.ddl +0 -7
  81. data/mcollective_additions/plugins/v2.2/validator/ipv6address_validator.rb +0 -16
  82. data/mcollective_additions/plugins/v2.2/validator/length_validator.ddl +0 -7
  83. data/mcollective_additions/plugins/v2.2/validator/length_validator.rb +0 -11
  84. data/mcollective_additions/plugins/v2.2/validator/regex_validator.ddl +0 -7
  85. data/mcollective_additions/plugins/v2.2/validator/regex_validator.rb +0 -9
  86. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.ddl +0 -7
  87. data/mcollective_additions/plugins/v2.2/validator/shellsafe_validator.rb +0 -13
  88. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.ddl +0 -7
  89. data/mcollective_additions/plugins/v2.2/validator/typecheck_validator.rb +0 -28
  90. data/mcollective_additions/redhat.mcollective.init +0 -139
  91. data/mcollective_additions/redhat.mcollective.service +0 -14
  92. data/mcollective_additions/server.cfg +0 -22
  93. data/src/etc/logrotate.d/mcollective +0 -10
  94. data/src/etc/mcollective.default +0 -6
@@ -1,11 +0,0 @@
1
- metadata :name => "flatfile",
2
- :description => "Flatfile based discovery for node identities",
3
- :author => "R.I.Pienaar <rip@devco.net>",
4
- :license => "ASL 2.0",
5
- :version => "0.1",
6
- :url => "http://marionette-collective.org/",
7
- :timeout => 0
8
-
9
- discovery do
10
- capabilities :identity
11
- end
@@ -1,48 +0,0 @@
1
- # discovers against a flatfile instead of the traditional network discovery
2
- # the flat file must have a node name per line which should match identities
3
- # as configured
4
- module MCollective
5
- class Discovery
6
- class Flatfile
7
- def self.discover(filter, timeout, limit=0, client=nil)
8
- unless client.options[:discovery_options].empty?
9
- file = client.options[:discovery_options].first
10
- else
11
- raise "The flatfile discovery method needs a path to a text file"
12
- end
13
-
14
- raise "Cannot read the file %s specified as discovery source" % file unless File.readable?(file)
15
-
16
- discovered = []
17
- hosts = []
18
-
19
- File.readlines(file).each do |host|
20
- host = host.chomp.strip
21
- if host.empty? || host.match(/^#/)
22
- next
23
- end
24
- raise 'Identities can only match /^[\w\.\-]+$/' unless host.match(/^[\w\.\-]+$/)
25
- hosts << host
26
- end
27
-
28
- # this plugin only supports identity filters, do regex matches etc against
29
- # the list found in the flatfile
30
- if !(filter["identity"].empty?)
31
- filter["identity"].each do |identity|
32
- identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
33
-
34
- if identity.is_a?(Regexp)
35
- discovered = hosts.grep(identity)
36
- elsif hosts.include?(identity)
37
- discovered << identity
38
- end
39
- end
40
- else
41
- discovered = hosts
42
- end
43
-
44
- discovered
45
- end
46
- end
47
- end
48
- end
@@ -1,11 +0,0 @@
1
- metadata :name => "mc",
2
- :description => "MCollective Broadcast based discovery",
3
- :author => "R.I.Pienaar <rip@devco.net>",
4
- :license => "ASL 2.0",
5
- :version => "0.1",
6
- :url => "http://marionette-collective.org/",
7
- :timeout => 2
8
-
9
- discovery do
10
- capabilities [:classes, :facts, :identity, :agents, :compound]
11
- end
@@ -1,30 +0,0 @@
1
- module MCollective
2
- class Discovery
3
- class Mc
4
- def self.discover(filter, timeout, limit, client)
5
- begin
6
- hosts = []
7
- Timeout.timeout(timeout) do
8
- reqid = client.sendreq("ping", "discovery", filter)
9
- Log.debug("Waiting #{timeout} seconds for discovery replies to request #{reqid}")
10
-
11
- loop do
12
- reply = client.receive(reqid)
13
- Log.debug("Got discovery reply from #{reply.payload[:senderid]}")
14
- hosts << reply.payload[:senderid]
15
-
16
- return hosts if limit > 0 && hosts.size == limit
17
- end
18
- end
19
- rescue Timeout::Error => e
20
- rescue Exception => e
21
- raise
22
- ensure
23
- client.unsubscribe("discovery", :reply)
24
- end
25
-
26
- hosts
27
- end
28
- end
29
- end
30
- end
@@ -1,11 +0,0 @@
1
- metadata :name => "stdin",
2
- :description => "STDIN based discovery for node identities",
3
- :author => "Tomas Doran <bobtfish@bobtfish.net.net>",
4
- :license => "ASL 2.0",
5
- :version => "0.1",
6
- :url => "http://marionette-collective.org/",
7
- :timeout => 0
8
-
9
- discovery do
10
- capabilities :identity
11
- end
@@ -1,66 +0,0 @@
1
- # discovers against stdin instead of the traditional network discovery
2
- # the input must be a flat file with a node name per line which should match identities as configured,
3
- # or it should be a json string as output by the -j option of mco rpc
4
- require 'mcollective/rpc/helpers'
5
-
6
- module MCollective
7
- class Discovery
8
- class Stdin
9
- def self.discover(filter, timeout, limit=0, client=nil)
10
- unless client.options[:discovery_options].empty?
11
- type = client.options[:discovery_options].first.downcase
12
- else
13
- type = 'auto'
14
- end
15
-
16
- discovered = []
17
-
18
- file = STDIN.read
19
-
20
- if file =~ /^\s*$/
21
- raise("data piped on STDIN contained only whitespace - could not discover hosts from it.")
22
- end
23
-
24
- if type == 'auto'
25
- if file =~ /^\s*\[/
26
- type = 'json'
27
- else
28
- type = 'text'
29
- end
30
- end
31
-
32
- if type == 'json'
33
- hosts = MCollective::RPC::Helpers.extract_hosts_from_json(file)
34
- elsif type == 'text'
35
- hosts = file.split("\n")
36
- else
37
- raise("stdin discovery plugin only knows the types auto/text/json, not \"#{type}\"")
38
- end
39
-
40
- hosts.map do |host|
41
- raise 'Identities can only match /\w\.\-/' unless host.match(/^[\w\.\-]+$/)
42
- host
43
- end
44
-
45
- # this plugin only supports identity filters, do regex matches etc against
46
- # the list found in the flatfile
47
- unless filter["identity"].empty?
48
- filter["identity"].each do |identity|
49
- identity = Regexp.new(identity.gsub("\/", "")) if identity.match("^/")
50
-
51
- if identity.is_a?(Regexp)
52
- discovered = hosts.grep(identity)
53
- elsif hosts.include?(identity)
54
- discovered << identity
55
- end
56
- end
57
- else
58
- discovered = hosts
59
- end
60
-
61
- discovered
62
- end
63
- end
64
- end
65
- end
66
-
@@ -1,37 +0,0 @@
1
- require 'open-uri'
2
- require 'timeout'
3
- require 'yaml'
4
-
5
- module MCollective
6
- module Facts
7
- # A factsource for pbuilder
8
- class Pbuilder_facts < Base
9
-
10
- def load_facts_from_source
11
- # ret = {"pbuilderid" => get_pbuilderid()}
12
- ret = {}
13
- yaml_file = '/etc/mcollective/facts.yaml'
14
- if File.exists?(yaml_file)
15
- yaml_facts = YAML.load_file(yaml_file)
16
- ret.merge!(yaml_facts)
17
- end
18
- ret.merge!("pbuilderid" => get_pbuilderid()) unless ret.keys.include?('pbuilderid')
19
- ret
20
- end
21
-
22
- def get_pbuilderid()
23
- ret = nil
24
- begin
25
- addr = "169.254.169.254"
26
- wait_sec = 2
27
- Timeout::timeout(wait_sec) {open("http://#{addr}:80/")}
28
- ret = OpenURI.open_uri("http://#{addr}/2008-02-01/meta-data/instance-id").read
29
- rescue Timeout::Error
30
- rescue
31
- #TODO: unexpected; write to log what error is
32
- end
33
- ret
34
- end
35
- end
36
- end
37
- end
@@ -1,61 +0,0 @@
1
- module MCollective
2
- module Facts
3
- require 'yaml'
4
-
5
- # A factsource that reads a hash of facts from a YAML file
6
- #
7
- # Multiple files can be specified seperated with a : in the
8
- # config file, they will be merged with later files overriding
9
- # earlier ones in the list.
10
- class Yaml_facts<Base
11
- def initialize
12
- @yaml_file_mtimes = {}
13
-
14
- super
15
- end
16
-
17
- def load_facts_from_source
18
- config = Config.instance
19
-
20
- fact_files = config.pluginconf["yaml"].split(File::PATH_SEPARATOR)
21
- facts = {}
22
-
23
- fact_files.each do |file|
24
- begin
25
- if File.exist?(file)
26
- facts.merge!(YAML.load_file(file))
27
- else
28
- raise("Can't find YAML file to load: #{file}")
29
- end
30
- rescue Exception => e
31
- Log.error("Failed to load yaml facts from #{file}: #{e.class}: #{e}")
32
- end
33
- end
34
-
35
- facts
36
- end
37
-
38
- # force fact reloads when the mtime on the yaml file change
39
- def force_reload?
40
- config = Config.instance
41
-
42
- fact_files = config.pluginconf["yaml"].split(File::PATH_SEPARATOR)
43
-
44
- fact_files.each do |file|
45
- @yaml_file_mtimes[file] ||= File.stat(file).mtime
46
- mtime = File.stat(file).mtime
47
-
48
- if mtime > @yaml_file_mtimes[file]
49
- @yaml_file_mtimes[file] = mtime
50
-
51
- Log.debug("Forcing fact reload due to age of #{file}")
52
-
53
- return true
54
- end
55
- end
56
-
57
- false
58
- end
59
- end
60
- end
61
- end
@@ -1,10 +0,0 @@
1
- module MCollective
2
- module Registration
3
- # A registration plugin that simply sends in the list of agents we have
4
- class Agentlist<Base
5
- def body
6
- Agents.agentlist
7
- end
8
- end
9
- end
10
- end
@@ -1,9 +0,0 @@
1
- metadata :name => 'sshkey',
2
- :description => 'Security Plugin that uses ssh keys for signing',
3
- :author => 'Pieter Loubser <pieter.loubser@puppetlabs.com>',
4
- :license => 'ASL 2.0',
5
- :version => '0.4',
6
- :url => 'http://projects.puppetlabs.com/projects/mcollective-plugins/wiki',
7
- :timeout => 10
8
-
9
- requires :mcollective => '2.2.1'
@@ -1,362 +0,0 @@
1
- module MCollective
2
- module Security
3
- # Configuration
4
- #
5
- # Client:
6
- # client.private_key : A private key used to sign requests with - defaults to ssh-agent
7
- # client.known_hosts : The known_hosts file to use - defaults to /home/callerid/.ssh/known_hosts
8
- # client.send_key : Send the client's public key with the request - doesn not send the key by default.
9
- # To send a key specify the key file to send.
10
- #
11
- # Server:
12
- # server.private_key : The private key used to sign replies with - Defaults to /etc/ssh/ssh_host_rsa_key * required
13
- # server.authorized_keys : The authorized_keys file to use - defaults to the caller's authorized_keys file in his home directory
14
- # server.send_key : Send the server's public key with the request - does not send the key by default.
15
- # To send a key specify the key file to send.
16
- #
17
- # Shared:
18
- # (client|server).publickey_dir : Directory to store received keys - defaults to none
19
- # (client|server).learn_public_keys : Allow writing public keys to publickey_dir - defaults to not sending.
20
- # (client|server).overwrite_stored_keys : Overwrite received keys - defaults to false
21
- class Sshkey < Base
22
- gem 'sshkeyauth', '>= 0.0.4'
23
-
24
- require 'ssh/key/signer'
25
- require 'ssh/key/verifier'
26
- require 'etc'
27
-
28
- def decodemsg(msg)
29
- body = Marshal.load(msg.payload)
30
-
31
- if validrequest?(body)
32
- body[:body] = Marshal.load(body[:body])
33
- return body
34
- else
35
- nil
36
- end
37
- end
38
-
39
- def encodereply(sender, msg, requestid, requestcallerid=nil)
40
- serialized_msg = Marshal.dump(msg)
41
- reply = create_reply(requestid, sender, serialized_msg)
42
- reply[:serialized_data] = Marshal.dump(create_hash_fields(serialized_msg, reply[:msgtime], requestid))
43
- reply[:hash] = makehash(reply[:serialized_data])
44
-
45
- if server_key = lookup_config_option('send_key')
46
- if File.exists?(server_key)
47
- reply[:public_key] = load_key(server_key)
48
- else
49
- raise("Cannot create reply. sshkey.server.send_key set but key '%s' does not exist." % server_key)
50
- end
51
- end
52
-
53
- Marshal.dump(reply)
54
- end
55
-
56
- def encoderequest(sender, msg, requestid, filter, target_agent, target_collective, ttl=60)
57
- serialized_msg = Marshal.dump(msg)
58
- req = create_request(requestid, filter, serialized_msg, @initiated_by, target_agent, target_collective, ttl)
59
-
60
-
61
- if client_key = lookup_config_option('send_key')
62
- if File.exists?(client_key)
63
- req[:public_key] = load_key(client_key)
64
- else
65
- raise("Cannot create request. sshkey.client.send_key set but key '%s' does not exist." % client_key)
66
- end
67
- end
68
-
69
- req[:serialized_data] = Marshal.dump(create_hash_fields(serialized_msg, req[:msgtime], requestid, ttl, callerid))
70
- req[:hash] = makehash(req[:serialized_data])
71
-
72
- Marshal.dump(req)
73
- end
74
-
75
- def validrequest?(req)
76
- # Check if verification keys are correctly configured
77
- valid_configuration?
78
- # Check if key should be written to disk and write it
79
- write_key_to_disk(req[:public_key], (req[:callerid] || req[:senderid]).split('=')[-1] ) if req[:public_key]
80
-
81
- if @initiated_by == :client
82
- Log.debug('Validating reply from node %s' % req[:senderid])
83
- verifier = client_verifier(req[:senderid])
84
- else
85
- Log.debug('Validating request from client %s' % req[:callerid])
86
- verifier = node_verifier(req[:callerid], (req[:agent] == 'registration'), req[:public_key])
87
- end
88
-
89
- signatures = Marshal.load(req[:hash])
90
-
91
- if verifier.verify?(signatures, req[:serialized_data])
92
- @stats.validated
93
- return true
94
- else
95
- @stats.unvalidated
96
- Log.debug('Received an invalid signature in message.')
97
- raise SecurityValidationFailed
98
- end
99
- end
100
-
101
- def callerid
102
- 'sshkey=%s' % Etc.getlogin
103
- end
104
-
105
- private
106
-
107
- # Checks that publickey_dir and known_hosts|authorized_keys are not set at the same time.
108
- def valid_configuration?
109
- if @initiated_by == :client
110
- if lookup_config_option('publickey_dir') && lookup_config_option('known_hosts')
111
- raise('Both publickey_dir and known_hosts are defined in client config. Cannot lookup public key')
112
- end
113
- elsif @initiated_by == :node
114
- if lookup_config_option('publickey_dir') && lookup_config_option('authorized_keys')
115
- raise('Both publickey_dir and authorized_keys are defiend in server config. Cannot lookup public key')
116
- end
117
- end
118
- end
119
-
120
- # Checks if the attached public key needs to be stored locally
121
- # Overwriting is disabled by default
122
- # - The publickey_directory config option needs to be set before
123
- # the file will be written.
124
- # - The directory must exist before writing.
125
- # - The learn_public_keys configuration option must be enabled.
126
- def write_key_to_disk(key, identity)
127
-
128
- # Writing is disabled. Don't bother checking any other states.
129
- return unless lookup_config_option('learn_public_keys') =~ /^1|y/
130
-
131
- publickey_dir = lookup_config_option('publickey_dir')
132
-
133
- unless publickey_dir
134
- Log.info("Public key sent with request but no publickey_dir defined in configuration. Not writing key to disk.")
135
- return
136
- end
137
-
138
- if File.directory?(publickey_dir)
139
- if File.exists?(old_keyfile = File.join(publickey_dir, "#{identity}_pub.pem"))
140
- old_key = File.read(old_keyfile).chomp
141
-
142
- unless old_key == key
143
- unless lookup_config_option('overwrite_stored_keys', 'n') =~ /^1|y/
144
- Log.warn("Public key sent from '%s' does not match the stored key. Not overwriting." % identity)
145
- else
146
- Log.warn("Public key sent from '%s' does not match the stored key. Overwriting." % identity)
147
- File.open(File.join(publickey_dir, "#{identity}_pub.pem"), 'w') { |f| f.puts key }
148
- end
149
- end
150
- else
151
- Log.debug("Discovered a new public key for '%s'. Writing to '%s'" % [identity, publickey_dir])
152
- File.open(File.join(publickey_dir, "#{identity}_pub.pem"), 'w') { |f| f.puts key }
153
- end
154
- else
155
- raise("Cannot write public key to '%s'. Directory does not exist." % publickey_dir)
156
- end
157
- end
158
-
159
- # Fetches the correct configuration option for a client or a server
160
- def lookup_config_option(opt, default = nil)
161
- if @initiated_by == :client
162
- result = @config.pluginconf.fetch("sshkey.client.#{opt}", default)
163
-
164
- if result && ["authorized_keys", "private_key", "send_key", "publickey_dir", "known_hosts"].include?(opt)
165
- return File.expand_path(result)
166
- else
167
- return result
168
- end
169
- elsif @initiated_by == :node
170
- return @config.pluginconf.fetch("sshkey.server.#{opt}", default)
171
- end
172
- end
173
-
174
- # Creates a hash of the fields used to sign a message
175
- # Response messages use the msg, msgtime and requestid fields.
176
- # Request messages use the same fields as response, but include
177
- # ttl and callerid.
178
- def create_hash_fields(msg, msgtime, requestid, ttl = nil, callerid = nil)
179
- map = {:msg => msg,
180
- :msgtime => msgtime,
181
- :requestid => requestid}
182
-
183
- # Check if this is a server hash
184
- return map if (ttl == nil && callerid == nil)
185
-
186
- map[:ttl] = ttl
187
- map[:callerid] = callerid
188
-
189
- map
190
- end
191
-
192
- # Adds a key to a signer object and disables ssh-agent
193
- def add_key_to_signer(signer, key)
194
- signer.add_key_file(key)
195
- signer.use_agent = false
196
- end
197
-
198
- # Creates a signed hash of fields using the node's private key
199
- def makehash(data)
200
- signer = SSH::Key::Signer.new
201
-
202
- # Check if the client is signing its request with a predefined
203
- # private key. If this is the case, disable ssh-agent.
204
- if @initiated_by == :client && (private_key = lookup_config_option('private_key'))
205
- unless File.exists?(private_key)
206
- raise("Cannot sign request - private key not found: '%s'" % private_key)
207
- else
208
- add_key_to_signer(signer, private_key)
209
- end
210
- elsif @initiated_by == :node
211
- if private_key = lookup_config_option('private_key')
212
- add_key_to_signer(signer, private_key)
213
- else
214
- # First try and default to ssh_host_dsa_key
215
- if File.exists?(private_key = '/etc/ssh/ssh_host_dsa_key')
216
- add_key_to_signer(signer, private_key)
217
- # If that fails, try ssh_host_rsa_key
218
- elsif File.exists?(private_key = '/etc/ssh/ssh_host_rsa_key')
219
- add_key_to_signer(signer, private_key)
220
- else
221
- raise("Cannot sign reply - private key not found: 's'" % private_key)
222
- end
223
- end
224
- end
225
-
226
- # Default to using ssh-agent for key signing
227
- signatures = signer.sign(data).collect { |s| s.signature }
228
- Marshal.dump(signatures)
229
- end
230
-
231
- #Returns the contents of a key file on disk
232
- def load_key(key)
233
- if File.exists?(key)
234
- return File.read(key).strip
235
- else
236
- nil
237
- end
238
- end
239
-
240
- # Looks for a specific key in a known hosts file
241
- def find_key_in_known_hosts(hostname, known_hosts)
242
- key = nil
243
- search_for = /^#{hostname}/
244
-
245
- if File.exists?(known_hosts)
246
- File.read(known_hosts).each_line do |line|
247
- fields = line.split
248
- fields[0].split(',').each do |maybehost|
249
- if maybehost =~ search_for
250
- fields = line.split
251
- key = fields[-2] << ' ' << fields[-1]
252
- break
253
- end
254
- end
255
- break unless key.nil?
256
- end
257
- end
258
-
259
- unless key
260
- Log.warn("Could not find a key for host '%s' in file '%s'" % [hostname, known_hosts])
261
- raise SecurityValidationFailed
262
- end
263
-
264
- key
265
- end
266
-
267
- # Create a client verifier object which uses the correct public key
268
- def client_verifier(senderid)
269
- verifier = SSH::Key::Verifier.new(senderid)
270
- verifier.use_authorized_keys = false
271
-
272
- if publickey_dir = lookup_config_option('publickey_dir')
273
- Log.debug("Using public key directory: '%s'" % publickey_dir)
274
- verifier.add_public_key_data(find_shared_public_key(publickey_dir, senderid))
275
-
276
- elsif (known_hosts = lookup_config_option('known_hosts'))
277
- Log.debug("Using custom known_hosts file: '%s'" % known_hosts)
278
- verifier.add_public_key_data(find_key_in_known_hosts(senderid, known_hosts))
279
-
280
- elsif (authorized_keys = lookup_config_option('authorized_keys'))
281
- Log.debug("Found custom authorized_keys file: '%s'" % authorized_keys)
282
- verifier.authorized_keys_file = authorized_keys
283
- verifier.use_authorized_keys = true
284
-
285
- else
286
- begin
287
- user = Etc.getlogin
288
- known_hosts = File.join(Etc.getpwnam(user).dir, '.ssh', 'known_hosts')
289
- Log.debug("Using default known_hosts file for user '%s': ''" % [user, known_hosts])
290
- verifier.add_public_key_data(find_key_in_known_hosts(senderid, "%s" % known_hosts))
291
- rescue => e
292
- raise("Cannot find known_hosts file for user '%s': '%s'" % [user, known_hosts])
293
- end
294
- end
295
-
296
- verifier.use_agent = false
297
-
298
- verifier
299
- end
300
-
301
- # Looks for a public key in a shared directory
302
- def find_shared_public_key(dir, id)
303
- unless File.directory?(dir)
304
- raise("Cannot read shared public key directory: '%s'" % dir)
305
- end
306
-
307
- if File.exists?(key_file = File.join(dir, "#{id}_pub.pem"))
308
- return File.read(key_file)
309
- else
310
- Log.warn("Cannot find public key for id '%s': '%s'" % [id, File.join(dir, "#{id}_pub.pem")])
311
- raise SecurityValidationFailed
312
- end
313
- end
314
-
315
- # Create a node verifier object which uses the correct public key
316
- def node_verifier(callerid, registration = false, pubkey = nil)
317
- user = callerid.split('=')[-1]
318
- verifier = SSH::Key::Verifier.new(user)
319
- verifier.use_agent = false
320
-
321
- # Here we deal with the special case where a registration message
322
- # is being validated. send_key has to be defined in the configuration.
323
- # TODO : This is a stop gap measure we should remove when we fix
324
- # registration
325
- if registration && pubkey
326
- Log.debug("Found registration message. Using sender's public key")
327
- verifier.add_public_key_data(pubkey)
328
- verifier.use_authorized_keys = false
329
-
330
- elsif registration && !pubkey
331
- Log.warn("Cannot verify registration request. Server did not send its public key")
332
- raise SecurityValidationFailed
333
-
334
- elsif publickey_dir = lookup_config_option('publickey_dir')
335
- if File.directory?(publickey_dir)
336
- Log.debug("Found shared public key directory: '%s'" % publickey_dir)
337
- verifier.add_public_key_data(find_shared_public_key(publickey_dir, user))
338
- verifier.use_authorized_keys = false
339
- else
340
- raise("Public key directory '%s' does not exist" % publickey_dir)
341
- end
342
-
343
- elsif (authorized_keys = lookup_config_option('authorized_keys'))
344
- authorized_keys = authorized_keys.sub('%u') { |c| user }
345
- Log.debug("Found custom authorized_keys file: '%s'" % authorized_keys)
346
- verifier.authorized_keys_file = authorized_keys
347
-
348
- else
349
- begin
350
- authorized_keys = File.join(Etc.getpwnam(user).dir, '.ssh', 'authorized_keys')
351
- Log.debug("No authorized_keys file or publickey_dir specified. Using '%s'" % authorized_keys)
352
- verifier.authorized_keys_file = authorized_keys
353
- rescue => e
354
- raise("Cannot find authorized_keys file for user '%s': '%s'" % [user, authorized_keys])
355
- end
356
- end
357
-
358
- verifier
359
- end
360
- end
361
- end
362
- end