capistrano_recia 0.0.2

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.
@@ -0,0 +1,64 @@
1
+ = RECIA Capistrano
2
+
3
+ This gem is used by the recia to implements specific behavior in capistrano. It furnish the following services :
4
+
5
+ - parents : call of hosts' parents to execute action on them
6
+ - filters : filter hosts to execute by its roles
7
+ - password manager : help to generate password and secure them.
8
+
9
+ == Parents
10
+
11
+ The function is to execute command on the parent host of current hosts. To do this, we need the gem "nagios_mklivestatus".
12
+
13
+ To call the function from a task, we need to call a specific method :
14
+
15
+ run_parent(cmd)
16
+
17
+ This will select only the servers' parents containing the guest (select parents which are servers).
18
+ There are some notable informations.
19
+
20
+ The method works as the standard run, except that the ENV['HOSTS'] are remplaced by their parents.
21
+ The command is replaced by its Capistrano::Command::Script version and the original hosts are ordered by their parents and given to the script.
22
+ If some variables are encountered, a loop is created to go through all guest of each host (parents).
23
+
24
+ Those are for functionality purpose if you need to execute command with guest as variables you should use this :
25
+
26
+ $PARENT:GUEST$ : variable that will be replaced by the name of the guest (we'll create a loop in script)
27
+ $PARENT:LOOP:START$ : variable that will be replaced by the start of the loop (if not defined and $PARENT:GUEST$ exists, its automatically placed at the start of the command)
28
+ $PARENT:LOOP:END$ : variable that will be replaced by the end of the loop (if not defined and $PARENT:GUEST$ exists, its automatically placed at the end of the command)
29
+
30
+ == Filters
31
+
32
+ This module is made to filter hosts with the roles in task options. It furnish 2 methods for task to run :
33
+
34
+ run_filter_roles(cmd) # the host must match one of the roles (connection SSH)
35
+ run_telnet_filter_roles(cmd) # the host must match one of the roles (connection Telnet)
36
+
37
+ If hosts does not correspond to the filter, they are removed from the list (with informations display) and the command is executed on the remaining hosts.
38
+
39
+ == Password manager
40
+
41
+ This is a class which help to manage password security inside capistrano. It's help to generate password (with save in a crypted file), and check the corruption of this password, plus it can securize all the password through a security automaton
42
+
43
+ To use the manager:
44
+
45
+ require 'capistrano_recia'
46
+ manager = Capistrano::Password::Manager.new(<file_path>)
47
+ # generate pass
48
+ new_pass = manager.generate
49
+ # generate and save
50
+ new_pass = manager.generate("key")
51
+
52
+ # test corruption
53
+ is_corrupt = manager.is_corrupted? "key"
54
+
55
+ # corrupt password (giving it to a non authorized person
56
+ pass = manager.corrupt "key"
57
+
58
+ # live the password uncorrupted when asking for it
59
+ pass = manager.live_uncorrupt "key"
60
+
61
+ # securize all corrupted password
62
+ # securized_pass is a hash of key => password
63
+ securized_pass = manager.securize
64
+
@@ -0,0 +1,9 @@
1
+ = capistrano_recia version 0.0.1
2
+
3
+ == 0.0.1
4
+
5
+ * Creation of the initial release of the gem
6
+
7
+ == 0.0.2
8
+
9
+ * adding password security manager
@@ -0,0 +1,9 @@
1
+ require 'capistrano'
2
+ require 'capistrano_telnet'
3
+ require 'capistrano_supports'
4
+ require 'nagios_mklivestatus'
5
+
6
+ load File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "parents.rb")
7
+ load File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "filter.rb")
8
+ load File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "password.rb")
9
+
@@ -0,0 +1,91 @@
1
+ ##
2
+ # override the actions invocation class of capistrano
3
+ # to add the run_parent method and give access to it inside task definition
4
+ ##
5
+ Capistrano::Configuration::Actions::Invocation.class_eval do
6
+
7
+ ##
8
+ # Check if host contains task
9
+ ##
10
+ def host_as_task_role(current_host)
11
+ # Active From debug Only !
12
+ # puts "DEBUG :: #{current_host}"
13
+
14
+ roles_ok_from_host = nil
15
+
16
+ current_task.options[:roles].each do |task_role|
17
+
18
+ # Active From debug Only !
19
+ # puts "DEBUG :: #{task_role.to_s} ::"
20
+ roles[:"#{task_role.to_s}"].servers.each do |server|
21
+ # Active From debug Only !
22
+ # puts "#{server}"
23
+ if server.host.to_s == current_host.to_s
24
+ roles_ok_from_host = 1
25
+ end
26
+ end
27
+ end
28
+ if roles_ok_from_host != nil && roles_ok_from_host != 0
29
+ return 1
30
+ else
31
+ return 0
32
+ end
33
+ end
34
+
35
+ ##
36
+ # Use the role task option to filter the server with this role
37
+ ##
38
+ def run_filter_roles(cmd, options={}, &block)
39
+
40
+ block ||= self.class.default_io_proc
41
+
42
+ hosts_server = find_servers_for_task(current_task)
43
+ hosts = Array.new
44
+
45
+ ## calcul des rôles de la tâche
46
+ if current_task.options[:roles].kind_of? Array
47
+ current_task.options[:roles].each do |task_role|
48
+ task_roles = "#{task_roles} #{task_role}"
49
+ end
50
+ else
51
+ task_roles = "#{current_task.options[:roles]}"
52
+ current_task.options[:roles] = [current_task.options[:roles]]
53
+ end
54
+
55
+ # redistribution des machines par hôte
56
+ hosts_server.each do |server|
57
+ if host_as_task_role(server).to_i == 0
58
+ logger.info "Ce Serveur (#{server}) n'a pas un des role de la tache :#{task_roles}"
59
+ else
60
+ hosts.push(server.to_s)
61
+ end
62
+ end
63
+
64
+ if hosts != nil and not hosts.empty?
65
+
66
+ # save remaining hosts as the callee
67
+ ENV['HOSTS'] = hosts.join(',')
68
+
69
+ # execute action.
70
+ tree = Capistrano::Command::Tree.new(self) { |t| t.else(cmd, &block) }
71
+ run_tree(tree, options)
72
+ else
73
+ logger.important "Aucun serveurs ne possede un role : #{task_roles}"
74
+ end
75
+ end
76
+
77
+ ##
78
+ # Use the role task option to filter the server with this role and run a telnet method
79
+ ##
80
+ def run_telnet_filter_roles(cmd, options={}, &block)
81
+
82
+ set(:telnet, "true")
83
+ options[:shell] = false
84
+
85
+ run_filter_roles(cmd, options, &block)
86
+
87
+ unset(:telnet)
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,77 @@
1
+ ##
2
+ # Include Nagios Query Helper to Capistrano::Configuration
3
+ # in order to access helper from methods.
4
+ ##
5
+ Capistrano::Configuration.class_eval do
6
+ include Nagios::MkLiveStatus::QueryHelper
7
+ end
8
+
9
+ ##
10
+ # override the actions invocation class of capistrano
11
+ # to add the run_parent method and give access to it inside task definition
12
+ ##
13
+ Capistrano::Configuration::Actions::Invocation.class_eval do
14
+
15
+ ##
16
+ # Calculate the parent server of those in parameters and execute the command on them.
17
+ # We can loop through the child by using:
18
+ # - $PARENT:GUEST$ : required if we loop through guests, its replaced by the child name of the host.
19
+ # - $PARENT:LOOP:START$ : (opt.) start of the loop if not defined its automatically positionned at the beginning of the command
20
+ # - $PARENT:LOOP:END$ : (opt.) end of the loop if not defined its automatically positionned at the end of the command
21
+ def run_parent(cmd, options={}, &block)
22
+
23
+ block ||= self.class.default_io_proc
24
+
25
+ guest_servers = find_servers_for_task(current_task)
26
+ hosts = Hash.new
27
+
28
+ # redistribution des machines par hôte
29
+ guest_servers.each do |server|
30
+ guest = server.to_s
31
+ mklive = Nagios::MkLiveStatus::Request.new(fetch(:nagios_path, nil))
32
+ query = Nagios::MkLiveStatus::Query.new()
33
+ query.get "hosts"
34
+ query.addColumn "parents"
35
+ query.addFilter nagmk_filter("host_name", "=", guest)
36
+
37
+ result = mklive.query(query)
38
+
39
+ parent = result.split("\n")[0] if result != nil
40
+
41
+ if parent == nil or parent.empty? or parent.match(/^rca/)
42
+ logger.important "Ce serveur (#{guest}) n'est pas une machine virtuelle : Aucun serveur hote trouve pour la machine"
43
+ else
44
+ if not hosts.key?(parent)
45
+ hosts[parent] = Array.new
46
+ end
47
+ hosts[parent].push(guest)
48
+ end
49
+
50
+ end
51
+
52
+ # save parent hosts as the callee
53
+ ENV['HOSTS'] = hosts.keys.join(',')
54
+
55
+ # create a command script.
56
+ cmd = Capistrano::Command::Script.new("#{cmd.gsub(/\\/, '\\').gsub(/\"/,'\"')}") if cmd.kind_of? String
57
+ cmd['host'] = hosts
58
+
59
+ ## replace vars if they are encountered
60
+ loop_start = "<% prop('host', Hash.new)['$CAPISTRANO:HOST$'].each do |guest| %>"
61
+ loop_end = "<% end %>"
62
+ loop_guest = "<%= guest %>"
63
+
64
+ if cmd.include? "$PARENT:GUEST$"
65
+ cmd.contents.insert(0, "$PARENT:LOOP:START$\n") if not cmd.include? "$PARENT:LOOP:START"
66
+ cmd.contents.insert(-1, "\n$PARENT:LOOP:END$") if not cmd.include? "$PARENT:LOOP:END"
67
+ end
68
+
69
+ cmd.gsub(/\$PARENT:LOOP:START\$/, loop_start)
70
+ cmd.gsub(/\$PARENT:LOOP:END\$/, loop_end)
71
+ cmd.gsub(/\$PARENT:GUEST\$/, loop_guest)
72
+
73
+ # execute action.
74
+ tree = Capistrano::Command::Tree.new(self) { |t| t.else(cmd, &block) }
75
+ run_tree(tree, options)
76
+ end
77
+ end
@@ -0,0 +1,7 @@
1
+ require 'keepass-password-generator'
2
+
3
+ module Capistrano::Password
4
+
5
+ end
6
+
7
+ load File.join(File.dirname(__FILE__), File.basename(__FILE__, ".rb"), "manager.rb")
@@ -0,0 +1,143 @@
1
+ # encoding: utf-8
2
+ class Capistrano::Password::Manager
3
+
4
+ require 'yaml'
5
+ require 'encrypted_strings'
6
+ require 'keepass/password'
7
+
8
+
9
+ # constructor must determine the path to the save file.
10
+ # if we need to change the keepass regexp, the second parameter is used for it (default [S]20)
11
+ def initialize(file_path, keepass = "[S]{20}")
12
+ @file_path = file_path
13
+ @salt = "recia_password"
14
+ @keepass_regex = keepass
15
+ end
16
+
17
+ # to use only in a secure context (batch, admins who should know the pass)
18
+ def live_uncorrupt(save_key)
19
+ pass = nil
20
+ # load yaml file
21
+ yaml = load_file
22
+ # if yaml file contains informations
23
+ if yaml and yaml.has_key? save_key
24
+ # get the password
25
+ pass = yaml[save_key]["password"]
26
+ end
27
+
28
+ # decrypt the password
29
+ if pass
30
+ pass = pass.decrypt(:symmetric, :password => @salt)
31
+ end
32
+
33
+ # return password
34
+ return pass
35
+ end
36
+
37
+ # permet de savoir si le mot de passe est corrompu
38
+ def is_corrupted?(save_key)
39
+ # load yaml file
40
+ yaml = load_file
41
+ if yaml and yaml.has_key? save_key
42
+ # check if password is corrupted
43
+ corrupt = yaml[save_key]["corrupt"]
44
+ if corrupt.to_s == "true"
45
+ return true
46
+ end
47
+ end
48
+
49
+ return false
50
+ end
51
+
52
+ # permet de récupérer les mots de passe corrompus
53
+ def corrupted()
54
+ list = Array.new
55
+
56
+ yaml = load_file
57
+
58
+ yaml.keys.each do |key|
59
+ if is_corrupted? key
60
+ list.push key
61
+ end
62
+ end
63
+
64
+ list
65
+ end
66
+
67
+ # permet de récupérer un mot de passe si sa clé de sauvegarde est enregistré, sinon retourne nil
68
+ def corrupt(save_key)
69
+ # get passwd
70
+ pass = live_uncorrupt save_key
71
+
72
+ # load yaml file
73
+ yaml = load_file
74
+
75
+ # if yaml file contains informations
76
+ if yaml and pass
77
+ # set password to corrupted
78
+ yaml[save_key]["corrupt"] = true
79
+
80
+ # save the information of corruption to the file
81
+ File.open(@file_path, "w") do |io|
82
+ io.write(yaml.to_yaml)
83
+ io.close
84
+ end
85
+ end
86
+
87
+ # return password
88
+ return pass
89
+ end
90
+
91
+ # permet de générer un mot de passe.
92
+ # le premier paramètre indique si nous devons sauvegarder ou non le mot de passe (nil ou "" aucune sauvegarde)
93
+ # le deuxième paramètre est celui des options de keepass.
94
+ def generate(save_key="")
95
+
96
+ # generate a password without lookalikes (l, I, !, ...)
97
+ pass = KeePass::Password.generate(@keepass_regex, :remove_lookalikes => true)
98
+
99
+ # crypt the password
100
+ enc_pass = pass.encrypt(:symmetric, :password => @salt)
101
+ enc_pass.send :remove_instance_variable, :@cipher
102
+
103
+ # if a save key is passed
104
+ if save_key and not save_key.empty?
105
+ # load yaml file
106
+ yaml = load_file
107
+ yaml[save_key] = Hash.new if not yaml.has_key? save_key
108
+ # add password to file
109
+ yaml[save_key]["password"] = enc_pass
110
+ yaml[save_key]["corrupt"] = false
111
+ # save file
112
+ File.open(@file_path, "w") do |io|
113
+ io.write(yaml.to_yaml)
114
+ io.close
115
+ end
116
+ end
117
+
118
+ return pass, enc_pass
119
+
120
+ end
121
+
122
+ # regenerate all corrupted password. and return all the password which are regenerated by keys
123
+ def securize()
124
+
125
+ securized = Hash.new
126
+
127
+ # for each corrupted passwd
128
+ corrupted.each do |key|
129
+ securized[key] = Hash.new
130
+ securized[key]['old'] = corrupt(key)
131
+ securized[key]['new'], crypted = generate(key)
132
+ end
133
+
134
+ securized
135
+ end
136
+
137
+ private
138
+ def load_file()
139
+ yaml = Hash.new
140
+ yaml = YAML::load_file(@file_path) if File.exists? @file_path
141
+ yaml
142
+ end
143
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano_recia
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Esco-lan Team
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-08-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: capistrano
16
+ requirement: &10927620 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.11.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *10927620
25
+ - !ruby/object:Gem::Dependency
26
+ name: capistrano_telnet
27
+ requirement: &10927080 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 0.0.1
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *10927080
36
+ - !ruby/object:Gem::Dependency
37
+ name: capistrano_supports
38
+ requirement: &10926320 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: 0.0.1
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *10926320
47
+ - !ruby/object:Gem::Dependency
48
+ name: nagios_mklivestatus
49
+ requirement: &10925540 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.0.11
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *10925540
58
+ - !ruby/object:Gem::Dependency
59
+ name: keepass-password-generator
60
+ requirement: &10924860 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: 0.1.1
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *10924860
69
+ - !ruby/object:Gem::Dependency
70
+ name: encrypted_strings
71
+ requirement: &10923940 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: 0.3.3
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *10923940
80
+ description: RECIA Capistrano Support
81
+ email: team@esco-lan.org
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files:
85
+ - README.rdoc
86
+ - RELEASE.rdoc
87
+ files:
88
+ - lib/capistrano_recia/filter.rb
89
+ - lib/capistrano_recia/password.rb
90
+ - lib/capistrano_recia/password/manager.rb
91
+ - lib/capistrano_recia/parents.rb
92
+ - lib/capistrano_recia.rb
93
+ - README.rdoc
94
+ - RELEASE.rdoc
95
+ homepage: https://github.com/RECIA/capistrano_recia
96
+ licenses: []
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ none: false
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ none: false
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.8
116
+ signing_key:
117
+ specification_version: 3
118
+ summary: Provides additionnal methods to capistrano like run_parent, run_filter_role_contained
119
+ and run_filter_role_uncontained
120
+ test_files: []