dynamo_secret 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 +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: []
|