yaml_vault 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 40d3decc007bc319e9a1a735ccf599dd706ddc5c
4
- data.tar.gz: 3f3c1c587bb2e0d9e401a5d9348f5904df040b63
3
+ metadata.gz: 2a0bdfb9602aac1932efba9fd68eab1083ed2c32
4
+ data.tar.gz: 2e8f8caede77d7f49d50f0354a39d9809b9cfbe5
5
5
  SHA512:
6
- metadata.gz: 23bf5c76edb6852b819c8e89cab6325b7ae77b88a4f729e4cb73f04cef470083318929993e9667fedc5aebfe61e8c594d126f4887f6182be0f8d048e6b7638f3
7
- data.tar.gz: f01be0901bc36145ac4d05eecc704c72822c5c9e8a570c644064365aae0bf17f5fce6f6b09ab5ccaa6afbec5db0ed53c1cd023428e7a7ebde5a2e99fdc64256d
6
+ metadata.gz: 1b994e252cb2d603a1bc69944a0d5d575ad1c10e51b10ff834024f6ffe939c935a7483bc8cdd258651b734fcddc394e193f957d351021de0b8ca0f9372daaeec
7
+ data.tar.gz: 7e2893a031100688009d2a71ac912b816cd85cc45c2bc802bd581aa29728a5f69d6a436d7d3b86515cdb3f065fcdbfae4471aa3431fed61e2912ed15d2ced025
data/.gitignore CHANGED
@@ -7,3 +7,5 @@
7
7
  /pkg/
8
8
  /spec/reports/
9
9
  /tmp/
10
+
11
+ .envrc
data/README.md CHANGED
@@ -1,6 +1,14 @@
1
1
  # YamlVault
2
+ [![Gem Version](https://badge.fury.io/rb/yaml_vault.svg)](https://badge.fury.io/rb/yaml_vault)
2
3
 
3
- Yaml file encryption/decription helper.
4
+ Yaml file encryption/decryption helper.
5
+
6
+ ## Encryption Algorithm
7
+
8
+ yaml_vault uses ActiveSupport::MessageEncryptor.
9
+
10
+ Default cipher is `aes-256-cbc`.
11
+ Default sign digest is `SHA256`.
4
12
 
5
13
  ## Installation
6
14
 
data/exe/yaml_vault CHANGED
@@ -7,35 +7,83 @@ require 'thor'
7
7
  class YamlVault::Cli < Thor
8
8
  include Thor::Actions
9
9
 
10
+ class_option :key, aliases: "-k", type: :string, banner: "KEYNAME (format: \"KEY1.INNER_KEY,KEY2\")", desc: "target key", default: "vault"
11
+ class_option :cryptor, type: :string, enum: %w(simple aws-kms), default: "simple"
12
+
13
+ class_option :salt, aliases: "-s", type: :string
14
+ class_option :cipher, type: :string, desc: "Encrypt cipher (see. OpenSSL::Cipher.ciphers)", default: "aes-256-cbc"
15
+ class_option :digest, type: :string, desc: "Sign digest algorithm (see. OpenSSL::Digest.constants)", default: "SHA256"
16
+ class_option :use_sign_passphrase, type: :boolean, default: false
17
+
18
+ class_option :aws_kms_key_id, type: :string
19
+ class_option :aws_region, type: :string
20
+ class_option :aws_access_key_id, type: :string
21
+ class_option :aws_secret_access_key, type: :string
22
+
10
23
  desc "encrypt YAML_FILE", "Encrypt yaml file"
11
24
  method_option :output, aliases: "-o", type: :string, required: true
12
- method_option :key, aliases: "-k", type: :string, desc: "target key (format: \"KEY1.INNER_KEY,KEY2\")", default: "vault"
13
- method_option :salt, aliases: "-s", type: :string
14
- method_option :passphrase, aliases: "-p", type: :string
15
- method_option :cipher, type: :string
16
25
  def encrypt(yaml_file)
17
- passphrase = ENV["YAML_VAULT_PASSPHRASE"] || options[:passphrase] || ask("Enter passphrase:", echo: false)
18
- raise "Please input passphrase" if passphrase.blank?
19
- keys = options[:key] ? options[:key].split(/,\s?/).map { |k| k.split(".") } : ["vault"]
20
- encrypted_yaml = YamlVault.encrypt_yaml(passphrase, yaml_file, keys, salt: options[:salt], cipher: options[:cipher])
26
+ passphrase, sign_passphrase = get_passphrase
27
+ encrypted_yaml = YamlVault::Main.new(
28
+ yaml_file,
29
+ target_keys,
30
+ options[:cryptor],
31
+ passphrase: passphrase,
32
+ sign_passphrase: sign_passphrase,
33
+ salt: options[:salt], cipher: options[:cipher], digest: options[:digest],
34
+ aws_kms_key_id: options[:aws_kms_key_id],
35
+ aws_region: options[:aws_region],
36
+ aws_access_key_id: options[:aws_access_key_id],
37
+ aws_secret_access_key: options[:aws_secret_access_key]
38
+ ).encrypt_yaml
21
39
  puts "encrypted #{yaml_file} -> #{options[:output]}"
22
40
  File.open(options[:output], "w") { |f| f.write encrypted_yaml }
23
41
  end
24
42
 
25
43
  desc "decrypt YAML_FILE", "Decrypt yaml file"
26
44
  method_option :output, aliases: "-o", type: :string, required: true
27
- method_option :key, aliases: "-k", type: :string, desc: "target key (format: \"KEY1.INNER_KEY,KEY2\")", default: "vault"
28
- method_option :salt, aliases: "-s", type: :string
29
- method_option :passphrase, aliases: "-p", type: :string
30
- method_option :cipher, type: :string
31
45
  def decrypt(yaml_file)
32
- passphrase = ENV["YAML_VAULT_PASSPHRASE"] || options[:passphrase] || ask("Enter passphrase:", echo: false)
33
- raise "Please input passphrase" if passphrase.blank?
34
- keys = options[:key] ? options[:key].split(/,\s?/).map { |k| k.split(".") } : ["vault"]
35
- decrypted_yaml = YamlVault.decrypt_yaml(passphrase, yaml_file, keys, salt: options[:salt], cipher: options[:cipher])
46
+ passphrase, sign_passphrase = get_passphrase
47
+ decrypted_yaml = YamlVault::Main.new(
48
+ yaml_file,
49
+ target_keys,
50
+ options[:cryptor],
51
+ passphrase: passphrase,
52
+ sign_passphrase: sign_passphrase,
53
+ salt: options[:salt], cipher: options[:cipher], digest: options[:digest],
54
+ aws_kms_key_id: options[:aws_kms_key_id],
55
+ aws_region: options[:aws_region],
56
+ aws_access_key_id: options[:aws_access_key_id],
57
+ aws_secret_access_key: options[:aws_secret_access_key]
58
+ ).decrypt_yaml
36
59
  puts "decrypted #{yaml_file} -> #{options[:output]}"
37
60
  File.open(options[:output], "w") { |f| f.write decrypted_yaml }
38
61
  end
62
+
63
+ private
64
+
65
+ def get_passphrase
66
+ return nil, nil unless options[:cryptor] == "simple"
67
+
68
+ passphrase = ENV["YAML_VAULT_PASSPHRASE"] || ask("Enter passphrase:", echo: false)
69
+ puts "\n"
70
+ if ENV["YAML_VAULT_SIGN_PASSPHRASE"]
71
+ sign_passphrase = ENV["YAML_VAULT_SIGN_PASSPHRASE"]
72
+ elsif options[:use_sign_passphrase]
73
+ sign_passphrase = ask("Enter sign passphrase:", echo: false)
74
+ puts "\n"
75
+ else
76
+ sign_passphrase = nil
77
+ end
78
+
79
+ raise "Please input passphrase" if passphrase.blank?
80
+
81
+ return passphrase, sign_passphrase
82
+ end
83
+
84
+ def target_keys
85
+ options[:key] ? options[:key].split(/,\s?/).map { |k| k.split(".") } : ["vault"]
86
+ end
39
87
  end
40
88
 
41
89
  YamlVault::Cli.start
@@ -1,3 +1,3 @@
1
1
  module YamlVault
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/yaml_vault.rb CHANGED
@@ -1,33 +1,65 @@
1
1
  require 'yaml_vault/version'
2
2
  require 'yaml'
3
+ require 'base64'
3
4
  require 'erb'
4
5
  require 'active_support'
5
6
 
6
7
  module YamlVault
7
- class << self
8
- def encrypt_yaml(passphrase, yaml, keys, salt: nil, cipher: nil)
9
- process_yaml(passphrase, yaml, keys, salt: salt.to_s, cipher: cipher) do |cryptor, data|
10
- do_process(cryptor, data, :encrypt)
8
+ class Main
9
+ def initialize(
10
+ yaml, keys, cryptor_name = nil,
11
+ passphrase: nil, sign_passphrase: nil, salt: nil, cipher: "aes-256-cbc", digest: "SHA256",
12
+ aws_kms_key_id: nil, aws_region: nil, aws_access_key_id: nil, aws_secret_access_key: nil
13
+ )
14
+ @yaml = yaml
15
+ @keys = keys
16
+
17
+ @passphrase = passphrase
18
+ @sign_passphrase = sign_passphrase
19
+ @salt = salt.to_s
20
+ @cipher = cipher
21
+ @digest = digest
22
+
23
+ @aws_kms_key_id = aws_kms_key_id
24
+ @aws_region = aws_region
25
+ @aws_access_key_id = aws_access_key_id
26
+ @aws_secret_access_key = aws_secret_access_key
27
+
28
+ @cryptor = get_cryptor(cryptor_name)
29
+ end
30
+
31
+ def encrypt_yaml
32
+ process_yaml do |data|
33
+ do_process(data, :encrypt)
11
34
  end
12
35
  end
13
36
 
14
- def decrypt_yaml(passphrase, yaml, keys, salt: nil, cipher: nil)
15
- process_yaml(passphrase, yaml, keys, salt: salt.to_s, cipher: cipher) do |cryptor, data|
16
- do_process(cryptor, data, :decrypt)
37
+ def decrypt_yaml
38
+ process_yaml do |data|
39
+ do_process(data, :decrypt)
17
40
  end
18
41
  end
19
42
 
20
43
  private
21
44
 
22
- def process_yaml(passphrase, yaml, keys, salt:, cipher:)
23
- cryptor = ValueCryptor.new(passphrase, salt, cipher)
24
- data = YAML.load(ERB.new(File.read(yaml)).result)
25
- keys.each do |key|
45
+ def get_cryptor(name)
46
+ if name == "simple"
47
+ ValueCryptor::Simple.new(@passphrase, @sign_passphrase, @salt, @cipher, @digest)
48
+ elsif name == "aws-kms"
49
+ ValueCryptor::KMS.new(@aws_kms_key_id, region: @aws_region, aws_access_key_id: @aws_access_key_id, aws_secret_access_key: @aws_secret_access_key)
50
+ else
51
+ ValueCryptor::Simple.new(@passphrase, @sign_passphrase, @salt, @cipher, @digest)
52
+ end
53
+ end
54
+
55
+ def process_yaml
56
+ data = YAML.load(ERB.new(File.read(@yaml)).result)
57
+ @keys.each do |key|
26
58
  target = key.inject(data) do |t, part|
27
59
  t[part]
28
60
  end
29
61
 
30
- vault_data = yield cryptor, target
62
+ vault_data = yield target
31
63
 
32
64
  target_parent = key[0..-2].inject(data) do |t, part|
33
65
  t[part]
@@ -37,42 +69,74 @@ module YamlVault
37
69
  data.to_yaml
38
70
  end
39
71
 
40
- def do_process(cryptor, data, method)
72
+ def do_process(data, method)
41
73
  case data
42
74
  when Hash
43
75
  data.each do |k, v|
44
76
  if v.is_a?(Hash) || v.is_a?(Array)
45
- do_process(cryptor, v, method)
77
+ do_process(v, method)
46
78
  else
47
- data[k] = cryptor.send(method, v)
79
+ data[k] = @cryptor.send(method, v)
48
80
  end
49
81
  end
50
82
  when Array
51
83
  data.each_with_index do |v, i|
52
84
  if v.is_a?(Hash) || v.is_a?(Array)
53
- do_process(cryptor, v, method)
85
+ do_process(v, method)
54
86
  else
55
- data[i] = cryptor.send(method, v)
87
+ data[i] = @cryptor.send(method, v)
56
88
  end
57
89
  end
58
90
  else
59
- cryptor.send(method, data)
91
+ @cryptor.send(method, data)
60
92
  end
61
93
  end
62
- end
63
94
 
64
- class ValueCryptor
65
- def initialize(passphrase, salt, cipher)
66
- key = ActiveSupport::KeyGenerator.new(passphrase, cipher: cipher || 'aes-256-cbc').generate_key(salt)
67
- @cryptor = ActiveSupport::MessageEncryptor.new(key)
68
- end
95
+ module ValueCryptor
96
+ class Simple
97
+ def initialize(passphrase, sign_passphrase, salt, cipher, digest, key_size = 64)
98
+ key = ActiveSupport::KeyGenerator.new(passphrase).generate_key(salt, key_size)
99
+ signature_key = ActiveSupport::KeyGenerator.new(sign_passphrase).generate_key(salt, key_size) if sign_passphrase
69
100
 
70
- def encrypt(value)
71
- @cryptor.encrypt_and_sign(value)
72
- end
101
+ if signature_key
102
+ @cryptor = ActiveSupport::MessageEncryptor.new(key, signature_key, cipher: cipher, digest: digest)
103
+ else
104
+ @cryptor = ActiveSupport::MessageEncryptor.new(key, cipher: cipher, digest: digest)
105
+ end
106
+ end
107
+
108
+ def encrypt(value)
109
+ @cryptor.encrypt_and_sign(value)
110
+ end
73
111
 
74
- def decrypt(value)
75
- @cryptor.decrypt_and_verify(value)
112
+ def decrypt(value)
113
+ @cryptor.decrypt_and_verify(value)
114
+ end
115
+ end
116
+
117
+ class KMS
118
+ def initialize(key_id, region: nil, aws_access_key_id: nil, aws_secret_access_key: nil)
119
+ require 'aws-sdk'
120
+ options = {}
121
+ options[:region] = region if region
122
+ options[:access_key_id] = aws_access_key_id if aws_access_key_id
123
+ options[:secret_access_key] = aws_secret_access_key if aws_secret_access_key
124
+ @client = Aws::KMS::Client.new(options)
125
+ @key_id = key_id
126
+ end
127
+
128
+ def encrypt(value)
129
+ resp = @client.encrypt(key_id: @key_id, plaintext: YAML.dump(value))
130
+ Base64.strict_encode64(resp.ciphertext_blob)
131
+ end
132
+
133
+ def decrypt(value)
134
+ resp = @client.decrypt(ciphertext_blob: Base64.strict_decode64(value))
135
+ YAML.load(resp.plaintext)
136
+ end
137
+ end
76
138
  end
139
+
140
+ private_constant :ValueCryptor
77
141
  end
78
142
  end
data/yaml_vault.gemspec CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.add_runtime_dependency "activesupport", ">= 4"
22
22
  spec.add_runtime_dependency "thor"
23
23
 
24
+ spec.add_development_dependency "aws-sdk", "~> 2.0"
24
25
  spec.add_development_dependency "bundler", "~> 1.11"
25
26
  spec.add_development_dependency "rake", "~> 10.0"
26
27
  spec.add_development_dependency "rspec", "~> 3.0"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yaml_vault
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joker1007
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-30 00:00:00.000000000 Z
11
+ date: 2016-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: aws-sdk
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement