CloudyScripts 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +7 -7
- data/README.rdoc +27 -27
- data/Rakefile +50 -50
- data/lib/cloudyscripts.rb +26 -26
- data/lib/help/dm_crypt_helper.rb +204 -204
- data/lib/help/ec2_helper.rb +54 -54
- data/lib/help/remote_command_handler.rb +203 -190
- data/lib/help/script_execution_state.rb +97 -95
- data/lib/help/state_change_listener.rb +13 -13
- data/lib/scripts/ec2/ami2_ebs_conversion.rb +446 -442
- data/lib/scripts/ec2/dm_encrypt.rb +194 -190
- data/lib/scripts/ec2/ec2_script.rb +41 -41
- metadata +2 -2
data/LICENSE
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
Copyright (c) 2010 Matthias Jung
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
-
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
-
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1
|
+
Copyright (c) 2010 Matthias Jung
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
CHANGED
@@ -1,27 +1,27 @@
|
|
1
|
-
# =About
|
2
|
-
# CloudyScripts is a library that implements tasks that support common
|
3
|
-
# usecases on Cloud Computing Infrastructures (such as Amazon EC2 or Rackspace).
|
4
|
-
# It aims to facilitate the implementation of usecases that are not directly
|
5
|
-
# available via the providers' API (e.g. like encrypting storage,
|
6
|
-
# migrating instances betweem accounts, activating HTTPS). The scripts typically
|
7
|
-
# use the provider APIs plus remote access to command-line tools installed on
|
8
|
-
# the instances themselves.
|
9
|
-
#
|
10
|
-
# =Installation and Usage
|
11
|
-
# ==Installation
|
12
|
-
# <tt>gem install CloudyScripts</tt>
|
13
|
-
#
|
14
|
-
# ==Usage
|
15
|
-
# All scripts are available under /lib/scripts/<provider>
|
16
|
-
# They are initialized with a set of parameters and return a well-define
|
17
|
-
# set of return values.
|
18
|
-
#
|
19
|
-
# =Scripts
|
20
|
-
# Here are the scripts implemented so far:
|
21
|
-
# * #DmEncrypt (encrypt Amazon EBS Storage using dm-encrypt)
|
22
|
-
#
|
23
|
-
# =Questions and Suggestions
|
24
|
-
# Matthias Jung
|
25
|
-
# matthias.jung@gmail.com
|
26
|
-
# http://elastic-security.com
|
27
|
-
|
1
|
+
# =About
|
2
|
+
# CloudyScripts is a library that implements tasks that support common
|
3
|
+
# usecases on Cloud Computing Infrastructures (such as Amazon EC2 or Rackspace).
|
4
|
+
# It aims to facilitate the implementation of usecases that are not directly
|
5
|
+
# available via the providers' API (e.g. like encrypting storage,
|
6
|
+
# migrating instances betweem accounts, activating HTTPS). The scripts typically
|
7
|
+
# use the provider APIs plus remote access to command-line tools installed on
|
8
|
+
# the instances themselves.
|
9
|
+
#
|
10
|
+
# =Installation and Usage
|
11
|
+
# ==Installation
|
12
|
+
# <tt>gem install CloudyScripts</tt>
|
13
|
+
#
|
14
|
+
# ==Usage
|
15
|
+
# All scripts are available under /lib/scripts/<provider>
|
16
|
+
# They are initialized with a set of parameters and return a well-define
|
17
|
+
# set of return values.
|
18
|
+
#
|
19
|
+
# =Scripts
|
20
|
+
# Here are the scripts implemented so far:
|
21
|
+
# * #DmEncrypt (encrypt Amazon EBS Storage using dm-encrypt)
|
22
|
+
#
|
23
|
+
# =Questions and Suggestions
|
24
|
+
# Matthias Jung
|
25
|
+
# matthias.jung@gmail.com
|
26
|
+
# http://elastic-security.com
|
27
|
+
|
data/Rakefile
CHANGED
@@ -1,50 +1,50 @@
|
|
1
|
-
#
|
2
|
-
# To change this template, choose Tools | Templates
|
3
|
-
# and open the template in the editor.
|
4
|
-
|
5
|
-
|
6
|
-
require 'rubygems'
|
7
|
-
require 'rake'
|
8
|
-
require 'rake/clean'
|
9
|
-
require 'rake/gempackagetask'
|
10
|
-
require 'rake/rdoctask'
|
11
|
-
require 'rake/testtask'
|
12
|
-
|
13
|
-
spec = Gem::Specification.new do |s|
|
14
|
-
s.name = 'CloudyScripts'
|
15
|
-
s.version = '0.0.
|
16
|
-
s.has_rdoc = true
|
17
|
-
s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
|
18
|
-
s.summary = 'Scripts to facilitate programming for infrastructure clouds.'
|
19
|
-
s.description = s.summary
|
20
|
-
s.homepage = "http://elastic-security.com"
|
21
|
-
s.rubyforge_project = "cloudyscripts"
|
22
|
-
s.author = 'Matthias Jung'
|
23
|
-
s.email = 'matthias.jung@gmail.com'
|
24
|
-
# s.executables = ['your_executable_here']
|
25
|
-
s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
26
|
-
s.require_path = "lib"
|
27
|
-
s.bindir = "bin"
|
28
|
-
s.has_rdoc = true
|
29
|
-
s.add_dependency("amazon-ec2")
|
30
|
-
s.add_dependency("net-ssh")
|
31
|
-
end
|
32
|
-
|
33
|
-
Rake::GemPackageTask.new(spec) do |p|
|
34
|
-
p.gem_spec = spec
|
35
|
-
p.need_tar = true
|
36
|
-
p.need_zip = true
|
37
|
-
end
|
38
|
-
|
39
|
-
Rake::RDocTask.new do |rdoc|
|
40
|
-
files =['README', 'LICENSE', 'lib/**/*.rb']
|
41
|
-
rdoc.rdoc_files.add(files)
|
42
|
-
rdoc.main = "README" # page to start on
|
43
|
-
rdoc.title = "CloudyScripts Docs"
|
44
|
-
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
45
|
-
rdoc.options << '--line-numbers'
|
46
|
-
end
|
47
|
-
|
48
|
-
Rake::TestTask.new do |t|
|
49
|
-
t.test_files = FileList['test/**/*.rb']
|
50
|
-
end
|
1
|
+
#
|
2
|
+
# To change this template, choose Tools | Templates
|
3
|
+
# and open the template in the editor.
|
4
|
+
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'rake'
|
8
|
+
require 'rake/clean'
|
9
|
+
require 'rake/gempackagetask'
|
10
|
+
require 'rake/rdoctask'
|
11
|
+
require 'rake/testtask'
|
12
|
+
|
13
|
+
spec = Gem::Specification.new do |s|
|
14
|
+
s.name = 'CloudyScripts'
|
15
|
+
s.version = '0.0.9'
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
|
18
|
+
s.summary = 'Scripts to facilitate programming for infrastructure clouds.'
|
19
|
+
s.description = s.summary
|
20
|
+
s.homepage = "http://elastic-security.com"
|
21
|
+
s.rubyforge_project = "cloudyscripts"
|
22
|
+
s.author = 'Matthias Jung'
|
23
|
+
s.email = 'matthias.jung@gmail.com'
|
24
|
+
# s.executables = ['your_executable_here']
|
25
|
+
s.files = %w(LICENSE README.rdoc Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
26
|
+
s.require_path = "lib"
|
27
|
+
s.bindir = "bin"
|
28
|
+
s.has_rdoc = true
|
29
|
+
s.add_dependency("amazon-ec2")
|
30
|
+
s.add_dependency("net-ssh")
|
31
|
+
end
|
32
|
+
|
33
|
+
Rake::GemPackageTask.new(spec) do |p|
|
34
|
+
p.gem_spec = spec
|
35
|
+
p.need_tar = true
|
36
|
+
p.need_zip = true
|
37
|
+
end
|
38
|
+
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
files =['README', 'LICENSE', 'lib/**/*.rb']
|
41
|
+
rdoc.rdoc_files.add(files)
|
42
|
+
rdoc.main = "README" # page to start on
|
43
|
+
rdoc.title = "CloudyScripts Docs"
|
44
|
+
rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
|
45
|
+
rdoc.options << '--line-numbers'
|
46
|
+
end
|
47
|
+
|
48
|
+
Rake::TestTask.new do |t|
|
49
|
+
t.test_files = FileList['test/**/*.rb']
|
50
|
+
end
|
data/lib/cloudyscripts.rb
CHANGED
@@ -1,26 +1,26 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'net/ssh'
|
3
|
-
require 'AWS'
|
4
|
-
|
5
|
-
# =About
|
6
|
-
# CloudyScripts is a library that implements tasks that support common
|
7
|
-
# usecases on Cloud Computing Infrastructures (such as Amazon EC2 or Rackspace).
|
8
|
-
# It aims to facilitate the implementation of usecases that are not directly
|
9
|
-
# available via the providers' API (e.g. like encrypting storage,
|
10
|
-
# migrating instances betweem accounts, activating HTTPS). The scripts typically
|
11
|
-
# use the provider APIs plus remote access to command-line tools installed on
|
12
|
-
# the instances themselves.
|
13
|
-
#
|
14
|
-
# =Installation and Usage
|
15
|
-
# ===Installation
|
16
|
-
# <tt>gem install CloudyScripts</tt>
|
17
|
-
#
|
18
|
-
# ===Usage
|
19
|
-
# All scripts are available under /lib/scripts/<em>provider</em>>
|
20
|
-
#
|
21
|
-
# ===Scripts
|
22
|
-
# Here are the scripts implemented so far:
|
23
|
-
# * #Scripts::EC2::DmEncrypt (encrypt Amazon EBS Storage using dm-encrypt)
|
24
|
-
#
|
25
|
-
class CloudyScripts
|
26
|
-
end
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'AWS'
|
4
|
+
|
5
|
+
# =About
|
6
|
+
# CloudyScripts is a library that implements tasks that support common
|
7
|
+
# usecases on Cloud Computing Infrastructures (such as Amazon EC2 or Rackspace).
|
8
|
+
# It aims to facilitate the implementation of usecases that are not directly
|
9
|
+
# available via the providers' API (e.g. like encrypting storage,
|
10
|
+
# migrating instances betweem accounts, activating HTTPS). The scripts typically
|
11
|
+
# use the provider APIs plus remote access to command-line tools installed on
|
12
|
+
# the instances themselves.
|
13
|
+
#
|
14
|
+
# =Installation and Usage
|
15
|
+
# ===Installation
|
16
|
+
# <tt>gem install CloudyScripts</tt>
|
17
|
+
#
|
18
|
+
# ===Usage
|
19
|
+
# All scripts are available under /lib/scripts/<em>provider</em>>
|
20
|
+
#
|
21
|
+
# ===Scripts
|
22
|
+
# Here are the scripts implemented so far:
|
23
|
+
# * #Scripts::EC2::DmEncrypt (encrypt Amazon EBS Storage using dm-encrypt)
|
24
|
+
#
|
25
|
+
class CloudyScripts
|
26
|
+
end
|
data/lib/help/dm_crypt_helper.rb
CHANGED
@@ -1,204 +1,204 @@
|
|
1
|
-
require 'help/remote_command_handler'
|
2
|
-
|
3
|
-
# This class implements helper methods for Dm Encryption
|
4
|
-
# (see #Scripts::EC2::DmEncrypt)
|
5
|
-
|
6
|
-
class DmCryptHelper < RemoteCommandHandler
|
7
|
-
|
8
|
-
# Encrypts the device and mounting it using dm-crypt tools. Uses LVM to
|
9
|
-
# work with virtual devices.
|
10
|
-
# Params
|
11
|
-
# * name: name of the virtual volume
|
12
|
-
# * password: paraphrase to be used for encryption
|
13
|
-
# * device: device to be encrypted
|
14
|
-
# * path: path to which the encrypted device is mounted
|
15
|
-
def encrypt_storage_lvm(name, password, device, path)
|
16
|
-
# first: check if a file in /dev/mapper exists
|
17
|
-
if file_exists?("/dev/mapper/dm-#{name}")
|
18
|
-
mapper_exists = true
|
19
|
-
else
|
20
|
-
mapper_exists = false
|
21
|
-
end
|
22
|
-
@logger.info "mapper exists = #{mapper_exists}"
|
23
|
-
exec_string = "cryptsetup create dm-#{name} #{device}"
|
24
|
-
if !mapper_exists
|
25
|
-
#mapper does not exist, create it
|
26
|
-
channel = @ssh_session.open_channel do |ch|
|
27
|
-
ch.send_data("#{password}\n")
|
28
|
-
@logger.debug "execute #{exec_string}"
|
29
|
-
ch.exec exec_string do |ch, success|
|
30
|
-
@logger.debug "success = #{success}"
|
31
|
-
if !success
|
32
|
-
err = "Failed during creation of encrypted partition"
|
33
|
-
#puts "#{err}: #{data}"
|
34
|
-
raise Exception.new(err)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
channel.wait
|
39
|
-
end
|
40
|
-
# now mapper is created
|
41
|
-
# second: check if pvscan sucessful
|
42
|
-
pv_exists = false
|
43
|
-
@ssh_session.exec! "/sbin/pvscan" do |ch, stream, data|
|
44
|
-
if stream == :stdout
|
45
|
-
if data.include?("vg-#{name}")
|
46
|
-
pv_exists = true
|
47
|
-
else
|
48
|
-
pv_exists = false
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
if !pv_exists
|
53
|
-
exec_string = "pvcreate /dev/mapper/dm-#{name}"
|
54
|
-
@logger.info "pv does not exist - execute: #{exec_string}"
|
55
|
-
#private volume does not exist, create it
|
56
|
-
channel = @ssh_session.open_channel do |ch|
|
57
|
-
ch.send_data("y\n")
|
58
|
-
ch.exec exec_string do |ch, success|
|
59
|
-
@logger.debug "success = #{success}"
|
60
|
-
if !success
|
61
|
-
err = "Failed during creation of physical volume"
|
62
|
-
#puts "#{err}: #{data}"
|
63
|
-
raise Exception.new(err)
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
channel.wait
|
68
|
-
end
|
69
|
-
# third: check if vgscan successful
|
70
|
-
vg_exists = false
|
71
|
-
@ssh_session.exec! "/sbin/vgscan" do |ch, stream, data|
|
72
|
-
if stream == :stdout
|
73
|
-
if data.include?("vg-#{name}")
|
74
|
-
vg_exists = true
|
75
|
-
else
|
76
|
-
vg_exists = false
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
if !vg_exists
|
81
|
-
exec_string = "vgcreate vg-#{name} /dev/mapper/dm-#{name}"
|
82
|
-
@logger.info "vg_exists == false; execute #{exec_string}"
|
83
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
84
|
-
if stream == :stderr && data != nil
|
85
|
-
err = "Failed during creation of volume group"
|
86
|
-
@logger.warn "#{err}: #{data}"
|
87
|
-
raise Exception.new(err)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
#exec_string = "lvcreate -n lv-#{name} -L#{size_in_mb.to_s}M vg-#{name}"
|
91
|
-
exec_string = "lvcreate -n lv-#{name} -l100%FREE vg-#{name}"
|
92
|
-
@logger.info "execute #{exec_string}"
|
93
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
94
|
-
if stream == :stderr && data != nil
|
95
|
-
err = "Failed during creation of logical volume"
|
96
|
-
@logger.debug "#{err}: #{data}"
|
97
|
-
raise Exception.new(err)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
exec_string = "mkfs -t ext3 /dev/vg-#{name}/lv-#{name}" #TODO: use method in remote_command_handler
|
101
|
-
@logger.info "execute #{exec_string}"
|
102
|
-
@ssh_session.exec! exec_string #do |ch, stream, data|
|
103
|
-
#if stream == :stderr && data != nil
|
104
|
-
#err = "Failed during creation of file-system"
|
105
|
-
#puts "#{err}: #{data}"
|
106
|
-
#raise Exception.new(err)
|
107
|
-
#end
|
108
|
-
#end
|
109
|
-
if !file_exists?("/dev/vg-#{name}/lv-#{name}")
|
110
|
-
err = "Missing file: /dev/vg-#{name}/lv-#{name}"
|
111
|
-
raise Exception.new(err)
|
112
|
-
end
|
113
|
-
else
|
114
|
-
exec_string = "/sbin/vgchange -a y vg-#{name}"
|
115
|
-
@logger.info "vg_exists == true; execute #{exec_string}"
|
116
|
-
@ssh_session.exec! exec_string do |ch, stream, data| #TODO: the right size instead L2G!
|
117
|
-
if stream == :stderr && data != nil
|
118
|
-
err = "Failed during re-activation of volume group"
|
119
|
-
@logger.info "#{err}: #{data}"
|
120
|
-
raise Exception.new(err)
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
# Undo encryption for the volume specified by name and path
|
127
|
-
def undo_encryption_lvm(name, path)
|
128
|
-
exec_string = "umount #{path}"
|
129
|
-
@logger.debug "going to execute #{exec_string}"
|
130
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
131
|
-
@logger.debug "returns #{data}"
|
132
|
-
end
|
133
|
-
exec_string = "lvremove --verbose vg-#{name} -f" #[with confirmation?]
|
134
|
-
@logger.debug "going to execute #{exec_string}"
|
135
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
136
|
-
@logger.debug "returns #{data}"
|
137
|
-
end
|
138
|
-
exec_string = "vgremove vg-#{name}"
|
139
|
-
@logger.debug "going to execute #{exec_string}"
|
140
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
141
|
-
@logger.debug "returns #{data}"
|
142
|
-
end
|
143
|
-
exec_string = "pvremove /dev/mapper/dm-#{name}"
|
144
|
-
@logger.debug "going to execute #{exec_string}"
|
145
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
146
|
-
@logger.debug "returns #{data}"
|
147
|
-
end
|
148
|
-
exec_string = "cryptsetup remove dm-#{name}"
|
149
|
-
@logger.debug "going to execute #{exec_string}"
|
150
|
-
@ssh_session.exec! exec_string do |ch, stream, data|
|
151
|
-
@logger.debug "returns #{data}"
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
# Encrypts the device and mounting it using dm-crypt tools.
|
156
|
-
# Params
|
157
|
-
# * name: name of the virtual volume
|
158
|
-
# * password: paraphrase to be used for encryption
|
159
|
-
# * device: device to be encrypted
|
160
|
-
# * path: path to which the encrypted device is mounted
|
161
|
-
def encrypt_storage(name, password, device, path)
|
162
|
-
if !
|
163
|
-
raise Exception.new("device #{device} is already used differently")
|
164
|
-
end
|
165
|
-
if file_exists?(device)
|
166
|
-
if !file_exists?("/dev/mapper/#{name}")
|
167
|
-
@logger.debug("mapper device #{name} not yet existing")
|
168
|
-
#device not configured, go ahead
|
169
|
-
|
170
|
-
@logger.debug("device #{device} formatted as #{name}")
|
171
|
-
|
172
|
-
@logger.debug("device #{device} / #{name} opened")
|
173
|
-
self.create_filesystem("ext3", "/dev/mapper/#{name}")
|
174
|
-
@logger.debug("filesystem created on /dev/mapper/#{name}")
|
175
|
-
self.mkdir(path)
|
176
|
-
self.mount("/dev/mapper/#{name}", path)
|
177
|
-
#TODO: make a final check that everything worked? ?
|
178
|
-
else
|
179
|
-
#device already exists, just re-activate it
|
180
|
-
@logger.debug("mapper device #{name} is existing")
|
181
|
-
|
182
|
-
@logger.debug("device #{device} /dev/mapper/#{name} opened")
|
183
|
-
self.mkdir(path) unless file_exists?(path)
|
184
|
-
self.mount("/dev/mapper/#{name}", path) unless drive_mounted_as?("/dev/mapper/#{name}", path)
|
185
|
-
end
|
186
|
-
else
|
187
|
-
#device does not even exist
|
188
|
-
raise Exception.new("device #{device} does not exist")
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
# Check if the storage is encrypted (not yet implemented).
|
194
|
-
def test_storage_encryption(password, mount_point, path)
|
195
|
-
end
|
196
|
-
|
197
|
-
def undo_encryption(name, path)
|
198
|
-
|
199
|
-
@logger.debug("drive #{path} unmounted")
|
200
|
-
|
201
|
-
@logger.debug("closed /dev/mapper/#{name} unmounted")
|
202
|
-
end
|
203
|
-
|
204
|
-
end
|
1
|
+
require 'help/remote_command_handler'
|
2
|
+
|
3
|
+
# This class implements helper methods for Dm Encryption
|
4
|
+
# (see #Scripts::EC2::DmEncrypt)
|
5
|
+
|
6
|
+
class DmCryptHelper < RemoteCommandHandler
|
7
|
+
|
8
|
+
# Encrypts the device and mounting it using dm-crypt tools. Uses LVM to
|
9
|
+
# work with virtual devices.
|
10
|
+
# Params
|
11
|
+
# * name: name of the virtual volume
|
12
|
+
# * password: paraphrase to be used for encryption
|
13
|
+
# * device: device to be encrypted
|
14
|
+
# * path: path to which the encrypted device is mounted
|
15
|
+
def encrypt_storage_lvm(name, password, device, path)
|
16
|
+
# first: check if a file in /dev/mapper exists
|
17
|
+
if file_exists?("/dev/mapper/dm-#{name}")
|
18
|
+
mapper_exists = true
|
19
|
+
else
|
20
|
+
mapper_exists = false
|
21
|
+
end
|
22
|
+
@logger.info "mapper exists = #{mapper_exists}"
|
23
|
+
exec_string = "cryptsetup create dm-#{name} #{device}"
|
24
|
+
if !mapper_exists
|
25
|
+
#mapper does not exist, create it
|
26
|
+
channel = @ssh_session.open_channel do |ch|
|
27
|
+
ch.send_data("#{password}\n")
|
28
|
+
@logger.debug "execute #{exec_string}"
|
29
|
+
ch.exec exec_string do |ch, success|
|
30
|
+
@logger.debug "success = #{success}"
|
31
|
+
if !success
|
32
|
+
err = "Failed during creation of encrypted partition"
|
33
|
+
#puts "#{err}: #{data}"
|
34
|
+
raise Exception.new(err)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
channel.wait
|
39
|
+
end
|
40
|
+
# now mapper is created
|
41
|
+
# second: check if pvscan sucessful
|
42
|
+
pv_exists = false
|
43
|
+
@ssh_session.exec! "/sbin/pvscan" do |ch, stream, data|
|
44
|
+
if stream == :stdout
|
45
|
+
if data.include?("vg-#{name}")
|
46
|
+
pv_exists = true
|
47
|
+
else
|
48
|
+
pv_exists = false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if !pv_exists
|
53
|
+
exec_string = "pvcreate /dev/mapper/dm-#{name}"
|
54
|
+
@logger.info "pv does not exist - execute: #{exec_string}"
|
55
|
+
#private volume does not exist, create it
|
56
|
+
channel = @ssh_session.open_channel do |ch|
|
57
|
+
ch.send_data("y\n")
|
58
|
+
ch.exec exec_string do |ch, success|
|
59
|
+
@logger.debug "success = #{success}"
|
60
|
+
if !success
|
61
|
+
err = "Failed during creation of physical volume"
|
62
|
+
#puts "#{err}: #{data}"
|
63
|
+
raise Exception.new(err)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
channel.wait
|
68
|
+
end
|
69
|
+
# third: check if vgscan successful
|
70
|
+
vg_exists = false
|
71
|
+
@ssh_session.exec! "/sbin/vgscan" do |ch, stream, data|
|
72
|
+
if stream == :stdout
|
73
|
+
if data.include?("vg-#{name}")
|
74
|
+
vg_exists = true
|
75
|
+
else
|
76
|
+
vg_exists = false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
if !vg_exists
|
81
|
+
exec_string = "vgcreate vg-#{name} /dev/mapper/dm-#{name}"
|
82
|
+
@logger.info "vg_exists == false; execute #{exec_string}"
|
83
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
84
|
+
if stream == :stderr && data != nil
|
85
|
+
err = "Failed during creation of volume group"
|
86
|
+
@logger.warn "#{err}: #{data}"
|
87
|
+
raise Exception.new(err)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
#exec_string = "lvcreate -n lv-#{name} -L#{size_in_mb.to_s}M vg-#{name}"
|
91
|
+
exec_string = "lvcreate -n lv-#{name} -l100%FREE vg-#{name}"
|
92
|
+
@logger.info "execute #{exec_string}"
|
93
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
94
|
+
if stream == :stderr && data != nil
|
95
|
+
err = "Failed during creation of logical volume"
|
96
|
+
@logger.debug "#{err}: #{data}"
|
97
|
+
raise Exception.new(err)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
exec_string = "mkfs -t ext3 /dev/vg-#{name}/lv-#{name}" #TODO: use method in remote_command_handler
|
101
|
+
@logger.info "execute #{exec_string}"
|
102
|
+
@ssh_session.exec! exec_string #do |ch, stream, data|
|
103
|
+
#if stream == :stderr && data != nil
|
104
|
+
#err = "Failed during creation of file-system"
|
105
|
+
#puts "#{err}: #{data}"
|
106
|
+
#raise Exception.new(err)
|
107
|
+
#end
|
108
|
+
#end
|
109
|
+
if !file_exists?("/dev/vg-#{name}/lv-#{name}")
|
110
|
+
err = "Missing file: /dev/vg-#{name}/lv-#{name}"
|
111
|
+
raise Exception.new(err)
|
112
|
+
end
|
113
|
+
else
|
114
|
+
exec_string = "/sbin/vgchange -a y vg-#{name}"
|
115
|
+
@logger.info "vg_exists == true; execute #{exec_string}"
|
116
|
+
@ssh_session.exec! exec_string do |ch, stream, data| #TODO: the right size instead L2G!
|
117
|
+
if stream == :stderr && data != nil
|
118
|
+
err = "Failed during re-activation of volume group"
|
119
|
+
@logger.info "#{err}: #{data}"
|
120
|
+
raise Exception.new(err)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Undo encryption for the volume specified by name and path
|
127
|
+
def undo_encryption_lvm(name, path)
|
128
|
+
exec_string = "umount #{path}"
|
129
|
+
@logger.debug "going to execute #{exec_string}"
|
130
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
131
|
+
@logger.debug "returns #{data}"
|
132
|
+
end
|
133
|
+
exec_string = "lvremove --verbose vg-#{name} -f" #[with confirmation?]
|
134
|
+
@logger.debug "going to execute #{exec_string}"
|
135
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
136
|
+
@logger.debug "returns #{data}"
|
137
|
+
end
|
138
|
+
exec_string = "vgremove vg-#{name}"
|
139
|
+
@logger.debug "going to execute #{exec_string}"
|
140
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
141
|
+
@logger.debug "returns #{data}"
|
142
|
+
end
|
143
|
+
exec_string = "pvremove /dev/mapper/dm-#{name}"
|
144
|
+
@logger.debug "going to execute #{exec_string}"
|
145
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
146
|
+
@logger.debug "returns #{data}"
|
147
|
+
end
|
148
|
+
exec_string = "cryptsetup remove dm-#{name}"
|
149
|
+
@logger.debug "going to execute #{exec_string}"
|
150
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
151
|
+
@logger.debug "returns #{data}"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# Encrypts the device and mounting it using dm-crypt tools.
|
156
|
+
# Params
|
157
|
+
# * name: name of the virtual volume
|
158
|
+
# * password: paraphrase to be used for encryption
|
159
|
+
# * device: device to be encrypted
|
160
|
+
# * path: path to which the encrypted device is mounted
|
161
|
+
def encrypt_storage(name, password, device, path)
|
162
|
+
if !remote_execute("cryptsetup isLuks #{device}")
|
163
|
+
raise Exception.new("device #{device} is already used differently")
|
164
|
+
end
|
165
|
+
if file_exists?(device)
|
166
|
+
if !file_exists?("/dev/mapper/#{name}")
|
167
|
+
@logger.debug("mapper device #{name} not yet existing")
|
168
|
+
#device not configured, go ahead
|
169
|
+
remote_execute("cryptsetup luksFormat -q #{device}", password)
|
170
|
+
@logger.debug("device #{device} formatted as #{name}")
|
171
|
+
remote_execute("cryptsetup luksOpen #{device} #{name}",password)
|
172
|
+
@logger.debug("device #{device} / #{name} opened")
|
173
|
+
self.create_filesystem("ext3", "/dev/mapper/#{name}")
|
174
|
+
@logger.debug("filesystem created on /dev/mapper/#{name}")
|
175
|
+
self.mkdir(path)
|
176
|
+
self.mount("/dev/mapper/#{name}", path)
|
177
|
+
#TODO: make a final check that everything worked? ?
|
178
|
+
else
|
179
|
+
#device already exists, just re-activate it
|
180
|
+
@logger.debug("mapper device #{name} is existing")
|
181
|
+
remote_execute("cryptsetup luksOpen #{device} #{name}")
|
182
|
+
@logger.debug("device #{device} /dev/mapper/#{name} opened")
|
183
|
+
self.mkdir(path) unless file_exists?(path)
|
184
|
+
self.mount("/dev/mapper/#{name}", path) unless drive_mounted_as?("/dev/mapper/#{name}", path)
|
185
|
+
end
|
186
|
+
else
|
187
|
+
#device does not even exist
|
188
|
+
raise Exception.new("device #{device} does not exist")
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
# Check if the storage is encrypted (not yet implemented).
|
194
|
+
def test_storage_encryption(password, mount_point, path)
|
195
|
+
end
|
196
|
+
|
197
|
+
def undo_encryption(name, path)
|
198
|
+
remote_execute("umount #{path}", nil, true)
|
199
|
+
@logger.debug("drive #{path} unmounted")
|
200
|
+
remote_execute("cryptsetup luksClose /dev/mapper/#{name}", nil, true)
|
201
|
+
@logger.debug("closed /dev/mapper/#{name} unmounted")
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|