dynamo_secret 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/LICENSE +21 -0
- data/README.md +46 -0
- data/bin/dynamo_secret +5 -0
- data/lib/dynamo_secret/cli.rb +98 -0
- data/lib/dynamo_secret/dynamodb.rb +70 -0
- data/lib/dynamo_secret/gpg.rb +24 -0
- data/lib/dynamo_secret/iam.rb +8 -0
- data/lib/dynamo_secret/kms.rb +49 -0
- data/lib/dynamo_secret/secret.rb +97 -0
- data/lib/dynamo_secret/version.rb +3 -0
- data/lib/dynamo_secret.rb +14 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eceed7ab952b1bfb775f44552c484acd65854864
|
4
|
+
data.tar.gz: 8c1b80312dedd3e880bcbff04ad3836cb577e56e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6ac8d52f9f3d97d0d4b7d921454484d533858021624d618b673f2b06e45c2f42e0f416cea761e20542a71b2f123d9e91262e589ba7513c36ac19a217f76ddc24
|
7
|
+
data.tar.gz: 29eb552532e791d797ca5db55397950e9552bd66f6d74a33cdd0a076222320e28ebb947e6ae66ffbf5f2e8107daf553d611bc516abf6907e9ef4779b8a6afc1e
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2017 Robert Bayerl
|
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 all
|
13
|
+
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 THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# dynamo_secret
|
2
|
+
Ruby gem for encrypting secrets with [GnuPG](https://gnupg.org/) and/or
|
3
|
+
[KMS](https://aws.amazon.com/kms/) and storing them in
|
4
|
+
[DynamoDB](https://aws.amazon.com/dynamodb/).
|
5
|
+
|
6
|
+
## Usage
|
7
|
+
`dynamo_secret` can be used to store, fetch, update, and delete encrypted
|
8
|
+
information. It is intended to be used as a remote password store, but could be
|
9
|
+
used for other things as well. Data is organized by site, and can contain
|
10
|
+
almost anything.
|
11
|
+
Usage:
|
12
|
+
```
|
13
|
+
dynamo_secret -l|--list
|
14
|
+
dynamo_secret -i|--init [-k|--kms]
|
15
|
+
dynamo_secret -g|--get [site] [key1,key2,...]
|
16
|
+
dynamo_secret -a|--add [site] [key1,key2,...] [val1,val2,...]
|
17
|
+
dynamo_secret -u|--update [site] [key1,key2,...] [val1,val2,...]
|
18
|
+
dynamo_secret -d|--delete [site]
|
19
|
+
```
|
20
|
+
|
21
|
+
### List
|
22
|
+
`dynamo_secret -l` will list all of the sites stored in the DynamoDB table.
|
23
|
+
|
24
|
+
### Init
|
25
|
+
Before storing secrets the table needs to be created. `dynamo_secret -i [-k]`
|
26
|
+
will create the table. If the optional `-k` flag is supplied a KMS key will
|
27
|
+
also be created. KMS keys do not qualify for free tier usage and will cost $1
|
28
|
+
or more per month.
|
29
|
+
|
30
|
+
### Get
|
31
|
+
`dynamo_secret -g|--get [site] [key1,key2,...]` will retreive and decrypt
|
32
|
+
information stored under the specified site. Specific fields (keys) can also
|
33
|
+
be specified if not all fields are wanted or required.
|
34
|
+
|
35
|
+
### Add
|
36
|
+
`dynamo_secret -a|--add [site] [key1,key2,...] [val1,val2,...]` stores key
|
37
|
+
value pairs under `site`. Values may be omitted to keep them out of history
|
38
|
+
files, or `-` may be used for extra sensitive secrets.
|
39
|
+
|
40
|
+
### Update
|
41
|
+
`dynamo_secret -u|--update` works exactly like `--put`, but it replaces the
|
42
|
+
specified key value pairs while keeping anything else.
|
43
|
+
|
44
|
+
### Delete
|
45
|
+
`dynamo_secret -d|--delete [site]` completely removes all records under `site`
|
46
|
+
from the DynamoDB table.
|
data/bin/dynamo_secret
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
module DynamoSecret
|
2
|
+
class CLI
|
3
|
+
def initialize(args)
|
4
|
+
@args = args
|
5
|
+
end
|
6
|
+
|
7
|
+
def run
|
8
|
+
load_config
|
9
|
+
parse_args(@args)
|
10
|
+
perform_action
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def ask_key_pairs(keys, values)
|
16
|
+
keys = keys.to_s.split(',')
|
17
|
+
values = values.to_s.split(',')
|
18
|
+
if keys.empty?
|
19
|
+
loop do
|
20
|
+
key = ask('Key [ENTER to quit]: ')
|
21
|
+
break if key == ''
|
22
|
+
keys << key
|
23
|
+
end
|
24
|
+
end
|
25
|
+
keys.map.with_index do |key, index|
|
26
|
+
{ key => values[index].nil? || values[index] == '-' ? ask("Value for #{key}: ") : values[index] }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def ask_secret_data
|
31
|
+
if @args.count > 3
|
32
|
+
$stderr.puts usage
|
33
|
+
exit 1
|
34
|
+
else
|
35
|
+
@config[:secret_data][site] = ask_key_pairs(@args.shift, @args.shift)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def load_config
|
40
|
+
config_file = "#{ENV['HOME']}/.dynamo_secret.yml"
|
41
|
+
@config = File.exist?(config_file) ? YAML.load_file(config_file) : {}
|
42
|
+
@config[:secret_data] = {}
|
43
|
+
end
|
44
|
+
|
45
|
+
def parse_args(args)
|
46
|
+
OptionParser.new do |opts|
|
47
|
+
opts.banner = usage
|
48
|
+
opts.version = VERSION
|
49
|
+
opts.on('-l', '--list', 'List all sites stored in table') { |_l| @action = 'list' }
|
50
|
+
opts.on('-i', '--init', 'Set up DynamoDB and KMS') { |_i| @action = 'init' }
|
51
|
+
opts.on('-g', '--get', 'Get a secret') { |_g| @action = 'get' }
|
52
|
+
opts.on('-a', '--add', 'Add a new secret') { |_a| @action = 'put' }
|
53
|
+
opts.on('-u', '--update', 'Update an existing secret') { |_u| @action = 'update' }
|
54
|
+
opts.on('-d', '--delete', 'Remove site from table') { |_d| @action = 'delete' }
|
55
|
+
opts.on('-k', '--kms', 'Enable KMS key creation (init only)') { |k| @config[:enable_kms] = k }
|
56
|
+
end.parse!(args)
|
57
|
+
@args = args
|
58
|
+
end
|
59
|
+
|
60
|
+
def perform_action
|
61
|
+
case @action
|
62
|
+
when 'init'
|
63
|
+
Secret.new(@config).setup
|
64
|
+
when 'get'
|
65
|
+
@config[:secret_data][site] = []
|
66
|
+
Secret.new(@config).get(@args.shift)
|
67
|
+
when 'put'
|
68
|
+
ask_secret_data
|
69
|
+
Secret.new(@config).put
|
70
|
+
when 'update'
|
71
|
+
ask_secret_data
|
72
|
+
Secret.new(@config).update
|
73
|
+
when 'delete'
|
74
|
+
@config[:secret_data][site] = []
|
75
|
+
Secret.new(@config).delete
|
76
|
+
when 'list'
|
77
|
+
DynamoDB.new(@config).list_secrets
|
78
|
+
else
|
79
|
+
$stderr.puts usage
|
80
|
+
exit 1
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def site
|
85
|
+
@site ||= @args.any? ? @args.shift : ask('Site: ')
|
86
|
+
end
|
87
|
+
|
88
|
+
def usage
|
89
|
+
'Usage:
|
90
|
+
dynamo_secret -l|--list
|
91
|
+
dynamo_secret -i|--init [-k|--kms]
|
92
|
+
dynamo_secret -g|--get [site] [key1,key2,...]
|
93
|
+
dynamo_secret -a|--add [site] [key1,key2,...] [val1,val2,...]
|
94
|
+
dynamo_secret -u|--update [site] [key1,key2,...] [val1,val2,...]
|
95
|
+
dynamo_secret -d|--delete [site]'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module DynamoSecret
|
2
|
+
class DynamoDB
|
3
|
+
def initialize(config)
|
4
|
+
@table_name = config[:table_name] || table_name
|
5
|
+
@region = config.fetch(:region, region)
|
6
|
+
@secret_data = config.fetch(:secret_data, {})
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_table
|
10
|
+
client.create_table(
|
11
|
+
attribute_definitions: [{ attribute_name: 'Site', attribute_type: 'S' }],
|
12
|
+
table_name: @table_name,
|
13
|
+
key_schema: [{ attribute_name: 'Site', key_type: 'HASH' }],
|
14
|
+
provisioned_throughput: {
|
15
|
+
read_capacity_units: 25,
|
16
|
+
write_capacity_units: 25
|
17
|
+
}
|
18
|
+
)
|
19
|
+
$stdout.puts "Created new table: #{@table_name}"
|
20
|
+
rescue Aws::DynamoDB::Errors::ResourceInUseException
|
21
|
+
$stderr.puts "Table #{@table_name} already exists"
|
22
|
+
end
|
23
|
+
|
24
|
+
def delete
|
25
|
+
client.delete_item(
|
26
|
+
key: {
|
27
|
+
'Site' => @secret_data.map { |k, _v| k }.first
|
28
|
+
},
|
29
|
+
table_name: @table_name
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_secret
|
34
|
+
client.get_item(
|
35
|
+
key: {
|
36
|
+
'Site' => @secret_data.map { |k, _v| k }.first
|
37
|
+
},
|
38
|
+
table_name: @table_name
|
39
|
+
).item
|
40
|
+
rescue Aws::DynamoDB::Errors::ResourceNotFoundException
|
41
|
+
$stderr.puts "Table #{@table_name} not found"
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def list_secrets
|
46
|
+
client.scan(table_name: @table_name).items.each { |item| $stdout.puts item['Site'] }
|
47
|
+
end
|
48
|
+
|
49
|
+
def put_secret(secret_data)
|
50
|
+
client.put_item(
|
51
|
+
item: secret_data,
|
52
|
+
table_name: @table_name
|
53
|
+
)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def client
|
59
|
+
@client ||= Aws::DynamoDB::Client.new(region: @region)
|
60
|
+
end
|
61
|
+
|
62
|
+
def region
|
63
|
+
ENV.fetch('AWS_REGION', 'us-west-2')
|
64
|
+
end
|
65
|
+
|
66
|
+
def table_name
|
67
|
+
"dynamo_secret_#{IAM.new.user_id}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module DynamoSecret
|
2
|
+
class Gpg
|
3
|
+
def decrypt(data)
|
4
|
+
crypto.decrypt(data).read
|
5
|
+
rescue GPGME::Error::NoData
|
6
|
+
$stderr.puts 'Key was found but GPG decrypt failed - skipping'
|
7
|
+
data
|
8
|
+
end
|
9
|
+
|
10
|
+
def encrypt(data)
|
11
|
+
crypto.encrypt(data, recipients: [key.uids.first.name]).read
|
12
|
+
end
|
13
|
+
|
14
|
+
def key
|
15
|
+
@gpg_key ||= GPGME::Key.find(:secret).map { |k| k if k.expires > Date.today.to_time }.first
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def crypto
|
21
|
+
@crypto ||= GPGME::Crypto.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module DynamoSecret
|
2
|
+
class Kms
|
3
|
+
def initialize(config)
|
4
|
+
@key_name = config[:key_name] || key_name
|
5
|
+
@region = config.fetch(:region, region)
|
6
|
+
end
|
7
|
+
|
8
|
+
def create_key
|
9
|
+
return $stdout.puts "KMS alias #{@key_name} already exists" if key
|
10
|
+
id = client.create_key(tags: [{ tag_key: 'Owner', tag_value: user_id }]).key_metadata.key_id
|
11
|
+
client.create_alias(alias_name: "alias/#{@key_name}", target_key_id: id)
|
12
|
+
end
|
13
|
+
|
14
|
+
def decrypt(data)
|
15
|
+
client.decrypt(ciphertext_blob: data).plaintext
|
16
|
+
rescue Aws::KMS::Errors::InvalidCiphertextException
|
17
|
+
$stderr.puts 'Key was found but KMS decrypt failed - skipping'
|
18
|
+
data
|
19
|
+
end
|
20
|
+
|
21
|
+
def encrypt(data)
|
22
|
+
client.encrypt(key_id: key, plaintext: data).ciphertext_blob
|
23
|
+
end
|
24
|
+
|
25
|
+
def key
|
26
|
+
@key ||= client.list_aliases.aliases.map do |kms_alias|
|
27
|
+
kms_alias.target_key_id if kms_alias.alias_name == "alias/#{@key_name}"
|
28
|
+
end.compact.first
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def client
|
34
|
+
@client ||= Aws::KMS::Client.new(region: @region)
|
35
|
+
end
|
36
|
+
|
37
|
+
def key_name
|
38
|
+
"dynamo_secret_#{user_id}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def region
|
42
|
+
ENV.fetch('AWS_REGION', 'us-west-2')
|
43
|
+
end
|
44
|
+
|
45
|
+
def user_id
|
46
|
+
@user_id ||= IAM.new.user_id
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module DynamoSecret
|
2
|
+
class Secret
|
3
|
+
def initialize(config)
|
4
|
+
@config = config
|
5
|
+
end
|
6
|
+
|
7
|
+
def delete
|
8
|
+
resp = ask("Really delete #{site}? (y/N) ")
|
9
|
+
return unless resp.casecmp('y')
|
10
|
+
dynamodb.delete
|
11
|
+
$stdout.puts "#{site} deleted"
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(fields)
|
15
|
+
secret = dynamodb.fetch_secret
|
16
|
+
return decrypt(secret, fields) if secret
|
17
|
+
$stderr.puts "Could not find record for #{site}"
|
18
|
+
exit 1
|
19
|
+
end
|
20
|
+
|
21
|
+
def put
|
22
|
+
if gpg.key.nil? && kms.key.nil?
|
23
|
+
$stderr.puts 'Refusing to store secrets in plain text'
|
24
|
+
exit 1
|
25
|
+
elsif dynamodb.fetch_secret
|
26
|
+
$stderr.puts "Site #{site} already exists"
|
27
|
+
exit 1
|
28
|
+
else
|
29
|
+
secret = encrypt
|
30
|
+
dynamodb.put_secret(secret)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def setup
|
35
|
+
dynamodb.create_table
|
36
|
+
kms.create_key unless @config.fetch(:enable_kms, nil).nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def update
|
40
|
+
secret = dynamodb.fetch_secret.merge(encrypt)
|
41
|
+
dynamodb.put_secret(secret)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def decode(data)
|
47
|
+
data = Base64.decode64(data)
|
48
|
+
data = kms.decrypt(data) if kms.key
|
49
|
+
data = gpg.decrypt(data) if gpg.key
|
50
|
+
data
|
51
|
+
end
|
52
|
+
|
53
|
+
def decrypt(data, fields)
|
54
|
+
headers = [['Key', 'Value'], ['---', '-----']]
|
55
|
+
fields ||= [['Site', data['Site']]] + data.map { |k, v| [k, decode(v)] unless k == 'Site' }.compact
|
56
|
+
output = if fields.is_a?(Array)
|
57
|
+
headers + fields
|
58
|
+
else
|
59
|
+
headers + data.map { |k, v| [k, decode(v)] if fields.include?(k) }.compact
|
60
|
+
end
|
61
|
+
widths = output.transpose.map { |x| x.map(&:length).max }.map { |w| "%-#{w}s" }.join(' ')
|
62
|
+
output.each { |line| $stdout.puts widths % line }
|
63
|
+
end
|
64
|
+
|
65
|
+
def encode(data)
|
66
|
+
data = gpg.encrypt(data) if gpg.key
|
67
|
+
data = kms.encrypt(data) if kms.key
|
68
|
+
Base64.encode64(data)
|
69
|
+
end
|
70
|
+
|
71
|
+
def dynamodb
|
72
|
+
@dynamodb ||= DynamoDB.new(@config)
|
73
|
+
end
|
74
|
+
|
75
|
+
def encrypt
|
76
|
+
encrypted_data = {
|
77
|
+
'Site' => site
|
78
|
+
}
|
79
|
+
@config[:secret_data][site].each do |kv|
|
80
|
+
kv.map { |k, v| encrypted_data[k] = encode(v) }
|
81
|
+
end
|
82
|
+
encrypted_data
|
83
|
+
end
|
84
|
+
|
85
|
+
def gpg
|
86
|
+
@gpg ||= Gpg.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def kms
|
90
|
+
@kms ||= Kms.new(@config)
|
91
|
+
end
|
92
|
+
|
93
|
+
def site
|
94
|
+
@config[:secret_data].map { |k, _v| k }.first
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'aws-sdk-dynamodb'
|
2
|
+
require 'aws-sdk-iam'
|
3
|
+
require 'aws-sdk-kms'
|
4
|
+
require 'gpgme'
|
5
|
+
require 'highline/import'
|
6
|
+
require 'optparse'
|
7
|
+
require 'yaml'
|
8
|
+
require 'dynamo_secret/cli'
|
9
|
+
require 'dynamo_secret/dynamodb'
|
10
|
+
require 'dynamo_secret/gpg'
|
11
|
+
require 'dynamo_secret/iam'
|
12
|
+
require 'dynamo_secret/kms'
|
13
|
+
require 'dynamo_secret/secret'
|
14
|
+
require 'dynamo_secret/version'
|
metadata
ADDED
@@ -0,0 +1,196 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dynamo_secret
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Rob Bayerl
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-10-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: aws-sdk-dynamodb
|
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: aws-sdk-iam
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: aws-sdk-kms
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: gpgme
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: highline
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: bump
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: single_cov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: Encrypt and decrypt secrets stored in DynamoDB with GPG and/or KMS
|
154
|
+
email:
|
155
|
+
executables:
|
156
|
+
- dynamo_secret
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- CHANGELOG.md
|
161
|
+
- LICENSE
|
162
|
+
- README.md
|
163
|
+
- bin/dynamo_secret
|
164
|
+
- lib/dynamo_secret.rb
|
165
|
+
- lib/dynamo_secret/cli.rb
|
166
|
+
- lib/dynamo_secret/dynamodb.rb
|
167
|
+
- lib/dynamo_secret/gpg.rb
|
168
|
+
- lib/dynamo_secret/iam.rb
|
169
|
+
- lib/dynamo_secret/kms.rb
|
170
|
+
- lib/dynamo_secret/secret.rb
|
171
|
+
- lib/dynamo_secret/version.rb
|
172
|
+
homepage: https://github.com/rbayerl/dynamo_secret
|
173
|
+
licenses:
|
174
|
+
- MIT
|
175
|
+
metadata: {}
|
176
|
+
post_install_message:
|
177
|
+
rdoc_options: []
|
178
|
+
require_paths:
|
179
|
+
- lib
|
180
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: '0'
|
190
|
+
requirements: []
|
191
|
+
rubyforge_project:
|
192
|
+
rubygems_version: 2.6.11
|
193
|
+
signing_key:
|
194
|
+
specification_version: 4
|
195
|
+
summary: Store and fetch encrypted secrets in DynamoDB
|
196
|
+
test_files: []
|