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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25943604a0d0c1ecf990e5dd50957ead16063674131ac14b97c0f1dfa70526ec
4
- data.tar.gz: a6282afcb3e99108abb97623e3304adcad0025d78193c7680c441f8be905a16c
3
+ metadata.gz: dff385a40c33fc32dc3c5b57c28c1c8493cf9e01dc6e79cfbfee08269a3bd072
4
+ data.tar.gz: ebdd7ba3f3a1020357301d281e4dc474195d8b765a25885f96e10e7a7e6b3573
5
5
  SHA512:
6
- metadata.gz: 6bf7b7f0d5cee948e82611da96eafedf13592b55cfd53af0bf9e314ac698825cd5ca4a9ed4e855e034a3aa751a893f8bbc1ef4b836d2a519bf5a5919d75113d5
7
- data.tar.gz: e76954478cfbc3eac2e6e4ea880077bcc7e22193f1f2f6945fafc172ea9f7e8a9be2ca7c7ab5be75ed7b6abbf49ca5209cc8be67f93983eaaa78162332c8e1c9
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.2
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.rc4)
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.13.0)
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.63.1)
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.63.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` endpoints as such sanctum will automatically add `/data` to your local path in order to reflect the endpoints see [Vault kv v2](https://www.vaultproject.io/docs/secrets/kv/kv-v2.html)**
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>/data/cool-app/dev/env
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>/data/cool-app/dev/env`. You could then push any changes with
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
- * This section is **NOT** required.
113
- * The `vault` section specifies the url, token, and transit_key to the Vault REST API endpoint.
114
- * url, token, and transit_key are **required** and can be set here or through environment variables.
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)
@@ -9,7 +9,7 @@ services:
9
9
  depends_on:
10
10
  - vault
11
11
  vault:
12
- image: vault:1.0.2
12
+ image: vault:1.0.3
13
13
  environment:
14
14
  SKIP_SETCAP: "true"
15
15
  VAULT_DEV_ROOT_TOKEN_ID: "514c55f0-c452-99e3-55e0-8301b770b92c"
data/docker-compose.yml CHANGED
@@ -11,7 +11,7 @@ services:
11
11
  volumes:
12
12
  - ".:/usr/src/app"
13
13
  vault:
14
- image: vault:1.0.2
14
+ image: vault:1.0.3
15
15
  environment:
16
16
  SKIP_SETCAP: "true"
17
17
  VAULT_DEV_ROOT_TOKEN_ID: "514c55f0-c452-99e3-55e0-8301b770b92c"
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: 'Comma seperated list of targets', required: true
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
@@ -10,21 +10,12 @@ module Sanctum
10
10
  include EditorHelper
11
11
  include PathsHelper
12
12
 
13
- attr_reader :options, :args, :transit_key, :targets, :config_file
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
- # If mount options is nil default to api version 1 otherwise use version value
62
- # generic mounts will not have a version specified
63
- if mounts_hash.dig(:data, :secret, "#{h[:prefix]}/".to_sym, :options).nil?
64
- h[:secrets_version] = "1"
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[:secrets_version] = mounts_hash.dig(:data, :secret, "#{h[:prefix]}/".to_sym, :options, :version).to_s
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 or path, add `/data` if secrets_version == "2"
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/data", :secrets_version=>"2"},{}]
74
- def update_prefix_or_path(targets)
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[0]
13
+ path = args.first
14
14
  validate_path(path)
15
- create_file(path, &block)
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
- raise red("Error with editor") unless system(editor, tmp_file.path)
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
@@ -9,15 +9,16 @@ module Sanctum
9
9
 
10
10
  def run(&block)
11
11
  if args.one?
12
- path = args[0]
13
- edit_file(path, &block)
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
- raise red("Error with editor") unless system(editor, tmp_file.path )
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
- rescue JSON::ParserError
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
@@ -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.
@@ -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
- # This inherits the setting from the `sanctum` section.
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. This does not apply to `generic` secrets backend.
32
- # see https://www.vaultproject.io/docs/secrets/kv/index.html
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
@@ -5,9 +5,15 @@ module Sanctum
5
5
  class View < Base
6
6
 
7
7
  def run(command="less")
8
- raise ArgumentError, red('Please provide at least one path') if args.empty?
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
- local_secrets = read_local_files(args)
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 final_options
20
+ def default_options
21
21
  # default_options will search for config_file or take the path specified via cli
22
- default_options = DefaultOptions.new(config_file).run
23
- config_options = ConfigFile.new(default_options[:config_file]).run
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
- merge_options(default_options, config_options, env_options, cli_options)
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"], transit_key: ENV["SANCTUM_TRANSIT_KEY"]}}
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
@@ -1,3 +1,3 @@
1
1
  module Sanctum
2
- VERSION = "0.8.5.rc4"
2
+ VERSION = "0.8.5.rc5"
3
3
  end
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.63.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.rc4
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-02-26 00:00:00.000000000 Z
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.63.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.63.0
124
+ version: 0.65.0
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: rubocop-rspec
127
127
  requirement: !ruby/object:Gem::Requirement