heirloom 0.9.0 → 0.10.0

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/.rvmrc CHANGED
@@ -1 +1 @@
1
- rvm use ruby-1.9.3-p194@heirloom --create
1
+ rvm use ruby-1.9.3-p327@heirloom --create
data/CHANGELOG CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.10.0:
2
+
3
+ * Confirm tar and gpg executables are present when necessary
4
+ * Switch to gpg for encryption
5
+ * S3 key names will have gpg appended when encrypted
6
+ * Switch rvm to 1.9.3-p327
7
+
1
8
  ## 0.9.0:
2
9
 
3
10
  * Updated tempfile logic to fix GC issues.
data/README.md CHANGED
@@ -22,7 +22,7 @@ Install the gem
22
22
  gem install heirloom --no-ri --no-rdoc
23
23
  ```
24
24
 
25
- To get started copy the sample below into ~/.heirloom.yml and update the specified fields.
25
+ To get started, copy the sample below to ~/.heirloom.yml and update the specified fields.
26
26
 
27
27
  ```
28
28
  aws:
@@ -31,16 +31,6 @@ aws:
31
31
  metadata_region: us-west-1
32
32
  ```
33
33
 
34
- Proxy Support
35
- -------------
36
-
37
- Heirloom supports accessing AWS API endpoint throught a proxy. This can be set via the http_proxy and https_proxy variables.
38
-
39
- ```
40
- export http_proxy=http://1.2.3.4:80
41
- export http_proxys=http://1.2.3.4:80
42
- ```
43
-
44
34
  Documentation
45
35
  -------------
46
36
 
data/lib/heirloom.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require "heirloom/utils"
2
+
1
3
  require "heirloom/acl"
2
4
  require "heirloom/archive"
3
5
  require "heirloom/aws"
@@ -11,20 +11,19 @@ module Heirloom
11
11
  end
12
12
 
13
13
  def allow_read_access_from_accounts(args)
14
- bucket = args[:bucket]
15
- key_name = args[:key_name]
14
+ bucket = args[:bucket]
15
+ key_name = args[:key_name]
16
16
  key_folder = args[:key_folder]
17
- accounts = args[:accounts]
17
+ accounts = args[:accounts]
18
18
 
19
- key = "#{key_folder}/#{key_name}.tar.gz"
19
+ key = "#{key_folder}/#{key_name}"
20
20
 
21
21
  current_acls = s3.get_bucket_acl bucket
22
+ name = current_acls['Owner']['Name']
23
+ id = current_acls['Owner']['ID']
22
24
 
23
- name = current_acls['Owner']['Name']
24
- id = current_acls['Owner']['ID']
25
-
26
- grants = build_bucket_grants :id => id,
27
- :name => name,
25
+ grants = build_bucket_grants :id => id,
26
+ :name => name,
28
27
  :accounts => accounts
29
28
 
30
29
  accounts.each do |a|
@@ -17,13 +17,15 @@ module Heirloom
17
17
 
18
18
  @logger.info "Authorizing #{@accounts.join(', ')}."
19
19
 
20
+ key_name = reader.key_name
21
+
20
22
  regions.each do |region|
21
23
  bucket = reader.get_bucket :region => region
22
24
 
23
25
  s3_acl = ACL::S3.new :config => @config,
24
26
  :region => region
25
27
 
26
- s3_acl.allow_read_access_from_accounts :key_name => @id,
28
+ s3_acl.allow_read_access_from_accounts :key_name => key_name,
27
29
  :key_folder => @name,
28
30
  :accounts => @accounts,
29
31
  :bucket => bucket
@@ -18,15 +18,15 @@ module Heirloom
18
18
  regions.each do |region|
19
19
  bucket = reader.get_bucket :region => region
20
20
 
21
- key = "#{@id}.tar.gz"
21
+ key_name = reader.key_name
22
22
 
23
23
  if bucket
24
- @logger.debug "Destroying 's3://#{bucket}/#{@name}/#{key}'."
24
+ @logger.debug "Destroying 's3://#{bucket}/#{@name}/#{key_name}'."
25
25
 
26
26
  s3_destroyer = Destroyer::S3.new :config => @config,
27
27
  :region => region
28
28
 
29
- s3_destroyer.destroy_file :key_name => key,
29
+ s3_destroyer.destroy_file :key_name => key_name,
30
30
  :bucket => bucket,
31
31
  :key_folder => @name
32
32
  end
@@ -12,8 +12,8 @@ module Heirloom
12
12
  def download(args)
13
13
  @region = args[:region]
14
14
  @bucket_prefix = args[:bucket_prefix]
15
+ @secret = args[:secret]
15
16
  extract = args[:extract]
16
- secret = args[:secret]
17
17
  output = args[:output] ||= './'
18
18
 
19
19
  @logger.info "Downloading s3://#{bucket}/#{key} from #{@region}."
@@ -28,7 +28,7 @@ module Heirloom
28
28
  return false unless raw_archive
29
29
 
30
30
  archive = cipher_data.decrypt_data :data => raw_archive,
31
- :secret => secret
31
+ :secret => @secret
32
32
 
33
33
  return false unless archive
34
34
 
@@ -44,12 +44,12 @@ module Heirloom
44
44
 
45
45
  private
46
46
 
47
- def file
47
+ def file
48
48
  "#{@id}.tar.gz"
49
49
  end
50
50
 
51
51
  def key
52
- "#{@name}/#{file}"
52
+ @secret ? "#{@name}/#{@id}.tar.gz.gpg" : "#{@name}/#{@id}.tar.gz"
53
53
  end
54
54
 
55
55
  def bucket
@@ -4,9 +4,9 @@ module Heirloom
4
4
 
5
5
  def initialize(args)
6
6
  @config = args[:config]
7
- @name = args[:name]
7
+ @name = args[:name]
8
+ @id = args[:id]
8
9
  @domain = "heirloom_#{@name}"
9
- @id = args[:id]
10
10
  @logger = @config.logger
11
11
  end
12
12
 
@@ -66,21 +66,31 @@ module Heirloom
66
66
  end
67
67
  end
68
68
 
69
+ def key_name
70
+ encrypted? ? "#{@id}.tar.gz.gpg" : "#{@id}.tar.gz"
71
+ end
72
+
69
73
  private
70
74
 
75
+ def encrypted?
76
+ show['encrypted'] == 'true'
77
+ end
78
+
71
79
  def domain_exists?
72
80
  sdb.domain_exists? @domain
73
81
  end
74
82
 
75
83
  def get_url(args)
84
+ region = args[:region]
85
+
76
86
  return nil unless exists?
77
- @logger.debug "Looking for #{args[:region]} endpoint for #{@id}"
78
- url = "#{args[:region]}-s3-url"
87
+ @logger.debug "Looking for #{region} endpoint for #{@id}"
88
+ url = "#{region}-s3-url"
79
89
  if show[url]
80
90
  @logger.debug "Found #{url} for #{@id}."
81
91
  show[url]
82
92
  else
83
- @logger.debug "#{args[:region]} endpoint for #{@id} not found."
93
+ @logger.debug "#{region} endpoint for #{@id} not found."
84
94
  nil
85
95
  end
86
96
  end
@@ -4,16 +4,19 @@ module Heirloom
4
4
 
5
5
  def initialize(args)
6
6
  @config = args[:config]
7
- @name = args[:name]
8
- @id = args[:id]
7
+ @name = args[:name]
8
+ @id = args[:id]
9
9
  @logger = @config.logger
10
10
  end
11
11
 
12
12
  def upload(args)
13
- heirloom_file = args[:file]
14
- bucket_prefix = args[:bucket_prefix]
15
- regions = args[:regions]
13
+ heirloom_file = args[:file]
14
+ bucket_prefix = args[:bucket_prefix]
15
+ regions = args[:regions]
16
16
  public_readable = args[:public_readable]
17
+ secret = args[:secret]
18
+
19
+ key_name = secret ? "#{@id}.tar.gz.gpg" : "#{@id}.tar.gz"
17
20
 
18
21
  regions.each do |region|
19
22
  bucket = "#{bucket_prefix}-#{region}"
@@ -26,13 +29,14 @@ module Heirloom
26
29
  :file => heirloom_file,
27
30
  :id => @id,
28
31
  :key_folder => @name,
29
- :key_name => "#{@id}.tar.gz",
32
+ :key_name => key_name,
30
33
  :name => @name,
31
34
  :public_readable => public_readable
32
35
 
33
- s3_uploader.add_endpoint_attributes :bucket => bucket,
34
- :id => @id,
35
- :name => @name
36
+ s3_uploader.add_endpoint_attributes :bucket => bucket,
37
+ :id => @id,
38
+ :name => @name,
39
+ :key_name => key_name
36
40
  end
37
41
  @logger.info "Upload complete."
38
42
  end
@@ -1,3 +1,5 @@
1
+ require 'tempfile'
2
+
1
3
  module Heirloom
2
4
  class Writer
3
5
 
@@ -1,2 +1,4 @@
1
+ require 'heirloom/cipher/shared'
2
+
1
3
  require 'heirloom/cipher/data'
2
4
  require 'heirloom/cipher/file'
@@ -1,36 +1,54 @@
1
- require 'openssl'
1
+ require 'tempfile'
2
2
 
3
3
  module Heirloom
4
4
  module Cipher
5
5
  class Data
6
6
 
7
+ include Heirloom::Cipher::Shared
8
+
7
9
  def initialize(args)
8
10
  @config = args[:config]
9
11
  @logger = @config.logger
10
12
  end
11
13
 
12
14
  def decrypt_data(args)
13
- data = args[:data]
14
- secret = args[:secret]
15
-
16
- return data unless args[:secret]
17
-
18
- @logger.info "Secret provided. Decrypting Heirloom."
19
-
20
- @aes = OpenSSL::Cipher::AES256.new(:CBC)
21
- @aes.decrypt
22
- @aes.key = Digest::SHA256.hexdigest secret
23
- @aes.iv = data.slice!(0,16)
24
- begin
25
- @aes.update(data) + @aes.final
26
- rescue OpenSSL::Cipher::CipherError => e
27
- if e.message == 'wrong final block length'
28
- @logger.error 'This Heirloom does not appear to be encrypted.'
29
- end
30
- @logger.error "Unable to decrypt Heirloom: '#{e.message}'"
15
+ @data = args[:data]
16
+ @secret = args[:secret]
17
+
18
+ return @data unless args[:secret]
19
+ return false unless gpg_in_path?
20
+
21
+ @encrypted_file = Tempfile.new('archive.tar.gz.gpg')
22
+ @decrypted_file = Tempfile.new('archive.tar.gz')
23
+
24
+ ::File.open(@encrypted_file, 'w') { |f| f.write @data }
25
+
26
+ decrypt
27
+ end
28
+
29
+ private
30
+
31
+ def decrypt
32
+ @logger.info "Secret provided. Decrypting with: '#{command}'"
33
+ output = `#{command(@secret)}`
34
+ @logger.debug "Decryption output: '#{output}'"
35
+
36
+ if $?.success?
37
+ @decrypted_file.read
38
+ else
39
+ @logger.error "Decryption failed with output: '#{output}'"
31
40
  false
32
41
  end
33
42
  end
43
+
44
+ def command(secret='XXXXXXXX')
45
+ "gpg --batch --yes --cipher-algo AES256 --passphrase #{secret} --output #{@decrypted_file.path} #{@encrypted_file.path} 2>&1"
46
+ end
47
+
48
+ def logger
49
+ @logger
50
+ end
51
+
34
52
  end
35
53
  end
36
54
  end
@@ -1,4 +1,3 @@
1
- require 'openssl'
2
1
  require 'tempfile'
3
2
  require 'fileutils'
4
3
 
@@ -6,45 +5,47 @@ module Heirloom
6
5
  module Cipher
7
6
  class File
8
7
 
8
+ include Heirloom::Cipher::Shared
9
+
9
10
  def initialize(args)
10
11
  @config = args[:config]
11
- @aes = OpenSSL::Cipher::AES256.new(:CBC)
12
+ @logger = @config.logger
12
13
  end
13
14
 
14
15
  def encrypt_file(args)
15
16
  @file = args[:file]
17
+ @secret = args[:secret]
16
18
  @encrypted_file = Tempfile.new('archive.tar.gz.enc')
17
- secret = args[:secret]
18
- iv = @aes.random_iv
19
-
20
- @aes.encrypt
21
- @aes.iv = iv
22
- @aes.key = Digest::SHA256.hexdigest secret
23
-
24
- # Need to refactor to be less complex
25
- # Additionally tests to do fully cover logic
26
- ::File.open(@encrypted_file,'w') do |enc|
27
- enc << iv
28
- ::File.open(@file) do |f|
29
- loop do
30
- r = f.read(4096)
31
- break unless r
32
- enc << @aes.update(r)
33
- end
34
- end
35
- enc << @aes.final
36
- end
19
+
20
+ return false unless gpg_in_path?
21
+ return false unless encrypt
37
22
 
38
23
  replace_file
39
24
  end
40
25
 
41
26
  private
42
27
 
28
+ def encrypt
29
+ @logger.info "Encrypting with: '#{command}'"
30
+ output = `#{command(@secret)}`
31
+ @logger.debug "Encryption output: '#{output}'"
32
+ @logger.error "Encryption failed with output: '#{output}'" unless $?.success?
33
+ $?.success?
34
+ end
35
+
36
+ def command(secret="XXXXXXXX")
37
+ "gpg --batch --yes -c --cipher-algo AES256 --passphrase #{secret} --output #{@encrypted_file.path} #{@file} 2>&1"
38
+ end
39
+
43
40
  def replace_file
44
41
  FileUtils.mv @encrypted_file.path, @file
45
42
  @encrypted_file.close!
46
43
  end
47
44
 
45
+ def logger
46
+ @logger
47
+ end
48
+
48
49
  end
49
50
  end
50
51
  end
@@ -0,0 +1,19 @@
1
+ require 'tempfile'
2
+
3
+ module Heirloom
4
+ module Cipher
5
+ module Shared
6
+
7
+ include Heirloom::Utils::File
8
+
9
+ def gpg_in_path?
10
+ unless which('gpg')
11
+ @logger.error "gpg not found in path."
12
+ return false
13
+ end
14
+ true
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -62,7 +62,8 @@ module Heirloom
62
62
  @archive.upload :bucket_prefix => @bucket_prefix,
63
63
  :regions => @regions,
64
64
  :public_readable => @opts[:public],
65
- :file => @file.path
65
+ :file => @file.path,
66
+ :secret => secret
66
67
 
67
68
  @file.close!
68
69
  end
@@ -2,6 +2,8 @@ module Heirloom
2
2
 
3
3
  class Directory
4
4
 
5
+ include Heirloom::Utils::File
6
+
5
7
  def initialize(args)
6
8
  @config = args[:config]
7
9
  @exclude = args[:exclude]
@@ -25,6 +27,7 @@ module Heirloom
25
27
  private
26
28
 
27
29
  def build_archive
30
+ return false unless tar_in_path?
28
31
  command = "cd #{@path} && tar czf #{@file} #{files_to_pack}"
29
32
  @logger.info "Archiving with: `#{command}`"
30
33
  output = `#{command}`
@@ -39,8 +42,16 @@ module Heirloom
39
42
  :secret => @secret
40
43
  end
41
44
 
45
+ def tar_in_path?
46
+ unless which('tar')
47
+ @logger.error "tar not found in path."
48
+ return false
49
+ end
50
+ true
51
+ end
52
+
42
53
  def files_to_pack
43
- (Dir.entries(@path) - ['.', '..'] - @exclude).map do |file|
54
+ @files_to_pack ||= (Dir.entries(@path) - ['.', '..'] - @exclude).map do |file|
44
55
  "'#{file}'"
45
56
  end.join(' ')
46
57
  end