dtk-node-agent 0.7.7 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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