sanctum 0.8.5.rc4 → 0.8.5.rc5
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 +4 -4
- data/Dockerfile +1 -1
- data/Gemfile.lock +6 -4
- data/README.md +13 -9
- data/docker-compose.test.yml +1 -1
- data/docker-compose.yml +1 -1
- data/lib/sanctum/cli.rb +4 -4
- data/lib/sanctum/command/base.rb +50 -23
- data/lib/sanctum/command/check.rb +1 -1
- data/lib/sanctum/command/create.rb +9 -15
- data/lib/sanctum/command/edit.rb +9 -4
- data/lib/sanctum/command/editor_helper.rb +19 -4
- data/lib/sanctum/command/pull.rb +4 -4
- data/lib/sanctum/command/push.rb +2 -2
- data/lib/sanctum/command/sanctum.example.yaml +20 -10
- data/lib/sanctum/command/update.rb +0 -26
- data/lib/sanctum/command/view.rb +8 -2
- data/lib/sanctum/get_config/config_merge.rb +16 -6
- data/lib/sanctum/get_config/env.rb +1 -1
- data/lib/sanctum/get_config/options.rb +1 -1
- data/lib/sanctum/vault_transit.rb +2 -0
- data/lib/sanctum/version.rb +1 -1
- data/sanctum.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dff385a40c33fc32dc3c5b57c28c1c8493cf9e01dc6e79cfbfee08269a3bd072
|
4
|
+
data.tar.gz: ebdd7ba3f3a1020357301d281e4dc474195d8b765a25885f96e10e7a7e6b3573
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23d19761e85666eb94b7c7e25a7957be59ba422f2967a930000b1171ae1280e0417b3ad767fc35e0c5c1a19cb61962c752c06d3ae381a1b54c2ef6e8c4cf9949
|
7
|
+
data.tar.gz: 8563efa095ac2a186572adcd14f999db22070e91803cc6ad89d67c29c009e4f8c6c005675b9f796744dbb76633381ad5df05cc8050366aa32e5e503aa860acb2
|
data/Dockerfile
CHANGED
@@ -2,7 +2,7 @@ FROM ruby:2.5-alpine
|
|
2
2
|
|
3
3
|
USER root
|
4
4
|
|
5
|
-
ENV VERSION 1.0.
|
5
|
+
ENV VERSION 1.0.3
|
6
6
|
ADD https://releases.hashicorp.com/vault/${VERSION}/vault_${VERSION}_linux_amd64.zip /tmp/
|
7
7
|
ADD https://releases.hashicorp.com/vault/${VERSION}/vault_${VERSION}_SHA256SUMS /tmp/
|
8
8
|
ADD https://releases.hashicorp.com/vault/${VERSION}/vault_${VERSION}_SHA256SUMS.sig /tmp/
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sanctum (0.8.5.
|
4
|
+
sanctum (0.8.5.rc5)
|
5
5
|
gli (~> 2.18)
|
6
6
|
hashdiff (~> 0.3)
|
7
7
|
vault (~> 0.12)
|
@@ -17,13 +17,14 @@ GEM
|
|
17
17
|
hashdiff (0.3.8)
|
18
18
|
jaro_winkler (1.5.2)
|
19
19
|
method_source (0.9.2)
|
20
|
-
parallel (1.
|
20
|
+
parallel (1.14.0)
|
21
21
|
parser (2.6.0.0)
|
22
22
|
ast (~> 2.4.0)
|
23
23
|
powerpack (0.1.2)
|
24
24
|
pry (0.12.2)
|
25
25
|
coderay (~> 1.1.0)
|
26
26
|
method_source (~> 0.9.0)
|
27
|
+
psych (3.1.0)
|
27
28
|
rainbow (3.0.0)
|
28
29
|
rake (12.3.2)
|
29
30
|
rspec (3.8.0)
|
@@ -39,11 +40,12 @@ GEM
|
|
39
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
40
41
|
rspec-support (~> 3.8.0)
|
41
42
|
rspec-support (3.8.0)
|
42
|
-
rubocop (0.
|
43
|
+
rubocop (0.65.0)
|
43
44
|
jaro_winkler (~> 1.5.1)
|
44
45
|
parallel (~> 1.10)
|
45
46
|
parser (>= 2.5, != 2.5.1.1)
|
46
47
|
powerpack (~> 0.1)
|
48
|
+
psych (>= 3.1.0)
|
47
49
|
rainbow (>= 2.2.2, < 4.0)
|
48
50
|
ruby-progressbar (~> 1.7)
|
49
51
|
unicode-display_width (~> 1.4.0)
|
@@ -62,7 +64,7 @@ DEPENDENCIES
|
|
62
64
|
pry (~> 0.12.0)
|
63
65
|
rake (~> 12.0)
|
64
66
|
rspec (~> 3.0)
|
65
|
-
rubocop (~> 0.
|
67
|
+
rubocop (~> 0.65.0)
|
66
68
|
rubocop-rspec (~> 1.32.0)
|
67
69
|
sanctum!
|
68
70
|
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ using the sanctum gem, you could run `sanctum pull`. Depending on the path you s
|
|
28
28
|
`sanctum push`.
|
29
29
|
|
30
30
|
### KV API v2
|
31
|
-
**NOTE: V2 API adds `/data` and `/metadata`
|
31
|
+
**NOTE: V2 Vault API adds `/data` and `/metadata` to the mounts endpoints see [Vault kv v2](https://www.vaultproject.io/docs/secrets/kv/kv-v2.html)**
|
32
32
|
|
33
33
|
Lets say you have a vault instance with `kv v2` enabled backend.
|
34
34
|
if you were to run, `vault kv secrets/cool-app/dev/env` you may see something similar to
|
@@ -52,10 +52,10 @@ token myrandomtoken
|
|
52
52
|
|
53
53
|
using the sanctum gem, you could run `sanctum pull`. Depending on the path you specified in the `sanctum.yaml` config file; Your local file system would look similar to
|
54
54
|
```
|
55
|
-
<path-specified>/
|
55
|
+
<path-specified>/cool-app/dev/env
|
56
56
|
```
|
57
57
|
|
58
|
-
`env` would contain a `transit` encrypted base64 encoded blob, which you could then edit with `sanctum edit <path-specified>/
|
58
|
+
`env` would contain a `transit` encrypted base64 encoded blob, which you could then edit with `sanctum edit <path-specified>/cool-app/dev/env`. You could then push any changes with
|
59
59
|
`sanctum push`.
|
60
60
|
|
61
61
|
## Installation
|
@@ -108,19 +108,23 @@ The higher the number the higher the precedence.(1 is the lowest precedence, 4 i
|
|
108
108
|
|
109
109
|
## Configuration file structure
|
110
110
|
The configuration file is a Hash represented in YAML format with three possible top-level keys: `sanctum`, `vault`, and `sync`.
|
111
|
-
* The `sanctum` section sets global defaults.
|
112
|
-
*
|
113
|
-
*
|
114
|
-
|
111
|
+
* The `sanctum` section sets global defaults.
|
112
|
+
* You can choose to set a `transit_key` default under this section, which can be overridden per target
|
113
|
+
* You can choose to set a `secrets_version` default under this section, which can be overridden per target
|
114
|
+
* The `vault` section specifies the url, token, to the Vault REST API endpoint.
|
115
|
+
* url, token are **required** and can be set here or through environment variables.
|
115
116
|
* The `sync` section sets the local paths and Vault prefixes you wish to synchronize.
|
116
117
|
* At lease one application/target definition is required.
|
118
|
+
* If you have not specified a global `transit_key` in the `sanctum` section you must add the key for each target
|
119
|
+
|
120
|
+
You can get more info by running `sanctum config` and viewing the generated file.
|
117
121
|
|
118
122
|
## Roadmap
|
119
123
|
* <strike>Add vault v2 API support</strike>
|
120
124
|
* <strike>Add upgrade option for v2 API</strike>
|
121
|
-
* If transit key doesn't exist try to create it(automatically)
|
122
|
-
* If secrets mount doesn't exist try to create it(automatically)
|
123
125
|
* <strike>Better/more Tests</strike>
|
126
|
+
* <strike>Support for multiple transit_keys</strike>
|
127
|
+
* <strike>Support for global secrets_version</strike>
|
124
128
|
* Built in Backup features
|
125
129
|
* Performance optimizations
|
126
130
|
* Reorganize/cleanup code(add adapters, etc)
|
data/docker-compose.test.yml
CHANGED
data/docker-compose.yml
CHANGED
data/lib/sanctum/cli.rb
CHANGED
@@ -67,7 +67,7 @@ module Sanctum
|
|
67
67
|
desc 'Create an encrypted file'
|
68
68
|
arg_name 'path/to/file'
|
69
69
|
command :create do |c|
|
70
|
-
common_options c, :config
|
70
|
+
common_options c, :targets, :config
|
71
71
|
c.action do |_,_,args|
|
72
72
|
Command::Create.new(@options_hash, args).run
|
73
73
|
end
|
@@ -76,7 +76,7 @@ module Sanctum
|
|
76
76
|
desc 'View encrypted file[s]'
|
77
77
|
arg_name 'path/to/file'
|
78
78
|
command :view do |c|
|
79
|
-
common_options c, :config
|
79
|
+
common_options c, :targets, :config
|
80
80
|
c.action do |_,_,args|
|
81
81
|
if args.empty?
|
82
82
|
help_now! "Please specify at least one argument"
|
@@ -88,7 +88,7 @@ module Sanctum
|
|
88
88
|
desc 'Edit an encrypted file'
|
89
89
|
arg_name 'path/to/file'
|
90
90
|
command :edit do |c|
|
91
|
-
common_options c, :config
|
91
|
+
common_options c, :targets, :config
|
92
92
|
|
93
93
|
c.action do |_,_,args|
|
94
94
|
Command::Edit.new(@options_hash, args).run
|
@@ -98,7 +98,7 @@ module Sanctum
|
|
98
98
|
desc 'Update secrets mount'
|
99
99
|
command :update do |c|
|
100
100
|
common_options c, :config, :force
|
101
|
-
c.flag [:targets, :t], desc: '
|
101
|
+
c.flag [:targets, :t], desc: 'Specify target to update', required: true
|
102
102
|
c.action do
|
103
103
|
Command::Update.new(@options_hash).run
|
104
104
|
end
|
data/lib/sanctum/command/base.rb
CHANGED
@@ -10,21 +10,12 @@ module Sanctum
|
|
10
10
|
include EditorHelper
|
11
11
|
include PathsHelper
|
12
12
|
|
13
|
-
attr_reader :options, :args, :
|
13
|
+
attr_reader :options, :args, :targets, :config_file
|
14
14
|
|
15
15
|
def initialize(options={}, args=[])
|
16
16
|
@options = options.to_h
|
17
17
|
@args = args
|
18
|
-
|
19
|
-
@transit_key = options.fetch(:vault).fetch(:transit_key)
|
20
|
-
# TODO: Fix, way to much is happening to targets in this initializer!
|
21
|
-
@targets = update_prefix_or_path(
|
22
|
-
set_secrets_version(
|
23
|
-
remove_trailing_slash(
|
24
|
-
options.fetch(:sync)
|
25
|
-
)
|
26
|
-
)
|
27
|
-
)
|
18
|
+
@targets = update_targets(options.fetch(:sync))
|
28
19
|
@config_file = options.fetch(:config_file)
|
29
20
|
end
|
30
21
|
|
@@ -43,14 +34,26 @@ module Sanctum
|
|
43
34
|
raise
|
44
35
|
end
|
45
36
|
|
37
|
+
# TODO: Most of this stuff should probably be done in a separate class, or even back in Samctum::GetConfig
|
38
|
+
# Internal: Modifies each target with some additional logic
|
39
|
+
# Returns: hash
|
40
|
+
def update_targets(targets)
|
41
|
+
default_transit_key = options.fetch(:sanctum).fetch(:transit_key, nil)
|
42
|
+
default_secrets_version = options.fetch(:sanctum).fetch(:secrets_version)
|
43
|
+
|
44
|
+
targets = remove_trailing_slash(targets)
|
45
|
+
targets = set_secrets_version(targets, default_secrets_version)
|
46
|
+
targets = set_transit_key(targets, default_transit_key)
|
47
|
+
targets = update_prefix(targets)
|
48
|
+
targets
|
49
|
+
end
|
50
|
+
|
46
51
|
# Internal: automatically detect the api version of the secrets mount
|
47
52
|
# and adds :secrets_version to hash if it doesn't exist
|
48
53
|
#
|
49
54
|
# Parameter: is an array of hashes: [{}, {}]
|
50
55
|
# Returns array of hashes: [{:name=>"vault-test", :prefix=>"vault-test", :path=>"vault/vault-test", :secrets_version=>"2"},{}]
|
51
|
-
def set_secrets_version(targets)
|
52
|
-
mounts_hash = mounts_info
|
53
|
-
|
56
|
+
def set_secrets_version(targets, default_secrets_version)
|
54
57
|
targets.each do |h|
|
55
58
|
if h.key?(:secrets_version)
|
56
59
|
# Ensure value is a string
|
@@ -58,25 +61,49 @@ module Sanctum
|
|
58
61
|
next
|
59
62
|
end
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
64
|
+
if default_secrets_version == "auto"
|
65
|
+
mounts_hash = mounts_info
|
66
|
+
|
67
|
+
# If mount options is nil default to api version 1 otherwise use version value
|
68
|
+
# generic mounts will not have a version specified
|
69
|
+
if mounts_hash.dig(:data, :secret, "#{h[:prefix]}/".to_sym, :options).nil?
|
70
|
+
h[:secrets_version] = "1"
|
71
|
+
else
|
72
|
+
h[:secrets_version] = mounts_hash.dig(:data, :secret, "#{h[:prefix]}/".to_sym, :options, :version).to_s
|
73
|
+
end
|
74
|
+
else
|
75
|
+
h[:secrets_version] = default_secrets_version
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Internal sets default transit_key if :transit_key doesn't exist in hash
|
81
|
+
#
|
82
|
+
# Parameter: is an array of hashes: [{}, {}]
|
83
|
+
# Returns array of hashes: [{:name=>"vault-test", :prefix=>"vault-test", :path=>"vault/vault-test", :secrets_version=>"2", :transit_key=>"transit/keys/vault-test"},{}]
|
84
|
+
def set_transit_key(targets, default_transit_key)
|
85
|
+
targets = targets.each do |h|
|
86
|
+
if h.key?(:transit_key)
|
87
|
+
# Ensure value is a string
|
88
|
+
h[:transit_key] = h[:transit_key].to_s
|
89
|
+
next
|
65
90
|
else
|
66
|
-
h[:
|
91
|
+
h[:transit_key] = default_transit_key.to_s
|
67
92
|
end
|
68
93
|
end
|
94
|
+
|
95
|
+
raise "transit_key must be specified under sanctum defaults, or on a per target bases" if targets.any?{ |h| h.dig(:transit_key).nil? }
|
96
|
+
targets
|
69
97
|
end
|
70
98
|
|
71
|
-
# Internal, update prefix
|
99
|
+
# Internal, update prefix , add `/data` if secrets_version == "2"
|
72
100
|
# Parameter is an array of hashes: [{}, {}]
|
73
|
-
# Returns array of hashes: [{:name=>"vault-test", :prefix=>"vault-test/data", :path=>"vault/vault-test
|
74
|
-
def
|
101
|
+
# Returns array of hashes: [{:name=>"vault-test", :prefix=>"vault-test/data", :path=>"vault/vault-test", :secrets_version=>"2"},{}]
|
102
|
+
def update_prefix(targets)
|
75
103
|
targets.each do |h|
|
76
104
|
next unless h[:secrets_version] == "2"
|
77
105
|
|
78
106
|
h[:prefix] = h[:prefix].include?("/data") ? h[:prefix] : "#{h[:prefix]}/data"
|
79
|
-
h[:path] = h[:path].include?("/data") ? h[:path] : "#{h[:path]}/data"
|
80
107
|
end
|
81
108
|
end
|
82
109
|
|
@@ -9,7 +9,7 @@ module Sanctum
|
|
9
9
|
# Read each file
|
10
10
|
local_secrets = read_local_files(local_paths)
|
11
11
|
# Decrypt each secret
|
12
|
-
local_secrets = VaultTransit.decrypt(vault_client, local_secrets, transit_key)
|
12
|
+
local_secrets = VaultTransit.decrypt(vault_client, local_secrets, target[:transit_key])
|
13
13
|
|
14
14
|
# Recursively get vault secrets for each prefix specified in sanctum.yaml
|
15
15
|
secrets_list = VaultSecrets.new(vault_client, target[:prefix], target[:secrets_version]).get_all
|
@@ -10,16 +10,17 @@ module Sanctum
|
|
10
10
|
|
11
11
|
def run(&block)
|
12
12
|
if args.one?
|
13
|
-
path = args
|
13
|
+
path = args.first
|
14
14
|
validate_path(path)
|
15
|
-
|
15
|
+
transit_key = determine_transit_key(path, targets)
|
16
|
+
create_file(path, transit_key, &block)
|
16
17
|
else
|
17
18
|
raise ArgumentError, red('Please pass only one path argument')
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
22
|
-
def create_file(path)
|
23
|
+
def create_file(path, transit_key)
|
23
24
|
# Calling vault_client will help prevent a race condition where the token is expired
|
24
25
|
# and contents fail to encrypt
|
25
26
|
vault_client
|
@@ -30,7 +31,11 @@ module Sanctum
|
|
30
31
|
yield tmp_file
|
31
32
|
else
|
32
33
|
editor = ENV.fetch('EDITOR', 'vi')
|
33
|
-
|
34
|
+
#This should help in the case where people are using macvim, atom, etc
|
35
|
+
command = Thread.new do
|
36
|
+
raise red("Error with editor") unless system(editor, tmp_file.path)
|
37
|
+
end
|
38
|
+
command.join
|
34
39
|
end
|
35
40
|
|
36
41
|
contents = File.read(tmp_file.path)
|
@@ -51,20 +56,9 @@ module Sanctum
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
# Check if the path you are creating matches a target path
|
55
|
-
# if secrets_version == 2 /data will be added to the path
|
56
|
-
# See command/base.rb
|
57
|
-
def path_matches_a_target?(path)
|
58
|
-
targets.each do |h|
|
59
|
-
path.to_s.include?(h[:path]) ? (return true) : (return false)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
59
|
def validate_path(path)
|
64
60
|
path = Pathname.new(path)
|
65
|
-
keys_to_print = targets.map { |h| h.slice(:name, :path) }
|
66
61
|
raise yellow("File exists, use edit command") if path.exist?
|
67
|
-
raise yellow("No targets contain a :path key that matches the path you specified\n#{keys_to_print}") unless path_matches_a_target?(path)
|
68
62
|
|
69
63
|
path.dirname.mkpath unless path.dirname.exist?
|
70
64
|
end
|
data/lib/sanctum/command/edit.rb
CHANGED
@@ -9,15 +9,16 @@ module Sanctum
|
|
9
9
|
|
10
10
|
def run(&block)
|
11
11
|
if args.one?
|
12
|
-
path = args
|
13
|
-
|
12
|
+
path = args.first
|
13
|
+
transit_key = determine_transit_key(path, targets)
|
14
|
+
edit_file(path, transit_key, &block)
|
14
15
|
else
|
15
16
|
raise ArgumentError, red('Please pass only one path argument')
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
19
20
|
private
|
20
|
-
def edit_file(path)
|
21
|
+
def edit_file(path, transit_key)
|
21
22
|
tmp_file = Tempfile.new(File.basename(path))
|
22
23
|
|
23
24
|
begin
|
@@ -33,7 +34,11 @@ module Sanctum
|
|
33
34
|
else
|
34
35
|
previous_contents = File.read(tmp_file.path)
|
35
36
|
editor = ENV.fetch('EDITOR', 'vi')
|
36
|
-
|
37
|
+
#This should help in the case where people are using macvim, atom, etc
|
38
|
+
command = Thread.new do
|
39
|
+
raise red("Error with editor") unless system(editor, tmp_file.path )
|
40
|
+
end
|
41
|
+
command.join
|
37
42
|
end
|
38
43
|
contents = File.read(tmp_file.path)
|
39
44
|
|
@@ -18,17 +18,21 @@ module Sanctum
|
|
18
18
|
def validate(contents)
|
19
19
|
validate_json(contents) || validate_yaml(contents) || raise
|
20
20
|
rescue
|
21
|
-
fail red("Invalid Contents")
|
21
|
+
fail red("Invalid Contents. Must be valid, json or yaml, in key/value pair format")
|
22
22
|
end
|
23
23
|
|
24
24
|
def validate_json(json)
|
25
|
-
JSON.parse(json)
|
26
|
-
|
25
|
+
json = JSON.parse(json)
|
26
|
+
raise TypeError.new('Data must be in key/value format') unless json.kind_of? Hash
|
27
|
+
json
|
28
|
+
rescue JSON::ParserError, TypeError
|
27
29
|
nil
|
28
30
|
end
|
29
31
|
|
30
32
|
def validate_yaml(yaml)
|
31
|
-
YAML.load(yaml)
|
33
|
+
yaml = YAML.load(yaml)
|
34
|
+
raise TypeError.new('Data must be in key/value format') unless yaml.kind_of? Hash
|
35
|
+
yaml
|
32
36
|
rescue YAML::SyntaxError
|
33
37
|
nil
|
34
38
|
end
|
@@ -53,6 +57,17 @@ module Sanctum
|
|
53
57
|
end
|
54
58
|
end
|
55
59
|
|
60
|
+
#TODO: Don't like this.. need to figure out a better way.
|
61
|
+
#Maybe require uses to specify the target when `create, update, or edit?`
|
62
|
+
def determine_transit_key(path, targets)
|
63
|
+
if targets.count > 1
|
64
|
+
targets.each do |h|
|
65
|
+
path.to_s.include?(h[:path]) ? (h[:transit_key]) : (raise "Unable to determine transit_key to use, please specify target via `-t <target>`")
|
66
|
+
end
|
67
|
+
else
|
68
|
+
targets.first[:transit_key]
|
69
|
+
end
|
70
|
+
end
|
56
71
|
end
|
57
72
|
end
|
58
73
|
end
|
data/lib/sanctum/command/pull.rb
CHANGED
@@ -18,7 +18,7 @@ module Sanctum
|
|
18
18
|
secrets_list.each do |k,v|
|
19
19
|
|
20
20
|
vault_secrets = build_vault_secrets(v, [target[:path]])
|
21
|
-
local_secrets = build_local_secrets(vault_secrets)
|
21
|
+
local_secrets = build_local_secrets(vault_secrets, target[:transit_key])
|
22
22
|
|
23
23
|
#Compare secrets, if there are no differences continue to next target
|
24
24
|
differences = compare_secrets(vault_secrets, local_secrets, target[:name], "pull")
|
@@ -33,11 +33,11 @@ module Sanctum
|
|
33
33
|
if force
|
34
34
|
# Write files to disk and encrypt with transit
|
35
35
|
warn red("#{target[:name]}: Forcefully writing differences to disk(pull)")
|
36
|
-
VaultTransit.write_to_file(vault_client, vault_secrets, transit_key)
|
36
|
+
VaultTransit.write_to_file(vault_client, vault_secrets, target[:transit_key])
|
37
37
|
else
|
38
38
|
#Confirm with user, and write to local file if approved
|
39
39
|
next unless confirmed_with_user?
|
40
|
-
VaultTransit.write_to_file(vault_client, vault_secrets, transit_key)
|
40
|
+
VaultTransit.write_to_file(vault_client, vault_secrets, target[:transit_key])
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -65,7 +65,7 @@ module Sanctum
|
|
65
65
|
vault_secrets
|
66
66
|
end
|
67
67
|
|
68
|
-
def build_local_secrets(vault_secrets)
|
68
|
+
def build_local_secrets(vault_secrets, transit_key)
|
69
69
|
|
70
70
|
# read_local_files uses vault_secrets paths to create a new hash with local paths and values.
|
71
71
|
# This means that we will only compare secrets/paths that exist in both vault and locally.
|
data/lib/sanctum/command/push.rb
CHANGED
@@ -17,7 +17,7 @@ module Sanctum
|
|
17
17
|
# Build array of local paths by recursively searching for local files for each path specified in sanctum.yaml
|
18
18
|
local_paths = get_local_paths(File.join(File.dirname(config_file), target[:path]))
|
19
19
|
|
20
|
-
local_secrets = build_local_secrets(local_paths)
|
20
|
+
local_secrets = build_local_secrets(local_paths, target[:transit_key])
|
21
21
|
vault_secrets = build_vault_secrets(local_paths, target[:prefix], target[:path], target[:secrets_version])
|
22
22
|
|
23
23
|
# Compare secrets
|
@@ -73,7 +73,7 @@ module Sanctum
|
|
73
73
|
tmp_hash
|
74
74
|
end
|
75
75
|
|
76
|
-
def build_local_secrets(local_paths)
|
76
|
+
def build_local_secrets(local_paths, transit_key)
|
77
77
|
# Read each local file
|
78
78
|
local_secrets = read_local_files(local_paths)
|
79
79
|
# Decrypt local secrets
|
@@ -1,20 +1,23 @@
|
|
1
1
|
# sanctum.yml
|
2
2
|
sanctum:
|
3
|
-
# force - defaults to false. Setting to true modifies behavior of push and pull commands.
|
4
|
-
# If true you will not be asked if you want to overwrite changes.
|
5
|
-
#force: false
|
6
3
|
# color - defaults to true. Setting to false will disable color to tty
|
7
4
|
#color: true
|
5
|
+
# force - defaults to false. Setting to true modifies behavior of push and pull commands.
|
6
|
+
# If true you will not be asked if you want to overwrite changes. Can be overridden on a per target basis.
|
7
|
+
#force: false
|
8
|
+
# secrets_version - defaults to `auto`, which will try to automatically detect secrets_version
|
9
|
+
# can be overridden on a per target basis
|
10
|
+
#secrets_version: auto
|
11
|
+
# transit_key - (required if not set ) default transit_key to be used, can be overridden on a per target basis
|
12
|
+
# Transit key ring used to encrypt/decrypt secrets for local storage.
|
13
|
+
# If you need to use multiple transit_keys you will need to create seperate config files
|
14
|
+
#transit_key: transit/keys/app-foo
|
8
15
|
|
9
16
|
vault:
|
10
17
|
# url - will use `ENV["VAULT_ADDR"]` if available, otherwise defaults to http://localhost:8200
|
11
18
|
#url: http://localhost:8200
|
12
19
|
# token - (required) will use `ENV["VAULT_TOKEN"]` if available, otherwise tries to read from `ENV["HOME"]/.vault-token`
|
13
20
|
#token: aaabbbcc-ddee-ffgg-hhii-jjkkllmmnnoop
|
14
|
-
# transit_key - (required) will use `ENV["SANCTUM_TRANSIT_KEY"]` if available.
|
15
|
-
# Transit key ring used to encrypt/decrypt secrets for local storage.
|
16
|
-
# If you need to use multiple transit_keys you will need to create seperate config files
|
17
|
-
#transit_key: transit/keys/app-foo
|
18
21
|
|
19
22
|
sync:
|
20
23
|
# sync is an array of hashes of sync target configurations
|
@@ -26,11 +29,18 @@ sync:
|
|
26
29
|
# with Vault. This path is calculated relative to the directory containing
|
27
30
|
# the sanctum configuration file.
|
28
31
|
# force - Whether or not to force push, pull actions (no user input)
|
29
|
-
#
|
32
|
+
# Inherits the setting from the `sanctum` section.
|
30
33
|
# secrets_version - The k/v secrets version `1`, or `2`. Sanctum will try to detect this automatically
|
31
|
-
# if not valued.
|
32
|
-
#
|
34
|
+
# if not valued. Inherits the setting from the `sanctum` section.
|
35
|
+
# transit_key - (required if not set in `sanctum` section) Transit key ring used to encrypt/decrypt secrets
|
36
|
+
# for local storage. Inherits the setting from the `sanctum` section.
|
33
37
|
#- name: app-foo
|
34
38
|
#prefix: secrets/app-foo
|
35
39
|
#path: vault/app-foo
|
36
40
|
#force: false
|
41
|
+
#- name: app-bar
|
42
|
+
#prefix: app-bar
|
43
|
+
#path: vault/app-bar
|
44
|
+
#transit_key: transit/keys/app-bar
|
45
|
+
#secrets_version: 2
|
46
|
+
#force: false
|
@@ -34,8 +34,6 @@ module Sanctum
|
|
34
34
|
upgrade_response = confirm_upgrade?(target) ? vault_client.request(:post, "/v1/sys/mounts/#{target[:prefix]}/tune", data) : nil
|
35
35
|
end
|
36
36
|
upgrade_response.nil? ? nothing_happened_warning : (warn yellow("#{upgrade_response}\n#{post_upgrade_warning}"))
|
37
|
-
|
38
|
-
post_upgrade_tasks(target)
|
39
37
|
end
|
40
38
|
|
41
39
|
def pre_upgrade_warning
|
@@ -91,30 +89,6 @@ module Sanctum
|
|
91
89
|
false
|
92
90
|
end
|
93
91
|
end
|
94
|
-
|
95
|
-
# Post upgrade tasks if mount is being upgraded from generic mount or v1 mount to v2 mount
|
96
|
-
# Ensure local files mimic vault v2 by add `/data` to local path
|
97
|
-
def post_upgrade_tasks(target)
|
98
|
-
config_path = Pathname.new(config_file).dirname.to_s
|
99
|
-
full_target_path = "#{config_path}/#{target[:path]}"
|
100
|
-
|
101
|
-
old_path = full_target_path.include?("/data") ? full_target_path.sub(/\/data/, "") : full_target_path
|
102
|
-
new_path = full_target_path.include?("/data") ? full_target_path : "#{full_target_path}/data"
|
103
|
-
|
104
|
-
# If old path does not exist, chances are sanctum upgrade is being run before sanctum pull/push.
|
105
|
-
return unless File.directory?(old_path)
|
106
|
-
|
107
|
-
files_to_move = Dir.chdir(old_path) { Dir.glob('*') }.delete_if {|i| i == "data"}
|
108
|
-
unless files_to_move.empty?
|
109
|
-
FileUtils.mkdir_p(new_path) unless File.directory?(new_path)
|
110
|
-
files_to_move.each do |f|
|
111
|
-
FileUtils.mv("#{old_path}/#{f}", new_path, secure: true)
|
112
|
-
end
|
113
|
-
end
|
114
|
-
rescue
|
115
|
-
warn red("Post upgrade tasks failed")
|
116
|
-
raise
|
117
|
-
end
|
118
92
|
end
|
119
93
|
end
|
120
94
|
end
|
data/lib/sanctum/command/view.rb
CHANGED
@@ -5,9 +5,15 @@ module Sanctum
|
|
5
5
|
class View < Base
|
6
6
|
|
7
7
|
def run(command="less")
|
8
|
-
|
8
|
+
if args.one?
|
9
|
+
path = args.first
|
10
|
+
transit_key = determine_transit_key(path, targets)
|
11
|
+
else
|
12
|
+
raise ArgumentError, red('Please pass only one path argument')
|
13
|
+
end
|
9
14
|
|
10
|
-
|
15
|
+
#TODO: Fix later, expects an array of paths
|
16
|
+
local_secrets = read_local_files(["#{path}"])
|
11
17
|
local_secrets = VaultTransit.decrypt(vault_client, local_secrets, transit_key)
|
12
18
|
begin
|
13
19
|
IO.popen(command, "w") { |f| f.puts "#{local_secrets.to_yaml}" }
|
@@ -17,24 +17,34 @@ module Sanctum
|
|
17
17
|
@force = force
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def default_options
|
21
21
|
# default_options will search for config_file or take the path specified via cli
|
22
|
-
|
23
|
-
|
24
|
-
env_options = Env.new.run
|
25
|
-
cli_options = {cli: {targets: targets, force: force }}
|
22
|
+
DefaultOptions.new(config_file).run
|
23
|
+
end
|
26
24
|
|
25
|
+
def config_options
|
26
|
+
config_options = ConfigFile.new(default_options[:config_file]).run
|
27
27
|
# Check that targets specified via commandline actually exist in config_file and update config_options[:sync] array
|
28
28
|
config_options = check_targets(targets, config_options) unless targets.nil?
|
29
|
+
config_options
|
30
|
+
end
|
29
31
|
|
30
|
-
|
32
|
+
def env_options
|
33
|
+
Env.new.run
|
31
34
|
end
|
32
35
|
|
36
|
+
def cli_options
|
37
|
+
{ cli: { targets: targets, force: force } }
|
38
|
+
end
|
33
39
|
|
34
40
|
def merge_options(default_options, config_options, env_options, cli_options)
|
35
41
|
default_options.deep_merge(config_options).deep_merge(env_options).deep_merge(cli_options)
|
36
42
|
end
|
37
43
|
|
44
|
+
def final_options
|
45
|
+
merge_options(default_options, config_options, env_options, cli_options)
|
46
|
+
end
|
47
|
+
|
38
48
|
def check_targets(targets, config_options)
|
39
49
|
tmp_array = Array.new
|
40
50
|
sync = config_options[:sync]
|
@@ -4,7 +4,7 @@ module Sanctum
|
|
4
4
|
attr_reader :env_options
|
5
5
|
|
6
6
|
def initialize
|
7
|
-
@env_options = {vault: {url: ENV["VAULT_ADDR"], token: ENV["VAULT_TOKEN"]
|
7
|
+
@env_options = { vault: { url: ENV["VAULT_ADDR"], token: ENV["VAULT_TOKEN"] } }
|
8
8
|
end
|
9
9
|
|
10
10
|
def run
|
@@ -13,7 +13,7 @@ module Sanctum
|
|
13
13
|
def run
|
14
14
|
{
|
15
15
|
config_file: config_file.nil? ? config_file_search : config_file,
|
16
|
-
sanctum: { color: true, force: false },
|
16
|
+
sanctum: { color: true, force: false, secrets_version: "auto", transit_key: nil },
|
17
17
|
vault: { token: get_vault_token, url: "https://127.0.0.1:8200" },
|
18
18
|
}
|
19
19
|
end
|
@@ -8,6 +8,8 @@ module Sanctum
|
|
8
8
|
def self.encrypt(vault_client, secrets, transit_key)
|
9
9
|
transit_key = Pathname.new(transit_key)
|
10
10
|
|
11
|
+
#TODO probably nice to do this check earlier on,
|
12
|
+
#Such as in command/base
|
11
13
|
unless transit_key_exist?(vault_client, transit_key)
|
12
14
|
raise red("#{transit_key} does not exist")
|
13
15
|
end
|
data/lib/sanctum/version.rb
CHANGED
data/sanctum.gemspec
CHANGED
@@ -31,6 +31,6 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'pry', '~> 0.12.0'
|
32
32
|
spec.add_development_dependency 'rake', '~> 12.0'
|
33
33
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
34
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
34
|
+
spec.add_development_dependency 'rubocop', '~> 0.65.0'
|
35
35
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.32.0'
|
36
36
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sanctum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.5.
|
4
|
+
version: 0.8.5.rc5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Corban Raun
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: vault
|
@@ -114,14 +114,14 @@ dependencies:
|
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
117
|
+
version: 0.65.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
124
|
+
version: 0.65.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: rubocop-rspec
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|