CloudyScripts 0.0.1
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.
- data/LICENSE +4 -0
- data/README +1 -0
- data/Rakefile +50 -0
- data/lib/cloudyscripts.rb +28 -0
- data/lib/help/dm_crypt_helper.rb +172 -0
- data/lib/help/remote_command_handler.rb +113 -0
- data/lib/help/script_execution_state.rb +69 -0
- data/lib/scripts/ec2/dm_encrypt.rb +182 -0
- data/lib/scripts/ec2/ec2_script.rb +12 -0
- metadata +83 -0
data/LICENSE
ADDED
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Scripts to facilitate programming for infrastructure clouds
|
data/Rakefile
ADDED
@@ -0,0 +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.1'
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ['README', '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 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
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
require 'AWS'
|
4
|
+
|
5
|
+
require "../test/mock/mocked_ec2_api"
|
6
|
+
require "../test/mock/mocked_remote_command_handler"
|
7
|
+
|
8
|
+
require "scripts/ec2/dm_encrypt"
|
9
|
+
|
10
|
+
rch = MockedRemoteCommandHandler.new
|
11
|
+
ec2 = MockedEc2Api.new
|
12
|
+
|
13
|
+
params = {
|
14
|
+
:remote_command_handler => rch,
|
15
|
+
:ec2_api_handler => ec2,
|
16
|
+
:password => "password",
|
17
|
+
:ip_address => "127.0.0.1",
|
18
|
+
:ssh_key_file => "/Users/mats/.ssh",
|
19
|
+
:device => "/dev/sdh",
|
20
|
+
:device_name => "device-vol-i-12345"
|
21
|
+
}
|
22
|
+
script = DmEncrypt.new(params)
|
23
|
+
script.start_script()
|
24
|
+
if script.get_execution_result[:failed] == nil || script.get_execution_result[:failed]
|
25
|
+
puts "script failed: #{script.get_execution_result[:failure_reason]}"
|
26
|
+
end
|
27
|
+
|
28
|
+
puts "done"
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'lib/ssh_api'
|
2
|
+
|
3
|
+
class DmCryptHelper
|
4
|
+
|
5
|
+
def set_ssh(ssh_session)
|
6
|
+
@ssh_session = ssh_session
|
7
|
+
end
|
8
|
+
|
9
|
+
def install()
|
10
|
+
#TODO: dm-crypt seems to be installed automatically
|
11
|
+
true
|
12
|
+
end
|
13
|
+
|
14
|
+
def tools_installed?()
|
15
|
+
@ssh_session.exec! "which dmsetup" do |ch, stream, data|
|
16
|
+
if stream == :stderr
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
@ssh_session.exec! "which cryptsetup" do |ch, stream, data|
|
21
|
+
if stream == :stderr
|
22
|
+
return false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
#TODO: check also that "/dev/mapper /dev/mapper/control" exist
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
def encrypt_storage(name, password, device, path)
|
30
|
+
# first: check if a file in /dev/mapper exists
|
31
|
+
if SshApi.file_exists?(@ssh_session, "/dev/mapper/dm-#{name}")
|
32
|
+
mapper_exists = true
|
33
|
+
else
|
34
|
+
mapper_exists = false
|
35
|
+
end
|
36
|
+
puts "mapper exists = #{mapper_exists}"
|
37
|
+
exec_string = "cryptsetup create dm-#{name} #{device}"
|
38
|
+
if !mapper_exists
|
39
|
+
#mapper does not exist, create it
|
40
|
+
channel = @ssh_session.open_channel do |ch|
|
41
|
+
ch.send_data("#{password}\n")
|
42
|
+
puts "execute #{exec_string}"
|
43
|
+
ch.exec exec_string do |ch, success|
|
44
|
+
puts "success = #{success}"
|
45
|
+
if !success
|
46
|
+
err = "Failed during creation of encrypted partition"
|
47
|
+
#puts "#{err}: #{data}"
|
48
|
+
raise Exception.new(err)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
channel.wait
|
53
|
+
end
|
54
|
+
# now mapper is created
|
55
|
+
# second: check if pvscan sucessful
|
56
|
+
pv_exists = false
|
57
|
+
@ssh_session.exec! "/sbin/pvscan" do |ch, stream, data|
|
58
|
+
if stream == :stdout
|
59
|
+
if data.include?("vg-#{name}")
|
60
|
+
pv_exists = true
|
61
|
+
else
|
62
|
+
pv_exists = false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
if !pv_exists
|
67
|
+
exec_string = "pvcreate /dev/mapper/dm-#{name}"
|
68
|
+
puts "pv does not exist - execute: #{exec_string}"
|
69
|
+
#private volume does not exist, create it
|
70
|
+
channel = @ssh_session.open_channel do |ch|
|
71
|
+
ch.send_data("y\n")
|
72
|
+
ch.exec exec_string do |ch, success|
|
73
|
+
puts "success = #{success}"
|
74
|
+
if !success
|
75
|
+
err = "Failed during creation of physical volume"
|
76
|
+
#puts "#{err}: #{data}"
|
77
|
+
raise Exception.new(err)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
channel.wait
|
82
|
+
end
|
83
|
+
# third: check if vgscan successful
|
84
|
+
vg_exists = false
|
85
|
+
@ssh_session.exec! "/sbin/vgscan" do |ch, stream, data|
|
86
|
+
if stream == :stdout
|
87
|
+
if data.include?("vg-#{name}")
|
88
|
+
vg_exists = true
|
89
|
+
else
|
90
|
+
vg_exists = false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
if !vg_exists
|
95
|
+
exec_string = "vgcreate vg-#{name} /dev/mapper/dm-#{name}"
|
96
|
+
puts "vg_exists == false; execute #{exec_string}"
|
97
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
98
|
+
if stream == :stderr && !data.blank?
|
99
|
+
err = "Failed during creation of volume group"
|
100
|
+
puts "#{err}: #{data}"
|
101
|
+
raise Exception.new(err)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
#exec_string = "lvcreate -n lv-#{name} -L#{size_in_mb.to_s}M vg-#{name}"
|
105
|
+
exec_string = "lvcreate -n lv-#{name} -l100%FREE vg-#{name}"
|
106
|
+
puts "execute #{exec_string}"
|
107
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
108
|
+
if stream == :stderr && !data.blank?
|
109
|
+
err = "Failed during creation of logical volume"
|
110
|
+
puts "#{err}: #{data}"
|
111
|
+
raise Exception.new(err)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
exec_string = "mkfs -t ext3 /dev/vg-#{name}/lv-#{name}"
|
115
|
+
puts "execute #{exec_string}"
|
116
|
+
@ssh_session.exec! exec_string #do |ch, stream, data|
|
117
|
+
#if stream == :stderr && !data.blank?
|
118
|
+
#err = "Failed during creation of file-system"
|
119
|
+
#puts "#{err}: #{data}"
|
120
|
+
#raise Exception.new(err)
|
121
|
+
#end
|
122
|
+
#end
|
123
|
+
if !SshApi.file_exists?(@ssh_session,"/dev/vg-#{name}/lv-#{name}")
|
124
|
+
err = "Missing file: /dev/vg-#{name}/lv-#{name}"
|
125
|
+
raise Exception.new(err)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
exec_string = "/sbin/vgchange -a y vg-#{name}"
|
129
|
+
puts "vg_exists == true; execute #{exec_string}"
|
130
|
+
@ssh_session.exec! exec_string do |ch, stream, data| #TODO: the right size instead L2G!
|
131
|
+
if stream == :stderr && !data.blank?
|
132
|
+
err = "Failed during re-activation of volume group"
|
133
|
+
puts "#{err}: #{data}"
|
134
|
+
raise Exception.new(err)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def test_storage_encryption(password, mount_point, path)
|
141
|
+
raise Exception.new("not yet implemented")
|
142
|
+
end
|
143
|
+
|
144
|
+
def undo_encryption(name, path)
|
145
|
+
exec_string = "umount #{path}"
|
146
|
+
puts "going to execute #{exec_string}"
|
147
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
148
|
+
puts "returns #{data}"
|
149
|
+
end
|
150
|
+
exec_string = "lvremove --verbose vg-#{name} -f" #[with confirmation?]
|
151
|
+
puts "going to execute #{exec_string}"
|
152
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
153
|
+
puts "returns #{data}"
|
154
|
+
end
|
155
|
+
exec_string = "vgremove vg-#{name}"
|
156
|
+
puts "going to execute #{exec_string}"
|
157
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
158
|
+
puts "returns #{data}"
|
159
|
+
end
|
160
|
+
exec_string = "pvremove /dev/mapper/dm-#{name}"
|
161
|
+
puts "going to execute #{exec_string}"
|
162
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
163
|
+
puts "returns #{data}"
|
164
|
+
end
|
165
|
+
exec_string = "cryptsetup remove dm-#{name}"
|
166
|
+
puts "going to execute #{exec_string}"
|
167
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
168
|
+
puts "returns #{data}"
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/ssh'
|
3
|
+
|
4
|
+
class RemoteCommandHandler
|
5
|
+
def initialize
|
6
|
+
@crypto = DmCryptHelper.new #TODO: instantiate helpers for different tools
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.file_exists?(ssh_session, path)
|
10
|
+
result = true
|
11
|
+
ssh_session.exec!("ls #{path}") do |ch, stream, data|
|
12
|
+
if stream == :stderr
|
13
|
+
result = false
|
14
|
+
end
|
15
|
+
end
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
def connect(ip, keyfile)
|
20
|
+
@ssh_session = Net::SSH.start(ip, 'root', :keys => [keyfile])
|
21
|
+
@crypto.set_ssh(@ssh_session)
|
22
|
+
end
|
23
|
+
|
24
|
+
def disconnect
|
25
|
+
@ssh_session.close
|
26
|
+
end
|
27
|
+
|
28
|
+
def install(software_package)
|
29
|
+
@crypto.install()
|
30
|
+
end
|
31
|
+
|
32
|
+
def tools_installed?(software_package)
|
33
|
+
@crypto.tools_installed?
|
34
|
+
end
|
35
|
+
|
36
|
+
def encrypt_storage(name, password, device, path)
|
37
|
+
@crypto.encrypt_storage(name, password, device, path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def storage_encrypted?(password, device, path)
|
41
|
+
drive_mounted?(path) #TODO: must at least also check the name
|
42
|
+
end
|
43
|
+
|
44
|
+
# Checks if the drive on path is mounted
|
45
|
+
def drive_mounted?(path)
|
46
|
+
#check if drive mounted
|
47
|
+
drive_found = false
|
48
|
+
@ssh_session.exec! "mount" do |ch, stream, data|
|
49
|
+
if stream == :stdout
|
50
|
+
puts "mount command produces the following data: #{data}\n---------------"
|
51
|
+
if data.include?("on #{path} type")
|
52
|
+
drive_found = true
|
53
|
+
else
|
54
|
+
puts "not mounted: #{data}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if drive_found
|
59
|
+
return SshApi.file_exists?(@ssh_session, path)
|
60
|
+
else
|
61
|
+
puts "not mounted (since #{path} non-existing)"
|
62
|
+
false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Checks if the drive on path is mounted with the specific device
|
67
|
+
def drive_mounted_as?(device, path)
|
68
|
+
#check if drive mounted
|
69
|
+
drive_mounted = false
|
70
|
+
@ssh_session.exec! "mount" do |ch, stream, data|
|
71
|
+
if stream == :stdout
|
72
|
+
if data.include?("#{device} on #{path} type")
|
73
|
+
drive_mounted = true
|
74
|
+
else
|
75
|
+
puts "not mounted: #{data}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
drive_mounted
|
80
|
+
end
|
81
|
+
|
82
|
+
def activate_encrypted_volume(name, path)
|
83
|
+
drive_mounted = drive_mounted?(path)
|
84
|
+
puts "drive #{path} mounted? #{drive_mounted}"
|
85
|
+
if !drive_mounted
|
86
|
+
@ssh_session.exec! "mkdir #{path}"
|
87
|
+
exec_string = "mount /dev/vg-#{name}/lv-#{name} #{path}"
|
88
|
+
puts "drive not mounted; execute: #{exec_string}"
|
89
|
+
@ssh_session.exec! "mount /dev/vg-#{name}/lv-#{name} #{path}" do |ch, stream, data|
|
90
|
+
if stream == :stderr && !data.blank?
|
91
|
+
err = "Failed during mounting encrypted device"
|
92
|
+
puts "#{err}: #{data}"
|
93
|
+
puts "mount /dev/vg-#{name}/lv-#{name} #{path}"
|
94
|
+
raise Exception.new(err)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def undo_encryption(name, path)
|
101
|
+
@crypto.undo_encryption(name, path)
|
102
|
+
end
|
103
|
+
|
104
|
+
def umount(path)
|
105
|
+
exec_string = "umount #{path}"
|
106
|
+
puts "going to execute #{exec_string}"
|
107
|
+
@ssh_session.exec! exec_string do |ch, stream, data|
|
108
|
+
puts "ssh_api.umount: returns #{data}"
|
109
|
+
end
|
110
|
+
!drive_mounted?(path)
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# Implements a little state-machine.
|
2
|
+
# Usage: for every state you need, extend this class.
|
3
|
+
# The method enter() must be implemented for every state you code and
|
4
|
+
# return another state.
|
5
|
+
class ScriptExecutionState
|
6
|
+
# context information for the state (hash)
|
7
|
+
attr_reader :context
|
8
|
+
|
9
|
+
def initialize(context)
|
10
|
+
@context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
# Start the state machine using this state as initial state.
|
14
|
+
def start_state_machine
|
15
|
+
@current_state = self
|
16
|
+
puts "start state machine with #{@current_state.inspect}"
|
17
|
+
while !@current_state.done? && !@current_state.failed?
|
18
|
+
begin
|
19
|
+
@current_state = @current_state.enter()
|
20
|
+
rescue Exception => e
|
21
|
+
@current_state = FailedState.new(@context, e.to_s, @current_state)
|
22
|
+
puts "Exception: #{e}"
|
23
|
+
puts "#{e.backtrace.join("\n")}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@current_state
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the state that is reached after execution.
|
30
|
+
def end_state
|
31
|
+
@current_state
|
32
|
+
end
|
33
|
+
|
34
|
+
# To be implemented. Executes the code for this state.
|
35
|
+
def enter
|
36
|
+
raise Exception.new("TaskExecutionState is abstract")
|
37
|
+
end
|
38
|
+
|
39
|
+
# To be implemented. Indicates if the final state is reached.
|
40
|
+
def done?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
# To be implemented. Indicates if the final state is a failure state.
|
45
|
+
def failed?
|
46
|
+
false
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
s = self.class.to_s
|
51
|
+
s.sub(/.*\:\:/,'')
|
52
|
+
end
|
53
|
+
|
54
|
+
class FailedState < ScriptExecutionState
|
55
|
+
attr_accessor :failure_reason, :from_state
|
56
|
+
def initialize(context, failure_reason, from_state)
|
57
|
+
super(context)
|
58
|
+
@failure_reason = failure_reason
|
59
|
+
@from_state = from_state
|
60
|
+
end
|
61
|
+
def done?
|
62
|
+
true
|
63
|
+
end
|
64
|
+
def failed?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,182 @@
|
|
1
|
+
require "help/script_execution_state"
|
2
|
+
require "scripts/ec2/ec2_script"
|
3
|
+
|
4
|
+
# Encrypts an EC2 Storage
|
5
|
+
class DmEncrypt < Ec2Script
|
6
|
+
def initialize(input_params)
|
7
|
+
super(input_params)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Input parameters
|
11
|
+
# aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
|
12
|
+
# aws_secret_key => the Amazon AWS Secret Key
|
13
|
+
# ip_address => IP Address of the machine to connect to
|
14
|
+
# ssh_key_file => Path of the keyfile used to connect to the machine
|
15
|
+
# device => Path of the device to encrypt
|
16
|
+
# device_name => Name of the Device to encrypt
|
17
|
+
# storage_path => Path on which the encrypted device is mounted
|
18
|
+
# remote_command_handler => object that allows to connect via ssh and execute commands
|
19
|
+
# ec2_api_handler => object that allows to access the EC2 API
|
20
|
+
# password => password used for encryption
|
21
|
+
#
|
22
|
+
def initialize(input_params)
|
23
|
+
super(input_params)
|
24
|
+
@result = {:done => false}
|
25
|
+
end
|
26
|
+
|
27
|
+
# Executes the script.
|
28
|
+
def start_script
|
29
|
+
begin
|
30
|
+
current_state = DmEncryptState.load_state(@input_params)
|
31
|
+
end_state = current_state.start_state_machine()
|
32
|
+
if end_state.failed?
|
33
|
+
@result[:failed] = true
|
34
|
+
@result[:failure_reason] = current_state.end_state.failure_reason
|
35
|
+
@result[:end_state] = current_state.end_state
|
36
|
+
else
|
37
|
+
@result[:failed] = false
|
38
|
+
end
|
39
|
+
rescue Exception => e
|
40
|
+
puts "exception during encryption: #{e}"
|
41
|
+
puts e.backtrace.join("\n")
|
42
|
+
err = e.to_s
|
43
|
+
err += " (in #{current_state.end_state.to_s})" unless current_state.blank?
|
44
|
+
@result[:failed] = true
|
45
|
+
@result[:failure_reason] = err
|
46
|
+
@result[:end_state] = current_state.end_state unless current_state.blank?
|
47
|
+
ensure
|
48
|
+
begin
|
49
|
+
@input_params[:remote_command_handler].disconnect
|
50
|
+
rescue Exception => e2
|
51
|
+
puts "rescue disconnect: #{e2}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
@result[:done] = true
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns a hash with the following information:
|
60
|
+
# :done => if execution is done
|
61
|
+
#
|
62
|
+
def get_execution_result
|
63
|
+
@result
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Here begins the state machine implementation
|
69
|
+
|
70
|
+
class DmEncryptState < ScriptExecutionState
|
71
|
+
|
72
|
+
def self.load_state(context)
|
73
|
+
InitialState.new(context)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# Starting state. Tries to connect via ssh.
|
78
|
+
class InitialState < DmEncryptState
|
79
|
+
def enter
|
80
|
+
connect()
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def connect()
|
86
|
+
puts "InitialState.connect"
|
87
|
+
@context[:remote_command_handler].connect(@context[:ip_address], @context[:ssh_key_file])
|
88
|
+
ConnectedState.new(@context)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Connected via SSH. Tries to install dm-encrypt.#TODO: depends on OS
|
93
|
+
class ConnectedState < DmEncryptState
|
94
|
+
def enter
|
95
|
+
install_tools()
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def install_tools
|
100
|
+
puts "ConnectedState.install_tools"
|
101
|
+
if !tools_installed?
|
102
|
+
@context[:remote_command_handler].install("dm-crypt") #TODO: constant somewhere? admin parameter?
|
103
|
+
end
|
104
|
+
if tools_installed?
|
105
|
+
puts "system says that tools are installed"
|
106
|
+
ToolInstalledState.new(@context)
|
107
|
+
else
|
108
|
+
FailedState.new(@context, "Installation of Tools failed", ConnectedState.new(@context))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def tools_installed?
|
113
|
+
if @context[:remote_command_handler].tools_installed?("dm-crypt")
|
114
|
+
true
|
115
|
+
else
|
116
|
+
false
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Connected and Tools installed. Start encryption.
|
122
|
+
class ToolInstalledState < DmEncryptState
|
123
|
+
def enter
|
124
|
+
create_encrypted_volume()
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
def create_encrypted_volume
|
129
|
+
puts "ToolInstalledState.create_encrypted_volume"
|
130
|
+
#first check if the drive is not yet mounted by someone else
|
131
|
+
if @context[:remote_command_handler].drive_mounted?(@context[:storage_path])
|
132
|
+
if !@context[:remote_command_handler].drive_mounted_as?(calc_device_name(), @context[:storage_path])
|
133
|
+
raise Exception.new("Drive is already used by another device")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
#
|
137
|
+
@context[:remote_command_handler].encrypt_storage(@context[:device_name],
|
138
|
+
@context[:password], @context[:device], @context[:storage_path])
|
139
|
+
VolumeCreatedState.new(@context)
|
140
|
+
end
|
141
|
+
|
142
|
+
def calc_device_name
|
143
|
+
dev = @context[:device_name].gsub(/[-]/,"--")
|
144
|
+
"/dev/mapper/vg--#{dev}-lv--#{dev}"
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
class VolumeCreatedState < DmEncryptState
|
150
|
+
def enter
|
151
|
+
mount_and_activate()
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
def mount_and_activate
|
156
|
+
puts "VolumeCreatedState.mount_and_activate"
|
157
|
+
@context[:remote_command_handler].activate_encrypted_volume(@context[:device_name],@context[:storage_path])
|
158
|
+
MountedAndActivatedState.new(@context)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class MountedAndActivatedState < DmEncryptState
|
163
|
+
def enter
|
164
|
+
cleanup()
|
165
|
+
end
|
166
|
+
|
167
|
+
private
|
168
|
+
def cleanup()
|
169
|
+
puts "MountedAndActivatedState.cleanup"
|
170
|
+
@context[:remote_command_handler].disconnect()
|
171
|
+
DoneState.new(@context)
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
class DoneState < DmEncryptState
|
177
|
+
def done?
|
178
|
+
true
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Base class for any script on EC2.
|
2
|
+
class Ec2Script
|
3
|
+
# Input parameters
|
4
|
+
# aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
|
5
|
+
# aws_secret_key => the Amazon AWS Secret Key
|
6
|
+
#
|
7
|
+
def initialize(input_params)
|
8
|
+
@input_params = input_params
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
|
metadata
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: CloudyScripts
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthias Jung
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-11 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: amazon-ec2
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: net-ssh
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: Scripts to facilitate programming for infrastructure clouds.
|
36
|
+
email: matthias.jung@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README
|
43
|
+
- LICENSE
|
44
|
+
files:
|
45
|
+
- LICENSE
|
46
|
+
- README
|
47
|
+
- Rakefile
|
48
|
+
- lib/cloudyscripts.rb
|
49
|
+
- lib/help/dm_crypt_helper.rb
|
50
|
+
- lib/help/remote_command_handler.rb
|
51
|
+
- lib/help/script_execution_state.rb
|
52
|
+
- lib/scripts/ec2/dm_encrypt.rb
|
53
|
+
- lib/scripts/ec2/ec2_script.rb
|
54
|
+
has_rdoc: true
|
55
|
+
homepage: http://elastic-security.com
|
56
|
+
licenses: []
|
57
|
+
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: "0"
|
68
|
+
version:
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
requirements: []
|
76
|
+
|
77
|
+
rubyforge_project: cloudyscripts
|
78
|
+
rubygems_version: 1.3.5
|
79
|
+
signing_key:
|
80
|
+
specification_version: 3
|
81
|
+
summary: Scripts to facilitate programming for infrastructure clouds.
|
82
|
+
test_files: []
|
83
|
+
|