sanctum 0.8.5.rc4 → 0.8.5.rc5

Sign up to get free protection for your applications and to get access to all the features.
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