vault_ruby_client 0.18.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +287 -0
  3. data/LICENSE +364 -0
  4. data/README.md +223 -0
  5. data/lib/vault/api/approle.rb +221 -0
  6. data/lib/vault/api/auth.rb +324 -0
  7. data/lib/vault/api/auth_tls.rb +95 -0
  8. data/lib/vault/api/auth_token.rb +245 -0
  9. data/lib/vault/api/help.rb +36 -0
  10. data/lib/vault/api/kv.rb +230 -0
  11. data/lib/vault/api/logical.rb +153 -0
  12. data/lib/vault/api/secret.rb +171 -0
  13. data/lib/vault/api/sys/audit.rb +94 -0
  14. data/lib/vault/api/sys/auth.rb +119 -0
  15. data/lib/vault/api/sys/health.rb +66 -0
  16. data/lib/vault/api/sys/init.rb +86 -0
  17. data/lib/vault/api/sys/leader.rb +51 -0
  18. data/lib/vault/api/sys/lease.rb +52 -0
  19. data/lib/vault/api/sys/mount.rb +165 -0
  20. data/lib/vault/api/sys/namespace.rb +86 -0
  21. data/lib/vault/api/sys/policy.rb +95 -0
  22. data/lib/vault/api/sys/quota.rb +110 -0
  23. data/lib/vault/api/sys/seal.rb +84 -0
  24. data/lib/vault/api/sys.rb +30 -0
  25. data/lib/vault/api/transform/alphabet.rb +46 -0
  26. data/lib/vault/api/transform/role.rb +45 -0
  27. data/lib/vault/api/transform/template.rb +57 -0
  28. data/lib/vault/api/transform/transformation.rb +64 -0
  29. data/lib/vault/api/transform.rb +32 -0
  30. data/lib/vault/api.rb +17 -0
  31. data/lib/vault/client.rb +460 -0
  32. data/lib/vault/configurable.rb +53 -0
  33. data/lib/vault/defaults.rb +218 -0
  34. data/lib/vault/encode.rb +22 -0
  35. data/lib/vault/errors.rb +87 -0
  36. data/lib/vault/persistent/connection.rb +45 -0
  37. data/lib/vault/persistent/pool.rb +51 -0
  38. data/lib/vault/persistent/timed_stack_multi.rb +73 -0
  39. data/lib/vault/persistent.rb +1161 -0
  40. data/lib/vault/request.rb +47 -0
  41. data/lib/vault/response.rb +92 -0
  42. data/lib/vault/vendor/connection_pool/timed_stack.rb +181 -0
  43. data/lib/vault/vendor/connection_pool/version.rb +8 -0
  44. data/lib/vault/vendor/connection_pool.rb +153 -0
  45. data/lib/vault/version.rb +6 -0
  46. data/lib/vault_ruby_client.rb +53 -0
  47. metadata +158 -0
@@ -0,0 +1,230 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ require_relative "secret"
5
+ require_relative "../client"
6
+ require_relative "../request"
7
+ require_relative "../response"
8
+
9
+ module Vault
10
+ class Client
11
+ # A proxy to the {KV} methods.
12
+ # @return [KV]
13
+ def kv(mount)
14
+ KV.new(self, mount)
15
+ end
16
+ end
17
+
18
+ class KV < Request
19
+ attr_reader :mount
20
+
21
+ def initialize(client, mount)
22
+ super client
23
+
24
+ @mount = mount
25
+ end
26
+
27
+ # List the names of secrets at the given path, if the path supports
28
+ # listing. If the the path does not exist, an empty array will be returned.
29
+ #
30
+ # @example
31
+ # Vault.kv("secret").list("foo") #=> ["bar", "baz"]
32
+ #
33
+ # @param [String] path
34
+ # the path to list
35
+ #
36
+ # @return [Array<String>]
37
+ def list(path = "", options = {})
38
+ headers = extract_headers!(options)
39
+ json = client.list("/v1/#{mount}/metadata/#{encode_path(path)}", {}, headers)
40
+ json[:data][:keys] || []
41
+ rescue HTTPError => e
42
+ return [] if e.code == 404
43
+ raise
44
+ end
45
+
46
+ # Read the secret at the given path. If the secret does not exist, +nil+
47
+ # will be returned. The latest version is returned by default, but you
48
+ # can request a specific version.
49
+ #
50
+ # @example
51
+ # Vault.kv("secret").read("password") #=> #<Vault::Secret lease_id="">
52
+ #
53
+ # @param [String] path
54
+ # the path to read
55
+ # @param [Integer] version
56
+ # the version of the secret
57
+ #
58
+ # @return [Secret, nil]
59
+ def read(path, version = nil, options = {})
60
+ headers = extract_headers!(options)
61
+ params = {}
62
+ params[:version] = version unless version.nil?
63
+
64
+ json = client.get("/v1/#{mount}/data/#{encode_path(path)}", params, headers)
65
+ return Secret.decode(json[:data])
66
+ rescue HTTPError => e
67
+ return nil if e.code == 404
68
+ raise
69
+ end
70
+
71
+ # Read the metadata of a secret at the given path. If the secret does not
72
+ # exist, nil will be returned.
73
+ #
74
+ # @example
75
+ # Vault.kv("secret").read_metadata("password") => {...}
76
+ #
77
+ # @param [String] path
78
+ # the path to read
79
+ #
80
+ # @return [Hash, nil]
81
+ def read_metadata(path)
82
+ client.get("/v1/#{mount}/metadata/#{encode_path(path)}")[:data]
83
+ rescue HTTPError => e
84
+ return nil if e.code == 404
85
+ raise
86
+ end
87
+
88
+ # Write the secret at the given path with the given data. Note that the
89
+ # data must be a {Hash}!
90
+ #
91
+ # @example
92
+ # Vault.logical.write("secret/password", value: "secret") #=> #<Vault::Secret lease_id="">
93
+ #
94
+ # @param [String] path
95
+ # the path to write
96
+ # @param [Hash] data
97
+ # the data to write
98
+ #
99
+ # @return [Secret]
100
+ def write(path, data = {}, options = {})
101
+ headers = extract_headers!(options)
102
+ json = client.post("/v1/#{mount}/data/#{encode_path(path)}", JSON.fast_generate(:data => data), headers)
103
+ if json.nil?
104
+ return true
105
+ else
106
+ return Secret.decode(json)
107
+ end
108
+ end
109
+
110
+ # Write the metadata of a secret at the given path. Note that the data must
111
+ # be a {Hash}.
112
+ #
113
+ # @example
114
+ # Vault.kv("secret").write_metadata("password", max_versions => 3)
115
+ #
116
+ # @param [String] path
117
+ # the path to write
118
+ # @param [Hash] metadata
119
+ # the metadata to write
120
+ #
121
+ # @return [true]
122
+ def write_metadata(path, metadata = {})
123
+ client.post("/v1/#{mount}/metadata/#{encode_path(path)}", JSON.fast_generate(metadata))
124
+
125
+ true
126
+ end
127
+
128
+ # Patch the metadata of a secret at the given path. Note that the data must
129
+ # be a {Hash}.
130
+ #
131
+ # @example
132
+ # Vault.kv("secret").patch_metadata("password", custom_metadata: { my_custom_key: "my_value" }, max_versions: 3)
133
+ #
134
+ # @param [String] path
135
+ # the path to patch
136
+ # @param [Hash] metadata
137
+ # the metadata to patch
138
+ #
139
+ # @return [true]
140
+ def patch_metadata(path, metadata = {}, options = {})
141
+ headers = extract_headers!(options)
142
+ headers["Content-Type"] = "application/merge-patch+json"
143
+ client.patch("/v1/#{mount}/metadata/#{encode_path(path)}", JSON.fast_generate(metadata), headers)
144
+
145
+ true
146
+ end
147
+
148
+ # Delete the secret at the given path. If the secret does not exist, vault
149
+ # will still return true.
150
+ #
151
+ # @example
152
+ # Vault.logical.delete("secret/password") #=> true
153
+ #
154
+ # @param [String] path
155
+ # the path to delete
156
+ #
157
+ # @return [true]
158
+ def delete(path)
159
+ client.delete("/v1/#{mount}/data/#{encode_path(path)}")
160
+
161
+ true
162
+ end
163
+
164
+ # Mark specific versions of a secret as deleted.
165
+ #
166
+ # @example
167
+ # Vault.kv("secret").delete_versions("password", [1, 2])
168
+ #
169
+ # @param [String] path
170
+ # the path to remove versions from
171
+ # @param [Array<Integer>] versions
172
+ # an array of versions to remove
173
+ #
174
+ # @return [true]
175
+ def delete_versions(path, versions)
176
+ client.post("/v1/#{mount}/delete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
177
+
178
+ true
179
+ end
180
+
181
+ # Mark specific versions of a secret as active.
182
+ #
183
+ # @example
184
+ # Vault.kv("secret").undelete_versions("password", [1, 2])
185
+ #
186
+ # @param [String] path
187
+ # the path to enable versions for
188
+ # @param [Array<Integer>] versions
189
+ # an array of versions to mark as undeleted
190
+ #
191
+ # @return [true]
192
+ def undelete_versions(path, versions)
193
+ client.post("/v1/#{mount}/undelete/#{encode_path(path)}", JSON.fast_generate(versions: versions))
194
+
195
+ true
196
+ end
197
+
198
+ # Completely remove a secret and its metadata.
199
+ #
200
+ # @example
201
+ # Vault.kv("secret").destroy("password")
202
+ #
203
+ # @param [String] path
204
+ # the path to remove
205
+ #
206
+ # @return [true]
207
+ def destroy(path)
208
+ client.delete("/v1/#{mount}/metadata/#{encode_path(path)}")
209
+
210
+ true
211
+ end
212
+
213
+ # Completely remove specific versions of a secret.
214
+ #
215
+ # @example
216
+ # Vault.kv("secret").destroy_versions("password", [1, 2])
217
+ #
218
+ # @param [String] path
219
+ # the path to remove versions from
220
+ # @param [Array<Integer>] versions
221
+ # an array of versions to destroy
222
+ #
223
+ # @return [true]
224
+ def destroy_versions(path, versions)
225
+ client.post("/v1/#{mount}/destroy/#{encode_path(path)}", JSON.fast_generate(versions: versions))
226
+
227
+ true
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,153 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ require_relative "secret"
5
+ require_relative "../client"
6
+ require_relative "../request"
7
+ require_relative "../response"
8
+
9
+ module Vault
10
+ class Client
11
+ # A proxy to the {Logical} methods.
12
+ # @return [Logical]
13
+ def logical
14
+ @logical ||= Logical.new(self)
15
+ end
16
+ end
17
+
18
+ class Logical < Request
19
+ # List the secrets at the given path, if the path supports listing. If the
20
+ # the path does not exist, an exception will be raised.
21
+ #
22
+ # @example
23
+ # Vault.logical.list("secret") #=> [#<Vault::Secret>, #<Vault::Secret>, ...]
24
+ #
25
+ # @param [String] path
26
+ # the path to list
27
+ #
28
+ # @return [Array<String>]
29
+ def list(path, options = {})
30
+ headers = extract_headers!(options)
31
+ json = client.list("/v1/#{encode_path(path)}", {}, headers)
32
+ json[:data][:keys] || []
33
+ rescue HTTPError => e
34
+ return [] if e.code == 404
35
+ raise
36
+ end
37
+
38
+ # Read the secret at the given path. If the secret does not exist, +nil+
39
+ # will be returned.
40
+ #
41
+ # @example
42
+ # Vault.logical.read("secret/password") #=> #<Vault::Secret lease_id="">
43
+ #
44
+ # @param [String] path
45
+ # the path to read
46
+ #
47
+ # @return [Secret, nil]
48
+ def read(path, options = {})
49
+ headers = extract_headers!(options)
50
+ json = client.get("/v1/#{encode_path(path)}", {}, headers)
51
+ return Secret.decode(json)
52
+ rescue HTTPError => e
53
+ return nil if e.code == 404
54
+ raise
55
+ end
56
+
57
+ # Write the secret at the given path with the given data. Note that the
58
+ # data must be a {Hash}!
59
+ #
60
+ # @example
61
+ # Vault.logical.write("secret/password", value: "secret") #=> #<Vault::Secret lease_id="">
62
+ #
63
+ # @param [String] path
64
+ # the path to write
65
+ # @param [Hash] data
66
+ # the data to write
67
+ #
68
+ # @return [Secret]
69
+ def write(path, data = {}, options = {})
70
+ headers = extract_headers!(options)
71
+ json = client.put("/v1/#{encode_path(path)}", JSON.fast_generate(data), headers)
72
+ if json.nil?
73
+ return true
74
+ else
75
+ return Secret.decode(json)
76
+ end
77
+ end
78
+
79
+ # Delete the secret at the given path. If the secret does not exist, vault
80
+ # will still return true.
81
+ #
82
+ # @example
83
+ # Vault.logical.delete("secret/password") #=> true
84
+ #
85
+ # @param [String] path
86
+ # the path to delete
87
+ #
88
+ # @return [true]
89
+ def delete(path)
90
+ client.delete("/v1/#{encode_path(path)}")
91
+ return true
92
+ end
93
+
94
+ # Unwrap the data stored against the given token. If the secret does not
95
+ # exist, `nil` will be returned.
96
+ #
97
+ # @example
98
+ # Vault.logical.unwrap("f363dba8-25a7-08c5-430c-00b2367124e6") #=> #<Vault::Secret lease_id="">
99
+ #
100
+ # @param [String] wrapper
101
+ # the token to use when unwrapping the value
102
+ #
103
+ # @return [Secret, nil]
104
+ def unwrap(wrapper)
105
+ client.with_token(wrapper) do |client|
106
+ json = client.get("/v1/cubbyhole/response")
107
+ secret = Secret.decode(json)
108
+
109
+ # If there is nothing in the cubbyhole, return early.
110
+ if secret.nil? || secret.data.nil? || secret.data[:response].nil?
111
+ return nil
112
+ end
113
+
114
+ # Extract the response and parse it into a new secret.
115
+ json = JSON.parse(secret.data[:response], symbolize_names: true)
116
+ secret = Secret.decode(json)
117
+ return secret
118
+ end
119
+ rescue HTTPError => e
120
+ return nil if e.code == 404
121
+ raise
122
+ end
123
+
124
+ # Unwrap a token in a wrapped response given the temporary token.
125
+ #
126
+ # @example
127
+ # Vault.logical.unwrap("f363dba8-25a7-08c5-430c-00b2367124e6") #=> "0f0f40fd-06ce-4af1-61cb-cdc12796f42b"
128
+ #
129
+ # @param [String, Secret] wrapper
130
+ # the token to unwrap
131
+ #
132
+ # @return [String, nil]
133
+ def unwrap_token(wrapper)
134
+ # If provided a secret, grab the token. This is really just to make the
135
+ # API a bit nicer.
136
+ if wrapper.is_a?(Secret)
137
+ wrapper = wrapper.wrap_info.token
138
+ end
139
+
140
+ # Unwrap
141
+ response = unwrap(wrapper)
142
+
143
+ # If nothing was there, return nil
144
+ if response.nil? || response.auth.nil?
145
+ return nil
146
+ end
147
+
148
+ return response.auth.client_token
149
+ rescue HTTPError => e
150
+ raise
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,171 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ require "time"
5
+
6
+ require_relative "../response"
7
+
8
+ module Vault
9
+ # Secret is a representation of a secret from Vault. Almost all data returned
10
+ # from Vault is represented as a secret.
11
+ class Secret < Response
12
+ # @!attribute [r] auth
13
+ # Authentication information for this secret, if any. Most secrets will
14
+ # contain this field, but it may also be `nil`. When authenticating to
15
+ # Vault, the resulting Vault token will be included in this embedded
16
+ # field.
17
+ #
18
+ # @example Authenticating to Vault
19
+ # secret = Vault.auth.userpass("username", "password")
20
+ # secret.auth.client_token #=> "fdb29070-6379-70c9-ca3a-46152fb66de1"
21
+ #
22
+ # @return [SecretAuth, nil]
23
+ field :auth, load: ->(v) { SecretAuth.decode(v) }
24
+
25
+ # @!attribute [r] data
26
+ # Arbitrary data returned by the secret. The keys returned are dependent
27
+ # upon the request made. For more information on the names of the keys
28
+ # that may be returned, please see the Vault documentation.
29
+ #
30
+ # @example Reading data
31
+ # secret = Vault.auth.token("abcd1234")
32
+ # secret.data[:id] #=> "abcd1234"
33
+ # secret.data[:ttl] #=> 0
34
+ #
35
+ # @return [Hash<Symbol, Object>]
36
+ field :data, freeze: true
37
+
38
+ # @!attribute [r] metadata
39
+ # Read-only metadata information related to the secret.
40
+ #
41
+ # @example Reading metadata
42
+ # secret = Vault.logical(:versioned).read("secret", "foo")
43
+ # secret.metadata[:created_time] #=> "2018-12-08T04:22:54.168065Z"
44
+ # secret.metadata[:version] #=> 1
45
+ # secret.metadata[:destroyed] #=> false
46
+ #
47
+ # @return [Hash<Symbol, Object>]
48
+ field :metadata, freeze: true
49
+
50
+ # @!attribute [r] lease_duration
51
+ # The number of seconds this lease is valid. If this number is 0 or nil,
52
+ # the secret does not expire.
53
+ #
54
+ # @example Getting lease duration
55
+ # secret = Vault.logical.read("secret/foo")
56
+ # secret.lease_duration #=> 2592000 # 30 days
57
+ #
58
+ # @return [Fixnum]
59
+ field :lease_duration
60
+
61
+ # @!attribute [r] lease_id
62
+ # Unique ID for the lease associated with this secret. The `lease_id` is a
63
+ # path and UUID that uniquely represents the secret. This may be used for
64
+ # renewing and revoking the secret, if permitted.
65
+ #
66
+ # @example Getting lease ID
67
+ # secret = Vault.logical.read("postgresql/creds/readonly")
68
+ # secret.lease_id #=> "postgresql/readonly/fdb29070-6379-70c9-ca3a-46152fb66de1"
69
+ #
70
+ # @return [String]
71
+ field :lease_id
72
+
73
+ # @!method [r] renewable?
74
+ # Returns whether this lease is renewable.
75
+ #
76
+ # @example Checking if a lease is renewable
77
+ # secret = Vault.logical.read("secret/foo")
78
+ # secret.renewable? #=> false
79
+ #
80
+ # @return [Boolean]
81
+ field :renewable, as: :renewable?
82
+
83
+ # @!attribute [r] warnings
84
+ # List of warnings returned by the Vault server. These are returned by the
85
+ # Vault server and may include deprecation information, new APIs, or
86
+ # request using the API differently in the future.
87
+ #
88
+ # @example Display warnings
89
+ # result = Vault.logical.read("secret/foo")
90
+ # result.warnings #=> ["This path has been deprecated"]
91
+ #
92
+ # @return [Array<String>, nil]
93
+ field :warnings, freeze: true
94
+
95
+ # @!attribute [r] wrap_info
96
+ # Wrapped information sent with the request (only present in Vault 0.6+).
97
+ # @return [WrapInfo, nil]
98
+ field :wrap_info, load: ->(v) { WrapInfo.decode(v) }
99
+ end
100
+
101
+ # SecretAuth is a struct that contains the information about auth data, if
102
+ # present. This is never returned alone and is usually embededded in a
103
+ # {Secret}.
104
+ class SecretAuth < Response
105
+ # @!attribute [r] accessor
106
+ # Accessor for the token. This is like a `lease_id`, but for a token.
107
+ # @return [String]
108
+ field :accessor
109
+
110
+ # @!attribute [r] client_token
111
+ # The client token for this authentication.
112
+ # @return [String]
113
+ field :client_token
114
+
115
+ # @!attribute [r] lease_duration
116
+ # Number of seconds the token is valid.
117
+ # @return [Fixnum]
118
+ field :lease_duration
119
+
120
+ # @!attribute [r] metadata
121
+ # Arbitrary metadata from the authentication.
122
+ #
123
+ # @example Listing metadata attached to an authentication
124
+ # auth.metadata #=> { :username => "sethvargo" }
125
+ #
126
+ # @return [Hash<Symbol, Object>, nil]
127
+ field :metadata, freeze: true
128
+
129
+ # @!attribute [r] policies
130
+ # List of policies attached to this authentication.
131
+ #
132
+ # @example Listing policies attached to an authentication
133
+ # auth.policies #=> ["default"]
134
+ #
135
+ # @return [Array<String>, nil]
136
+ field :policies, freeze: true
137
+
138
+ # @!attribute [r] renewable
139
+ # Returns whether this authentication is renewable.
140
+ #
141
+ # @example Checking if an authentication is renewable
142
+ # auth.renewable? #=> false
143
+ #
144
+ # @return [Boolean]
145
+ field :renewable, as: :renewable?
146
+ end
147
+
148
+ # WrapInfo is the information returned by a wrapped response. This is almost
149
+ # always embedded as part of a {Secret}.
150
+ class WrapInfo < Response
151
+ # @!attribute [r] token
152
+ # Wrapped response token. This token may be used to unwrap the response.
153
+ # @return [String]
154
+ field :token
155
+
156
+ # @!attribute [r] wrapped_accessor
157
+ # Accessor for the wrapped token. This is like a `lease_id`, but for a token.
158
+ # @return [String]
159
+ field :wrapped_accessor
160
+
161
+ # @!attribute [r] creation_time
162
+ # Date & time when the wrapped token was created
163
+ # @return [Time]
164
+ field :creation_time, load: ->(v) { Time.parse(v) }
165
+
166
+ # @!attribute [r] ttl
167
+ # The TTL on the token returned in seconds.
168
+ # @return [Fixnum]
169
+ field :ttl
170
+ end
171
+ end
@@ -0,0 +1,94 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ require "json"
5
+
6
+ module Vault
7
+ class Audit < Response
8
+ # @!attribute [r] description
9
+ # Description of the audit backend.
10
+ # @return [String]
11
+ field :description
12
+
13
+ # @!attribute [r] options
14
+ # Map of options configured to the audit backend.
15
+ # @return [Hash<Symbol, Object>]
16
+ field :options
17
+
18
+ # @!attribute [r] type
19
+ # Name of the audit backend.
20
+ # @return [String]
21
+ field :type
22
+ end
23
+
24
+ class Sys
25
+ # List all audits for the vault.
26
+ #
27
+ # @example
28
+ # Vault.sys.audits #=> { :file => #<Audit> }
29
+ #
30
+ # @return [Hash<Symbol, Audit>]
31
+ def audits
32
+ json = client.get("/v1/sys/audit")
33
+ json = json[:data] if json[:data]
34
+ return Hash[*json.map do |k,v|
35
+ [k.to_s.chomp("/").to_sym, Audit.decode(v)]
36
+ end.flatten]
37
+ end
38
+
39
+ # Enable a particular audit. Note: the +options+ depend heavily on the
40
+ # type of audit being enabled. Please refer to audit-specific documentation
41
+ # for which need to be enabled.
42
+ #
43
+ # @example
44
+ # Vault.sys.enable_audit("/file-audit", "file", "File audit", path: "/path/on/disk") #=> true
45
+ #
46
+ # @param [String] path
47
+ # the path to mount the audit
48
+ # @param [String] type
49
+ # the type of audit to enable
50
+ # @param [String] description
51
+ # a human-friendly description of the audit backend
52
+ # @param [Hash] options
53
+ # audit-specific options
54
+ #
55
+ # @return [true]
56
+ def enable_audit(path, type, description, options = {})
57
+ client.put("/v1/sys/audit/#{encode_path(path)}", JSON.fast_generate(
58
+ type: type,
59
+ description: description,
60
+ options: options,
61
+ ))
62
+ return true
63
+ end
64
+
65
+ # Disable a particular audit. If an audit does not exist, and error will be
66
+ # raised.
67
+ #
68
+ # @param [String] path
69
+ # the path of the audit to disable
70
+ #
71
+ # @return [true]
72
+ def disable_audit(path)
73
+ client.delete("/v1/sys/audit/#{encode_path(path)}")
74
+ return true
75
+ end
76
+
77
+ # Generates a HMAC verifier for a given input.
78
+ #
79
+ # @example
80
+ # Vault.sys.audit_hash("file-audit", "my input") #=> "hmac-sha256:30aa7de18a5e90bbc1063db91e7c387b32b9fa895977eb8c177bbc91e7d7c542"
81
+ #
82
+ # @param [String] path
83
+ # the path of the audit backend
84
+ # @param [String] input
85
+ # the input to generate a HMAC for
86
+ #
87
+ # @return [String]
88
+ def audit_hash(path, input)
89
+ json = client.post("/v1/sys/audit-hash/#{encode_path(path)}", JSON.fast_generate(input: input))
90
+ json = json[:data] if json[:data]
91
+ json[:hash]
92
+ end
93
+ end
94
+ end