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 CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2011 SecludIT (http://secludit.com)
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
- # Matthias Jung
25
- # matthias.jung@gmail.com
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.52' #<number cloud-stacks supported>.<number cloud-scripts>.<counting releases>
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
- while timeout > 0 && !done
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
@@ -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
- @context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by Cloudy_Scripts - copy_snapshot")
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
- post_mesage("Lunching an Helper instance in source Region...")
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
- @context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by CloudyScripts - copy_mswindows_ami")
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
- @context[:new_snapshot_id] = create_snapshot(@context[:target_volume_id], "Created by Cloudy_Scripts - copy_snapshot")
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
@@ -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
  # Checks for all security groups if sensible ports are opened for the wide
10
10
  # public.
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: 95
4
+ hash: 91
5
5
  prerelease: false
6
6
  segments:
7
7
  - 2
8
8
  - 14
9
- - 52
10
- version: 2.14.52
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-02-23 00:00:00 +00:00
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