capistrano_recia 0.0.2

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