vault 0.4.0 → 0.5.0

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
  SHA1:
3
- metadata.gz: c591681b73cba4f23a6c399ce65ecb232be4c8bb
4
- data.tar.gz: 7f01da9d58aae383b63dd8bc666db5ca7e2181d8
3
+ metadata.gz: efbf977407c93919ed45ceff129bc3df6088d462
4
+ data.tar.gz: 7b3a458357a1a3a9eef3606eb5d1a8160d1d04c5
5
5
  SHA512:
6
- metadata.gz: 1efa7198ad5a0713ba37826978cd417ac6de66da5023d220890b092c8758af7fb9a7a494ea9db685e1e21011e4f62fc4379c42b50f0d3fa6992a68d57ad8a319
7
- data.tar.gz: 415e4410e7f5ba98827996d47ad10ef8f81caa12dd0a213698b019306717bfb08694a2ea598428a72629c3c6180739a49f6541c9553f3355f33391efcd6adc73
6
+ metadata.gz: ef87eb90b77096ce92ab3f2c765f9b897bac05ec82da49ac600b62b05847ab02cfa9f29f2d09244527be308be61e1f24b3bfa99cac7df5aef45d458c993d76d2
7
+ data.tar.gz: 01b3384ce315cfc0e30ee11fdc020327172cde312de1f89bff1b63bf6eacd8f18425234d742b76d5551428212315424612420969c2d16edaa09bb500dea75e21
@@ -3,7 +3,7 @@ cache: bundler
3
3
  sudo: false
4
4
 
5
5
  before_install: |-
6
- wget -O vault.zip -q https://releases.hashicorp.com/vault/0.5.2/vault_0.5.2_linux_amd64.zip
6
+ curl -so vault.zip https://releases.hashicorp.com/vault/0.6.0/vault_0.6.0_linux_amd64.zip
7
7
  unzip vault.zip
8
8
  mkdir ~/bin
9
9
  mv vault ~/bin
@@ -1,5 +1,17 @@
1
1
  # Vault Ruby Changelog
2
2
 
3
+ ## v0.4.0.dev (Unreleased)
4
+
5
+ NEW FEATURES
6
+
7
+ - Add TTL wrapping to logical and auth backends
8
+ - Support passing PGP keys to init
9
+
10
+ BUG FIXES
11
+
12
+ - New API documentation
13
+ - Remove recursive requires
14
+
3
15
  ## v0.4.0 (March 31, 2016)
4
16
 
5
17
  NEW FEATURES
data/README.md CHANGED
@@ -151,11 +151,39 @@ Vault.logical.read("secret/bacon")
151
151
  #=> #<Vault::Secret lease_id="">
152
152
  ```
153
153
 
154
- #### Seal the Vault
154
+ #### Retrieve the Contents of a Secret
155
155
  ```ruby
156
- Vault.sys.seal #=> true
156
+ secret = Vault.logical.read("secret/bacon")
157
+ secret.data #=> { :cooktime = >"11", :delicious => true }
157
158
  ```
158
159
 
160
+ ### Response wrapping
161
+
162
+ ```ruby
163
+ # Request new access token as wrapped response where the TTL of the temporary
164
+ # token is "5s".
165
+ wrapped = Vault.auth_token.create(wrap_ttl: "5s")
166
+
167
+ # Unwrap the wrapped response to get the final token using the initial temporary
168
+ # token from the first request.
169
+ unwrapped = Vault.logical.unwrap(wrapped.wrap_info.token)
170
+
171
+ # Extract the final token from the response.
172
+ token = unwrapped.data.auth.client_token
173
+ ```
174
+
175
+ A helper function is also provided when unwrapping a token directly:
176
+
177
+ ```ruby
178
+ # Request new access token as wrapped response where the TTL of the temporary
179
+ # token is "5s".
180
+ wrapped = Vault.auth_token.create(wrap_ttl: "5s")
181
+
182
+ # Unwrap wrapped response for final token using the initial temporary token.
183
+ token = Vault.logical.unwrap_token(wrapped)
184
+ ```
185
+
186
+
159
187
  Development
160
188
  -----------
161
189
  1. Clone the project on GitHub
@@ -167,3 +195,4 @@ Important Notes:
167
195
  - **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.
168
196
  - **The tests must be be idempotent.** The HTTP calls made during a test should be able to be run over and over.
169
197
  - **Tests are order independent.** The default RSpec configuration randomizes the test order, so this should not be a problem.
198
+ - **Integration tests require Vault** Vault must be available in the path for the integration tests to pass.
@@ -15,16 +15,45 @@ module Vault
15
15
  end
16
16
 
17
17
  class AuthToken < Request
18
- # Create an authentication token.
18
+ # Create an authentication token. Note that the parameters specified below
19
+ # are not validated and passed directly to the Vault server. Depending on
20
+ # the version of Vault in operation, some of these options may not work, and
21
+ # newer options may be available that are not listed here.
19
22
  #
20
- # @example
23
+ # @example Creating a token
21
24
  # Vault.auth_token.create #=> #<Vault::Secret lease_id="">
22
25
  #
26
+ # @example Creating a token assigned to policies with a wrap TTL
27
+ # Vault.auth_token.create(
28
+ # policies: ["myapp"],
29
+ # wrap_ttl: 500,
30
+ # )
31
+ #
23
32
  # @param [Hash] options
33
+ # @option options [String] :id
34
+ # The ID of the client token - this can only be specified for root tokens
35
+ # @option options [Array<String>] :policies
36
+ # List of policies to apply to the token
37
+ # @option options [Fixnum, String] :wrap_ttl
38
+ # The number of seconds or a golang-formatted timestamp like "5s" or "10m"
39
+ # for the TTL on the wrapped response
40
+ # @option options [Hash<String, String>] :meta
41
+ # A map of metadata that is passed to audit backends
42
+ # @option options [Boolean] :no_parent
43
+ # Create a token without a parent - see also {#create_orphan}
44
+ # @option options [Boolean] :no_default_policy
45
+ # Create a token without the default policy attached
46
+ # @option options [Boolean] :renewable
47
+ # Set whether this token is renewable or not
48
+ # @option options [String] :display_name
49
+ # Name of the token
50
+ # @option options [Fixnum] :num_uses
51
+ # Maximum number of uses for the token
24
52
  #
25
53
  # @return [Secret]
26
54
  def create(options = {})
27
- json = client.post("/v1/auth/token/create", JSON.fast_generate(options))
55
+ headers = extract_headers!(options)
56
+ json = client.post("/v1/auth/token/create", JSON.fast_generate(options), headers)
28
57
  return Secret.decode(json)
29
58
  end
30
59
 
@@ -33,11 +62,27 @@ module Vault
33
62
  # @example
34
63
  # Vault.auth_token.create_orphan #=> #<Vault::Secret lease_id="">
35
64
  #
36
- # @param [Hash] options
65
+ # @param (see #create)
66
+ # @option (see #create)
37
67
  #
38
68
  # @return [Secret]
39
69
  def create_orphan(options = {})
40
- json = client.post("/v1/auth/token/create-orphan", JSON.fast_generate(options))
70
+ headers = extract_headers!(options)
71
+ json = client.post("/v1/auth/token/create-orphan", JSON.fast_generate(options), headers)
72
+ return Secret.decode(json)
73
+ end
74
+
75
+ # Create an orphaned authentication token.
76
+ #
77
+ # @example
78
+ # Vault.auth_token.create_with_role("developer") #=> #<Vault::Secret lease_id="">
79
+ #
80
+ # @param [Hash] options
81
+ #
82
+ # @return [Secret]
83
+ def create_with_role(name, options = {})
84
+ headers = extract_headers!(options)
85
+ json = client.post("/v1/auth/token/create/#{CGI.escape(name)}", JSON.fast_generate(options), headers)
41
86
  return Secret.decode(json)
42
87
  end
43
88
 
@@ -126,8 +171,8 @@ module Vault
126
171
  # @example
127
172
  # Vault.auth_token.revoke_prefix("abcd-1234") #=> true
128
173
  #
129
- # @param [String] id
130
- # the auth id
174
+ # @param [String] prefix
175
+ # the prefix to revoke
131
176
  #
132
177
  # @return [true]
133
178
  def revoke_prefix(prefix)
@@ -3,13 +3,23 @@ require_relative "../response"
3
3
 
4
4
  module Vault
5
5
  # Help is the response from a help query.
6
- class Help < Response.new(:help, :see_also); end
6
+ class Help < Response
7
+ # @!attribute [r] help
8
+ # The help information.
9
+ # @return [String]
10
+ field :help
11
+
12
+ # @!attribute [r] see_also
13
+ # Additional help documentation to see.
14
+ # @return [String]
15
+ field :see_also
16
+ end
7
17
 
8
18
  class Client
9
19
  # Gets help for the given path.
10
20
  #
11
21
  # @example
12
- # Vault.help #=> #<Vault::Help help="..." see_also="...">
22
+ # Vault.help("secret") #=> #<Vault::Help help="..." see_also="...">
13
23
  #
14
24
  # @param [String] path
15
25
  # the path to get help for
@@ -23,8 +23,9 @@ module Vault
23
23
  # the path to list
24
24
  #
25
25
  # @return [Array<String>]
26
- def list(path)
27
- json = client.get("/v1/#{CGI.escape(path)}", list: true)
26
+ def list(path, options = {})
27
+ headers = extract_headers!(options)
28
+ json = client.list("/v1/#{CGI.escape(path)}", {}, headers)
28
29
  json[:data][:keys] || []
29
30
  rescue HTTPError => e
30
31
  return [] if e.code == 404
@@ -41,8 +42,9 @@ module Vault
41
42
  # the path to read
42
43
  #
43
44
  # @return [Secret, nil]
44
- def read(path)
45
- json = client.get("/v1/#{CGI.escape(path)}")
45
+ def read(path, options = {})
46
+ headers = extract_headers!(options)
47
+ json = client.get("/v1/#{CGI.escape(path)}", {}, headers)
46
48
  return Secret.decode(json)
47
49
  rescue HTTPError => e
48
50
  return nil if e.code == 404
@@ -61,8 +63,9 @@ module Vault
61
63
  # the data to write
62
64
  #
63
65
  # @return [Secret]
64
- def write(path, data = {})
65
- json = client.put("/v1/#{CGI.escape(path)}", JSON.fast_generate(data))
66
+ def write(path, data = {}, options = {})
67
+ headers = extract_headers!(options)
68
+ json = client.put("/v1/#{CGI.escape(path)}", JSON.fast_generate(data), headers)
66
69
  if json.nil?
67
70
  return true
68
71
  else
@@ -84,5 +87,64 @@ module Vault
84
87
  client.delete("/v1/#{CGI.escape(path)}")
85
88
  return true
86
89
  end
90
+
91
+ # Unwrap the data stored against the given token. If the secret does not
92
+ # exist, `nil` will be returned.
93
+ #
94
+ # @example
95
+ # Vault.logical.unwrap("f363dba8-25a7-08c5-430c-00b2367124e6") #=> #<Vault::Secret lease_id="">
96
+ #
97
+ # @param [String] wrapper
98
+ # the token to use when unwrapping the value
99
+ #
100
+ # @return [Secret, nil]
101
+ def unwrap(wrapper)
102
+ client.with_token(wrapper) do |client|
103
+ json = client.get("/v1/cubbyhole/response")
104
+ secret = Secret.decode(json)
105
+
106
+ # If there is nothing in the cubbyhole, return early.
107
+ if secret.nil? || secret.data.nil? || secret.data[:response].nil?
108
+ return nil
109
+ end
110
+
111
+ # Extract the response and parse it into a new secret.
112
+ json = JSON.parse(secret.data[:response], symbolize_names: true)
113
+ secret = Secret.decode(json)
114
+ return secret
115
+ end
116
+ rescue HTTPError => e
117
+ return nil if e.code == 404
118
+ raise
119
+ end
120
+
121
+ # Unwrap a token in a wrapped response given the temporary token.
122
+ #
123
+ # @example
124
+ # Vault.logical.unwrap("f363dba8-25a7-08c5-430c-00b2367124e6") #=> "0f0f40fd-06ce-4af1-61cb-cdc12796f42b"
125
+ #
126
+ # @param [String, Secret] wrapper
127
+ # the token to unwrap
128
+ #
129
+ # @return [String, nil]
130
+ def unwrap_token(wrapper)
131
+ # If provided a secret, grab the token. This is really just to make the
132
+ # API a bit nicer.
133
+ if wrapper.is_a?(Secret)
134
+ wrapper = wrapper.wrap_info.token
135
+ end
136
+
137
+ # Unwrap
138
+ response = unwrap(wrapper)
139
+
140
+ # If nothing was there, return nil
141
+ if response.nil? || response.auth.nil?
142
+ return nil
143
+ end
144
+
145
+ return response.auth.client_token
146
+ rescue HTTPError => e
147
+ raise
148
+ end
87
149
  end
88
150
  end
@@ -1,23 +1,154 @@
1
1
  require_relative "../response"
2
2
 
3
3
  module Vault
4
- # Secret is a representation of a secret.
5
- class Secret < Response.new(:lease_id, :lease_duration, :renewable, :data, :auth)
6
- alias_method :renewable?, :renewable
7
-
8
- alias_method :raw_auth, :auth
9
- def auth
10
- return @auth if defined?(@auth)
11
- if raw_auth.nil?
12
- @auth = nil
13
- else
14
- @auth = SecretAuth.decode(raw_auth)
15
- end
16
- end
4
+ # Secret is a representation of a secret from Vault. Almost all data returned
5
+ # from Vault is represented as a secret.
6
+ class Secret < Response
7
+ # @!attribute [r] auth
8
+ # Authentication information for this secret, if any. Most secrets will
9
+ # contain this field, but it may also be `nil`. When authenticating to
10
+ # Vault, the resulting Vault token will be included in this embedded
11
+ # field.
12
+ #
13
+ # @example Authenticating to Vault
14
+ # secret = Vault.auth.userpass("username", "password")
15
+ # secret.auth.client_token #=> "fdb29070-6379-70c9-ca3a-46152fb66de1"
16
+ #
17
+ # @return [SecretAuth, nil]
18
+ field :auth, load: ->(v) { SecretAuth.decode(v) }
19
+
20
+ # @!attribute [r] data
21
+ # Arbitrary data returned by the secret. The keys returned are dependent
22
+ # upon the request made. For more information on the names of the keys
23
+ # that may be returned, please see the Vault documentation.
24
+ #
25
+ # @example Reading data
26
+ # secret = Vault.auth.token("abcd1234")
27
+ # secret.data[:id] #=> "abcd1234"
28
+ # secret.data[:ttl] #=> 0
29
+ #
30
+ # @return [Hash<Symbol, Object>]
31
+ field :data, freeze: true
32
+
33
+ # @!attribute [r] lease_duration
34
+ # The number of seconds this lease is valid. If this number is 0 or nil,
35
+ # the secret does not expire.
36
+ #
37
+ # @example Getting lease duration
38
+ # secret = Vault.logical.read("secret/foo")
39
+ # secret.lease_duration #=> 2592000 # 30 days
40
+ #
41
+ # @return [Fixnum]
42
+ field :lease_duration
43
+
44
+ # @!attribute [r] lease_id
45
+ # Unique ID for the lease associated with this secret. The `lease_id` is a
46
+ # path and UUID that uniquely represents the secret. This may be used for
47
+ # renewing and revoking the secret, if permitted.
48
+ #
49
+ # @example Getting lease ID
50
+ # secret = Vault.logical.read("postgresql/creds/readonly")
51
+ # secret.lease_id #=> "postgresql/readonly/fdb29070-6379-70c9-ca3a-46152fb66de1"
52
+ #
53
+ # @return [String]
54
+ field :lease_id
55
+
56
+ # @!method [r] renewable?
57
+ # Returns whether this lease is renewable.
58
+ #
59
+ # @example Checking if a lease is renewable
60
+ # secret = Vault.logical.read("secret/foo")
61
+ # secret.renewable? #=> false
62
+ #
63
+ # @return [Boolean]
64
+ field :renewable, as: :renewable?
65
+
66
+ # @!attribute [r] warnings
67
+ # List of warnings returned by the Vault server. These are returned by the
68
+ # Vault server and may include deprecation information, new APIs, or
69
+ # request using the API differently in the future.
70
+ #
71
+ # @example Display warnings
72
+ # result = Vault.logical.read("secret/foo")
73
+ # result.warnings #=> ["This path has been deprecated"]
74
+ #
75
+ # @return [Array<String>, nil]
76
+ field :warnings, freeze: true
77
+
78
+ # @!attribute [r] wrap_info
79
+ # Wrapped information sent with the request (only present in Vault 0.6+).
80
+ # @return [WrapInfo, nil]
81
+ field :wrap_info, load: ->(v) { WrapInfo.decode(v) }
82
+ end
83
+
84
+ # SecretAuth is a struct that contains the information about auth data, if
85
+ # present. This is never returned alone and is usually embededded in a
86
+ # {Secret}.
87
+ class SecretAuth < Response
88
+ # @!attribute [r] accessor
89
+ # Accessor for the token. This is like a `lease_id`, but for a token.
90
+ # @return [String]
91
+ field :accessor
92
+
93
+ # @!attribute [r] client_token
94
+ # The client token for this authentication.
95
+ # @return [String]
96
+ field :client_token
97
+
98
+ # @!attribute [r] lease_duration
99
+ # Number of seconds the token is valid.
100
+ # @return [Fixnum]
101
+ field :lease_duration
102
+
103
+ # @!attribute [r] metadata
104
+ # Arbitrary metadata from the authentication.
105
+ #
106
+ # @example Listing metadata attached to an authentication
107
+ # auth.metadata #=> { :username => "sethvargo" }
108
+ #
109
+ # @return [Hash<Symbol, Object>, nil]
110
+ field :metadata, freeze: true
111
+
112
+ # @!attribute [r] policies
113
+ # List of policies attached to this authentication.
114
+ #
115
+ # @example Listing policies attached to an authentication
116
+ # auth.policies #=> ["default"]
117
+ #
118
+ # @return [Array<String>, nil]
119
+ field :policies, freeze: true
120
+
121
+ # @!attribute [r] renewable
122
+ # Returns whether this authentication is renewable.
123
+ #
124
+ # @example Checking if an authentication is renewable
125
+ # auth.renewable? #=> false
126
+ #
127
+ # @return [Boolean]
128
+ field :renewable, as: :renewable?
17
129
  end
18
130
 
19
- # SecretAuth is a struct that contains the information about auth data if present.
20
- class SecretAuth < Response.new(:client_token, :policies, :metadata, :lease_duration, :renewable)
21
- alias_method :renewable?, :renewable
131
+ # WrapInfo is the information returned by a wrapped response. This is almost
132
+ # always embedded as part of a {Secret}.
133
+ class WrapInfo < Response
134
+ # @!attribute [r] token
135
+ # Wrapped response token. This token may be used to unwrap the response.
136
+ # @return [String]
137
+ field :token
138
+
139
+ # @!attribute [r] wrapped_accessor
140
+ # Accessor for the wrapped token. This is like a `lease_id`, but for a token.
141
+ # @return [String]
142
+ field :wrapped_accessor
143
+
144
+ # @!attribute [r] creation_time
145
+ # Date & time when the wrapped token was created
146
+ # @return [Time]
147
+ field :creation_time, load: ->(v) { Time.parse(v) }
148
+
149
+ # @!attribute [r] ttl
150
+ # The TTL on the token returned in seconds.
151
+ # @return [Fixnum]
152
+ field :ttl
22
153
  end
23
154
  end
@@ -1,9 +1,22 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class Audit < Response.new(:type, :description, :options); end
4
+ class Audit < Response
5
+ # @!attribute [r] description
6
+ # Description of the audit backend.
7
+ # @return [String]
8
+ field :description
9
+
10
+ # @!attribute [r] options
11
+ # Map of options configured to the audit backend.
12
+ # @return [Hash<Symbol, Object>]
13
+ field :options
14
+
15
+ # @!attribute [r] type
16
+ # Name of the audit backend.
17
+ # @return [String]
18
+ field :type
19
+ end
7
20
 
8
21
  class Sys
9
22
  # List all audis for the vault.
@@ -1,9 +1,17 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class Auth < Response.new(:type, :description); end
4
+ class Auth < Response
5
+ # @!attribute [r] description
6
+ # Description of the auth backend.
7
+ # @return [String]
8
+ field :description
9
+
10
+ # @!attribute [r] type
11
+ # Name of the auth backend.
12
+ # @return [String]
13
+ field :type
14
+ end
7
15
 
8
16
  class Sys
9
17
  # List all auths in Vault.
@@ -1,12 +1,23 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class InitResponse < Response.new(:keys, :root_token); end
4
+ class InitResponse < Response
5
+ # @!attribute [r] keys
6
+ # List of unseal keys.
7
+ # @return [Array<String>]
8
+ field :keys
9
+
10
+ # @!attribute [r] root_token
11
+ # Initial root token.
12
+ # @return [String]
13
+ field :root_token
14
+ end
7
15
 
8
- class InitStatus < Response.new(:initialized)
9
- alias_method :initialized?, :initialized
16
+ class InitStatus < Response
17
+ # @!method initialized?
18
+ # Returns whether the Vault server is initialized.
19
+ # @return [Boolean]
20
+ field :initialized, as: :initialized?
10
21
  end
11
22
 
12
23
  class Sys
@@ -33,12 +44,15 @@ module Vault
33
44
  # the number of shares
34
45
  # @option options [Fixnum] :threshold
35
46
  # the number of keys needed to unlock
47
+ # @option options [Array] :pgp_keys
48
+ # an optional Array of base64-encoded PGP public keys to encrypt shares with
36
49
  #
37
50
  # @return [InitResponse]
38
51
  def init(options = {})
39
52
  json = client.put("/v1/sys/init", JSON.fast_generate(
40
53
  secret_shares: options.fetch(:shares, 5),
41
54
  secret_threshold: options.fetch(:threshold, 3),
55
+ pgp_keys: options.fetch(:pgp_keys, nil)
42
56
  ))
43
57
  return InitResponse.decode(json)
44
58
  end
@@ -1,13 +1,31 @@
1
- require_relative "../sys"
2
-
3
1
  module Vault
4
- class LeaderStatus < Response.new(:ha_enabled, :is_self, :leader_address)
5
- alias_method :ha_enabled?, :ha_enabled
6
- alias_method :ha?, :ha_enabled
7
- alias_method :is_self?, :is_self
8
- alias_method :is_leader?, :is_self
9
- alias_method :leader?, :is_self
10
- alias_method :address, :leader_address
2
+ class LeaderStatus < Response
3
+ # @!method ha_enabled?
4
+ # Returns whether the high-availability mode is enabled.
5
+ # @return [Boolean]
6
+ field :ha_enabled, as: :ha_enabled?
7
+
8
+ # @!method leader?
9
+ # Returns whether the Vault server queried is the leader.
10
+ # @return [Boolean]
11
+ field :is_self, as: :leader?
12
+
13
+ # @!attribute [r] address
14
+ # URL where the server is running.
15
+ # @return [String]
16
+ field :leader_address, as: :address
17
+
18
+ # @deprecated Use {#ha_enabled?} instead
19
+ def ha?; ha_enabled?; end
20
+
21
+ # @deprecated Use {#leader?} instead
22
+ def is_leader?; leader?; end
23
+
24
+ # @deprecated Use {#leader?} instead
25
+ def is_self?; leader?; end
26
+
27
+ # @deprecated Use {#leader?} instead
28
+ def self?; leader?; end
11
29
  end
12
30
 
13
31
  class Sys
@@ -1,5 +1,3 @@
1
- require_relative "../sys"
2
-
3
1
  module Vault
4
2
  class Sys
5
3
  # Renew a lease with the given ID.
@@ -1,9 +1,22 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class Mount < Response.new(:type, :description); end
4
+ class Mount < Response
5
+ # @!attribute [r] config
6
+ # Arbitrary configuration for the backend.
7
+ # @return [Hash<Symbol, Object>]
8
+ field :config
9
+
10
+ # @!attribute [r] description
11
+ # Description of the mount.
12
+ # @return [String]
13
+ field :description
14
+
15
+ # @!attribute [r] type
16
+ # Type of the mount.
17
+ # @return [String]
18
+ field :type
19
+ end
7
20
 
8
21
  class Sys < Request
9
22
  # List all mounts in the vault.
@@ -38,6 +51,20 @@ module Vault
38
51
  return true
39
52
  end
40
53
 
54
+ # Tune a mount at the given path.
55
+ #
56
+ # @example
57
+ # Vault.sys.mount_tune("pki", max_lease_ttl: '87600h') #=> true
58
+ #
59
+ # @param [String] path
60
+ # the path to write
61
+ # @param [Hash] data
62
+ # the data to write
63
+ def mount_tune(path, data = {})
64
+ json = client.post("/v1/sys/mounts/#{CGI.escape(path)}/tune", JSON.fast_generate(data))
65
+ return true
66
+ end
67
+
41
68
  # Unmount the thing at the given path. If the mount does not exist, an error
42
69
  # will be raised.
43
70
  #
@@ -1,9 +1,25 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class Policy < Response.new(:rules); end
4
+ class Policy < Response
5
+ # @!attribute [r] name
6
+ # Name of the policy.
7
+ #
8
+ # @example Get the name of the policy
9
+ # policy.name #=> "default"
10
+ #
11
+ # @return [String]
12
+ field :name
13
+
14
+ # @!attribute [r] rules
15
+ # Raw HCL policy.
16
+ #
17
+ # @example Display the list of rules
18
+ # policy.rules #=> "path \"secret/foo\" {}"
19
+ #
20
+ # @return [String]
21
+ field :rules
22
+ end
7
23
 
8
24
  class Sys
9
25
  # The list of policies in vault.
@@ -1,10 +1,42 @@
1
1
  require "json"
2
2
 
3
- require_relative "../sys"
4
-
5
3
  module Vault
6
- class SealStatus < Response.new(:sealed, :t, :n, :progress)
7
- alias_method :sealed?, :sealed
4
+ class SealStatus < Response
5
+ # @!method sealed?
6
+ # Returns if the Vault is sealed.
7
+ #
8
+ # @example Check if the Vault is sealed
9
+ # status.sealed? #=> true
10
+ #
11
+ # @return [Boolean]
12
+ field :sealed, as: :sealed?
13
+
14
+ # @!attribute t
15
+ # Threshold of keys required to unseal the Vault.
16
+ #
17
+ # @example Get the threshold of keys
18
+ # status.t #=> 3
19
+ #
20
+ # @return [Fixnum]
21
+ field :t
22
+
23
+ # @!attribute n
24
+ # Total number of unseal keys.
25
+ #
26
+ # @example Get the total number of keys
27
+ # status.n #=> 5
28
+ #
29
+ # @return [Fixnum]
30
+ field :n
31
+
32
+ # @!attribute progress
33
+ # Number of keys that have been entered.
34
+ #
35
+ # @example Get the current unseal progress
36
+ # status.progress #=> 2
37
+ #
38
+ # @return [Fixnum]
39
+ field :progress
8
40
  end
9
41
 
10
42
  class Sys
@@ -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 wrapped request ttl.
20
+ WRAP_TTL_HEADER = "X-Vault-Wrap-TTL".freeze
21
+
19
22
  # The name of the header used for redirection.
20
23
  LOCATION_HEADER = "location".freeze
21
24
 
@@ -66,6 +69,18 @@ module Vault
66
69
  end
67
70
  end
68
71
 
72
+ # Creates and yields a new client object with the given token. This may be
73
+ # used safely in a threadsafe manner because the original client remains
74
+ # unchanged. The value of the block is returned.
75
+ #
76
+ # @yield [Vault::Client]
77
+ def with_token(token)
78
+ client = self.dup
79
+ client.token = token
80
+ return yield client if block_given?
81
+ return nil
82
+ end
83
+
69
84
  # Determine if the given options are the same as ours.
70
85
  # @return [true, false]
71
86
  def same_options?(opts)
@@ -78,6 +93,13 @@ module Vault
78
93
  request(:get, path, params, headers)
79
94
  end
80
95
 
96
+ # Perform a LIST request.
97
+ # @see Client#request
98
+ def list(path, params = {}, headers = {})
99
+ params = params.merge(list: true)
100
+ request(:get, path, params, headers)
101
+ end
102
+
81
103
  # Perform a POST request.
82
104
  # @see Client#request
83
105
  def post(path, data = {}, headers = {})
@@ -132,7 +154,7 @@ module Vault
132
154
  # Add the Vault token header - users could still override this on a
133
155
  # per-request basis
134
156
  if !token.nil?
135
- request.add_field(TOKEN_HEADER, token)
157
+ headers[TOKEN_HEADER] ||= token
136
158
  end
137
159
 
138
160
  # Add headers
@@ -47,7 +47,7 @@ module Vault
47
47
  end
48
48
 
49
49
  if VAULT_DISK_TOKEN.exist? && VAULT_DISK_TOKEN.readable?
50
- return VAULT_DISK_TOKEN.read
50
+ return VAULT_DISK_TOKEN.read.chomp
51
51
  end
52
52
 
53
53
  nil
@@ -128,7 +128,7 @@ module Vault
128
128
  def ssl_verify
129
129
  # Vault CLI uses this envvar, so accept it by precedence
130
130
  if !ENV["VAULT_SKIP_VERIFY"].nil?
131
- return true
131
+ return false
132
132
  end
133
133
 
134
134
  if ENV["VAULT_SSL_VERIFY"].nil?
@@ -15,5 +15,27 @@ module Vault
15
15
  def inspect
16
16
  "#<#{self.class.name}:0x#{"%x" % (self.object_id << 1)}>"
17
17
  end
18
+
19
+ private
20
+
21
+ # Removes the given header fields from options and returns the result. This
22
+ # modifies the given options in place.
23
+ #
24
+ # @param [Hash] options
25
+ #
26
+ # @return [Hash]
27
+ def extract_headers!(options = {})
28
+ extract = {
29
+ wrap_ttl: Vault::Client::WRAP_TTL_HEADER,
30
+ }
31
+
32
+ {}.tap do |h|
33
+ extract.each do |k,v|
34
+ if options[k]
35
+ h[v] = options.delete(k)
36
+ end
37
+ end
38
+ end
39
+ end
18
40
  end
19
41
  end
@@ -1,18 +1,64 @@
1
1
  module Vault
2
- module Response
3
- def self.new(*members)
4
- Struct.new(*members) do
5
- def self.decode(object)
6
- self.new(*object.values_at(*self.members))
7
- end
2
+ class Response
3
+ # Defines a new field. This is designed to be used by the subclass as a
4
+ # mini-DSL.
5
+ #
6
+ # @example Default
7
+ # field :data
8
+ #
9
+ # @example With a mutator
10
+ # field :present, as: :present?
11
+ #
12
+ # @param n [Symbol] the name of the field
13
+ # @option opts [Symbol] :as alias for method name
14
+ #
15
+ # @!visibility private
16
+ def self.field(n, opts = {})
17
+ self.fields[n] = opts
8
18
 
9
- def to_s
10
- "#<#{self.class.name}>"
19
+ if opts[:as].nil?
20
+ attr_reader n
21
+ else
22
+ define_method(opts[:as]) do
23
+ instance_variable_get(:"@#{n}")
11
24
  end
25
+ end
26
+ end
27
+
28
+ # Returns the list of fields defined on this subclass.
29
+ # @!visibility private
30
+ def self.fields
31
+ @fields ||= {}
32
+ end
33
+
34
+ # Decodes the given object (usually a Hash) into an instance of this class.
35
+ #
36
+ # @param object [Hash<Symbol, Object>]
37
+ def self.decode(object)
38
+ self.new(object)
39
+ end
40
+
41
+ def initialize(opts = {})
42
+ # Initialize all fields as nil to start
43
+ self.class.fields.each do |k, _|
44
+ instance_variable_set(:"@#{k}", nil)
45
+ end
46
+
47
+ # For each supplied option, set the instance variable if it was defined
48
+ # as a field.
49
+ opts.each do |k, v|
50
+ if self.class.fields.key?(k)
51
+ opts = self.class.fields[k]
52
+
53
+ if (m = opts[:load]) && !v.nil?
54
+ v = m.call(v)
55
+ end
56
+
57
+ if opts[:freeze]
58
+ v = v.freeze
59
+ end
12
60
 
13
- def inspect
14
- data = self.members.map { |m| "@#{m}=#{self.public_send(m).inspect}" }.join(", ")
15
- "#<#{self.class.name} #{data}>"
61
+ instance_variable_set(:"@#{k}", v)
16
62
  end
17
63
  end
18
64
  end
@@ -1,3 +1,3 @@
1
1
  module Vault
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -23,5 +23,6 @@ Gem::Specification.new do |spec|
23
23
  spec.add_development_dependency "pry"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
25
  spec.add_development_dependency "rspec", "~> 3.2"
26
+ spec.add_development_dependency "yard"
26
27
  spec.add_development_dependency "webmock", "~> 1.22"
27
28
  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.4.0
4
+ version: 0.5.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: 2016-03-31 00:00:00.000000000 Z
11
+ date: 2016-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '3.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: webmock
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -139,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
153
  version: '0'
140
154
  requirements: []
141
155
  rubyforge_project:
142
- rubygems_version: 2.2.3
156
+ rubygems_version: 2.4.5.1
143
157
  signing_key:
144
158
  specification_version: 4
145
159
  summary: Vault is a Ruby API client for interacting with a Vault server.