33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
# File 'lib/ec2/amitools/bundle.rb', line 33
def self.bundle_image( image_file,
user,
arch,
image_type,
destination,
user_private_key_path,
user_cert_path,
ec2_cert_path,
prefix,
optional_args,
debug = false,
inherit = true
)
begin
raise "invalid image-type #{image_type}" unless image_type.is_a? Bundle::ImageType
digest_pipe = File::join('/tmp', "ec2-bundle-image-digest-pipe-#{$$}")
File::delete(digest_pipe) if File::exist?(digest_pipe)
unless system( "mkfifo #{digest_pipe}" )
raise "Error creating named pipe #{digest_pipe}"
end
if prefix and File::basename( image_file ) != prefix
image_file_link = File::join( destination, prefix )
begin
FileUtils.ln_s(image_file, image_file_link)
rescue Exception => e
raise "Error creating symlink to image file, #{e.message}."
end
image_file = image_file_link
end
name = prefix || File::basename( image_file )
manifest_file = File.join( destination, name + '.manifest.xml')
bundled_file_path = File::join( destination, name + '.tar.gz.enc' )
user_public_key = Crypto::certfile2pubkey( user_cert_path )
ec2_public_key = Crypto::certfile2pubkey( ec2_cert_path )
key = Format::bin2hex( Crypto::gensymkey )
iv = Format::bin2hex( Crypto::gensymkey )
tar = EC2::Platform::Current::Tar::Command.new.create.dereference.sparse
tar.owner(0).group(0)
tar.add(File::basename( image_file ), File::dirname( image_file ))
openssl = EC2::Platform::Current::Constants::Utility::OPENSSL
pipeline = EC2::Platform::Current::Pipeline.new('image-bundle-pipeline', debug)
pipeline.concat([
['tar', "#{openssl} sha1 < #{digest_pipe} & " + tar.expand],
['tee', "tee #{digest_pipe}"],
['gzip', 'gzip -9'],
['encrypt', "#{openssl} enc -e -aes-128-cbc -K #{key} -iv #{iv} > #{bundled_file_path}"]
])
digest = nil
begin
digest = pipeline.execute.split(/\s+/).last.strip
rescue EC2::Platform::Current::Pipeline::ExecutionError => e
$stderr.puts e.message
exit 1
end
parts = Bundle::split( bundled_file_path, name, destination )
bundled_size = 0
parts.each do |part|
bundled_size += File.size( File.join( destination, part ) )
end
padding = OpenSSL::PKey::RSA::PKCS1_PADDING
user_encrypted_key = user_public_key.public_encrypt( key, padding )
ec2_encrypted_key = ec2_public_key.public_encrypt( key, padding )
user_encrypted_iv = user_public_key.public_encrypt( iv, padding )
ec2_encrypted_iv = ec2_public_key.public_encrypt( iv, padding )
part_digest_list = Bundle::digest_parts( parts, destination )
patch_in_instance_meta_data(image_type, optional_args) if inherit
bdm = optional_args[:block_device_mapping]
if bdm.is_a? Hash
[ 'root', 'ami' ].each do |item|
if bdm[item].to_s.strip.empty?
$stdout.puts "Block-device-mapping has no '#{item}' entry. A launch-time default will be used."
end
end
end
$stdout.puts 'Creating bundle manifest...'
manifest = ManifestV20071010.new()
manifest.init(optional_args.merge({:name => name,
:user => user,
:image_type => image_type.to_s,
:arch => arch,
:reserved => nil,
:parts => part_digest_list,
:size => File::size( image_file ),
:bundled_size => bundled_size,
:user_encrypted_key => Format::bin2hex( user_encrypted_key ),
:ec2_encrypted_key => Format::bin2hex( ec2_encrypted_key ),
:cipher_algorithm => Crypto::SYM_ALG,
:user_encrypted_iv => Format::bin2hex( user_encrypted_iv ),
:ec2_encrypted_iv => Format::bin2hex( ec2_encrypted_iv ),
:digest => digest,
:digest_algorithm => Crypto::DIGEST_ALG,
:privkey_filename => user_private_key_path,
:kernel_id => optional_args[:kernel_id],
:ramdisk_id => optional_args[:ramdisk_id],
:product_codes => optional_args[:product_codes],
:ancestor_ami_ids => optional_args[:ancestor_ami_ids],
:block_device_mapping => optional_args[:block_device_mapping],
:bundler_name => EC2Version::PKG_NAME,
:bundler_version => EC2Version::PKG_VERSION,
:bundler_release => EC2Version::PKG_RELEASE}))
File.open( manifest_file, 'w' ) { |f| f.write( manifest.to_s ) }
$stdout.puts 'Bundle manifest is %s' % manifest_file
ensure
if bundled_file_path and File.exist?( bundled_file_path )
File.delete( bundled_file_path )
end
File::delete( digest_pipe ) if digest_pipe and File::exist?(digest_pipe)
if image_file_link and File::exist?( image_file_link )
File::delete( image_file_link )
end
end
end
|