team-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 +7 -0
- data/.gitignore +59 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +32 -0
- data/README.md +45 -0
- data/Rakefile +7 -0
- data/lib/team-secrets/file_manager.rb +31 -0
- data/lib/team-secrets/key_helper.rb +20 -0
- data/lib/team-secrets/manifest_manager.rb +72 -0
- data/lib/team-secrets/master_key.rb +73 -0
- data/lib/team-secrets/secret_manager.rb +121 -0
- data/lib/team-secrets/user_manager.rb +110 -0
- data/lib/team-secrets.rb +448 -0
- data/spec/file_manager_spec.rb +57 -0
- data/spec/manifest_manager_spec.rb +70 -0
- data/spec/master_key_spec.rb +107 -0
- data/spec/secret_manager_spec.rb +122 -0
- data/spec/support/test_key +30 -0
- data/spec/support/test_key.pub +1 -0
- data/spec/support/test_key.pub.pem +8 -0
- data/spec/user_manager_spec.rb +67 -0
- data/team-secrets.gemspec +19 -0
- metadata +72 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'team-secrets/secret_manager'
|
|
2
|
+
require 'team-secrets/master_key'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
describe SecretManager do
|
|
6
|
+
|
|
7
|
+
context 'secret management' do
|
|
8
|
+
master_key = MasterKey.generate
|
|
9
|
+
secrets = SecretManager.new master_key
|
|
10
|
+
|
|
11
|
+
it 'can add a secret' do
|
|
12
|
+
# add(secret_name, secret, account = nil, category = nil, notes = nil)
|
|
13
|
+
secrets.add('SMTP_PASS', 'sMith_bArney!', 'mailer@example.com', [:PROD], 'Production SMTP password')
|
|
14
|
+
secrets.add('SMTP_PASS', 'jAmes_fRanke1', 'dev@example.com', [:DEV], 'Development SMTP password')
|
|
15
|
+
secrets.add('SMS_API_KEY', '843jds83jd82jd', nil, [:PROD, :DEV])
|
|
16
|
+
secrets.add('DEPLOY_KEY', '84dk84ujd83jeallmxcjrujdjjfjkhkjhakjshdfjk')
|
|
17
|
+
|
|
18
|
+
expect(secrets.data).to be_a(Array)
|
|
19
|
+
expect(secrets.data.size).to eq(4)
|
|
20
|
+
expect(secrets.data[0].keys).to eq([:name, :tags, :account, :secret, :notes, :added])
|
|
21
|
+
expect(secrets.data[0][:name]).to eq('SMTP_PASS')
|
|
22
|
+
expect(secrets.data[0][:secret]).to_not eq('sMith_bArney!')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'find a secret with data' do
|
|
26
|
+
# No tag
|
|
27
|
+
res = secrets.find('SMTP_PASS')
|
|
28
|
+
expect(res.length).to eq(2)
|
|
29
|
+
|
|
30
|
+
# With tags
|
|
31
|
+
res = secrets.find('SMTP_PASS', [:DEV], false)
|
|
32
|
+
expect(res.length).to eq(1)
|
|
33
|
+
|
|
34
|
+
expect(res[0][:name]).to eq('SMTP_PASS')
|
|
35
|
+
expect(res[0][:secret]).to_not eq('jAmes_fRanke1')
|
|
36
|
+
expect(res[0][:account]).to eq('dev@example.com')
|
|
37
|
+
expect(res[0][:tags]).to eq([:DEV])
|
|
38
|
+
expect(res[0][:notes]).to eq('Development SMTP password')
|
|
39
|
+
expect(res[0][:added]).to be
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'can get a secret' do
|
|
43
|
+
# No tags
|
|
44
|
+
res = secrets.getSecret('SMTP_PASS')
|
|
45
|
+
expect(res.length).to eq(2)
|
|
46
|
+
expect(res).to include('jAmes_fRanke1')
|
|
47
|
+
expect(res).to include('sMith_bArney!')
|
|
48
|
+
|
|
49
|
+
# With tag
|
|
50
|
+
res = secrets.getSecret('SMTP_PASS', :DEV)
|
|
51
|
+
expect(res).to eq('jAmes_fRanke1')
|
|
52
|
+
|
|
53
|
+
# Can we get it twice?
|
|
54
|
+
res = secrets.getSecret('SMTP_PASS', [:DEV])
|
|
55
|
+
expect(res).to eq('jAmes_fRanke1')
|
|
56
|
+
|
|
57
|
+
# With the other tags
|
|
58
|
+
res = secrets.getSecret('SMTP_PASS', [:PROD])
|
|
59
|
+
expect(res).to eq('sMith_bArney!')
|
|
60
|
+
|
|
61
|
+
# With both tags, no matches
|
|
62
|
+
res = secrets.getSecret('SMTP_PASS', [:DEV, :PROD])
|
|
63
|
+
expect(res).to be_nil
|
|
64
|
+
|
|
65
|
+
# A longer string, matches both tags
|
|
66
|
+
res = secrets.getSecret('SMS_API_KEY', [:DEV, :PROD])
|
|
67
|
+
expect(res).to eq('843jds83jd82jd')
|
|
68
|
+
|
|
69
|
+
# No match, wrong tags
|
|
70
|
+
res = secrets.getSecret('SMS_API_KEY', [:DEV, :QA])
|
|
71
|
+
expect(res).to be_nil
|
|
72
|
+
|
|
73
|
+
# No category
|
|
74
|
+
res = secrets.getSecret('DEPLOY_KEY')
|
|
75
|
+
expect(res).to eq('84dk84ujd83jeallmxcjrujdjjfjkhkjhakjshdfjk')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'can return all secrets' do
|
|
79
|
+
res = secrets.getAll
|
|
80
|
+
expect(res.length).to eq(4)
|
|
81
|
+
|
|
82
|
+
res = secrets.getAll(:DEV)
|
|
83
|
+
expect(res.length).to eq(2)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'can remove a secret' do
|
|
87
|
+
res = secrets.getAll
|
|
88
|
+
expect(res.length).to eq(4)
|
|
89
|
+
|
|
90
|
+
# Remove nothing, tag doesn't match
|
|
91
|
+
secrets.remove('SMS_API_KEY', :NOPE)
|
|
92
|
+
res = secrets.getAll
|
|
93
|
+
expect(res.length).to eq(4)
|
|
94
|
+
|
|
95
|
+
secrets.remove('SMS_API_KEY', [:PROD, :DEV])
|
|
96
|
+
res = secrets.getAll
|
|
97
|
+
expect(res.length).to eq(3)
|
|
98
|
+
|
|
99
|
+
secrets.remove('SMTP_PASS')
|
|
100
|
+
res = secrets.getAll
|
|
101
|
+
expect(res.length).to eq(1)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'can rotate encryption keys' do
|
|
105
|
+
secrets.add('ROTATE_TEST_1', 'alskdfjalskjdf3984')
|
|
106
|
+
secrets.add('ROTATE_TEST_2', '2o341-llakdsjfjfdk')
|
|
107
|
+
|
|
108
|
+
secret_ref = []
|
|
109
|
+
for i in 0..2
|
|
110
|
+
secret_ref.push secrets.data[i][:secret]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
secrets.rotateMasterKey(MasterKey.generate)
|
|
114
|
+
|
|
115
|
+
for i in 0..2
|
|
116
|
+
expect(secret_ref).not_to include(secrets.data[i][:secret])
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
Proc-Type: 4,ENCRYPTED
|
|
3
|
+
DEK-Info: AES-128-CBC,976BA65B445F48E06F6486493B76E3ED
|
|
4
|
+
|
|
5
|
+
6Y+inTC0bI9bPKYuz9+zZjyST5h/iAxApDSjIZzntp7j8oM6XxVb4DeLyG1L/Don
|
|
6
|
+
VMbjx3NCnsGNSTw51MrV9Kwhsq0CvtgIOW6CdP3oQT3D4wA8516r6qjNm6NF0ePz
|
|
7
|
+
/e7CxzFIOcX1TUbwBYc7/rTQg27Ll77tcoCSO3P6Pn1U/QSIHQO8U7LKNVPt5JFo
|
|
8
|
+
TUM7m50dWUuqgcQLqicfyZoG2EB3T0a/YsmDiBG49gepCjmiPAaTC8O0YqaeMREZ
|
|
9
|
+
UuxWHB22LuNc689FFrf4WNajw+DVgpGHdRRotILZcT6JftpHvHe+7I3TbRxglUsm
|
|
10
|
+
30XHGnn+yQntHmQ0JFaMoZeBn3C0KGg0e213Nb35OHWkMO/NBRXQpYFAECCx26wz
|
|
11
|
+
GP71+oYe8xysatUC7t9eBaFhQuFU9vKCW5Vw0nkpwIaUAuWVExMtSiaV909BfQ/G
|
|
12
|
+
TZcwqeFi2U7TNGaGQN0Bky1bAIHDHPrmJ3DVs0Ql1TNRszIkyjiFUFBK27k3Yn4K
|
|
13
|
+
Xs4WUihzYuPgzh7pZ40vldhbVHMTSQtLRX9TptiRMEqtTXl6hVb701w+zDcE0sDQ
|
|
14
|
+
G2mNOihE12CRMLBo9TMWDyAeXxSNu4JRJnXMzLCIwCl6McE+0TW8nFf5wQ1gJ85Z
|
|
15
|
+
TCDXpVM9U3MQcpLoPsBoLBiJRGqi3dcuimjDNuZAoIbTk6yQ4c6frLUWG4+kfuCI
|
|
16
|
+
moK23uCdFVY3F6KrNFv4YnWlO5lSnWOFA21RKraGhvwIId+LK126cIDuwlL/TEI8
|
|
17
|
+
FviFBYCkwVsxv8EhcF/hllGIHfVi45ONjzECLLJGH7bplURaDB+tcXUtdJ6orUjI
|
|
18
|
+
k9ZONkIO8AlYJ0VMv2O/qjXKbNFOoch/LUC2J6DDcKKcNj8KX2Q803K+mcFOgzLz
|
|
19
|
+
FkWru6CBQVdSo3vR0gX47BBMJWWksEMuxLq7dh1KZ+LLZQtsjU3bAlYpl2gcEhTC
|
|
20
|
+
W0L+OE8J5C1ER/SniJ84hgF2kkTQjBHSHQOlrc+b/FbxgCMphdUekP1hTfr74CfV
|
|
21
|
+
Su13SFxnvNVxjyuHMRVI6iICsAbpicKAbakqqCzEChT5jaNDQpATevdhiAMZsJAO
|
|
22
|
+
7YxozipZu6j8Uxgvwwv+hHKE0JHATJ223alBHPrFZLd8Kj0yGpx3b4yT8psfHZHb
|
|
23
|
+
ptEPosz9EcdF6zO4FH6dV6kX1JLBu+jwYQqrlgmk3KraYNlWpPKbB0/eQD9GLpds
|
|
24
|
+
JnqHD5lAunYyEQwmnm5S+sojT7nxM7WmOhwHxJNtFAZevMMJ7EPKwuaFhFq5B1qt
|
|
25
|
+
2rZIERYWF4EYn3V2AGh37HAyJQGc2pQRacVdzwC9oiqo7wdu7TaqEks5+iKMspK7
|
|
26
|
+
lpFAnXfa0GFnJHHyCyC0qxuzU/kSaWxrTIzxirl8wABndoqZfWjh9f+eMVMrr6CR
|
|
27
|
+
IFll1vwPhqUe2SniRBPDfIsSVCLxtQnFXnJ3zxj2VQRODJP/FICItHqy5R2S2qTW
|
|
28
|
+
9J7KGpaC3elDKcpuUULeoLwzqEu7Gl8sRq8zSzcP9QOuRo6a2iFeRMgtthSbL1xe
|
|
29
|
+
jiYehLZWZoh+TlHqe2ED8uR9inTFtddS85Z4i1eXoKBxHN7kP46ENtkC8jp+g80S
|
|
30
|
+
-----END RSA PRIVATE KEY-----
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKyRjeNjDigBgFdRl9BkAaWMuZZJ6hRm4UaDOdScZxeahgdpKh0YnceFF5CBTBcKfotfAHh13yKqCZNDOXQOAycZFF6NiRnqSHemIkPNtwUP27Cuh/emHsCyvElBr6Gh3Hlr0kcnPwe6xKfRG+kSoTFt8sqQ/ZiOCs6fguZXTEMpsWCEt6QyLKcSV8N/ow4TcJ39DhanIm+nm4wsGafvgAsuGTuzTus4EuOmQg3CxCsxxri2EcnqewLXyqzHiQUQneO9oLq6i1rmL0XiM0h9mmojqj4m1WPWGYGnz6oWRqm3P9ReyJhnLqmTCenoouCo5y/OO7Rc9Fm/brf8Wxn7Ib example@example.local
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
-----BEGIN RSA PUBLIC KEY-----
|
|
2
|
+
MIIBCgKCAQEAyskY3jYw4oAYBXUZfQZAGljLmWSeoUZuFGgznUnGcXmoYHaSodGJ
|
|
3
|
+
3HhReQgUwXCn6LXwB4dd8iqgmTQzl0DgMnGRRejYkZ6kh3piJDzbcFD9uwrof3ph
|
|
4
|
+
7AsrxJQa+hodx5a9JHJz8HusSn0RvpEqExbfLKkP2YjgrOn4LmV0xDKbFghLekMi
|
|
5
|
+
ynElfDf6MOE3Cd/Q4WpyJvp5uMLBmn74ALLhk7s07rOBLjpkINwsQrMca4thHJ6n
|
|
6
|
+
sC18qsx4kFEJ3jvaC6uota5i9F4jNIfZpqI6o+JtVj1hmBp8+qFkaptz/UXsiYZy
|
|
7
|
+
6pkwnp6KLgqOcvzju0XPRZv263/FsZ+yGwIDAQAB
|
|
8
|
+
-----END RSA PUBLIC KEY-----
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'team-secrets/user_manager'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
|
|
4
|
+
describe UserManager do
|
|
5
|
+
|
|
6
|
+
context 'user management' do
|
|
7
|
+
temp_folder = File.dirname(File.dirname(__FILE__)) +'/tmp'
|
|
8
|
+
|
|
9
|
+
before(:all) do
|
|
10
|
+
Dir.mkdir(temp_folder) unless File.exists?(temp_folder)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after(:all) do
|
|
14
|
+
FileUtils.rm_rf(temp_folder+'/users') if File.exists?(temp_folder+'/users')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'can add a user' do
|
|
18
|
+
users = UserManager.new
|
|
19
|
+
|
|
20
|
+
users.working_dir = temp_folder
|
|
21
|
+
users.user_dir = temp_folder+'/users'
|
|
22
|
+
|
|
23
|
+
users.add('new_guy', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
24
|
+
users.add('new_gal', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
25
|
+
|
|
26
|
+
expect(users.data).to be_a(Array)
|
|
27
|
+
expect(users.data.size).to eq(2)
|
|
28
|
+
expect(users.data[0].keys).to eq([:user, :public_key, :added, :lock_box, :sha256])
|
|
29
|
+
expect(users.all).to eq(['new_guy', 'new_gal'])
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'can find a user' do
|
|
33
|
+
users = UserManager.new
|
|
34
|
+
|
|
35
|
+
users.working_dir = temp_folder
|
|
36
|
+
users.user_dir = temp_folder+'/users'
|
|
37
|
+
|
|
38
|
+
users.add('new_guy', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
39
|
+
users.add('new_gal', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
40
|
+
|
|
41
|
+
expect(users.find('fake_bud')).to be_nil
|
|
42
|
+
expect(users.find('new_guy')).to be
|
|
43
|
+
expect(users.find('new_gal')).to have_key(:public_key)
|
|
44
|
+
expect(users.find('new_gal')[:user]).to eq('new_gal')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'can remove a user' do
|
|
48
|
+
users = UserManager.new
|
|
49
|
+
|
|
50
|
+
users.working_dir = temp_folder
|
|
51
|
+
users.user_dir = temp_folder+'/users'
|
|
52
|
+
|
|
53
|
+
users.add('good_gal', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
54
|
+
users.add('bad_guy', File.dirname(__FILE__) +'/support/test_key.pub.pem')
|
|
55
|
+
|
|
56
|
+
expect(users.data).to be_a(Array)
|
|
57
|
+
expect(users.data.size).to eq(2)
|
|
58
|
+
expect(users.all).to eq(['good_gal', 'bad_guy'])
|
|
59
|
+
|
|
60
|
+
users.remove('bad_guy')
|
|
61
|
+
|
|
62
|
+
expect(users.data.size).to eq(1)
|
|
63
|
+
expect(users.all).to eq(['good_gal'])
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.name = 'team-secrets'
|
|
6
|
+
gem.version = '0.1.0'
|
|
7
|
+
gem.platform = Gem::Platform::RUBY
|
|
8
|
+
gem.authors = ['Eric Bigoness']
|
|
9
|
+
gem.email = ['design@firelit.com']
|
|
10
|
+
gem.homepage = 'https://github.com/firelit/secrets'
|
|
11
|
+
|
|
12
|
+
gem.summary = 'A utility for securely managing team secrets'
|
|
13
|
+
gem.description = 'Encyrpt and store team secrets, passwords and API keys in a repository with built-in user management'
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split("\n")
|
|
16
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*.rb`.split("\n")
|
|
17
|
+
gem.require_paths = ["lib"]
|
|
18
|
+
|
|
19
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: team-secrets
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Eric Bigoness
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2017-02-25 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Encyrpt and store team secrets, passwords and API keys in a repository
|
|
14
|
+
with built-in user management
|
|
15
|
+
email:
|
|
16
|
+
- design@firelit.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- ".gitignore"
|
|
22
|
+
- ".rspec"
|
|
23
|
+
- ".travis.yml"
|
|
24
|
+
- Gemfile
|
|
25
|
+
- Gemfile.lock
|
|
26
|
+
- README.md
|
|
27
|
+
- Rakefile
|
|
28
|
+
- lib/team-secrets.rb
|
|
29
|
+
- lib/team-secrets/file_manager.rb
|
|
30
|
+
- lib/team-secrets/key_helper.rb
|
|
31
|
+
- lib/team-secrets/manifest_manager.rb
|
|
32
|
+
- lib/team-secrets/master_key.rb
|
|
33
|
+
- lib/team-secrets/secret_manager.rb
|
|
34
|
+
- lib/team-secrets/user_manager.rb
|
|
35
|
+
- spec/file_manager_spec.rb
|
|
36
|
+
- spec/manifest_manager_spec.rb
|
|
37
|
+
- spec/master_key_spec.rb
|
|
38
|
+
- spec/secret_manager_spec.rb
|
|
39
|
+
- spec/support/test_key
|
|
40
|
+
- spec/support/test_key.pub
|
|
41
|
+
- spec/support/test_key.pub.pem
|
|
42
|
+
- spec/user_manager_spec.rb
|
|
43
|
+
- team-secrets.gemspec
|
|
44
|
+
homepage: https://github.com/firelit/secrets
|
|
45
|
+
licenses: []
|
|
46
|
+
metadata: {}
|
|
47
|
+
post_install_message:
|
|
48
|
+
rdoc_options: []
|
|
49
|
+
require_paths:
|
|
50
|
+
- lib
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
requirements: []
|
|
62
|
+
rubyforge_project:
|
|
63
|
+
rubygems_version: 2.6.8
|
|
64
|
+
signing_key:
|
|
65
|
+
specification_version: 4
|
|
66
|
+
summary: A utility for securely managing team secrets
|
|
67
|
+
test_files:
|
|
68
|
+
- spec/file_manager_spec.rb
|
|
69
|
+
- spec/manifest_manager_spec.rb
|
|
70
|
+
- spec/master_key_spec.rb
|
|
71
|
+
- spec/secret_manager_spec.rb
|
|
72
|
+
- spec/user_manager_spec.rb
|