CloudyScripts 2.14.52 → 2.14.54
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +1 -1
- data/README.rdoc +7 -3
- data/Rakefile +1 -1
- data/lib/help/remote_command_handler.rb +2 -1
- data/lib/help/state_transition_helper.rb +41 -1
- data/lib/scripts/ec2/check_cloudyscripts.rb +142 -0
- data/lib/scripts/ec2/copy_ami.rb +5 -1
- data/lib/scripts/ec2/copy_mswindows_ami.rb +3 -0
- data/lib/scripts/ec2/copy_mswindows_snapshot.rb +8 -4
- data/lib/scripts/ec2/copy_snapshot.rb +5 -1
- data/lib/scripts/ec2/vpc_critical_ports_audit.rb +1 -1
- metadata +5 -4
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2010-
|
1
|
+
Copyright (c) 2010-2012 SecludIT (http://secludit.com)
|
2
2
|
|
3
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
4
|
|
data/README.rdoc
CHANGED
@@ -19,9 +19,13 @@
|
|
19
19
|
# =Scripts
|
20
20
|
# Here are the scripts implemented so far:
|
21
21
|
# * #DmEncrypt (encrypt Amazon EBS Storage using dm-encrypt)
|
22
|
+
# * #CopyAmi (copy Amazon AMI between Regions)
|
23
|
+
# * #CopySnapshot (copy Amazon Snapshot between Regions)
|
24
|
+
# * #Ami2EbsConversion (create an EBS-Backed Amazon AMI from an Instance-Store Amazon AMI)
|
25
|
+
# * #CriticalPortsAudit (check Amazon SecurityGroups for publicly opened critical ports)
|
26
|
+
# * #OpenPortChecker (check Amazon SecurityGroups and Instances to found opened port without service running behind)
|
22
27
|
#
|
23
28
|
# =Questions and Suggestions
|
24
|
-
#
|
25
|
-
#
|
29
|
+
# Frederic Donnat
|
30
|
+
# frederic.donnat@secludit.com
|
26
31
|
# http://elastic-security.com
|
27
|
-
|
data/Rakefile
CHANGED
@@ -12,7 +12,7 @@ require 'rake/testtask'
|
|
12
12
|
|
13
13
|
spec = Gem::Specification.new do |s|
|
14
14
|
s.name = 'CloudyScripts'
|
15
|
-
s.version = '2.14.
|
15
|
+
s.version = '2.14.54' #<number cloud-stacks supported>.<number cloud-scripts>.<counting releases>
|
16
16
|
s.has_rdoc = true
|
17
17
|
s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
|
18
18
|
s.summary = 'Scripts to facilitate programming for infrastructure clouds.'
|
@@ -43,9 +43,10 @@ class RemoteCommandHandler
|
|
43
43
|
# * ip: ip address of the machine to connect to
|
44
44
|
# * user: user name
|
45
45
|
# * key_data: key_data to be used for authentication
|
46
|
+
# NB: set paranoid to false in order to avoid server key verification, thus avoiding probleme when IP are reused
|
46
47
|
def connect(ip, user, key_data, timeout = 30)
|
47
48
|
@use_sudo = false
|
48
|
-
@ssh_session = Net::SSH.start(ip, user, :key_data => [key_data], :timeout => timeout, :verbose => :warn)
|
49
|
+
@ssh_session = Net::SSH.start(ip, user, :key_data => [key_data], :timeout => timeout, :paranoid => false, :verbose => :warn)
|
49
50
|
@use_sudo = true unless user.strip == 'root'
|
50
51
|
end
|
51
52
|
|
@@ -178,7 +178,7 @@ module StateTransitionHelper
|
|
178
178
|
@logger.debug "start instance #{instance_id}"
|
179
179
|
ec2_handler().start_instances(:instance_id => instance_id)
|
180
180
|
end
|
181
|
-
|
181
|
+
while timeout > 1 && !done
|
182
182
|
res = ec2_handler().describe_instances(:instance_id => instance_id)
|
183
183
|
state = res['reservationSet']['item'][0]['instancesSet']['item'][0]['instanceState']
|
184
184
|
@logger.debug "instance in state '#{state['name']}' (#{state['code']})"
|
@@ -208,6 +208,36 @@ module StateTransitionHelper
|
|
208
208
|
post_message("#{msg}")
|
209
209
|
return instance_id, dns_name
|
210
210
|
end
|
211
|
+
|
212
|
+
def describe_instance(instance_id)
|
213
|
+
res = ec2_handler.describe_instances(:instance_id => instance_id)
|
214
|
+
state = res['reservationSet']['item'][0]['instancesSet']['item'][0]['instanceState']
|
215
|
+
@logger.info "instance is in state #{state['name']} (#{state['code']})"
|
216
|
+
dns_name = ""
|
217
|
+
availability_zone = ""
|
218
|
+
kernel_id = ""
|
219
|
+
ramdisk_id = ""
|
220
|
+
architecture = ""
|
221
|
+
root_device_name = ""
|
222
|
+
if state['code'].to_i == 16
|
223
|
+
started = true
|
224
|
+
post_message("instance is up and running")
|
225
|
+
dns_name = res['reservationSet']['item'][0]['instancesSet']['item'][0]['dnsName']
|
226
|
+
availability_zone = res['reservationSet']['item'][0]['instancesSet']['item'][0]['placement']['availabilityZone']
|
227
|
+
kernel_id = res['reservationSet']['item'][0]['instancesSet']['item'][0]['kernelId']
|
228
|
+
ramdisk_id = res['reservationSet']['item'][0]['instancesSet']['item'][0]['ramdiskId']
|
229
|
+
architecture = res['reservationSet']['item'][0]['instancesSet']['item'][0]['architecture']
|
230
|
+
root_device_name = res['reservationSet']['item'][0]['instancesSet']['item'][0]['rootDeviceName']
|
231
|
+
else
|
232
|
+
post_message("instance is not up and running: code #{state['code'].to_i}")
|
233
|
+
availability_zone = res['reservationSet']['item'][0]['instancesSet']['item'][0]['placement']['availabilityZone']
|
234
|
+
kernel_id = res['reservationSet']['item'][0]['instancesSet']['item'][0]['kernelId']
|
235
|
+
ramdisk_id = res['reservationSet']['item'][0]['instancesSet']['item'][0]['ramdiskId']
|
236
|
+
architecture = res['reservationSet']['item'][0]['instancesSet']['item'][0]['architecture']
|
237
|
+
root_device_name = res['reservationSet']['item'][0]['instancesSet']['item'][0]['rootDeviceName']
|
238
|
+
end
|
239
|
+
return instance_id, dns_name, availability_zone, kernel_id, ramdisk_id, architecture, root_device_name
|
240
|
+
end
|
211
241
|
|
212
242
|
# Shuts down an instance.
|
213
243
|
# Input Parameters:
|
@@ -1175,6 +1205,16 @@ module StateTransitionHelper
|
|
1175
1205
|
return region
|
1176
1206
|
end
|
1177
1207
|
|
1208
|
+
# Check if string is not more than 255 character and contains wide char
|
1209
|
+
def check_string_alnum(str)
|
1210
|
+
if str.match(/^[0-9a-z\-\_\ ]{1,255}$/i)
|
1211
|
+
return 0
|
1212
|
+
else
|
1213
|
+
return 1
|
1214
|
+
end
|
1215
|
+
return 1
|
1216
|
+
end
|
1217
|
+
|
1178
1218
|
#setting/retrieving handlers
|
1179
1219
|
|
1180
1220
|
def remote_handler()
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require "help/script_execution_state"
|
2
|
+
require "scripts/ec2/ec2_script"
|
3
|
+
require "help/remote_command_handler"
|
4
|
+
require "help/dm_crypt_helper"
|
5
|
+
require "help/ec2_helper"
|
6
|
+
require "AWS"
|
7
|
+
|
8
|
+
# Goal: check internal piece of CloudyScripts without launching the full scripts
|
9
|
+
#
|
10
|
+
|
11
|
+
class CheckCloudyScripts < Ec2Script
|
12
|
+
|
13
|
+
def initialize(input_params)
|
14
|
+
super(input_params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def check_input_parameters()
|
18
|
+
if @input_params[:ami_id] == nil && !(@input_params[:ami_id] =~ /^ami-.*$/)
|
19
|
+
raise Exception.new("Invalid AMI ID specified: #{@input_params[:ami_id]}")
|
20
|
+
end
|
21
|
+
ec2_helper = Ec2Helper.new(@input_params[:ec2_api_handler])
|
22
|
+
if ec2_helper.ami_prop(@input_params[:ami_id], 'rootDeviceType') != "ebs"
|
23
|
+
raise Exception.new("must be an EBS type image")
|
24
|
+
end
|
25
|
+
local_ec2_helper = ec2_helper
|
26
|
+
if !local_ec2_helper.check_open_port('default', 22)
|
27
|
+
raise Exception.new("Port 22 must be opened for security group 'default' to connect via SSH in source-region")
|
28
|
+
end
|
29
|
+
remote_ec2_helper = Ec2Helper.new(@input_params[:target_ec2_handler])
|
30
|
+
if !remote_ec2_helper.check_open_port('default', 22)
|
31
|
+
raise Exception.new("Port 22 must be opened for security group 'default' to connect via SSH in target-region")
|
32
|
+
end
|
33
|
+
if @input_params[:root_device_name] == nil
|
34
|
+
@input_params[:root_device_name] = "/dev/sda1"
|
35
|
+
end
|
36
|
+
if @input_params[:temp_device_name] == nil
|
37
|
+
@input_params[:temp_device_name] = "/dev/sdj"
|
38
|
+
end
|
39
|
+
if @input_params[:source_ssh_username] == nil
|
40
|
+
@input_params[:source_ssh_username] = "root"
|
41
|
+
end
|
42
|
+
if @input_params[:target_ssh_username] == nil
|
43
|
+
@input_params[:target_ssh_username] = "root"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Load the initial state for the script.
|
48
|
+
# Abstract method to be implemented by extending classes.
|
49
|
+
def load_initial_state()
|
50
|
+
CheckCloudyScriptsState.load_state(@input_params)
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Here begins the state machine implementation
|
56
|
+
class CheckCloudyScriptsState < ScriptExecutionState
|
57
|
+
|
58
|
+
def self.load_state(context)
|
59
|
+
InitialState.new(context)
|
60
|
+
end
|
61
|
+
|
62
|
+
def local_region
|
63
|
+
self.ec2_handler=(@context[:ec2_api_handler])
|
64
|
+
end
|
65
|
+
|
66
|
+
def remote_region
|
67
|
+
self.ec2_handler=(@context[:target_ec2_handler])
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Initial state: start up AMI in source region
|
72
|
+
class InitialState < CheckCloudyScriptsState
|
73
|
+
def enter()
|
74
|
+
post_message("INFO: Entering InitialState...")
|
75
|
+
|
76
|
+
#@context[:source_instance_id], @context[:source_dns_name], @context[:source_availability_zone],
|
77
|
+
# @context[:kernel_id], @context[:ramdisk_id], @context[:architecture], @context[:root_device_name] =
|
78
|
+
# launch_instance(@context[:ami_id], @context[:source_key_name], "default")
|
79
|
+
start_instance(@context[:source_instance_id])
|
80
|
+
res = describe_instance(@context[:source_instance_id])
|
81
|
+
puts "DEBUG: instance: #{res.inspect}"
|
82
|
+
#@context[:source_instance_id] = "i-0a663643"
|
83
|
+
@context[:source_dns_name] = res[1]
|
84
|
+
@context[:source_availability_zone] = res[2]
|
85
|
+
@context[:kernel_id] = res[3]
|
86
|
+
@context[:ramdisk_id] = res[4]
|
87
|
+
@context[:architecture] = res[5]
|
88
|
+
@context[:root_device_name] = res[6]
|
89
|
+
|
90
|
+
ec2_helper = Ec2Helper.new(@context[:ec2_api_handler])
|
91
|
+
puts "DEBUG: get_attached returns: #{ec2_helper.get_attached_volumes(@context[:source_instance_id]).inspect}"
|
92
|
+
@context[:ebs_volume_id] = ec2_helper.get_attached_volumes(@context[:source_instance_id])[0]['volumeId']#TODO: what when more root devices?
|
93
|
+
|
94
|
+
CSTestingState.new(@context)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Snapshot is created from the AMI. Create a volume from the snapshot, attach and mount the volume as second device.
|
99
|
+
class CSTestingState < CheckCloudyScriptsState
|
100
|
+
def enter()
|
101
|
+
post_message("INFO: Entering CSTestingState...")
|
102
|
+
|
103
|
+
#@context[:source_volume_id] = create_volume_from_snapshot(@context[:snapshot_id],
|
104
|
+
# @context[:source_availability_zone])
|
105
|
+
@context[:source_volume_id] = "vol-6eb34b06"
|
106
|
+
|
107
|
+
device = @context[:temp_device_name]
|
108
|
+
mount_point = "/mnt/tmp_#{@context[:source_volume_id]}"
|
109
|
+
attach_volume(@context[:source_volume_id], @context[:source_instance_id], device)
|
110
|
+
connect(@context[:source_dns_name], @context[:source_ssh_username], nil, @context[:source_ssh_keydata])
|
111
|
+
# detect if there is a shift for device mapping (between AWS and the operating system of the system)
|
112
|
+
root_device_name = get_root_device_name()
|
113
|
+
# detect letters
|
114
|
+
aws_root_device = @context[:root_device_name]
|
115
|
+
aws_letter = aws_root_device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
|
116
|
+
os_letter = root_device_name.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
|
117
|
+
aws_device_letter = device.split('/')[2].gsub('sd', '').gsub('xvd', '').gsub(/[0-9]/, '')
|
118
|
+
puts "DEBUG: AWS info: #{aws_root_device}, #{aws_letter}"
|
119
|
+
puts "DEBUG: OS info: #{root_device_name}, #{os_letter}"
|
120
|
+
if !aws_letter.eql?(os_letter)
|
121
|
+
post_message("Detected specific kernel with shift between AWS and Kernel OS for device naming")
|
122
|
+
puts "Detected specific kernel with shift between AWS and Kernel OS for device naming (#{aws_root_device} vs #{root_device_name})"
|
123
|
+
end
|
124
|
+
while !aws_letter.eql?(os_letter)
|
125
|
+
aws_letter.succ!
|
126
|
+
aws_device_letter.succ!
|
127
|
+
end
|
128
|
+
device = "/dev/sd#{aws_device_letter}"
|
129
|
+
post_message("Using AWS name '#{@context[:temp_device_name]}' and OS name '#{device}'")
|
130
|
+
puts "Using AWS name '#{@context[:temp_device_name]}' and OS name '#{device}'"
|
131
|
+
mount_fs(mount_point, device)
|
132
|
+
# get root partition label and filesystem type
|
133
|
+
#@context[:label] = get_root_partition_label()
|
134
|
+
#@context[:fs_type] = get_root_partition_fs_type()
|
135
|
+
@context[:fs_type], @context[:label] = get_root_partition_fs_type_and_label()
|
136
|
+
disconnect()
|
137
|
+
|
138
|
+
Done.new()
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|
data/lib/scripts/ec2/copy_ami.rb
CHANGED
@@ -65,6 +65,9 @@ class CopyAmi < Ec2Script
|
|
65
65
|
if @input_params[:target_ssh_username] == nil
|
66
66
|
@input_params[:target_ssh_username] = "root"
|
67
67
|
end
|
68
|
+
if @input_params[:description] == nil || check_string_alnum(@input_params[:description])
|
69
|
+
@input_params[:description] = "Created by Cloudy_Scripts - copy_ami"
|
70
|
+
end
|
68
71
|
end
|
69
72
|
|
70
73
|
# Load the initial state for the script.
|
@@ -230,7 +233,8 @@ class CopyAmi < Ec2Script
|
|
230
233
|
class DataCopiedState < CopyAmiState
|
231
234
|
def enter()
|
232
235
|
remote_region()
|
233
|
-
|
236
|
+
#@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by Cloudy_Scripts - copy_ami")
|
237
|
+
@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], @context[:description])
|
234
238
|
TargetSnapshotCreatedState.new(@context)
|
235
239
|
end
|
236
240
|
end
|
@@ -102,6 +102,9 @@ class CopyMsWindowsAmi < Ec2Script
|
|
102
102
|
if @input_params[:fs_type] == nil
|
103
103
|
@input_params[:fs_type] = "ext3"
|
104
104
|
end
|
105
|
+
if @input_params[:description] == nil || check_string_alnum(@input_params[:description])
|
106
|
+
@input_params[:description] = "Created by Cloudy_Scripts - copy_mswindows_ami"
|
107
|
+
end
|
105
108
|
end
|
106
109
|
|
107
110
|
# Load the initial state for the script.
|
@@ -4,7 +4,7 @@ require "help/remote_command_handler"
|
|
4
4
|
require "help/dm_crypt_helper"
|
5
5
|
require "help/ec2_helper"
|
6
6
|
require "AWS"
|
7
|
-
require 'pp'
|
7
|
+
#require 'pp'
|
8
8
|
|
9
9
|
# Copy a given snapshot to another region
|
10
10
|
# * start up instance in source-region, create a snapshot from the mounted EBS
|
@@ -83,6 +83,9 @@ class CopyMsWindowsSnapshot < Ec2Script
|
|
83
83
|
if @input_params[:fs_type] == nil
|
84
84
|
@input_params[:fs_type] = "ext3"
|
85
85
|
end
|
86
|
+
if @input_params[:description] == nil || check_string_alnum(@input_params[:description])
|
87
|
+
@input_params[:description] = "Created by Cloudy_Scripts - copy_mswindows_snapshot"
|
88
|
+
end
|
86
89
|
end
|
87
90
|
|
88
91
|
# Load the initial state for the script.
|
@@ -122,7 +125,7 @@ class CopyMsWindowsSnapshot < Ec2Script
|
|
122
125
|
local_region()
|
123
126
|
post_message("Retrieving Snapshot parammeters (volume size)")
|
124
127
|
@context[:volume_size] = @local_ec2_helper.snapshot_prop(@context[:snapshot_id], :volumeSize).to_i
|
125
|
-
|
128
|
+
|
126
129
|
InitialStateDone.new(@context)
|
127
130
|
end
|
128
131
|
end
|
@@ -131,7 +134,7 @@ class CopyMsWindowsSnapshot < Ec2Script
|
|
131
134
|
class InitialStateDone < CopyMsWindowsSnapshotState
|
132
135
|
def enter()
|
133
136
|
local_region()
|
134
|
-
|
137
|
+
post_message("Lunching an Helper instance in source Region...")
|
135
138
|
result = launch_instance(@context[:source_ami_id], @context[:source_key_name], @context[:source_security_groups])
|
136
139
|
@context[:source_instance_id] = result.first
|
137
140
|
@context[:source_dns_name] = result[1]
|
@@ -348,7 +351,8 @@ class CopyMsWindowsSnapshot < Ec2Script
|
|
348
351
|
def enter()
|
349
352
|
remote_region()
|
350
353
|
detach_volume(@context[:target_volume_id], @context[:target_instance_id])
|
351
|
-
|
354
|
+
#@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by CloudyScripts - copy_mswindows_ami")
|
355
|
+
@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], @context[:description])
|
352
356
|
@context[:result][:snapshot_id] = @context[:new_snapshot_id]
|
353
357
|
|
354
358
|
TargetSnapshotCreatedState.new(@context)
|
@@ -49,6 +49,9 @@ class CopySnapshot< Ec2Script
|
|
49
49
|
if @input_params[:target_ssh_username] == nil
|
50
50
|
@input_params[:target_ssh_username] = "root"
|
51
51
|
end
|
52
|
+
if @input_params[:description] == nil || check_string_alnum(@input_params[:description])
|
53
|
+
@input_params[:description] = "Created by Cloudy_Scripts - copy_snapshot"
|
54
|
+
end
|
52
55
|
end
|
53
56
|
|
54
57
|
# Load the initial state for the script.
|
@@ -191,7 +194,8 @@ class CopySnapshot< Ec2Script
|
|
191
194
|
class DataCopiedState < CopySnapshotState
|
192
195
|
def enter()
|
193
196
|
remote_region()
|
194
|
-
|
197
|
+
#@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by Cloudy_Scripts - copy_snapshot")
|
198
|
+
@context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], @context[:description])
|
195
199
|
@context[:result][:snapshot_id] = @context[:new_snapshot_id]
|
196
200
|
SnapshotCreatedState.new(@context)
|
197
201
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: CloudyScripts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 91
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 2
|
8
8
|
- 14
|
9
|
-
-
|
10
|
-
version: 2.14.
|
9
|
+
- 54
|
10
|
+
version: 2.14.54
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matthias Jung
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2012-
|
18
|
+
date: 2012-06-25 00:00:00 +00:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -257,6 +257,7 @@ files:
|
|
257
257
|
- lib/scripts/ec2/vpc_critical_ports_audit.rb
|
258
258
|
- lib/scripts/ec2/ami2_ebs_conversion.rb
|
259
259
|
- lib/scripts/ec2/copy_mswindows_ami.rb
|
260
|
+
- lib/scripts/ec2/check_cloudyscripts.rb
|
260
261
|
- lib/scripts/ec2/audit_via_ssh.rb
|
261
262
|
- lib/scripts/ec2/open_port_checker.rb
|
262
263
|
- lib/scripts/ec2/copy_ami.rb
|