heirloom 0.11.0.beta.1 → 0.11.0.beta.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,6 +8,7 @@
8
8
  * Updated catalog output to include s3 urls
9
9
  * Catalog output renamed Bucket Prefix to bucket_prefix
10
10
  * Catalog output renamed Region to region
11
+ * Add `rotate` command to allow for encryption key rotation
11
12
 
12
13
  ## 0.10.1 (02/28/2013):
13
14
 
data/README.md CHANGED
@@ -26,7 +26,7 @@ To get started, copy the sample below to ~/.heirloom.yml and update the specifie
26
26
 
27
27
  ```
28
28
  # default environment
29
- aws:
29
+ default:
30
30
  access_key: UPDATE_ME
31
31
  secret_key: UPDATE_ME
32
32
  metadata_region: us-west-1
@@ -9,6 +9,7 @@ require "heirloom/config"
9
9
  require "heirloom/destroyer"
10
10
  require "heirloom/directory"
11
11
  require "heirloom/downloader"
12
+ require "heirloom/exceptions"
12
13
  require "heirloom/logger"
13
14
  require "heirloom/uploader"
14
15
  require "heirloom/version"
@@ -1,16 +1,16 @@
1
- require 'heirloom/archive/lister.rb'
2
- require 'heirloom/archive/reader.rb'
1
+ require 'heirloom/archive/authorizer.rb'
3
2
  require 'heirloom/archive/builder.rb'
4
- require 'heirloom/archive/updater.rb'
5
- require 'heirloom/archive/uploader.rb'
3
+ require 'heirloom/archive/checker.rb'
4
+ require 'heirloom/archive/destroyer.rb'
6
5
  require 'heirloom/archive/downloader.rb'
6
+ require 'heirloom/archive/lister.rb'
7
+ require 'heirloom/archive/reader.rb'
7
8
  require 'heirloom/archive/setuper.rb'
8
9
  require 'heirloom/archive/teardowner.rb'
9
- require 'heirloom/archive/writer.rb'
10
- require 'heirloom/archive/authorizer.rb'
11
- require 'heirloom/archive/destroyer.rb'
10
+ require 'heirloom/archive/updater.rb'
11
+ require 'heirloom/archive/uploader.rb'
12
12
  require 'heirloom/archive/verifier.rb'
13
- require 'heirloom/archive/checker.rb'
13
+ require 'heirloom/archive/writer.rb'
14
14
 
15
15
  module Heirloom
16
16
 
@@ -79,6 +79,23 @@ module Heirloom
79
79
  reader.show.merge reader.object_acls
80
80
  end
81
81
 
82
+ def rotate(args)
83
+ temp_dir = Dir.mktmpdir
84
+ temp_file = Tempfile.new('archive.tar.gz')
85
+
86
+ unless download({ :output => temp_dir, :secret => args[:old_secret], :extract => true }.merge(args))
87
+ raise Heirloom::Exceptions::RotateFailed.new "Download failed - aborting rotation"
88
+ end
89
+ unless build({ :directory => temp_dir, :secret => args[:new_secret], :file => temp_file.path }.merge(args))
90
+ raise Heirloom::Exceptions::RotateFailed.new "Build failed - aborting rotation"
91
+ end
92
+ destroy
93
+ upload({ :file => temp_file.path, :secret => args[:new_secret] }.merge(args))
94
+ ensure
95
+ temp_file.close!
96
+ FileUtils.remove_entry temp_dir
97
+ end
98
+
82
99
  def list(limit=10)
83
100
  lister.list(limit)
84
101
  end
@@ -1,18 +1,20 @@
1
1
  require 'json'
2
2
  require 'trollop'
3
3
 
4
+ require 'heirloom/cli/formatter'
4
5
  require 'heirloom/cli/shared'
6
+
5
7
  require 'heirloom/cli/authorize'
6
8
  require 'heirloom/cli/catalog'
7
- require 'heirloom/cli/upload'
8
- require 'heirloom/cli/setup'
9
+ require 'heirloom/cli/destroy'
10
+ require 'heirloom/cli/download'
9
11
  require 'heirloom/cli/list'
12
+ require 'heirloom/cli/rotate'
13
+ require 'heirloom/cli/setup'
10
14
  require 'heirloom/cli/show'
11
15
  require 'heirloom/cli/tag'
12
- require 'heirloom/cli/download'
13
- require 'heirloom/cli/destroy'
14
16
  require 'heirloom/cli/teardown'
15
- require 'heirloom/cli/formatter'
17
+ require 'heirloom/cli/upload'
16
18
 
17
19
  module Heirloom
18
20
  module CLI
@@ -30,15 +32,17 @@ module Heirloom
30
32
  CLI::Download.new.download
31
33
  when 'list'
32
34
  CLI::List.new.list
35
+ when 'rotate'
36
+ CLI::Rotate.new.rotate
33
37
  when 'setup'
34
38
  CLI::Setup.new.setup
35
39
  when 'show'
36
40
  CLI::Show.new.show
41
+ when 'tag', 'update'
42
+ CLI::Tag.new.tag
37
43
  when 'teardown'
38
44
  CLI::Teardown.new.teardown
39
- when 'update', 'tag'
40
- CLI::Tag.new.tag
41
- when 'build', 'upload'
45
+ when 'upload', 'build'
42
46
  CLI::Upload.new.upload
43
47
  when '-v'
44
48
  puts Heirloom::VERSION
@@ -0,0 +1,82 @@
1
+ module Heirloom
2
+ module CLI
3
+ class Rotate
4
+
5
+ include Heirloom::CLI::Shared
6
+
7
+ def initialize
8
+ @opts = read_options
9
+ @logger = HeirloomLogger.new :log_level => @opts[:level]
10
+ @config = load_config :logger => @logger,
11
+ :opts => @opts
12
+
13
+ ensure_valid_options :provided => @opts,
14
+ :required => [:name, :id, :old_secret, :new_secret],
15
+ :config => @config
16
+
17
+ @catalog = Heirloom::Catalog.new :name => @opts[:name],
18
+ :config => @config
19
+
20
+ @archive = Archive.new :name => @opts[:name],
21
+ :config => @config,
22
+ :id => @opts[:id]
23
+
24
+ unless @opts[:bucket_prefix]
25
+ ensure_archive_exists :archive => @archive,
26
+ :config => @config
27
+ end
28
+
29
+ # Lookup upload regions, metadata region, and bucket_prefix from simpledb unless specified
30
+ @opts[:regions] ||= @catalog.regions
31
+ @opts[:region] ||= @catalog.regions.first
32
+ @opts[:bucket_prefix] ||= @catalog.bucket_prefix
33
+ end
34
+
35
+ def rotate
36
+ @archive.rotate @opts
37
+ rescue Heirloom::Exceptions::RotateFailed => e
38
+ @config.logger.error e.message
39
+ exit 1
40
+ end
41
+
42
+ private
43
+
44
+ def read_options
45
+ Trollop::options do
46
+ version Heirloom::VERSION
47
+ banner <<-EOS
48
+
49
+ Rotate keys for an Heirloom.
50
+
51
+ Will download the heirloom to temp directory, decrypt, encrypt, and upload, replacing original.
52
+
53
+ Usage:
54
+
55
+ heirloom rotate -n NAME -i ID --new-secret MY_NEW_SECRET --old-secret MY_OLD_SECRET
56
+
57
+ To rotate Heirloom without looking up details in SimpleDB, specify region (-r) and bucket_prefix (-b) options.
58
+
59
+ EOS
60
+ opt :bucket_prefix, "Bucket prefix of the Heirloom to download.", :type => :string
61
+ opt :help, "Display Help"
62
+ opt :id, "ID of the Heirloom to rotate.", :type => :string
63
+ opt :level, "Log level [debug|info|warn|error].", :type => :string,
64
+ :default => 'info'
65
+ opt :metadata_region, "AWS region to store Heirloom metadata.", :type => :string,
66
+ :default => 'us-west-1'
67
+ opt :name, "Name of Heirloom.", :type => :string
68
+ opt :region, "Region to download Heirloom.", :type => :string,
69
+ :default => 'us-west-1'
70
+ opt :new_secret, "New Secret for encrypted Heirloom.", :type => :string,
71
+ :short => :none
72
+ opt :old_secret, "Old secret for encrypted Heirloom.", :type => :string,
73
+ :short => :none
74
+ opt :aws_access_key, "AWS Access Key ID", :type => :string,
75
+ :short => :none
76
+ opt :aws_secret_key, "AWS Secret Access Key", :type => :string,
77
+ :short => :none
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -6,7 +6,7 @@ module Heirloom
6
6
 
7
7
  def initialize(args)
8
8
  @config = args[:config]
9
- @exclude = args[:exclude]
9
+ @exclude = args[:exclude] ||= []
10
10
  @path = args[:path]
11
11
  @file = args[:file]
12
12
  @logger = @config.logger
@@ -1,5 +1,6 @@
1
- module Stackster
1
+ module Heirloom
2
2
  module Exceptions
3
+
3
4
  class Base < RuntimeError
4
5
  attr_accessor :message
5
6
 
@@ -7,5 +8,9 @@ module Stackster
7
8
  @message = message
8
9
  end
9
10
  end
11
+
12
+ class RotateFailed < Base
13
+ end
14
+
10
15
  end
11
16
  end
@@ -1,3 +1,3 @@
1
1
  module Heirloom
2
- VERSION = "0.11.0.beta.1"
2
+ VERSION = "0.11.0.beta.2"
3
3
  end
@@ -3,7 +3,8 @@ require 'spec_helper'
3
3
  describe Heirloom do
4
4
 
5
5
  before do
6
- @config_mock = mock 'config'
6
+ @logger_mock = mock 'logger', :info => true, :debug => true, :error => true
7
+ @config_mock = mock 'config', :logger => @logger_mock
7
8
  @archive = Heirloom::Archive.new :config => @config_mock,
8
9
  :name => 'chef',
9
10
  :id => '123'
@@ -223,4 +224,83 @@ describe Heirloom do
223
224
  end
224
225
 
225
226
  end
227
+
228
+ context "rotate" do
229
+ before do
230
+
231
+ @tmp_dir = '/path/to/temp/dir'
232
+ Dir.stub(:mktmpdir).and_return @tmp_dir
233
+
234
+ @tmp_file = mock 'file'
235
+ @tmp_file.stub :path => '/path/to/tmp/file', :close! => true
236
+ Tempfile.stub :new => @tmp_file
237
+ FileUtils.stub :remove_entry => true
238
+
239
+ end
240
+
241
+ it "should rotate an archive by downloading and re-uploading" do
242
+
243
+ @archive.should_receive(:download).
244
+ with(hash_including(:output => @tmp_dir,
245
+ :secret => "oldpassword",
246
+ :extract => true)).
247
+ and_return true
248
+ @archive.should_receive(:build).
249
+ with(hash_including(:directory => @tmp_dir,
250
+ :secret => "newpassword",
251
+ :file => @tmp_file.path)).
252
+ and_return true
253
+ @archive.should_receive(:destroy).with(no_args)
254
+ @archive.should_receive(:upload).
255
+ with(hash_including(:secret => "newpassword",
256
+ :file => @tmp_file.path))
257
+
258
+ @archive.rotate({ :new_secret => "newpassword", :old_secret => "oldpassword" })
259
+ end
260
+
261
+ context "failing download" do
262
+
263
+ before do
264
+ @archive.stub :download => false, :build => true, :destroy => nil, :upload => true
265
+ end
266
+
267
+ it "should raise an exception when download fails" do
268
+ expect {
269
+ @archive.rotate({ :new_secret => "new", :old_secret => "old" })
270
+ }.to raise_error Heirloom::Exceptions::RotateFailed
271
+ end
272
+
273
+ it "should not destroy the file when download fails" do
274
+ @archive.should_not_receive(:destroy)
275
+ begin
276
+ @archive.rotate({ :new_secret => "new", :old_secret => "old" })
277
+ rescue Heirloom::Exceptions::RotateFailed
278
+ end
279
+ end
280
+
281
+ end
282
+
283
+ context "failing build" do
284
+
285
+ before do
286
+ @archive.stub :download => true, :build => false, :destroy => nil, :upload => true
287
+ end
288
+
289
+ it "should raise an exception when build fails" do
290
+ expect {
291
+ @archive.rotate({ :new_secret => "new", :old_secret => "old" })
292
+ }.to raise_error Heirloom::Exceptions::RotateFailed
293
+ end
294
+
295
+ it "should not destroy the file when build fails" do
296
+ @archive.should_not_receive(:destroy)
297
+ begin
298
+ @archive.rotate({ :new_secret => "new", :old_secret => "old" })
299
+ rescue Heirloom::Exceptions::RotateFailed
300
+ end
301
+ end
302
+
303
+ end
304
+
305
+ end
226
306
  end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ require 'heirloom/cli'
3
+
4
+ describe Heirloom do
5
+
6
+ before do
7
+
8
+ options = { :name => 'archive_name',
9
+ :id => '1.0.0',
10
+ :bucket_prefix => 'bp',
11
+ :old_secret => 'oldpassword',
12
+ :new_secret => 'newpassword',
13
+ :aws_access_key => 'key',
14
+ :aws_secret_key => 'secret' }
15
+ Trollop.stub(:options).and_return options
16
+
17
+ catalog_stub = stub :regions => ['us-east-1', 'us-west-1']
18
+ Heirloom::Catalog.stub(:new).and_return catalog_stub
19
+
20
+ @archive_mock = mock 'archive'
21
+ Heirloom::Archive.stub(:new).and_return @archive_mock
22
+
23
+ end
24
+
25
+ it "should delegate to archive object" do
26
+
27
+ @archive_mock.should_receive :rotate
28
+
29
+ Heirloom::CLI::Rotate.new.rotate
30
+
31
+ end
32
+
33
+ it "should log and do a SystemExit when a rotate fails" do
34
+
35
+ @archive_mock.stub(:rotate).and_raise Heirloom::Exceptions::RotateFailed.new("failed")
36
+
37
+ @logger_mock = mock 'logger'
38
+ Heirloom::HeirloomLogger.stub :new => @logger_mock
39
+
40
+ @logger_mock.should_receive(:error).with "failed"
41
+ expect {
42
+ Heirloom::CLI::Rotate.new.rotate
43
+ }.to raise_error SystemExit
44
+
45
+ end
46
+
47
+ end
@@ -91,6 +91,23 @@ describe Heirloom::Directory do
91
91
  end
92
92
  end
93
93
 
94
+ context "parameter validation" do
95
+ before do
96
+ Dir.stub(:entries).and_return ['pack_me', 'dont_pack_me']
97
+ end
98
+
99
+ it "should not fail if exclude is nil" do
100
+ @directory = Heirloom::Directory.new :config => @config_mock,
101
+ :exclude => nil,
102
+ :path => '/dir',
103
+ :file => '/tmp/file.tar.gz'
104
+ @directory.stub(:`).and_return 'cmd output'
105
+ lambda {
106
+ @directory.build_artifact_from_directory(:exclude => nil)
107
+ }.should_not raise_error
108
+ end
109
+ end
110
+
94
111
  end
95
112
 
96
113
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heirloom
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0.beta.1
4
+ version: 0.11.0.beta.2
5
5
  prerelease: 7
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-10 00:00:00.000000000 Z
12
+ date: 2013-04-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -150,6 +150,7 @@ files:
150
150
  - lib/heirloom/cli/formatter/catalog.rb
151
151
  - lib/heirloom/cli/formatter/show.rb
152
152
  - lib/heirloom/cli/list.rb
153
+ - lib/heirloom/cli/rotate.rb
153
154
  - lib/heirloom/cli/setup.rb
154
155
  - lib/heirloom/cli/shared.rb
155
156
  - lib/heirloom/cli/show.rb
@@ -204,6 +205,7 @@ files:
204
205
  - spec/cli/formatter/catalog_spec.rb
205
206
  - spec/cli/formatter/show_spec.rb
206
207
  - spec/cli/list_spec.rb
208
+ - spec/cli/rotate_spec.rb
207
209
  - spec/cli/setup_spec.rb
208
210
  - spec/cli/shared_spec.rb
209
211
  - spec/cli/show_spec.rb
@@ -233,7 +235,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
235
  version: '0'
234
236
  segments:
235
237
  - 0
236
- hash: -822415306799597358
238
+ hash: -211146683438990673
237
239
  required_rubygems_version: !ruby/object:Gem::Requirement
238
240
  none: false
239
241
  requirements:
@@ -280,6 +282,7 @@ test_files:
280
282
  - spec/cli/formatter/catalog_spec.rb
281
283
  - spec/cli/formatter/show_spec.rb
282
284
  - spec/cli/list_spec.rb
285
+ - spec/cli/rotate_spec.rb
283
286
  - spec/cli/setup_spec.rb
284
287
  - spec/cli/shared_spec.rb
285
288
  - spec/cli/show_spec.rb