vault 0.4.0 → 0.5.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
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.