vault 0.10.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +68 -0
- data/README.md +31 -7
- data/lib/vault/api.rb +2 -0
- data/lib/vault/api/auth.rb +113 -8
- data/lib/vault/api/auth_token.rb +2 -2
- data/lib/vault/api/kv.rb +207 -0
- data/lib/vault/api/secret.rb +12 -0
- data/lib/vault/api/sys.rb +3 -0
- data/lib/vault/api/sys/audit.rb +18 -1
- data/lib/vault/api/sys/health.rb +63 -0
- data/lib/vault/api/sys/mount.rb +7 -2
- data/lib/vault/api/sys/namespace.rb +83 -0
- data/lib/vault/api/sys/quota.rb +107 -0
- data/lib/vault/api/transform.rb +29 -0
- data/lib/vault/api/transform/alphabet.rb +43 -0
- data/lib/vault/api/transform/role.rb +42 -0
- data/lib/vault/api/transform/template.rb +54 -0
- data/lib/vault/api/transform/transformation.rb +61 -0
- data/lib/vault/client.rb +19 -5
- data/lib/vault/configurable.rb +2 -0
- data/lib/vault/defaults.rb +27 -2
- data/lib/vault/persistent.rb +2 -7
- data/lib/vault/persistent/pool.rb +1 -1
- data/lib/vault/request.rb +1 -0
- data/lib/vault/version.rb +1 -1
- metadata +40 -24
- data/.gitignore +0 -41
- data/.rspec +0 -2
- data/.travis.yml +0 -24
- data/Gemfile +0 -3
- data/Rakefile +0 -6
- data/vault.gemspec +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 46c570463a1aba190e789e5b2516b4140d48961611ff058235d3b9744e6a6b24
|
4
|
+
data.tar.gz: c84a96cf71d9f405281f56629e0fb68a6ce051740ea46da60e35cabf37d8b44e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98a20e963ec212e2269d1c28b581c24b356495789b4b37b20ebcb829c17904b518fc32f9cd2dadfcd59b957361410e7aa61f88e7ad419d72533d0ac1bd0ec68d
|
7
|
+
data.tar.gz: 35f0126a7e7ba6173662222a9006cd02bc2f78d6d674533546b68ad87420f99b1e26f1f160058b2a051c36a5faac219921ab24191f9165212ddc8f15c440e0a6
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,73 @@
|
|
1
1
|
# Vault Ruby Changelog
|
2
2
|
|
3
|
+
## v0.16.0 (??? ??, 2021)
|
4
|
+
|
5
|
+
IMPROVEMENTS
|
6
|
+
|
7
|
+
- The timeout used to get a connection from the connection pool that talks with vault is now configurable. Using `Vault.pool_timeout` or the env var `VAULT_POOL_TIMEOUT`.
|
8
|
+
|
9
|
+
## v0.15.0 (July 29, 2020)
|
10
|
+
|
11
|
+
IMPROVEMENTS
|
12
|
+
|
13
|
+
- Added support for Resource Quotas
|
14
|
+
|
15
|
+
## v0.14.0 (May 28, 2020)
|
16
|
+
|
17
|
+
IMPROVEMENTS
|
18
|
+
|
19
|
+
- Added support for the Transform Secrets Engine
|
20
|
+
|
21
|
+
## v0.13.2 (May 7, 2020)
|
22
|
+
|
23
|
+
BUG FIXES
|
24
|
+
|
25
|
+
- Fixed the ability to use namespace as an option for each request. Previously, that option was ignored.
|
26
|
+
- aws-sigv4 gem was unlocked after a bug in 1.1.2 broke CI
|
27
|
+
|
28
|
+
## v0.13.1 (April 28, 2020)
|
29
|
+
|
30
|
+
IMPROVEMENTS
|
31
|
+
|
32
|
+
- Added support for defining a namespace when initializing the client, as well as options for changing the namespace via method.
|
33
|
+
- Added support for sys/namespaces API. Ability to Get, Create, Delete, and List namespaces has been provided.
|
34
|
+
|
35
|
+
## v0.13.0 (October 1, 2019)
|
36
|
+
|
37
|
+
IMPROVEMENTS
|
38
|
+
|
39
|
+
- Add support for versioned KV secrets in the client
|
40
|
+
|
41
|
+
## v0.12.0 (August 14, 2018)
|
42
|
+
|
43
|
+
IMPROVEMENTS
|
44
|
+
|
45
|
+
- Expose the github login path as an optional argument
|
46
|
+
- Support HTTP basic auth [GH-181]
|
47
|
+
- Expose the AWS IAM path to use [GH-180]
|
48
|
+
- Add GCP Auth [GH-173]
|
49
|
+
- Add shutdown functionality to close persistent connections [GH-175]
|
50
|
+
|
51
|
+
BUG FIXES
|
52
|
+
|
53
|
+
- Specifing the hostname for SNI didn't work. The functionality has been disabled for now.
|
54
|
+
|
55
|
+
## v0.11.0 (March 19, 2018)
|
56
|
+
|
57
|
+
IMPROVEMENTS
|
58
|
+
|
59
|
+
- Access to health has been added.
|
60
|
+
- Added ability to handle a Base64 encoded PEM (useful for certs in environment variables)
|
61
|
+
- Added IAM EC2 authentication support
|
62
|
+
- Add custom mount path support to TLS authentication
|
63
|
+
|
64
|
+
## v0.10.1 (May 8, 2017)
|
65
|
+
|
66
|
+
IMPROVEMENTS
|
67
|
+
|
68
|
+
- `vault-ruby` is licensed under Mozilla Public License 2.0, and has been for over 2 years. This patch release updates the gemspec to use the correct SPDX ID string for reporting this license, but **no change to the licensing of this gem has occurred**.
|
69
|
+
|
70
|
+
|
3
71
|
## v0.10.0 (April 19, 2017)
|
4
72
|
|
5
73
|
IMPROVEMENTS
|
data/README.md
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
-
Vault Ruby Client [![Build Status](https://
|
1
|
+
Vault Ruby Client [![Build Status](https://circleci.com/gh/hashicorp/vault-ruby.svg?style=shield)](https://circleci.com/gh/hashicorp/vault-ruby)
|
2
2
|
=================
|
3
3
|
|
4
4
|
Vault is the official Ruby client for interacting with [Vault](https://vaultproject.io) by HashiCorp.
|
5
5
|
|
6
|
-
**
|
6
|
+
**If you're viewing this README from GitHub on the `master` branch, know that it may contain unreleased features or
|
7
|
+
different APIs than the most recently released version. Please see the Git tag that corresponds to your version of the
|
8
|
+
Vault Ruby client for the proper documentation.**
|
7
9
|
|
8
10
|
Quick Start
|
9
11
|
-----------
|
10
12
|
Install Ruby 2.0+: [Guide](https://www.ruby-lang.org/en/documentation/installation/).
|
11
13
|
|
12
|
-
> Please note that
|
14
|
+
> Please note that as of Vault Ruby version 0.14.0 versions of Ruby prior to 2.0 are no longer supported.
|
13
15
|
|
14
16
|
Install via Rubygems:
|
15
17
|
|
@@ -18,7 +20,7 @@ Install via Rubygems:
|
|
18
20
|
or add it to your Gemfile if you're using Bundler:
|
19
21
|
|
20
22
|
```ruby
|
21
|
-
gem "vault"
|
23
|
+
gem "vault"
|
22
24
|
```
|
23
25
|
|
24
26
|
and then run the `bundle` command to install.
|
@@ -28,6 +30,8 @@ Start a Vault client:
|
|
28
30
|
```ruby
|
29
31
|
Vault.address = "http://127.0.0.1:8200" # Also reads from ENV["VAULT_ADDR"]
|
30
32
|
Vault.token = "abcd-1234" # Also reads from ENV["VAULT_TOKEN"]
|
33
|
+
# Optional - if using the Namespace enterprise feature
|
34
|
+
# Vault.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
|
31
35
|
|
32
36
|
Vault.sys.mounts #=> { :secret => #<struct Vault::Mount type="generic", description="generic secret storage"> }
|
33
37
|
```
|
@@ -43,6 +47,8 @@ Vault.configure do |config|
|
|
43
47
|
|
44
48
|
# The token to authenticate with Vault, also read as ENV["VAULT_TOKEN"]
|
45
49
|
config.token = "abcd-1234"
|
50
|
+
# Optional - if using the Namespace enterprise feature
|
51
|
+
# config.namespace = "my-namespace" # Also reads from ENV["VAULT_NAMESPACE"]
|
46
52
|
|
47
53
|
# Proxy connection information, also read as ENV["VAULT_PROXY_(thing)"]
|
48
54
|
config.proxy_address = "..."
|
@@ -53,6 +59,10 @@ Vault.configure do |config|
|
|
53
59
|
# Custom SSL PEM, also read as ENV["VAULT_SSL_CERT"]
|
54
60
|
config.ssl_pem_file = "/path/on/disk.pem"
|
55
61
|
|
62
|
+
# As an alternative to a pem file, you can provide the raw PEM string, also read in the following order of preference:
|
63
|
+
# ENV["VAULT_SSL_PEM_CONTENTS_BASE64"] then ENV["VAULT_SSL_PEM_CONTENTS"]
|
64
|
+
config.ssl_pem_contents = "-----BEGIN ENCRYPTED..."
|
65
|
+
|
56
66
|
# Use SSL verification, also read as ENV["VAULT_SSL_VERIFY"]
|
57
67
|
config.ssl_verify = false
|
58
68
|
|
@@ -75,6 +85,17 @@ client_1 = Vault::Client.new(address: "https://vault.mycompany.com")
|
|
75
85
|
client_2 = Vault::Client.new(address: "https://other-vault.mycompany.com")
|
76
86
|
```
|
77
87
|
|
88
|
+
And if you want to authenticate with a `AWS EC2` :
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
# Export VAULT_ADDR to ENV then
|
92
|
+
# Get the pkcs7 value from AWS
|
93
|
+
signature = `curl http://169.254.169.254/latest/dynamic/instance-identity/pkcs7`
|
94
|
+
iam_role = `curl http://169.254.169.254/latest/meta-data/iam/security-credentials/`
|
95
|
+
vault_token = Vault.auth.aws_ec2(iam_role, signature, nil)
|
96
|
+
vault_client = Vault::Client.new(address: ENV["VAULT_ADDR"], token: vault_token.auth.client_token)
|
97
|
+
```
|
98
|
+
|
78
99
|
### Making requests
|
79
100
|
All of the methods and API calls are heavily documented with examples inline using YARD. In order to keep the examples versioned with the code, the README only lists a few examples for using the Vault gem. Please see the inline documentation for the full API documentation. The tests in the 'spec' directory are an additional source of examples.
|
80
101
|
|
@@ -103,7 +124,9 @@ For advanced users, the first argument of the block is the attempt number and th
|
|
103
124
|
|
104
125
|
```ruby
|
105
126
|
Vault.with_retries(Vault::HTTPConnectionError, Vault::HTTPError) do |attempt, e|
|
106
|
-
|
127
|
+
if e
|
128
|
+
log "Received exception #{e} from Vault - attempt #{attempt}"
|
129
|
+
end
|
107
130
|
Vault.logical.read("secret/bacon")
|
108
131
|
end
|
109
132
|
```
|
@@ -192,7 +215,8 @@ Development
|
|
192
215
|
|
193
216
|
Important Notes:
|
194
217
|
|
195
|
-
- **All new features must include test coverage.** At a bare minimum, Unit tests are required. It is preferred if you include
|
196
|
-
- **The tests must be
|
218
|
+
- **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.
|
219
|
+
- **The tests must be idempotent.** The HTTP calls made during a test should be able to be run over and over.
|
197
220
|
- **Tests are order independent.** The default RSpec configuration randomizes the test order, so this should not be a problem.
|
198
221
|
- **Integration tests require Vault** Vault must be available in the path for the integration tests to pass.
|
222
|
+
- **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.
|
data/lib/vault/api.rb
CHANGED
@@ -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
|
data/lib/vault/api/auth.rb
CHANGED
@@ -155,9 +155,9 @@ module Vault
|
|
155
155
|
# @param [String] github_token
|
156
156
|
#
|
157
157
|
# @return [Secret]
|
158
|
-
def github(github_token)
|
158
|
+
def github(github_token, path="/v1/auth/github/login")
|
159
159
|
payload = {token: github_token}
|
160
|
-
json = client.post(
|
160
|
+
json = client.post(path, JSON.fast_generate(payload))
|
161
161
|
secret = Secret.decode(json)
|
162
162
|
client.token = secret.auth.client_token
|
163
163
|
return secret
|
@@ -173,12 +173,95 @@ module Vault
|
|
173
173
|
# @param [String] role
|
174
174
|
# @param [String] pkcs7
|
175
175
|
# pkcs7 returned by the instance identity document (with line breaks removed)
|
176
|
-
# @param [String] nonce
|
176
|
+
# @param [String] nonce optional
|
177
|
+
# @param [String] route optional
|
177
178
|
#
|
178
179
|
# @return [Secret]
|
179
|
-
def aws_ec2(role, pkcs7, nonce)
|
180
|
-
|
181
|
-
|
180
|
+
def aws_ec2(role, pkcs7, nonce = nil, route = nil)
|
181
|
+
route ||= '/v1/auth/aws-ec2/login'
|
182
|
+
payload = { role: role, pkcs7: pkcs7 }
|
183
|
+
# Set a custom nonce if client is providing one
|
184
|
+
payload[:nonce] = nonce if nonce
|
185
|
+
json = client.post(route, JSON.fast_generate(payload))
|
186
|
+
secret = Secret.decode(json)
|
187
|
+
client.token = secret.auth.client_token
|
188
|
+
return secret
|
189
|
+
end
|
190
|
+
|
191
|
+
# Authenticate via AWS IAM auth method by providing a AWS CredentialProvider (either ECS, AssumeRole, etc.)
|
192
|
+
# If authentication is successful, the resulting token will be stored on the client and used
|
193
|
+
# for future requests.
|
194
|
+
#
|
195
|
+
# @example
|
196
|
+
# Vault.auth.aws_iam("dev-role-iam", Aws::InstanceProfileCredentials.new, "vault.example.com", "https://sts.us-east-2.amazonaws.com") #=> #<Vault::Secret lease_id="">
|
197
|
+
#
|
198
|
+
# @param [String] role
|
199
|
+
# @param [CredentialProvider] credentials_provider
|
200
|
+
# https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/CredentialProvider.html
|
201
|
+
# @param [String] iam_auth_header_value optional
|
202
|
+
# As of Jan 2018, Vault will accept ANY or NO header if none is configured by the Vault server admin
|
203
|
+
# @param [String] sts_endpoint optional
|
204
|
+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html
|
205
|
+
# @param [String] route optional
|
206
|
+
# @return [Secret]
|
207
|
+
def aws_iam(role, credentials_provider, iam_auth_header_value = nil, sts_endpoint = 'https://sts.amazonaws.com', route = nil)
|
208
|
+
require "aws-sigv4"
|
209
|
+
require "base64"
|
210
|
+
|
211
|
+
request_body = 'Action=GetCallerIdentity&Version=2011-06-15'
|
212
|
+
request_method = 'POST'
|
213
|
+
|
214
|
+
route ||= '/v1/auth/aws/login'
|
215
|
+
|
216
|
+
vault_headers = {
|
217
|
+
'User-Agent' => Vault::Client::USER_AGENT,
|
218
|
+
'Content-Type' => 'application/x-www-form-urlencoded; charset=utf-8'
|
219
|
+
}
|
220
|
+
|
221
|
+
vault_headers['X-Vault-AWS-IAM-Server-ID'] = iam_auth_header_value if iam_auth_header_value
|
222
|
+
|
223
|
+
sig4_headers = Aws::Sigv4::Signer.new(
|
224
|
+
service: 'sts',
|
225
|
+
region: region_from_sts_endpoint(sts_endpoint),
|
226
|
+
credentials_provider: credentials_provider
|
227
|
+
).sign_request(
|
228
|
+
http_method: request_method,
|
229
|
+
url: sts_endpoint,
|
230
|
+
headers: vault_headers,
|
231
|
+
body: request_body
|
232
|
+
).headers
|
233
|
+
|
234
|
+
payload = {
|
235
|
+
role: role,
|
236
|
+
iam_http_request_method: request_method,
|
237
|
+
iam_request_url: Base64.strict_encode64(sts_endpoint),
|
238
|
+
iam_request_headers: Base64.strict_encode64(vault_headers.merge(sig4_headers).to_json),
|
239
|
+
iam_request_body: Base64.strict_encode64(request_body)
|
240
|
+
}
|
241
|
+
|
242
|
+
json = client.post(route, JSON.fast_generate(payload))
|
243
|
+
secret = Secret.decode(json)
|
244
|
+
client.token = secret.auth.client_token
|
245
|
+
return secret
|
246
|
+
end
|
247
|
+
|
248
|
+
# Authenticate via the GCP authentication method. If authentication is
|
249
|
+
# successful, the resulting token will be stored on the client and used
|
250
|
+
# for future requests.
|
251
|
+
#
|
252
|
+
# @example
|
253
|
+
# Vault.auth.gcp("read-only", "jwt", "gcp") #=> #<Vault::Secret lease_id="">
|
254
|
+
#
|
255
|
+
# @param [String] role
|
256
|
+
# @param [String] jwt
|
257
|
+
# jwt returned by the instance identity metadata, or iam api
|
258
|
+
# @param [String] path optional
|
259
|
+
# the path were the gcp auth backend is mounted
|
260
|
+
#
|
261
|
+
# @return [Secret]
|
262
|
+
def gcp(role, jwt, path = 'gcp')
|
263
|
+
payload = { role: role, jwt: jwt }
|
264
|
+
json = client.post("/v1/auth/#{CGI.escape(path)}/login", JSON.fast_generate(payload))
|
182
265
|
secret = Secret.decode(json)
|
183
266
|
client.token = secret.auth.client_token
|
184
267
|
return secret
|
@@ -194,18 +277,40 @@ module Vault
|
|
194
277
|
# @example Reading a pem from disk
|
195
278
|
# Vault.auth.tls(File.read("/path/to/my/certificate.pem")) #=> #<Vault::Secret lease_id="">
|
196
279
|
#
|
280
|
+
# @example Sending to a cert authentication backend mounted at a custom location
|
281
|
+
# Vault.auth.tls(pem_contents, 'custom/location') #=> #<Vault::Secret lease_id="">
|
282
|
+
#
|
197
283
|
# @param [String] pem (default: the configured SSL pem file or contents)
|
198
284
|
# The raw pem contents to use for the login procedure.
|
199
285
|
#
|
286
|
+
# @param [String] path (default: 'cert')
|
287
|
+
# The path to the auth backend to use for the login procedure.
|
288
|
+
#
|
200
289
|
# @return [Secret]
|
201
|
-
def tls(pem = nil)
|
290
|
+
def tls(pem = nil, path = 'cert')
|
202
291
|
new_client = client.dup
|
203
292
|
new_client.ssl_pem_contents = pem if !pem.nil?
|
204
293
|
|
205
|
-
json = new_client.post("/v1/auth/
|
294
|
+
json = new_client.post("/v1/auth/#{CGI.escape(path)}/login")
|
206
295
|
secret = Secret.decode(json)
|
207
296
|
client.token = secret.auth.client_token
|
208
297
|
return secret
|
209
298
|
end
|
299
|
+
|
300
|
+
private
|
301
|
+
|
302
|
+
# Parse an AWS region from a STS endpoint
|
303
|
+
# STS in the China (Beijing) region (cn-north-1) is sts.cn-north-1.amazonaws.com.cn
|
304
|
+
# Take care changing below regex with that edge case in mind
|
305
|
+
#
|
306
|
+
# @param [String] sts_endpoint
|
307
|
+
# https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html
|
308
|
+
#
|
309
|
+
# @return [String] aws region
|
310
|
+
def region_from_sts_endpoint(sts_endpoint)
|
311
|
+
valid_sts_endpoint = %r{https:\/\/sts\.?(.*).amazonaws.com}.match(sts_endpoint)
|
312
|
+
raise "Unable to parse STS endpoint #{sts_endpoint}" unless valid_sts_endpoint
|
313
|
+
valid_sts_endpoint[1].empty? ? 'us-east-1' : valid_sts_endpoint[1]
|
314
|
+
end
|
210
315
|
end
|
211
316
|
end
|
data/lib/vault/api/auth_token.rb
CHANGED
@@ -102,7 +102,7 @@ module Vault
|
|
102
102
|
# Lookup information about the current token.
|
103
103
|
#
|
104
104
|
# @example
|
105
|
-
# Vault.auth_token.
|
105
|
+
# Vault.auth_token.lookup("abcd-...") #=> #<Vault::Secret lease_id="">
|
106
106
|
#
|
107
107
|
# @param [String] token
|
108
108
|
# @param [Hash] options
|
@@ -215,7 +215,7 @@ module Vault
|
|
215
215
|
# @return [true]
|
216
216
|
def revoke_accessor(accessor, options = {})
|
217
217
|
headers = extract_headers!(options)
|
218
|
-
client.put("/v1/auth/
|
218
|
+
client.put("/v1/auth/token/revoke-accessor", JSON.fast_generate(
|
219
219
|
accessor: accessor,
|
220
220
|
), headers)
|
221
221
|
return true
|
data/lib/vault/api/kv.rb
ADDED
@@ -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
|