vault 0.6.0 → 0.7.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: 7c5b5358811dba9b5864bc118f19b2cb0c9b7925
4
- data.tar.gz: 41acb15b4a2148910f3c7fb8a01f7b51ce31e8aa
3
+ metadata.gz: 59a8ecc9e18c8112104e721f65e10cd56377803c
4
+ data.tar.gz: 28937a7a2360736b70cbae0f53c7103659a6ade0
5
5
  SHA512:
6
- metadata.gz: d6ec85927a497e7dcef985d8b32b59db6c5169c1c95820e311c3f3c6617c893e520c592b411806cf81a18d03d5a1dfab9988fb319a43330a4137d18dee7b61d0
7
- data.tar.gz: 787597e6f6315e2620c766d5f83e625f520401399221bc0774d9f76b6a08d342baea5fe09d061fa6dc892876167af750800b7660dc6afff99abb15b025d6c33d
6
+ metadata.gz: 91b7a092f7dc019da3b410c744351686f146bd8c72d57f1a096f20e107df19ec9ef34b36125131d993d8539899713cdd014cfc98ac6b7e69a1f64729f1f982fb
7
+ data.tar.gz: 292bfa0003747c1e02cbe6ab3332e6a05b449db6d4f812d440864927f7c4f3b3dcd6ace36adc7574e9ac9849a32091c43d0b236765ed03e70c178a266677d961
@@ -3,11 +3,10 @@ cache: bundler
3
3
  sudo: false
4
4
 
5
5
  env:
6
+ - VAULT_VERSION=0.6.2
6
7
  - VAULT_VERSION=0.6.1
7
8
  - VAULT_VERSION=0.6.0
8
9
  - VAULT_VERSION=0.5.3
9
- - VAULT_VERSION=0.4.1
10
- - VAULT_VERSION=0.3.1
11
10
 
12
11
  before_install:
13
12
  - wget -O vault.zip -q https://releases.hashicorp.com/vault/${VAULT_VERSION}/vault_${VAULT_VERSION}_linux_amd64.zip
@@ -1,6 +1,22 @@
1
1
  # Vault Ruby Changelog
2
2
 
3
- ## v0.6.0.dev (Unreleased)
3
+ ## v0.7.0 (October 18, 2016)
4
+
5
+ DEPRECATIONS
6
+
7
+ - Vault versions older than 0.5.3 are no longer tested
8
+
9
+ NEW FEATURES
10
+
11
+ - Add support for AppRole
12
+ - Expose the auth/tune API
13
+ - Add support for leader step down
14
+ - Use persistent connections to Vault to speed up requests
15
+ - Add support for a custom ssl certificate store
16
+
17
+ BUG FIXES
18
+
19
+ - Allow for spaces in secret names properly
4
20
 
5
21
  ## v0.6.0 (August 30, 2016)
6
22
 
@@ -1,5 +1,6 @@
1
1
  module Vault
2
2
  module API
3
+ require_relative "api/approle"
3
4
  require_relative "api/auth_token"
4
5
  require_relative "api/auth_tls"
5
6
  require_relative "api/auth"
@@ -0,0 +1,218 @@
1
+ require "json"
2
+
3
+ require_relative "secret"
4
+ require_relative "../client"
5
+ require_relative "../request"
6
+ require_relative "../response"
7
+
8
+ module Vault
9
+ class Client
10
+ # A proxy to the {AppRole} methods.
11
+ # @return [AppRole]
12
+ def approle
13
+ @approle ||= AppRole.new(self)
14
+ end
15
+ end
16
+
17
+ class AppRole < Request
18
+ # Creates a new AppRole or update an existing AppRole with the given name
19
+ # and attributes.
20
+ #
21
+ # @example
22
+ # Vault.approle.set_role("testrole", {
23
+ # secret_id_ttl: "10m",
24
+ # token_ttl: "20m",
25
+ # policies: "default",
26
+ # period: 3600,
27
+ # }) #=> true
28
+ #
29
+ # @param [String] name
30
+ # The name of the AppRole
31
+ # @param [Hash] options
32
+ # @option options [Boolean] :bind_secret_id
33
+ # Require secret_id to be presented when logging in using this AppRole.
34
+ # @option options [String] :bound_cidr_list
35
+ # Comma-separated list of CIDR blocks. Specifies blocks of IP addresses
36
+ # which can perform the login operation.
37
+ # @option options [String] :policies
38
+ # Comma-separated list of policies set on tokens issued via this AppRole.
39
+ # @option options [String] :secret_id_num_uses
40
+ # Number of times any particular SecretID can be used to fetch a token
41
+ # from this AppRole, after which the SecretID will expire.
42
+ # @option options [Fixnum, String] :secret_id_ttl
43
+ # The number of seconds or a golang-formatted timestamp like "60m" after
44
+ # which any SecretID expires.
45
+ # @option options [Fixnum, String] :token_ttl
46
+ # The number of seconds or a golang-formatted timestamp like "60m" to set
47
+ # as the TTL for issued tokens and at renewal time.
48
+ # @option options [Fixnum, String] :token_max_ttl
49
+ # The number of seconds or a golang-formatted timestamp like "60m" after
50
+ # which the issued token can no longer be renewed.
51
+ # @option options [Fixnum, String] :period
52
+ # The number of seconds or a golang-formatted timestamp like "60m".
53
+ # If set, the token generated using this AppRole is a periodic token.
54
+ # So long as it is renewed it never expires, but the TTL set on the token
55
+ # at each renewal is fixed to the value specified here. If this value is
56
+ # modified, the token will pick up the new value at its next renewal.
57
+ #
58
+ # @return [true]
59
+ def set_role(name, options = {})
60
+ headers = extract_headers!(options)
61
+ client.post("/v1/auth/approle/role/#{encode_path(name)}", JSON.fast_generate(options), headers)
62
+ return true
63
+ end
64
+
65
+ # Gets the AppRole by the given name. If an AppRole does not exist by that
66
+ # name, +nil+ is returned.
67
+ #
68
+ # @example
69
+ # Vault.approle.role("testrole") #=> #<Vault::Secret lease_id="...">
70
+ #
71
+ # @return [Secret, nil]
72
+ def role(name)
73
+ json = client.get("/v1/auth/approle/role/#{encode_path(name)}")
74
+ return Secret.decode(json)
75
+ rescue HTTPError => e
76
+ return nil if e.code == 404
77
+ raise
78
+ end
79
+
80
+ # Gets the list of AppRoles in vault auth backend.
81
+ #
82
+ # @example
83
+ # Vault.approle.roles #=> ["testrole"]
84
+ #
85
+ # @return [Array<String>]
86
+ def roles(options = {})
87
+ headers = extract_headers!(options)
88
+ json = client.list("/v1/auth/approle/role", options, headers)
89
+ return Secret.decode(json).data[:keys] || []
90
+ rescue HTTPError => e
91
+ return [] if e.code == 404
92
+ raise
93
+ end
94
+
95
+ # Reads the RoleID of an existing AppRole. If an AppRole does not exist by
96
+ # that name, +nil+ is returned.
97
+ #
98
+ # @example
99
+ # Vault.approle.role_id("testrole") #=> #<Vault::Secret lease_id="...">
100
+ #
101
+ # @return [Secret, nil]
102
+ def role_id(name)
103
+ json = client.get("/v1/auth/approle/role/#{encode_path(name)}/role-id")
104
+ return Secret.decode(json).data[:role_id]
105
+ rescue HTTPError => e
106
+ return nil if e.code == 404
107
+ raise
108
+ end
109
+
110
+ # Updates the RoleID of an existing AppRole to a custom value.
111
+ #
112
+ # @example
113
+ # Vault.approle.set_role_id("testrole") #=> true
114
+ #
115
+ # @return [true]
116
+ def set_role_id(name, role_id)
117
+ options = { role_id: role_id }
118
+ client.post("/v1/auth/approle/role/#{encode_path(name)}/role-id", JSON.fast_generate(options))
119
+ return true
120
+ end
121
+
122
+ # Deletes the AppRole with the given name. If an AppRole does not exist,
123
+ # vault will not return an error.
124
+ #
125
+ # @example
126
+ # Vault.approle.delete_role("testrole") #=> true
127
+ #
128
+ # @param [String] name
129
+ # the name of the certificate
130
+ def delete_role(name)
131
+ client.delete("/v1/auth/approle/role/#{encode_path(name)}")
132
+ return true
133
+ end
134
+
135
+ # Generates and issues a new SecretID on an existing AppRole.
136
+ #
137
+ # @example Generate a new SecretID
138
+ # result = Vault.approle.create_secret_id("testrole") #=> #<Vault::Secret lease_id="...">
139
+ # result.data[:secret_id] #=> "841771dc-11c9-bbc7-bcac-6a3945a69cd9"
140
+ #
141
+ # @example Assign a custom SecretID
142
+ # result = Vault.approle.create_secret_id("testrole", {
143
+ # secret_id: "testsecretid"
144
+ # }) #=> #<Vault::Secret lease_id="...">
145
+ # result.data[:secret_id] #=> "testsecretid"
146
+ #
147
+ # @param [String] role_name
148
+ # The name of the AppRole
149
+ # @param [Hash] options
150
+ # @option options [String] :secret_id
151
+ # SecretID to be attached to the Role. If not set, then the new SecretID
152
+ # will be generated
153
+ # @option options [Hash<String, String>] :metadata
154
+ # Metadata to be tied to the SecretID. This should be a JSON-formatted
155
+ # string containing the metadata in key-value pairs. It will be set on
156
+ # tokens issued with this SecretID, and is logged in audit logs in
157
+ # plaintext.
158
+ #
159
+ # @return [true]
160
+ def create_secret_id(role_name, options = {})
161
+ headers = extract_headers!(options)
162
+ if options[:secret_id]
163
+ json = client.post("/v1/auth/approle/role/#{encode_path(role_name)}/custom-secret-id", JSON.fast_generate(options), headers)
164
+ else
165
+ json = client.post("/v1/auth/approle/role/#{encode_path(role_name)}/secret-id", JSON.fast_generate(options), headers)
166
+ end
167
+ return Secret.decode(json)
168
+ end
169
+
170
+ # Reads out the properties of a SecretID assigned to an AppRole.
171
+ # If the specified SecretID don't exist, +nil+ is returned.
172
+ #
173
+ # @example
174
+ # Vault.approle.role("testrole", "841771dc-11c9-...") #=> #<Vault::Secret lease_id="...">
175
+ #
176
+ # @param [String] role_name
177
+ # The name of the AppRole
178
+ # @param [String] secret_id
179
+ # SecretID belonging to AppRole
180
+ #
181
+ # @return [Secret, nil]
182
+ def secret_id(role_name, secret_id)
183
+ opts = { secret_id: secret_id }
184
+ json = client.post("/v1/auth/approle/role/#{encode_path(role_name)}/secret-id/lookup", JSON.fast_generate(opts), {})
185
+ return nil unless json
186
+ return Secret.decode(json)
187
+ rescue HTTPError => e
188
+ if e.code == 404 || e.code == 405
189
+ begin
190
+ json = client.get("/v1/auth/approle/role/#{encode_path(role_name)}/secret-id/#{encode_path(secret_id)}")
191
+ return Secret.decode(json)
192
+ rescue HTTPError => e
193
+ return nil if e.code == 404
194
+ raise e
195
+ end
196
+ end
197
+
198
+ raise
199
+ end
200
+
201
+ # Lists the accessors of all the SecretIDs issued against the AppRole.
202
+ # This includes the accessors for "custom" SecretIDs as well. If there are
203
+ # no SecretIDs against this role, an empty array will be returned.
204
+ #
205
+ # @example
206
+ # Vault.approle.secret_ids("testrole") #=> ["ce102d2a-...", "a1c8dee4-..."]
207
+ #
208
+ # @return [Array<String>]
209
+ def secret_id_accessors(role_name, options = {})
210
+ headers = extract_headers!(options)
211
+ json = client.list("/v1/auth/approle/role/#{encode_path(role_name)}/secret-id", options, headers)
212
+ return Secret.decode(json).data[:keys] || []
213
+ rescue HTTPError => e
214
+ return [] if e.code == 404
215
+ raise
216
+ end
217
+ end
218
+ end
@@ -74,6 +74,30 @@ module Vault
74
74
  return secret
75
75
  end
76
76
 
77
+ # Authenticate via the "approle" authentication method. If authentication is
78
+ # successful, the resulting token will be stored on the client and used for
79
+ # future requests.
80
+ #
81
+ # @example
82
+ # Vault.auth.approle(
83
+ # "db02de05-fa39-4855-059b-67221c5c2f63",
84
+ # "6a174c20-f6de-a53c-74d2-6018fcceff64",
85
+ # ) #=> #<Vault::Secret lease_id="">
86
+ #
87
+ # @param [String] role_id
88
+ # @param [String] secret_id (default: nil)
89
+ # It is required when `bind_secret_id` is enabled for the specified role_id
90
+ #
91
+ # @return [Secret]
92
+ def approle(role_id, secret_id=nil)
93
+ payload = { role_id: role_id }
94
+ payload[:secret_id] = secret_id if secret_id
95
+ json = client.post("/v1/auth/approle/login", JSON.fast_generate(payload))
96
+ secret = Secret.decode(json)
97
+ client.token = secret.auth.client_token
98
+ return secret
99
+ end
100
+
77
101
  # Authenticate via the "userpass" authentication method. If authentication
78
102
  # is successful, the resulting token will be stored on the client and used
79
103
  # for future requests.
@@ -93,7 +117,7 @@ module Vault
93
117
  # @return [Secret]
94
118
  def userpass(username, password, options = {})
95
119
  payload = { password: password }.merge(options)
96
- json = client.post("/v1/auth/userpass/login/#{CGI.escape(username)}", JSON.fast_generate(payload))
120
+ json = client.post("/v1/auth/userpass/login/#{encode_path(username)}", JSON.fast_generate(payload))
97
121
  secret = Secret.decode(json)
98
122
  client.token = secret.auth.client_token
99
123
  return secret
@@ -115,7 +139,7 @@ module Vault
115
139
  # @return [Secret]
116
140
  def ldap(username, password, options = {})
117
141
  payload = { password: password }.merge(options)
118
- json = client.post("/v1/auth/ldap/login/#{CGI.escape(username)}", JSON.fast_generate(payload))
142
+ json = client.post("/v1/auth/ldap/login/#{encode_path(username)}", JSON.fast_generate(payload))
119
143
  secret = Secret.decode(json)
120
144
  client.token = secret.auth.client_token
121
145
  return secret
@@ -42,7 +42,7 @@ module Vault
42
42
  # @return [true]
43
43
  def set_certificate(name, options = {})
44
44
  headers = extract_headers!(options)
45
- client.post("/v1/auth/cert/certs/#{CGI.escape(name)}", JSON.fast_generate(options), headers)
45
+ client.post("/v1/auth/cert/certs/#{encode_path(name)}", JSON.fast_generate(options), headers)
46
46
  return true
47
47
  end
48
48
 
@@ -54,7 +54,7 @@ module Vault
54
54
  #
55
55
  # @return [Secret, nil]
56
56
  def certificate(name)
57
- json = client.get("/v1/auth/cert/certs/#{CGI.escape(name)}")
57
+ json = client.get("/v1/auth/cert/certs/#{encode_path(name)}")
58
58
  return Secret.decode(json)
59
59
  rescue HTTPError => e
60
60
  return nil if e.code == 404
@@ -85,7 +85,7 @@ module Vault
85
85
  # @param [String] name
86
86
  # the name of the certificate
87
87
  def delete_certificate(name)
88
- client.delete("/v1/auth/cert/certs/#{CGI.escape(name)}")
88
+ client.delete("/v1/auth/cert/certs/#{encode_path(name)}")
89
89
  return true
90
90
  end
91
91
  end
@@ -95,7 +95,7 @@ module Vault
95
95
  # @return [Secret]
96
96
  def create_with_role(name, options = {})
97
97
  headers = extract_headers!(options)
98
- json = client.post("/v1/auth/token/create/#{CGI.escape(name)}", JSON.fast_generate(options), headers)
98
+ json = client.post("/v1/auth/token/create/#{encode_path(name)}", JSON.fast_generate(options), headers)
99
99
  return Secret.decode(json)
100
100
  end
101
101
 
@@ -108,7 +108,7 @@ module Vault
108
108
  #
109
109
  # @return [Secret]
110
110
  def lookup(token)
111
- json = client.get("/v1/auth/token/lookup/#{CGI.escape(token)}")
111
+ json = client.get("/v1/auth/token/lookup/#{encode_path(token)}")
112
112
  return Secret.decode(json)
113
113
  end
114
114
 
@@ -26,7 +26,7 @@ module Vault
26
26
  #
27
27
  # @return [Help]
28
28
  def help(path)
29
- json = self.get("/v1/#{CGI.escape(path)}", help: 1)
29
+ json = self.get("/v1/#{EncodePath.encode_path(path)}", help: 1)
30
30
  return Help.decode(json)
31
31
  end
32
32
  end
@@ -25,7 +25,7 @@ module Vault
25
25
  # @return [Array<String>]
26
26
  def list(path, options = {})
27
27
  headers = extract_headers!(options)
28
- json = client.list("/v1/#{CGI.escape(path)}", {}, headers)
28
+ json = client.list("/v1/#{encode_path(path)}", {}, headers)
29
29
  json[:data][:keys] || []
30
30
  rescue HTTPError => e
31
31
  return [] if e.code == 404
@@ -44,7 +44,7 @@ module Vault
44
44
  # @return [Secret, nil]
45
45
  def read(path, options = {})
46
46
  headers = extract_headers!(options)
47
- json = client.get("/v1/#{CGI.escape(path)}", {}, headers)
47
+ json = client.get("/v1/#{encode_path(path)}", {}, headers)
48
48
  return Secret.decode(json)
49
49
  rescue HTTPError => e
50
50
  return nil if e.code == 404
@@ -65,7 +65,7 @@ module Vault
65
65
  # @return [Secret]
66
66
  def write(path, data = {}, options = {})
67
67
  headers = extract_headers!(options)
68
- json = client.put("/v1/#{CGI.escape(path)}", JSON.fast_generate(data), headers)
68
+ json = client.put("/v1/#{encode_path(path)}", JSON.fast_generate(data), headers)
69
69
  if json.nil?
70
70
  return true
71
71
  else
@@ -84,7 +84,7 @@ module Vault
84
84
  #
85
85
  # @return [true]
86
86
  def delete(path)
87
- client.delete("/v1/#{CGI.escape(path)}")
87
+ client.delete("/v1/#{encode_path(path)}")
88
88
  return true
89
89
  end
90
90
 
@@ -51,7 +51,7 @@ module Vault
51
51
  #
52
52
  # @return [true]
53
53
  def enable_audit(path, type, description, options = {})
54
- client.put("/v1/sys/audit/#{CGI.escape(path)}", JSON.fast_generate(
54
+ client.put("/v1/sys/audit/#{encode_path(path)}", JSON.fast_generate(
55
55
  type: type,
56
56
  description: description,
57
57
  options: options,
@@ -67,7 +67,7 @@ module Vault
67
67
  #
68
68
  # @return [true]
69
69
  def disable_audit(path)
70
- client.delete("/v1/sys/audit/#{CGI.escape(path)}")
70
+ client.delete("/v1/sys/audit/#{encode_path(path)}")
71
71
  return true
72
72
  end
73
73
  end
@@ -13,6 +13,18 @@ module Vault
13
13
  field :type
14
14
  end
15
15
 
16
+ class AuthConfig < Response
17
+ # @!attribute [r] default_lease_ttl
18
+ # The default time-to-live.
19
+ # @return [String]
20
+ field :default_lease_ttl
21
+
22
+ # @!attribute [r] max_lease_ttl
23
+ # The maximum time-to-live.
24
+ # @return [String]
25
+ field :max_lease_ttl
26
+ end
27
+
16
28
  class Sys
17
29
  # List all auths in Vault.
18
30
  #
@@ -45,7 +57,7 @@ module Vault
45
57
  payload = { type: type }
46
58
  payload[:description] = description if !description.nil?
47
59
 
48
- client.post("/v1/sys/auth/#{CGI.escape(path)}", JSON.fast_generate(payload))
60
+ client.post("/v1/sys/auth/#{encode_path(path)}", JSON.fast_generate(payload))
49
61
  return true
50
62
  end
51
63
 
@@ -60,8 +72,45 @@ module Vault
60
72
  #
61
73
  # @return [true]
62
74
  def disable_auth(path)
63
- client.delete("/v1/sys/auth/#{CGI.escape(path)}")
75
+ client.delete("/v1/sys/auth/#{encode_path(path)}")
64
76
  return true
65
77
  end
78
+
79
+ # Read the given auth path's configuration.
80
+ #
81
+ # @example
82
+ # Vault.sys.auth_tune("github") #=> #<Vault::AuthConfig "default_lease_ttl"=3600, "max_lease_ttl"=7200>
83
+ #
84
+ # @param [String] path
85
+ # the path to retrieve configuration for
86
+ #
87
+ # @return [AuthConfig]
88
+ # configuration of the given auth path
89
+ def auth_tune(path)
90
+ json = client.get("/v1/sys/auth/#{encode_path(path)}/tune")
91
+ return AuthConfig.decode(json)
92
+ rescue HTTPError => e
93
+ return nil if e.code == 404
94
+ raise
95
+ end
96
+
97
+ # Write the given auth path's configuration.
98
+ #
99
+ # @example
100
+ # Vault.sys.auth_tune("github", "default_lease_ttl" => 600, "max_lease_ttl" => 1200 ) #=> true
101
+ #
102
+ # @param [String] path
103
+ # the path to retrieve configuration for
104
+ #
105
+ # @return [AuthConfig]
106
+ # configuration of the given auth path
107
+ def put_auth_tune(path, config = {})
108
+ json = client.put("/v1/sys/auth/#{encode_path(path)}/tune", JSON.fast_generate(config))
109
+ if json.nil?
110
+ return true
111
+ else
112
+ return Secret.decode(json)
113
+ end
114
+ end
66
115
  end
67
116
  end