itamae-secrets 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: df379b9fa313eb7a3516694a0efc764d086d23cf
4
+ data.tar.gz: 08e47d784901105a67f80ac1b1340e61e8e6524a
5
+ SHA512:
6
+ metadata.gz: bffd0e6a9b7def10679ef9783cbc908cc909e1cfa778463a31f3a25eec6afc630c270fc92445c2caa6dde0802df4529231211b46e07d708dcc2393d6fa86a446
7
+ data.tar.gz: 740a9e5f8bd2d130769b94a7399aad5769d9631a2b1cdb79a8a6e29dacbc9025027e48ce9c74f6613257d225436f522d8fefaef3034fbe851a6e4caec54cc7d9
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.10.5
data/CONTRIBUTING.md ADDED
@@ -0,0 +1 @@
1
+ __Security issues?__ Send me directly at `security@sorah.jp`. My GPG key is available here: <http://sorah.jp/id.html> ([SSL](https://github.com/sorah/sorah.jp/tree/master/source/pgp-pubkeys))
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in itamae-secrets.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Shota Fukumori (sora_h)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,92 @@
1
+ # Itamae::Secrets - Encrypted Data Bag for Itamae
2
+
3
+ This is [itamae](https://github.com/itamae-kitchen/itamae) plugin that provides store for secrets, like encrypted data bag in chef.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ gem 'itamae-secrets'
9
+ ```
10
+
11
+ or
12
+
13
+ ```
14
+ $ gem install itamae-secrets
15
+ ```
16
+
17
+ ## Basic
18
+
19
+ - `itamae-secrets` command for storing data or manually reading
20
+ - specify base directory to `--base` option
21
+ - you should exclude `${base}/keys` from checking into VCS. (`.gitignore` it!)
22
+
23
+ ## Walkthrough
24
+
25
+ ### Generate a key
26
+
27
+ ##### randomly
28
+
29
+ ```
30
+ $ itamae-secrets newkey --base=./secret --method=aes-random
31
+ ```
32
+
33
+ ##### from passphrase
34
+
35
+ ```
36
+ $ itamae-secrets newkey --base=./secret --method=aes-passphrase
37
+ ```
38
+
39
+ Both generates `./secret/keys/default`. Make sure `./secret/keys` be excluded from VCS.
40
+
41
+ ### Store value
42
+
43
+ ```
44
+ $ itamae-secrets set --base=./secret awesome_secret value
45
+ ```
46
+
47
+ (when omit `value`, it'll read from STDIN until EOF. You can also use `--noecho` if you want hide value in your terminal's buffer completely.)
48
+
49
+ ### Reading data from itamae
50
+
51
+ on your itamae recipe, do:
52
+
53
+ ``` ruby
54
+ require 'itamae/secrets'
55
+ node[:secrets] = Itamae::Secrets(File.join(__dir__, 'secrets'))
56
+
57
+ # Use it
58
+ p node[:secrets][:awesome_secret]
59
+ ```
60
+
61
+ ### Reading data fro CLI
62
+
63
+ ```
64
+ $ itamae-secrets get --base=./secret awesome_secret
65
+ ```
66
+
67
+ ### Remembering `--base`
68
+
69
+ ```
70
+ $ echo 'base: ./secret' >> .itamae-secrets.yml
71
+ ```
72
+
73
+ ## Development
74
+
75
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
76
+
77
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
78
+
79
+ ## Contributing
80
+
81
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sorah/itamae-secrets.
82
+
83
+ __Security issues?__ Send me directly at `security@sorah.jp`. My GPG key is available here: <http://sorah.jp/id.html> ([SSL](https://github.com/sorah/sorah.jp/tree/master/source/pgp-pubkeys))
84
+
85
+
86
+ ## License
87
+
88
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
89
+
90
+ ## To-dos
91
+
92
+ - [ ] Missing test :(
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'itamae/secrets/cli'
3
+
4
+ Itamae::Secrets::Cli.start
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'itamae/secrets/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "itamae-secrets"
8
+ spec.version = Itamae::Secrets::VERSION
9
+ spec.authors = ["Shota Fukumori (sora_h)"]
10
+ spec.email = ["her@sorah.jp"]
11
+
12
+ spec.summary = %q{Encrypted Data Bag for itamae}
13
+ spec.homepage = "https://github.com/sorah/itamae-secrets"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "bin"
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'thor'
22
+
23
+ spec.add_development_dependency "bundler"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec"
26
+ end
@@ -0,0 +1,12 @@
1
+ require "itamae/secrets/version"
2
+ require "itamae/secrets/store"
3
+
4
+ module Itamae
5
+ def self.Secrets(*args)
6
+ Itamae::Secrets::Store.new *args
7
+ end
8
+
9
+ module Secrets
10
+ end
11
+
12
+ end
@@ -0,0 +1,63 @@
1
+ require 'openssl'
2
+ require 'json'
3
+
4
+ module Itamae
5
+ module Secrets
6
+ class AesKey
7
+ AES1_KEY_LEN = OpenSSL::Cipher.new('aes-256-gcm').key_len
8
+
9
+ def self.key_len_for_type(type)
10
+ case type
11
+ when 'aes1'
12
+ AES1_KEY_LEN
13
+ else
14
+ raise ArgumentError, "unknown type #{type.inspect}"
15
+ end
16
+ end
17
+
18
+ def self.generate_random(name)
19
+ key_len = key_len_for_type('aes1')
20
+ new name, 'aes1', OpenSSL::Random.random_bytes(key_len)
21
+ end
22
+
23
+ def self.generate_pkcs5(name, passphrase)
24
+ key_len = key_len_for_type('aes1')
25
+
26
+ salt = OpenSSL::Digest::SHA256.digest(name)
27
+ key = OpenSSL::PKCS5.pbkdf2_hmac(passphrase, salt, 30000, key_len, OpenSSL::Digest::SHA256.new)
28
+
29
+ new name, 'aes1', key
30
+ end
31
+
32
+ def self.load_json(json)
33
+ data = JSON.parse(json)
34
+ new(data['name'], data['type'], data['key'].unpack('m*')[0])
35
+ end
36
+
37
+ def initialize(name, type, key)
38
+ raise ArgumentError, "name must not contain slashes, commas, backslackes" if name.include?("\\") || name.include?(?/) || name.include?(?:)
39
+ @name = name
40
+ @type = type
41
+ @key = key
42
+ end
43
+
44
+ attr_reader :name, :type, :key
45
+
46
+ def algorithm_compatible?(algorithm)
47
+ algorithm == 'aes-256-gcm'
48
+ end
49
+
50
+ def to_s
51
+ key
52
+ end
53
+
54
+ def to_json
55
+ {
56
+ name: name,
57
+ type: type,
58
+ key: [key].pack('m*'),
59
+ }.to_json
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,120 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+ require 'pathname'
4
+
5
+ require 'itamae/secrets/aes_key'
6
+ require 'itamae/secrets/store'
7
+
8
+ module Itamae
9
+ module Secrets
10
+ class Cli < Thor
11
+ class_option :base, type: :string, desc: 'path to base directory for storing secrets and keys'
12
+
13
+
14
+ desc 'newkey [KEYNAME]', 'generate then save key'
15
+ method_option :method, type: :string, required: true, desc: 'generating method (aes-file, aes-passphrase)'
16
+ method_option :confirm_passphrase, type: :boolean, default: true, desc: 'Confirm passphrase when asking'
17
+
18
+ def newkey(name='default')
19
+ if keychain.exist?(name)
20
+ raise ArgumentError, "key #{name} already exists"
21
+ end
22
+
23
+ key = case options[:method] || config['generate_method']
24
+ when 'aes-random'
25
+ AesKey.generate_random(name)
26
+ when 'aes-passphrase'
27
+ passphrase = ask_noecho('Passphrase:', true)
28
+ AesKey.generate_pkcs5(name, passphrase)
29
+ else
30
+ raise ArgumentError, "Unknown method: #{name.inspect}"
31
+ end
32
+
33
+ keychain.save(key)
34
+ end
35
+
36
+ desc 'set VARNAME [VALUE]', 'store value (when VALUE is omitted, read from STDIN)'
37
+ method_option :key, type: :string, default: 'default', desc: 'key name'
38
+ method_option :noecho, type: :boolean, desc: 'Ask one-line value with noecho when stdin is tty'
39
+ def set(name, value = nil)
40
+ value ||= if options[:noecho]
41
+ ask_noecho("#{name}:", false)
42
+ else
43
+ $stdin.read.chomp
44
+ end
45
+
46
+ store.store(name, value, options[:key])
47
+ end
48
+
49
+ desc 'get VARNAME', 'read value'
50
+ def get(name)
51
+ value = store[name]
52
+ if value
53
+ puts value
54
+ else
55
+ exit 1
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def store
62
+ @store ||= Store.new base_dir
63
+ end
64
+
65
+ def keychain
66
+ store.keychain
67
+ end
68
+
69
+ def base_dir
70
+ unless config['base']
71
+ raise ArgumentError, 'Missing --base'
72
+ end
73
+ Pathname.new config['base']
74
+ end
75
+
76
+ def config
77
+ @config ||= config_file.merge(
78
+ 'base' => config_file['base'] || options[:base],
79
+ )
80
+ end
81
+
82
+ def config_file
83
+ @config_file ||= if File.exist?('./.itamae-secrets.yml')
84
+ YAML.load_file('./.itamae-secrets.yml')
85
+ else
86
+ {}
87
+ end
88
+ end
89
+
90
+ def ask_noecho(prompt, confirm = true)
91
+ io_console = false
92
+ begin
93
+ require 'io/console'
94
+ io_console = true
95
+ rescue LoadError
96
+ end
97
+
98
+ get = -> do
99
+ if $stdin.tty?
100
+ $stdin.noecho { $stdin.gets.chomp }
101
+ else
102
+ $stdin.gets.chomp
103
+ end
104
+ end
105
+
106
+ loop do
107
+ $stdout.print "#{prompt} "
108
+ value = get.call
109
+
110
+ break value unless confirm
111
+
112
+ $stdout.print "(confirm) #{prompt} "
113
+ break value if value == get.call
114
+
115
+ $stderr.puts "Confirmation didn't match..."
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,77 @@
1
+ require 'openssl'
2
+
3
+ module Itamae
4
+ module Secrets
5
+ class Decryptor
6
+ ALGORITHM = 'aes-256-gcm'
7
+
8
+ def self.load_json(json, key = nil)
9
+ data = JSON.parse(json)
10
+
11
+ raise ArgumentError, "unknown version #{data['version'].inspect}" if data['version'] != 1
12
+ raise ArgumentError, "unknown version #{data['algorithm'].inspect}" if data['algorithm'] != ALGORITHM
13
+
14
+ new(
15
+ data['ciphertext'],
16
+ data['auth_tag'],
17
+ data['iv'],
18
+ data['key_name'],
19
+ key
20
+ )
21
+ end
22
+
23
+ def initialize(ciphertext, auth_tag, iv, key_name, key = nil)
24
+ ensure_algorithm_key_compatiblity!(key) if key
25
+ @ciphertext = ciphertext
26
+ @auth_tag = auth_tag
27
+ @iv = iv
28
+ @key_name = key_name
29
+ @key = key
30
+ end
31
+
32
+ attr_reader :ciphertext, :auth_tag, :iv, :key_name
33
+ attr_accessor :key
34
+
35
+ def key=(other)
36
+ raise "can't overwrite" if @key
37
+ ensure_algorithm_key_compatiblity!(other)
38
+ @key = other
39
+ end
40
+
41
+ def plaintext
42
+ @plaintext ||= begin
43
+ txt = cipher.update(ciphertext.unpack('m*')[0])
44
+ txt << cipher.final
45
+ end
46
+ end
47
+
48
+ def version
49
+ 1
50
+ end
51
+
52
+ def algorithm
53
+ ALGORITHM
54
+ end
55
+
56
+ def cipher
57
+ @cipher ||= OpenSSL::Cipher.new(algorithm).tap do |c|
58
+ raise 'key is required to proceed' unless key
59
+ c.decrypt
60
+ c.key = key.to_s
61
+ c.iv = iv.unpack('m*')[0]
62
+ c.auth_data = ''
63
+ c.auth_tag = auth_tag.unpack('m*')[0]
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def ensure_algorithm_key_compatiblity!(key)
70
+ unless key.algorithm_compatible?(algorithm)
71
+ raise ArgumentError, "#{key.type} is not compatible"
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+
@@ -0,0 +1,86 @@
1
+ require 'openssl'
2
+
3
+ module Itamae
4
+ module Secrets
5
+ class Encryptor
6
+ ALGORITHM = 'aes-256-gcm'
7
+
8
+ def initialize(plaintext, key = nil, iv = nil)
9
+ ensure_algorithm_key_compatiblity!(key) if key
10
+ @key = key
11
+ @iv = iv
12
+ @plaintext = plaintext
13
+ end
14
+
15
+ attr_reader :key, :plaintext
16
+
17
+ def key=(other)
18
+ raise "can't overwrite" if @key
19
+ ensure_algorithm_key_compatiblity!(other)
20
+ @key = other
21
+ end
22
+
23
+ def to_s
24
+ {
25
+ version: version,
26
+ algorithm: algorithm,
27
+ key_name: key.name,
28
+ ciphertext: ciphertext,
29
+ iv: iv,
30
+ auth_tag: auth_tag,
31
+ }.to_json
32
+ end
33
+
34
+ alias data to_s
35
+
36
+ def ciphertext
37
+ @ciphertext ||= begin
38
+ data = cipher.update(plaintext)
39
+ data << cipher.final
40
+ @auth_tag = cipher.auth_tag
41
+ [data].pack('m*')
42
+ end
43
+ end
44
+
45
+ def iv
46
+ @iv && [@iv].pack('m*')
47
+ end
48
+
49
+ def auth_tag
50
+ if @auth_tag
51
+ [@auth_tag].pack('m*')
52
+ else
53
+ raise '[BUG] auth_tag not exists'
54
+ end
55
+ end
56
+
57
+ def version
58
+ 1
59
+ end
60
+
61
+ def algorithm
62
+ ALGORITHM
63
+ end
64
+
65
+ def cipher
66
+ @cipher ||= OpenSSL::Cipher.new(algorithm).tap do |c|
67
+ raise 'key is required to proceed' unless key
68
+ c.encrypt
69
+ c.key = key.to_s
70
+ # XXX: avoid generate IV here, but consider if extract to a method like #iv, it have to know Cipher#iv_len...
71
+ @iv ||= c.random_iv
72
+ c.iv = @iv
73
+ c.auth_data = ''
74
+ end
75
+ end
76
+
77
+ private
78
+
79
+ def ensure_algorithm_key_compatiblity!(key)
80
+ unless key.algorithm_compatible?(algorithm)
81
+ raise ArgumentError, "#{key.type} is not compatible"
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,32 @@
1
+ require 'pathname'
2
+ require 'itamae/secrets/aes_key'
3
+
4
+ module Itamae
5
+ module Secrets
6
+ class Keychain
7
+ class KeyNotFound < StandardError; end
8
+
9
+ def initialize(path)
10
+ @path = Pathname.new(path)
11
+ end
12
+
13
+ attr_reader :path
14
+
15
+ def exist?(name)
16
+ @path.join(name).exist?
17
+ end
18
+
19
+ def load(name)
20
+ AesKey.load_json @path.join(name).read
21
+ rescue File::ENOENT
22
+ raise KeyNotFound, "Couldn't find key #{name.inspect}"
23
+ end
24
+
25
+ def save(key)
26
+ open(@path.join(key.name), 'w', 0600) do |io|
27
+ io.puts key.to_json
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,81 @@
1
+ require 'pathname'
2
+
3
+ require 'itamae/secrets/keychain'
4
+ require 'itamae/secrets/encryptor'
5
+ require 'itamae/secrets/decryptor'
6
+
7
+ module Itamae
8
+ module Secrets
9
+ class Store
10
+ def initialize(base_dir)
11
+ @base_dir = Pathname.new(base_dir)
12
+ ensure_base_dir!
13
+ end
14
+
15
+ attr_reader :base_dir
16
+
17
+ def keychain_path
18
+ base_dir.join('keys')
19
+ end
20
+
21
+ def values_path
22
+ base_dir.join('values')
23
+ end
24
+
25
+ def keychain
26
+ @keychain ||= Keychain.new(keychain_path)
27
+ end
28
+
29
+ def [](name)
30
+ name = name.to_s
31
+ validate_name!(name)
32
+
33
+ value_path = values_path.join(name)
34
+
35
+ if value_path.exist?
36
+ encrypted_data = Decryptor.load_json(value_path.read)
37
+ encrypted_data.key = keychain.load(encrypted_data.key_name)
38
+ JSON.parse(encrypted_data.plaintext)['value']
39
+ else
40
+ nil
41
+ end
42
+ end
43
+
44
+ def []=(*args)
45
+ case args.size
46
+ when 2
47
+ store(*args)
48
+ when 3
49
+ store(args[0], args[2], args[1])
50
+ else
51
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 2..3)"
52
+ end
53
+ end
54
+
55
+ def store(name, value, key = 'default')
56
+ name = name.to_s
57
+ validate_name!(name)
58
+ value_path = values_path.join(name)
59
+
60
+ encrypted_data = Encryptor.new({value: value}.to_json, keychain.load(key))
61
+
62
+ open(value_path, 'w', 0600) do |io|
63
+ io.puts encrypted_data.to_s
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def ensure_base_dir!
70
+ base_dir.mkpath
71
+ base_dir.join('keys').mkpath
72
+ base_dir.join('values').mkpath
73
+ end
74
+
75
+ def validate_name!(name)
76
+ # XXX: dupe
77
+ raise ArgumentError, "name must not contain slashes, commas, backslackes" if name.include?("\\") || name.include?(?/) || name.include?(?:)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,5 @@
1
+ module Itamae
2
+ module Secrets
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
data/script/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "itamae/secrets"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/script/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: itamae-secrets
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shota Fukumori (sora_h)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-08-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - her@sorah.jp
72
+ executables:
73
+ - itamae-secrets
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rspec"
79
+ - ".travis.yml"
80
+ - CONTRIBUTING.md
81
+ - Gemfile
82
+ - LICENSE.txt
83
+ - README.md
84
+ - Rakefile
85
+ - bin/itamae-secrets
86
+ - itamae-secrets.gemspec
87
+ - lib/itamae/secrets.rb
88
+ - lib/itamae/secrets/aes_key.rb
89
+ - lib/itamae/secrets/cli.rb
90
+ - lib/itamae/secrets/decryptor.rb
91
+ - lib/itamae/secrets/encryptor.rb
92
+ - lib/itamae/secrets/keychain.rb
93
+ - lib/itamae/secrets/store.rb
94
+ - lib/itamae/secrets/version.rb
95
+ - script/console
96
+ - script/setup
97
+ homepage: https://github.com/sorah/itamae-secrets
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.4.5
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Encrypted Data Bag for itamae
121
+ test_files: []