vault 0.12.0 → 0.15.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 5eeb054b599872ef7a225999772c0b486554f339
4
- data.tar.gz: b1524f9c83ea5c2e5c3c74f66fafaa69e47b8c94
2
+ SHA256:
3
+ metadata.gz: 267c85a379172af5c24fd3c3d4e14b9f07991e058f64933b3c56cc07036b053e
4
+ data.tar.gz: 847ead8ea9965e449dfbf11e3447b240e5c016fbe90e177f1ba6adca0615ee18
5
5
  SHA512:
6
- metadata.gz: d49f63c294a4165babfa3c6f2d2dfd90baabff86a964b895eb16b4ab08bd493fb07266c53f95fe2a255e2435df6f2ba42a921a97dfa1b94fe235a8c43e6aa77f
7
- data.tar.gz: c4aa7afc3b28a1aa5912ee184c7a24d07d6c19d61ae922c409cd0c0aaf6cf3efff3c5dd2269ab1d65251a7f1ce35f8cd8810c7b4d516bfd83fff93153ad39ed1
6
+ metadata.gz: 744df9d7282b0f873f008667fbd9c5bd943eea362535cdf872598c5eb5cb9fa36bb91d182a2b3ad0a2877294c16e345d371b33998a83645ba4e6880b13980e0e
7
+ data.tar.gz: 64ac03ddf3a2c5609e2224548353be0d9e640bfba1ec0ec0e215f541f2802db830238373a5b38fb15f77675d75717847468b8e5c2a1331cf609e87ca497e812a
@@ -0,0 +1,85 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ gem: zfhui/ruby-gem@0.2.1
5
+
6
+ references:
7
+ images:
8
+ ubuntu: &UBUNTU_IMAGE ubuntu-1604:201903-01
9
+
10
+ jobs:
11
+ test:
12
+ machine:
13
+ image: *UBUNTU_IMAGE
14
+ parameters:
15
+ ruby-version:
16
+ type: string
17
+ vault-version:
18
+ type: string
19
+ steps:
20
+ - checkout
21
+ # Restore bundle cache
22
+ - restore_cache:
23
+ keys:
24
+ - v1-dependencies-bundler-<< parameters.ruby-version >>-{{ checksum "vault.gemspec" }}
25
+ # fallback to using the latest cache if no exact match is found
26
+ - v1-dependencies-bundler-
27
+ - run:
28
+ name: Install vault
29
+ command: |
30
+ curl -sLo vault.zip https://releases.hashicorp.com/vault/<< parameters.vault-version >>/vault_<< parameters.vault-version >>_linux_amd64.zip
31
+ unzip vault.zip
32
+ mkdir -p ~/bin
33
+ mv vault ~/bin
34
+ export PATH="~/bin:$PATH"
35
+ - run:
36
+ name: Set ruby version
37
+ command: |
38
+ rvm install << parameters.ruby-version >>
39
+ echo . $(rvm << parameters.ruby-version >> do rvm env --path) >> $BASH_ENV
40
+ - run:
41
+ name: Run tests
42
+ command: |
43
+ export VAULT_VERSION=<< parameters.vault-version >>
44
+ ruby --version
45
+ gem install bundler
46
+ bundle -v
47
+ bundle install --jobs=3 --retry=3 --path=vendor/bundle
48
+ bundle exec rake
49
+ # Store bundle cache
50
+ - save_cache:
51
+ key: v1-dependencies-bundler-<< parameters.ruby-version >>-{{ checksum "vault.gemspec" }}
52
+ paths:
53
+ - vendor/bundle
54
+
55
+ build-release:
56
+ working_directory: ~/repo
57
+ executor: gem/default
58
+ steps:
59
+ - gem/build:
60
+ gem-name: vault
61
+ - gem/release:
62
+ gem-name: vault
63
+ gem-credentials-env-name: $RUBYGEMS_API_KEY
64
+
65
+ workflows:
66
+ run-tests:
67
+ jobs:
68
+ - test:
69
+ filters:
70
+ tags:
71
+ only: /^v[0-9]+\.[0-9]+\.[0-9]+.*/
72
+ matrix:
73
+ parameters:
74
+ ruby-version: ["2.7.1", "2.6", "2.5"]
75
+ vault-version: ["1.5.0", "1.4.2", "1.4.1", "1.4.0", "1.3.6"]
76
+ name: test-ruby-<< matrix.ruby-version >>-vault-<< matrix.vault-version >>
77
+ - build-release:
78
+ requires:
79
+ - test
80
+ context: vault-gem-release
81
+ filters:
82
+ tags:
83
+ only: /^v[0-9]+\.[0-9]+\.[0-9]+.*/
84
+ branches:
85
+ ignore: /.*/
@@ -1,5 +1,37 @@
1
1
  # Vault Ruby Changelog
2
2
 
3
+ ## v0.15.0 (July 29, 2020)
4
+
5
+ IMPROVEMENTS
6
+
7
+ - Added support for Resource Quotas
8
+
9
+ ## v0.14.0 (May 28, 2020)
10
+
11
+ IMPROVEMENTS
12
+
13
+ - Added support for the Transform Secrets Engine
14
+
15
+ ## v0.13.2 (May 7, 2020)
16
+
17
+ BUG FIXES
18
+
19
+ - Fixed the ability to use namespace as an option for each request. Previously, that option was ignored.
20
+ - aws-sigv4 gem was unlocked after a bug in 1.1.2 broke CI
21
+
22
+ ## v0.13.1 (April 28, 2020)
23
+
24
+ IMPROVEMENTS
25
+
26
+ - Added support for defining a namespace when initializing the client, as well as options for changing the namespace via method.
27
+ - Added support for sys/namespaces API. Ability to Get, Create, Delete, and List namespaces has been provided.
28
+
29
+ ## v0.13.0 (October 1, 2019)
30
+
31
+ IMPROVEMENTS
32
+
33
+ - Add support for versioned KV secrets in the client
34
+
3
35
  ## v0.12.0 (August 14, 2018)
4
36
 
5
37
  IMPROVEMENTS
data/README.md CHANGED
@@ -28,6 +28,8 @@ Start a Vault client:
28
28
  ```ruby
29
29
  Vault.address = "http://127.0.0.1:8200" # Also reads from ENV["VAULT_ADDR"]
30
30
  Vault.token = "abcd-1234" # Also reads from ENV["VAULT_TOKEN"]
31
+ # Optional - if using the Namespace enterprise feature
32
+ # Vault.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
31
33
 
32
34
  Vault.sys.mounts #=> { :secret => #<struct Vault::Mount type="generic", description="generic secret storage"> }
33
35
  ```
@@ -43,6 +45,8 @@ Vault.configure do |config|
43
45
 
44
46
  # The token to authenticate with Vault, also read as ENV["VAULT_TOKEN"]
45
47
  config.token = "abcd-1234"
48
+ # Optional - if using the Namespace enterprise feature
49
+ # config.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
46
50
 
47
51
  # Proxy connection information, also read as ENV["VAULT_PROXY_(thing)"]
48
52
  config.proxy_address = "..."
@@ -85,7 +89,8 @@ And if you want to authenticate with a `AWS EC2` :
85
89
  # Export VAULT_ADDR to ENV then
86
90
  # Get the pkcs7 value from AWS
87
91
  signature = `curl http://169.254.169.254/latest/dynamic/instance-identity/pkcs7`
88
- vault_token = Vault.auth.aws_ec2(ENV['EC2_ROLE'], signature, nil)
92
+ iam_role = `curl http://169.254.169.254/latest/meta-data/iam/security-credentials/`
93
+ vault_token = Vault.auth.aws_ec2(iam_role, signature, nil)
89
94
  vault_client = Vault::Client.new(address: ENV["VAULT_ADDR"], token: vault_token.auth.client_token)
90
95
  ```
91
96
 
@@ -117,7 +122,9 @@ For advanced users, the first argument of the block is the attempt number and th
117
122
 
118
123
  ```ruby
119
124
  Vault.with_retries(Vault::HTTPConnectionError, Vault::HTTPError) do |attempt, e|
120
- log "Received exception #{e} from Vault - attempt #{attempt}"
125
+ if e
126
+ log "Received exception #{e} from Vault - attempt #{attempt}"
127
+ end
121
128
  Vault.logical.read("secret/bacon")
122
129
  end
123
130
  ```
@@ -206,7 +213,8 @@ Development
206
213
 
207
214
  Important Notes:
208
215
 
209
- - **All new features must include test coverage.** At a bare minimum, Unit tests are required. It is preferred if you include acceptance tests as well.
216
+ - **All new features must include test coverage.** At a bare minimum, Unit tests are required. It is preferred if you include integration tests as well.
210
217
  - **The tests must be be idempotent.** The HTTP calls made during a test should be able to be run over and over.
211
218
  - **Tests are order independent.** The default RSpec configuration randomizes the test order, so this should not be a problem.
212
219
  - **Integration tests require Vault** Vault must be available in the path for the integration tests to pass.
220
+ - **In order to be considered an integration test:** The test MUST use the `vault_test_client` or `vault_redirect_test_client` as the client. This spawns a process, or uses an already existing process from another test, to run against.
@@ -5,8 +5,10 @@ module Vault
5
5
  require_relative "api/auth_tls"
6
6
  require_relative "api/auth"
7
7
  require_relative "api/help"
8
+ require_relative "api/kv"
8
9
  require_relative "api/logical"
9
10
  require_relative "api/secret"
10
11
  require_relative "api/sys"
12
+ require_relative "api/transform"
11
13
  end
12
14
  end
@@ -0,0 +1,207 @@
1
+ require_relative "secret"
2
+ require_relative "../client"
3
+ require_relative "../request"
4
+ require_relative "../response"
5
+
6
+ module Vault
7
+ class Client
8
+ # A proxy to the {KV} methods.
9
+ # @return [KV]
10
+ def kv(mount)
11
+ KV.new(self, mount)
12
+ end
13
+ end
14
+
15
+ class KV < Request
16
+ attr_reader :mount
17
+
18
+ def initialize(client, mount)
19
+ super client
20
+
21
+ @mount = mount
22
+ end
23
+
24
+ # List the names of secrets at the given path, if the path supports
25
+ # listing. If the the path does not exist, an empty array will be returned.
26
+ #
27
+ # @example
28
+ # Vault.kv("secret").list("foo") #=> ["bar", "baz"]
29
+ #
30
+ # @param [String] path
31
+ # the path to list
32
+ #
33
+ # @return [Array<String>]
34
+ def list(path = "", options = {})
35
+ headers = extract_headers!(options)
36
+ json = client.list("/v1/#{mount}/metadata/#{encode_path(path)}", {}, headers)
37
+ json[:data][:keys] || []
38
+ rescue HTTPError => e
39
+ return [] if e.code == 404
40
+ raise
41
+ end
42
+
43
+ # Read the secret at the given path. If the secret does not exist, +nil+
44
+ # will be returned. The latest version is returned by default, but you
45
+ # can request a specific version.
46
+ #
47
+ # @example
48
+ # Vault.kv("secret").read("password") #=> #<Vault::Secret lease_id="">
49
+ #
50
+ # @param [String] path
51
+ # the path to read
52
+ # @param [Integer] version
53
+ # the version of the secret
54
+ #
55
+ # @return [Secret, nil]
56
+ def read(path, version = nil, options = {})
57
+ headers = extract_headers!(options)
58
+ params = {}
59
+ params[:version] = version unless version.nil?
60
+
61
+ json = client.get("/v1/#{mount}/data/#{encode_path(path)}", params, headers)
62
+ return Secret.decode(json[:data])
63
+ rescue HTTPError => e
64
+ return nil if e.code == 404
65
+ raise
66
+ end
67
+
68
+ # Read the metadata of a secret at the given path. If the secret does not
69
+ # exist, nil will be returned.
70
+ #
71
+ # @example
72
+ # Vault.kv("secret").read_metadata("password") => {...}
73
+ #
74
+ # @param [String] path
75
+ # the path to read
76
+ #
77
+ # @return [Hash, nil]
78
+ def read_metadata(path)
79
+ client.get("/v1/#{mount}/metadata/#{encode_path(path)}")[:data]
80
+ rescue HTTPError => e
81
+ return nil if e.code == 404
82
+ raise
83
+ end
84
+
85
+ # Write the secret at the given path with the given data. Note that the
86
+ # data must be a {Hash}!
87
+ #
88
+ # @example
89
+ # Vault.logical.write("secret/password", value: "secret") #=> #<Vault::Secret lease_id="">
90
+ #
91
+ # @param [String] path
92
+ # the path to write
93
+ # @param [Hash] data
94
+ # the data to write
95
+ #
96
+ # @return [Secret]
97
+ def write(path, data = {}, options = {})
98
+ headers = extract_headers!(options)
99
+ json = client.post("/v1/#{mount}/data/#{encode_path(path)}", JSON.fast_generate(:data => data), headers)
100
+ if json.nil?
101
+ return true
102
+ else
103
+ return Secret.decode(json)
104
+ end
105
+ end
106
+
107
+ # Write the metadata of a secret at the given path. Note that the data must
108
+ # be a {Hash}.
109
+ #
110
+ # @example
111
+ # Vault.kv("secret").write_metadata("password", max_versions => 3)
112
+ #
113
+ # @param [String] path
114
+ # the path to write
115
+ # @param [Hash] metadata
116
+ # the metadata to write
117
+ #
118
+ # @return [true]
119
+ def write_metadata(path, metadata = {})
120
+ client.post("/v1/#{mount}/metadata/#{encode_path(path)}", JSON.fast_generate(metadata))
121
+
122
+ true
123
+ end
124
+
125
+ # Delete the secret at the given path. If the secret does not exist, vault
126
+ # will still return true.
127
+ #
128
+ # @example
129
+ # Vault.logical.delete("secret/password") #=> true
130
+ #
131
+ # @param [String] path
132
+ # the path to delete
133
+ #
134
+ # @return [true]
135
+ def delete(path)
136
+ client.delete("/v1/#{mount}/data/#{encode_path(path)}")
137
+
138
+ true
139
+ end
140
+
141
+ # Mark specific versions of a secret as deleted.
142
+ #
143
+ # @example
144
+ # Vault.kv("secret").delete_versions("password", [1, 2])
145
+ #
146
+ # @param [String] path
147
+ # the path to remove versions from
148
+ # @param [Array<Integer>] versions
149
+ # an array of versions to remove
150
+ #
151
+ # @return [true]
152
+ def delete_versions(path, versions)
153
+ client.post("/v1/#{mount}/delete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
154
+
155
+ true
156
+ end
157
+
158
+ # Mark specific versions of a secret as active.
159
+ #
160
+ # @example
161
+ # Vault.kv("secret").undelete_versions("password", [1, 2])
162
+ #
163
+ # @param [String] path
164
+ # the path to enable versions for
165
+ # @param [Array<Integer>] versions
166
+ # an array of versions to mark as undeleted
167
+ #
168
+ # @return [true]
169
+ def undelete_versions(path, versions)
170
+ client.post("/v1/#{mount}/undelete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
171
+
172
+ true
173
+ end
174
+
175
+ # Completely remove a secret and its metadata.
176
+ #
177
+ # @example
178
+ # Vault.kv("secret").destroy("password")
179
+ #
180
+ # @param [String] path
181
+ # the path to remove
182
+ #
183
+ # @return [true]
184
+ def destroy(path)
185
+ client.delete("/v1/#{mount}/metadata/#{encode_path(path)}")
186
+
187
+ true
188
+ end
189
+
190
+ # Completely remove specific versions of a secret.
191
+ #
192
+ # @example
193
+ # Vault.kv("secret").destroy_versions("password", [1, 2])
194
+ #
195
+ # @param [String] path
196
+ # the path to remove versions from
197
+ # @param [Array<Integer>] versions
198
+ # an array of versions to destroy
199
+ #
200
+ # @return [true]
201
+ def destroy_versions(path, versions)
202
+ client.post("/v1/#{mount}/destroy/#{encode_path(path)}", JSON.fast_generate(versions: versions))
203
+
204
+ true
205
+ end
206
+ end
207
+ end
@@ -32,6 +32,18 @@ module Vault
32
32
  # @return [Hash<Symbol, Object>]
33
33
  field :data, freeze: true
34
34
 
35
+ # @!attribute [r] metadata
36
+ # Read-only metadata information related to the secret.
37
+ #
38
+ # @example Reading metadata
39
+ # secret = Vault.logical(:versioned).read("secret", "foo")
40
+ # secret.metadata[:created_time] #=> "2018-12-08T04:22:54.168065Z"
41
+ # secret.metadata[:version] #=> 1
42
+ # secret.metadata[:destroyed] #=> false
43
+ #
44
+ # @return [Hash<Symbol, Object>]
45
+ field :metadata, freeze: true
46
+
35
47
  # @!attribute [r] lease_duration
36
48
  # The number of seconds this lease is valid. If this number is 0 or nil,
37
49
  # the secret does not expire.
@@ -21,5 +21,7 @@ require_relative "sys/init"
21
21
  require_relative "sys/leader"
22
22
  require_relative "sys/lease"
23
23
  require_relative "sys/mount"
24
+ require_relative "sys/namespace"
24
25
  require_relative "sys/policy"
26
+ require_relative "sys/quota"
25
27
  require_relative "sys/seal"
@@ -16,6 +16,11 @@ module Vault
16
16
  # Type of the mount.
17
17
  # @return [String]
18
18
  field :type
19
+
20
+ # @!attribute [r] type
21
+ # Options given to the mount.
22
+ # @return [Hash<Symbol, Object>]
23
+ field :options
19
24
  end
20
25
 
21
26
  class Sys < Request
@@ -44,8 +49,8 @@ module Vault
44
49
  # the type of mount
45
50
  # @param [String] description
46
51
  # a human-friendly description (optional)
47
- def mount(path, type, description = nil)
48
- payload = { type: type }
52
+ def mount(path, type, description = nil, options = {})
53
+ payload = options.merge type: type
49
54
  payload[:description] = description if !description.nil?
50
55
 
51
56
  client.post("/v1/sys/mounts/#{encode_path(path)}", JSON.fast_generate(payload))
@@ -0,0 +1,83 @@
1
+ module Vault
2
+ class Namespace < Response
3
+ # @!attribute [r] id
4
+ # ID of the namespace
5
+ # @return [String]
6
+ field :id
7
+
8
+ # @!attribute [r] path
9
+ # Path of the namespace, includes parent paths if nested.
10
+ # @return [String]
11
+ field :path
12
+ end
13
+
14
+ class Sys
15
+ # List all namespaces in a given scope. Ignores nested namespaces.
16
+ #
17
+ # @example
18
+ # Vault.sys.namespaces #=> { :foo => #<struct Vault::Namespace id="xxxx1", path="foo/" }
19
+ #
20
+ # @return [Hash<Symbol, Namespace>]
21
+ def namespaces(scoped=nil)
22
+ path = ["v1", scoped, "sys", "namespaces"].compact
23
+ json = client.list(path.join("/"))
24
+ json = json[:data] if json[:data]
25
+ if json[:key_info]
26
+ json = json[:key_info]
27
+ hash = {}
28
+ json.each do |k,v|
29
+ hash[k.to_s.chomp("/").to_sym] = Namespace.decode(v)
30
+ end
31
+ hash
32
+ else
33
+ json
34
+ end
35
+ end
36
+
37
+ # Create a namespace. Nests the namespace if a namespace header is provided.
38
+ #
39
+ # @example
40
+ # Vault.sys.create_namespace("foo")
41
+ #
42
+ # @param [String] namespace
43
+ # the potential path of the namespace, without any parent path provided
44
+ #
45
+ # @return [true]
46
+ def create_namespace(namespace)
47
+ client.put("/v1/sys/namespaces/#{namespace}", {})
48
+ return true
49
+ end
50
+
51
+ # Delete a namespace. Raises an error if the namespace provided is not empty.
52
+ #
53
+ # @example
54
+ # Vault.sys.delete_namespace("foo")
55
+ #
56
+ # @param [String] namespace
57
+ # the path of the namespace to be deleted
58
+ #
59
+ # @return [true]
60
+ def delete_namespace(namespace)
61
+ client.delete("/v1/sys/namespaces/#{namespace}")
62
+ return true
63
+ end
64
+
65
+ # Retrieve a namespace by path.
66
+ #
67
+ # @example
68
+ # Vault.sys.get_namespace("foo")
69
+ #
70
+ # @param [String] namespace
71
+ # the path of the namespace ot be retrieved
72
+ #
73
+ # @return [Namespace]
74
+ def get_namespace(namespace)
75
+ json = client.get("/v1/sys/namespaces/#{namespace}")
76
+ if data = json.dig(:data)
77
+ Namespace.decode(data)
78
+ else
79
+ json
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,107 @@
1
+ module Vault
2
+ class Quota < Response
3
+ # @!attribute [r] name
4
+ # Name of the quota rule.
5
+ # @return [String]
6
+ field :name
7
+
8
+ # @!attribute [r] path
9
+ # Namespace/Path combination the quota applies to.
10
+ # @return [String]
11
+ field :path
12
+
13
+ # @!attribute [r] type
14
+ # Type of the quota rule, must be one of "lease-count" or "rate-limit"
15
+ # @return [String]
16
+ field :type
17
+ end
18
+
19
+ class RateLimitQuota < Quota
20
+ # @!attribute [r] rate
21
+ # The rate at which allowed requests are refilled per second by the quota
22
+ # rule.
23
+ # @return [Float]
24
+ field :rate
25
+
26
+ # @!attribute [r] burst
27
+ # The maximum number of requests at any given second allowed by the quota
28
+ # rule.
29
+ # @return [Int]
30
+ field :burst
31
+ end
32
+
33
+ class LeaseCountQuota < Quota
34
+ # @!attribute [r] counter
35
+ # Number of currently active leases for the quota.
36
+ # @return [Int]
37
+ field :counter
38
+
39
+ # @!attribute [r] max_leases
40
+ # The maximum number of allowed leases for this quota.
41
+ # @return [Int]
42
+ field :max_leases
43
+ end
44
+
45
+ class Sys
46
+ def quotas(type)
47
+ path = generate_path(type)
48
+ json = client.list(path)
49
+ if data = json.dig(:data, :key_info)
50
+ data.map do |item|
51
+ type_class(type).decode(item)
52
+ end
53
+ else
54
+ json
55
+ end
56
+ end
57
+
58
+ def create_quota(type, name, opts={})
59
+ path = generate_path(type, name)
60
+ client.post(path, JSON.fast_generate(opts))
61
+ return true
62
+ end
63
+
64
+ def delete_quota(type, name)
65
+ path = generate_path(type, name)
66
+ client.delete(path)
67
+ return true
68
+ end
69
+
70
+ def get_quota(type, name)
71
+ path = generate_path(type, name)
72
+ response = client.get(path)
73
+ if data = response[:data]
74
+ type_class(type).decode(data)
75
+ end
76
+ end
77
+
78
+ def get_quota_config
79
+ client.get("v1/sys/quotas/config")
80
+ end
81
+
82
+ def update_quota_config(opts={})
83
+ client.post("v1/sys/quotas/config", JSON.fast_generate(opts))
84
+ return true
85
+ end
86
+
87
+ private
88
+
89
+ def generate_path(type, name=nil)
90
+ verify_type(type)
91
+ path = ["v1", "sys", "quotas", type, name].compact
92
+ path.join("/")
93
+ end
94
+
95
+ def verify_type(type)
96
+ return if ["rate-limit", "lease-count"].include?(type)
97
+ raise ArgumentError, "type must be one of \"rate-limit\" or \"lease-count\""
98
+ end
99
+
100
+ def type_class(type)
101
+ case type
102
+ when "lease-count" then LeaseCountQuota
103
+ when "rate-limit" then RateLimitQuota
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,29 @@
1
+ require_relative '../client'
2
+ require_relative '../request'
3
+
4
+ module Vault
5
+ class Client
6
+ # A proxy to the {Transform} methods.
7
+ # @return [Transform]
8
+ def transform
9
+ @transform ||= Transform.new(self)
10
+ end
11
+ end
12
+
13
+ class Transform < Request
14
+ def encode(role_name:, **opts)
15
+ opts ||= {}
16
+ client.post("/v1/transform/encode/#{encode_path(role_name)}", JSON.fast_generate(opts))
17
+ end
18
+
19
+ def decode(role_name:, **opts)
20
+ opts ||= {}
21
+ client.post("/v1/transform/decode/#{encode_path(role_name)}", JSON.fast_generate(opts))
22
+ end
23
+ end
24
+ end
25
+
26
+ require_relative 'transform/alphabet'
27
+ require_relative 'transform/role'
28
+ require_relative 'transform/template'
29
+ require_relative 'transform/transformation'
@@ -0,0 +1,43 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Alphabet < Response
7
+ # @!attribute [r] id
8
+ # String listing all possible characters of the alphabet
9
+ # @return [String]
10
+ field :alphabet
11
+ end
12
+
13
+ def create_alphabet(name, alphabet:, **opts)
14
+ opts ||= {}
15
+ opts[:alphabet] = alphabet
16
+ client.post("/v1/transform/alphabet/#{encode_path(name)}", JSON.fast_generate(opts))
17
+ return true
18
+ end
19
+
20
+ def get_alphabet(name)
21
+ json = client.get("/v1/transform/alphabet/#{encode_path(name)}")
22
+ if data = json.dig(:data)
23
+ Alphabet.decode(data)
24
+ else
25
+ json
26
+ end
27
+ end
28
+
29
+ def delete_alphabet(name)
30
+ client.delete("/v1/transform/alphabet/#{encode_path(name)}")
31
+ true
32
+ end
33
+
34
+ def alphabets
35
+ json = client.list("/v1/transform/alphabet")
36
+ if keys = json.dig(:data, :keys)
37
+ keys
38
+ else
39
+ json
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,42 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Role < Response
7
+ # @!attribute [r] transformations
8
+ # Array of all transformations the role has access to
9
+ # @return [Array<String>]
10
+ field :transformations
11
+ end
12
+
13
+ def create_role(name, **opts)
14
+ opts ||= {}
15
+ client.post("/v1/transform/role/#{encode_path(name)}", JSON.fast_generate(opts))
16
+ return true
17
+ end
18
+
19
+ def get_role(name)
20
+ json = client.get("/v1/transform/role/#{encode_path(name)}")
21
+ if data = json.dig(:data)
22
+ Role.decode(data)
23
+ else
24
+ json
25
+ end
26
+ end
27
+
28
+ def delete_role(name)
29
+ client.delete("/v1/transform/role/#{encode_path(name)}")
30
+ true
31
+ end
32
+
33
+ def roles
34
+ json = client.list("/v1/transform/role")
35
+ if keys = json.dig(:data, :keys)
36
+ keys
37
+ else
38
+ json
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,54 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Template < Response
7
+ # @!attribute [r] alphabet
8
+ # Name of the alphabet to be used in the template
9
+ # @return [String]
10
+ field :alphabet
11
+
12
+ # @!attribute [r] pattern
13
+ # Regex string to detect and match for the template
14
+ # @return [String]
15
+ field :pattern
16
+
17
+ # @!attribute [r] type
18
+ # Type of the template, currently, only "regex" is supported
19
+ # @return [String]
20
+ field :type
21
+ end
22
+
23
+ def create_template(name, type:, pattern:, **opts)
24
+ opts ||= {}
25
+ opts[:type] = type
26
+ opts[:pattern] = pattern
27
+ client.post("/v1/transform/template/#{encode_path(name)}", JSON.fast_generate(opts))
28
+ return true
29
+ end
30
+
31
+ def get_template(name)
32
+ json = client.get("/v1/transform/template/#{encode_path(name)}")
33
+ if data = json.dig(:data)
34
+ Template.decode(data)
35
+ else
36
+ json
37
+ end
38
+ end
39
+
40
+ def delete_template(name)
41
+ client.delete("/v1/transform/template/#{encode_path(name)}")
42
+ true
43
+ end
44
+
45
+ def templates
46
+ json = client.list("/v1/transform/template")
47
+ if keys = json.dig(:data, :keys)
48
+ keys
49
+ else
50
+ json
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ require_relative '../../request'
2
+ require_relative '../../response'
3
+
4
+ module Vault
5
+ class Transform < Request
6
+ class Transformation < Response
7
+ # @!attribute [r] allowed_roles
8
+ # Array of role names that are allowed to use this transformation
9
+ # @return [Array<String>]
10
+ field :allowed_roles
11
+
12
+ # @!attribute [r] templates
13
+ # Array of template names accessible to this transformation
14
+ # @return [Array<String>]
15
+ field :templates
16
+
17
+ # @!attribute [r] tweak_source
18
+ # String representing how a tweak is provided for this transformation.
19
+ # Available tweaks are "supplied", "generated", and "internal"
20
+ # @return [String]
21
+ field :tweak_source
22
+
23
+ # @!attribute [r] type
24
+ # String representing the type of transformation this is.
25
+ # Available types are "fpe", and "masking"
26
+ # @return [String]
27
+ field :type
28
+ end
29
+
30
+ def create_transformation(name, type:, template:, **opts)
31
+ opts ||= {}
32
+ opts[:type] = type
33
+ opts[:template] = template
34
+ client.post("/v1/transform/transformation/#{encode_path(name)}", JSON.fast_generate(opts))
35
+ return true
36
+ end
37
+
38
+ def get_transformation(name)
39
+ json = client.get("/v1/transform/transformation/#{encode_path(name)}")
40
+ if data = json.dig(:data)
41
+ Transformation.decode(data)
42
+ else
43
+ json
44
+ end
45
+ end
46
+
47
+ def delete_transformation(name)
48
+ client.delete("/v1/transform/transformation/#{encode_path(name)}")
49
+ true
50
+ end
51
+
52
+ def transformations
53
+ json = client.list("/v1/transform/transformation")
54
+ if keys = json.dig(:data, :keys)
55
+ keys
56
+ else
57
+ json
58
+ end
59
+ end
60
+ end
61
+ end
@@ -16,6 +16,9 @@ module Vault
16
16
  # The name of the header used to hold the Vault token.
17
17
  TOKEN_HEADER = "X-Vault-Token".freeze
18
18
 
19
+ # The name of the header used to hold the Namespace.
20
+ NAMESPACE_HEADER = "X-Vault-Namespace".freeze
21
+
19
22
  # The name of the header used to hold the wrapped request ttl.
20
23
  WRAP_TTL_HEADER = "X-Vault-Wrap-TTL".freeze
21
24
 
@@ -255,6 +258,12 @@ module Vault
255
258
  headers[TOKEN_HEADER] ||= token
256
259
  end
257
260
 
261
+ # Add the Vault Namespace header - users could still override this on a
262
+ # per-request basis
263
+ if !namespace.nil?
264
+ headers[NAMESPACE_HEADER] ||= namespace
265
+ end
266
+
258
267
  # Add headers
259
268
  headers.each do |key, value|
260
269
  request.add_field(key, value)
@@ -7,6 +7,7 @@ module Vault
7
7
  :address,
8
8
  :token,
9
9
  :hostname,
10
+ :namespace,
10
11
  :open_timeout,
11
12
  :proxy_address,
12
13
  :proxy_password,
@@ -61,6 +61,13 @@ module Vault
61
61
  nil
62
62
  end
63
63
 
64
+
65
+ # Vault Namespace, if any.
66
+ # @return [String, nil]
67
+ def namespace
68
+ ENV["VAULT_NAMESPACE"]
69
+ end
70
+
64
71
  # The SNI host to use when connecting to Vault via TLS.
65
72
  # @return [String, nil]
66
73
  def hostname
@@ -29,6 +29,7 @@ module Vault
29
29
  def extract_headers!(options = {})
30
30
  extract = {
31
31
  wrap_ttl: Vault::Client::WRAP_TTL_HEADER,
32
+ namespace: Vault::Client::NAMESPACE_HEADER,
32
33
  }
33
34
 
34
35
  {}.tap do |h|
@@ -1,3 +1,3 @@
1
1
  module Vault
2
- VERSION = "0.12.0"
2
+ VERSION = "0.15.0"
3
3
  end
@@ -21,10 +21,10 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_runtime_dependency "aws-sigv4"
23
23
 
24
- spec.add_development_dependency "bundler"
25
- spec.add_development_dependency "pry"
24
+ spec.add_development_dependency "bundler", "~> 2"
25
+ spec.add_development_dependency "pry", "~> 0.13.1"
26
26
  spec.add_development_dependency "rake", "~> 12.0"
27
27
  spec.add_development_dependency "rspec", "~> 3.5"
28
- spec.add_development_dependency "yard"
29
- spec.add_development_dependency "webmock", "~> 2.3"
28
+ spec.add_development_dependency "yard", "~> 0.9.24"
29
+ spec.add_development_dependency "webmock", "~> 3.8.3"
30
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vault
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seth Vargo
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-14 00:00:00.000000000 Z
11
+ date: 2020-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sigv4
@@ -28,30 +28,30 @@ dependencies:
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '2'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '2'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.13.1
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.13.1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -84,30 +84,30 @@ dependencies:
84
84
  name: yard
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ">="
87
+ - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0'
89
+ version: 0.9.24
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ">="
94
+ - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0'
96
+ version: 0.9.24
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: webmock
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '2.3'
103
+ version: 3.8.3
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '2.3'
110
+ version: 3.8.3
111
111
  description: Vault is a Ruby API client for interacting with a Vault server.
112
112
  email:
113
113
  - sethvargo@gmail.com
@@ -115,9 +115,9 @@ executables: []
115
115
  extensions: []
116
116
  extra_rdoc_files: []
117
117
  files:
118
+ - ".circleci/config.yml"
118
119
  - ".gitignore"
119
120
  - ".rspec"
120
- - ".travis.yml"
121
121
  - CHANGELOG.md
122
122
  - Gemfile
123
123
  - LICENSE
@@ -130,6 +130,7 @@ files:
130
130
  - lib/vault/api/auth_tls.rb
131
131
  - lib/vault/api/auth_token.rb
132
132
  - lib/vault/api/help.rb
133
+ - lib/vault/api/kv.rb
133
134
  - lib/vault/api/logical.rb
134
135
  - lib/vault/api/secret.rb
135
136
  - lib/vault/api/sys.rb
@@ -140,8 +141,15 @@ files:
140
141
  - lib/vault/api/sys/leader.rb
141
142
  - lib/vault/api/sys/lease.rb
142
143
  - lib/vault/api/sys/mount.rb
144
+ - lib/vault/api/sys/namespace.rb
143
145
  - lib/vault/api/sys/policy.rb
146
+ - lib/vault/api/sys/quota.rb
144
147
  - lib/vault/api/sys/seal.rb
148
+ - lib/vault/api/transform.rb
149
+ - lib/vault/api/transform/alphabet.rb
150
+ - lib/vault/api/transform/role.rb
151
+ - lib/vault/api/transform/template.rb
152
+ - lib/vault/api/transform/transformation.rb
145
153
  - lib/vault/client.rb
146
154
  - lib/vault/configurable.rb
147
155
  - lib/vault/defaults.rb
@@ -177,8 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
185
  - !ruby/object:Gem::Version
178
186
  version: '0'
179
187
  requirements: []
180
- rubyforge_project:
181
- rubygems_version: 2.6.14
188
+ rubygems_version: 3.1.2
182
189
  signing_key:
183
190
  specification_version: 4
184
191
  summary: Vault is a Ruby API client for interacting with a Vault server.
@@ -1,26 +0,0 @@
1
- dist: trusty
2
- sudo: false
3
- language: ruby
4
- cache: bundler
5
-
6
- env:
7
- - VAULT_VERSION=0.8.3
8
- - VAULT_VERSION=0.7.3
9
- - VAULT_VERSION=0.6.5
10
- - VAULT_VERSION=0.5.3
11
-
12
- before_install:
13
- - curl -sLo vault.zip https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
14
- - unzip vault.zip
15
- - mkdir -p ~/bin
16
- - mv vault ~/bin
17
- - export PATH="~/bin:$PATH"
18
-
19
- branches:
20
- only:
21
- - master
22
-
23
- rvm:
24
- - 2.2
25
- - 2.3
26
- - 2.4