vault_ruby_client 0.18.2

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.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +287 -0
  3. data/LICENSE +364 -0
  4. data/README.md +223 -0
  5. data/lib/vault/api/approle.rb +221 -0
  6. data/lib/vault/api/auth.rb +324 -0
  7. data/lib/vault/api/auth_tls.rb +95 -0
  8. data/lib/vault/api/auth_token.rb +245 -0
  9. data/lib/vault/api/help.rb +36 -0
  10. data/lib/vault/api/kv.rb +230 -0
  11. data/lib/vault/api/logical.rb +153 -0
  12. data/lib/vault/api/secret.rb +171 -0
  13. data/lib/vault/api/sys/audit.rb +94 -0
  14. data/lib/vault/api/sys/auth.rb +119 -0
  15. data/lib/vault/api/sys/health.rb +66 -0
  16. data/lib/vault/api/sys/init.rb +86 -0
  17. data/lib/vault/api/sys/leader.rb +51 -0
  18. data/lib/vault/api/sys/lease.rb +52 -0
  19. data/lib/vault/api/sys/mount.rb +165 -0
  20. data/lib/vault/api/sys/namespace.rb +86 -0
  21. data/lib/vault/api/sys/policy.rb +95 -0
  22. data/lib/vault/api/sys/quota.rb +110 -0
  23. data/lib/vault/api/sys/seal.rb +84 -0
  24. data/lib/vault/api/sys.rb +30 -0
  25. data/lib/vault/api/transform/alphabet.rb +46 -0
  26. data/lib/vault/api/transform/role.rb +45 -0
  27. data/lib/vault/api/transform/template.rb +57 -0
  28. data/lib/vault/api/transform/transformation.rb +64 -0
  29. data/lib/vault/api/transform.rb +32 -0
  30. data/lib/vault/api.rb +17 -0
  31. data/lib/vault/client.rb +460 -0
  32. data/lib/vault/configurable.rb +53 -0
  33. data/lib/vault/defaults.rb +218 -0
  34. data/lib/vault/encode.rb +22 -0
  35. data/lib/vault/errors.rb +87 -0
  36. data/lib/vault/persistent/connection.rb +45 -0
  37. data/lib/vault/persistent/pool.rb +51 -0
  38. data/lib/vault/persistent/timed_stack_multi.rb +73 -0
  39. data/lib/vault/persistent.rb +1161 -0
  40. data/lib/vault/request.rb +47 -0
  41. data/lib/vault/response.rb +92 -0
  42. data/lib/vault/vendor/connection_pool/timed_stack.rb +181 -0
  43. data/lib/vault/vendor/connection_pool/version.rb +8 -0
  44. data/lib/vault/vendor/connection_pool.rb +153 -0
  45. data/lib/vault/version.rb +6 -0
  46. data/lib/vault_ruby_client.rb +53 -0
  47. metadata +158 -0
@@ -0,0 +1,218 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ require "pathname"
5
+ require "base64"
6
+
7
+ module Vault
8
+ module Defaults
9
+ # The default vault address.
10
+ # @return [String]
11
+ VAULT_ADDRESS = "https://127.0.0.1:8200".freeze
12
+
13
+ # The default path to the vault token on disk.
14
+ # @return [String]
15
+ DEFAULT_VAULT_DISK_TOKEN = Pathname.new("#{ENV["HOME"]}/.vault-token").expand_path.freeze
16
+
17
+ # The list of SSL ciphers to allow. You should not change this value unless
18
+ # you absolutely know what you are doing!
19
+ # @return [String]
20
+ SSL_CIPHERS = "TLSv1.2:!aNULL:!eNULL".freeze
21
+
22
+ # The default number of attempts.
23
+ # @return [Fixnum]
24
+ RETRY_ATTEMPTS = 2
25
+
26
+ # The default backoff interval.
27
+ # @return [Fixnum]
28
+ RETRY_BASE = 0.05
29
+
30
+ # The maximum amount of time for a single exponential backoff to sleep.
31
+ RETRY_MAX_WAIT = 2.0
32
+
33
+ # The default size of the connection pool
34
+ DEFAULT_POOL_SIZE = 16
35
+
36
+ # The default timeout in seconds for retrieving a connection from the connection pool
37
+ DEFAULT_POOL_TIMEOUT = 0.5
38
+
39
+ # The set of exceptions that are detect and retried by default
40
+ # with `with_retries`
41
+ RETRIED_EXCEPTIONS = [HTTPServerError, MissingRequiredStateError]
42
+
43
+ class << self
44
+ # The list of calculated options for this configurable.
45
+ # @return [Hash]
46
+ def options
47
+ Hash[*Configurable.keys.map { |key| [key, public_send(key)] }.flatten]
48
+ end
49
+
50
+ # The address to communicate with Vault.
51
+ # @return [String]
52
+ def address
53
+ ENV["VAULT_ADDR"] || VAULT_ADDRESS
54
+ end
55
+
56
+ # The vault token to use for authentiation.
57
+ # @return [String, nil]
58
+ def token
59
+ ENV["VAULT_TOKEN"] || fetch_from_disk("VAULT_TOKEN_FILE")
60
+ end
61
+
62
+ def fetch_from_disk(env_var)
63
+ path = ENV[env_var] ? Pathname.new(ENV[env_var]) : DEFAULT_VAULT_DISK_TOKEN
64
+ if path.exist? && path.readable?
65
+ path.read.chomp
66
+ end
67
+ end
68
+
69
+ # Vault Namespace, if any.
70
+ # @return [String, nil]
71
+ def namespace
72
+ ENV["VAULT_NAMESPACE"]
73
+ end
74
+
75
+ # The SNI host to use when connecting to Vault via TLS.
76
+ # @return [String, nil]
77
+ def hostname
78
+ ENV["VAULT_TLS_SERVER_NAME"]
79
+ end
80
+
81
+ # The number of seconds to wait when trying to open a connection before
82
+ # timing out
83
+ # @return [String, nil]
84
+ def open_timeout
85
+ ENV["VAULT_OPEN_TIMEOUT"]
86
+ end
87
+
88
+ # The size of the connection pool to communicate with Vault
89
+ # @return Integer
90
+ def pool_size
91
+ if var = ENV["VAULT_POOL_SIZE"]
92
+ var.to_i
93
+ else
94
+ DEFAULT_POOL_SIZE
95
+ end
96
+ end
97
+
98
+ # The timeout for getting a connection from the connection pool that communicates with Vault
99
+ # @return Float
100
+ def pool_timeout
101
+ if var = ENV["VAULT_POOL_TIMEOUT"]
102
+ var.to_f
103
+ else
104
+ DEFAULT_POOL_TIMEOUT
105
+ end
106
+ end
107
+
108
+ # The HTTP Proxy server address as a string
109
+ # @return [String, nil]
110
+ def proxy_address
111
+ ENV["VAULT_PROXY_ADDRESS"]
112
+ end
113
+
114
+ # The HTTP Proxy server username as a string
115
+ # @return [String, nil]
116
+ def proxy_username
117
+ ENV["VAULT_PROXY_USERNAME"]
118
+ end
119
+
120
+ # The HTTP Proxy user password as a string
121
+ # @return [String, nil]
122
+ def proxy_password
123
+ ENV["VAULT_PROXY_PASSWORD"]
124
+ end
125
+
126
+ # The HTTP Proxy server port as a string
127
+ # @return [String, nil]
128
+ def proxy_port
129
+ ENV["VAULT_PROXY_PORT"]
130
+ end
131
+
132
+ # The number of seconds to wait when reading a response before timing out
133
+ # @return [String, nil]
134
+ def read_timeout
135
+ ENV["VAULT_READ_TIMEOUT"]
136
+ end
137
+
138
+ # The ciphers that will be used when communicating with vault over ssl
139
+ # You should only change the defaults if the ciphers are not available on
140
+ # your platform and you know what you are doing
141
+ # @return [String]
142
+ def ssl_ciphers
143
+ ENV["VAULT_SSL_CIPHERS"] || SSL_CIPHERS
144
+ end
145
+
146
+ # The raw contents (as a string) for the pem file. To specify the path to
147
+ # the pem file, use {#ssl_pem_file} instead. This value is preferred over
148
+ # the value for {#ssl_pem_file}, if set.
149
+ # @return [String, nil]
150
+ def ssl_pem_contents
151
+ if ENV["VAULT_SSL_PEM_CONTENTS_BASE64"]
152
+ Base64.decode64(ENV["VAULT_SSL_PEM_CONTENTS_BASE64"])
153
+ else
154
+ ENV["VAULT_SSL_PEM_CONTENTS"]
155
+ end
156
+ end
157
+
158
+ # The path to a pem on disk to use with custom SSL verification
159
+ # @return [String, nil]
160
+ def ssl_pem_file
161
+ ENV["VAULT_SSL_CERT"] || ENV["VAULT_SSL_PEM_FILE"]
162
+ end
163
+
164
+ # Passphrase to the pem file on disk to use with custom SSL verification
165
+ # @return [String, nil]
166
+ def ssl_pem_passphrase
167
+ ENV["VAULT_SSL_CERT_PASSPHRASE"]
168
+ end
169
+
170
+ # The path to the CA cert on disk to use for certificate verification
171
+ # @return [String, nil]
172
+ def ssl_ca_cert
173
+ ENV["VAULT_CACERT"]
174
+ end
175
+
176
+ # The CA cert store to use for certificate verification
177
+ # @return [OpenSSL::X509::Store, nil]
178
+ def ssl_cert_store
179
+ nil
180
+ end
181
+
182
+ # The path to the directory on disk holding CA certs to use
183
+ # for certificate verification
184
+ # @return [String, nil]
185
+ def ssl_ca_path
186
+ ENV["VAULT_CAPATH"]
187
+ end
188
+
189
+ # Verify SSL requests (default: true)
190
+ # @return [true, false]
191
+ def ssl_verify
192
+ # Vault CLI uses this envvar, so accept it by precedence
193
+ if !ENV["VAULT_SKIP_VERIFY"].nil?
194
+ return false
195
+ end
196
+
197
+ if ENV["VAULT_SSL_VERIFY"].nil?
198
+ true
199
+ else
200
+ %w[t y].include?(ENV["VAULT_SSL_VERIFY"].downcase[0])
201
+ end
202
+ end
203
+
204
+ # The number of seconds to wait for connecting and verifying SSL
205
+ # @return [String, nil]
206
+ def ssl_timeout
207
+ ENV["VAULT_SSL_TIMEOUT"]
208
+ end
209
+
210
+ # A default meta-attribute to set all timeout values - individually set
211
+ # timeout values will take precedence
212
+ # @return [String, nil]
213
+ def timeout
214
+ ENV["VAULT_TIMEOUT"]
215
+ end
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,22 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ module Vault
5
+ module EncodePath
6
+
7
+ # Encodes a string according to the rules for URL paths. This is
8
+ # used as opposed to CGI.escape because in a URL path, space
9
+ # needs to be escaped as %20 and CGI.escapes a space as +.
10
+ #
11
+ # @param [String]
12
+ #
13
+ # @return [String]
14
+ def encode_path(path)
15
+ path.b.gsub(%r!([^a-zA-Z0-9_.-/]+)!) { |m|
16
+ '%' + m.unpack('H2' * m.bytesize).join('%').upcase
17
+ }
18
+ end
19
+
20
+ module_function :encode_path
21
+ end
22
+ end
@@ -0,0 +1,87 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ module Vault
5
+ class VaultError < RuntimeError; end
6
+
7
+ class MissingTokenError < VaultError
8
+ def initialize
9
+ super <<-EOH
10
+ Missing Vault token! I cannot make requests to Vault without a token. Please
11
+ set a Vault token in the client:
12
+
13
+ Vault.token = "42d1dee5-eb6e-102c-8d23-cc3ba875da51"
14
+
15
+ or authenticate with Vault using the Vault CLI:
16
+
17
+ $ vault auth ...
18
+
19
+ or set the environment variable $VAULT_TOKEN to the token value:
20
+
21
+ $ export VAULT_TOKEN="..."
22
+
23
+ Please refer to the documentation for more examples.
24
+ EOH
25
+ end
26
+ end
27
+
28
+ class MissingRequiredStateError < VaultError
29
+ def initialize
30
+ super <<-EOH
31
+ The performance standby node does not yet have the
32
+ most recent index state required to authenticate
33
+ the request.
34
+
35
+ Generally, the request should be retried with the with_retries clause.
36
+ EOH
37
+ end
38
+ end
39
+
40
+ class HTTPConnectionError < VaultError
41
+ attr_reader :address
42
+
43
+ def initialize(address, exception)
44
+ @address = address
45
+ @exception = exception
46
+
47
+ super <<-EOH
48
+ The Vault server at `#{address}' is not currently
49
+ accepting connections. Please ensure that the server is running and that your
50
+ authentication information is correct.
51
+
52
+ The original error was `#{exception.class}'. Additional information (if any) is
53
+ shown below:
54
+
55
+ #{exception.message}
56
+
57
+ Please refer to the documentation for more help.
58
+ EOH
59
+ end
60
+
61
+ def original_exception
62
+ @exception
63
+ end
64
+ end
65
+
66
+ class HTTPError < VaultError
67
+ attr_reader :address, :response, :code, :errors
68
+
69
+ def initialize(address, response, errors = [])
70
+ @address, @response, @errors = address, response, errors
71
+ @code = response.code.to_i
72
+ errors = errors.map { |error| " * #{error}" }
73
+
74
+ super <<-EOH
75
+ The Vault server at `#{address}' responded with a #{code}.
76
+ Any additional information the server supplied is shown below:
77
+
78
+ #{errors.join("\n").rstrip}
79
+
80
+ Please refer to the documentation for help.
81
+ EOH
82
+ end
83
+ end
84
+
85
+ class HTTPClientError < HTTPError; end
86
+ class HTTPServerError < HTTPError; end
87
+ end
@@ -0,0 +1,45 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ ##
5
+ # A Net::HTTP connection wrapper that holds extra information for managing the
6
+ # connection's lifetime.
7
+
8
+ module Vault
9
+ class PersistentHTTP::Connection # :nodoc:
10
+
11
+ attr_accessor :http
12
+
13
+ attr_accessor :last_use
14
+
15
+ attr_accessor :requests
16
+
17
+ attr_accessor :ssl_generation
18
+
19
+ def initialize http_class, http_args, ssl_generation
20
+ @http = http_class.new(*http_args)
21
+ @ssl_generation = ssl_generation
22
+
23
+ reset
24
+ end
25
+
26
+ def finish
27
+ @http.finish
28
+ rescue IOError
29
+ ensure
30
+ reset
31
+ end
32
+
33
+ def reset
34
+ @last_use = PersistentHTTP::EPOCH
35
+ @requests = 0
36
+ end
37
+
38
+ def ressl ssl_generation
39
+ @ssl_generation = ssl_generation
40
+
41
+ finish
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ module Vault
5
+ class PersistentHTTP::Pool < Vault::ConnectionPool # :nodoc:
6
+
7
+ attr_reader :available # :nodoc:
8
+ attr_reader :key # :nodoc:
9
+
10
+ def initialize(options = {}, &block)
11
+ super
12
+
13
+ @available = PersistentHTTP::TimedStackMulti.new(@size, &block)
14
+ @key = :"current-#{@available.object_id}"
15
+ end
16
+
17
+ def checkin net_http_args
18
+ stack = Thread.current[@key][net_http_args]
19
+
20
+ raise ConnectionPool::Error, 'no connections are checked out' if
21
+ stack.empty?
22
+
23
+ conn = stack.pop
24
+
25
+ if stack.empty?
26
+ @available.push conn, connection_args: net_http_args
27
+ end
28
+
29
+ nil
30
+ end
31
+
32
+ def checkout net_http_args
33
+ stacks = Thread.current[@key] ||= Hash.new { |h, k| h[k] = [] }
34
+ stack = stacks[net_http_args]
35
+
36
+ if stack.empty? then
37
+ conn = @available.pop @timeout, connection_args: net_http_args
38
+ else
39
+ conn = stack.last
40
+ end
41
+
42
+ stack.push conn
43
+
44
+ conn
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ require_relative 'timed_stack_multi'
51
+
@@ -0,0 +1,73 @@
1
+ # Copyright (c) HashiCorp, Inc.
2
+ # SPDX-License-Identifier: MPL-2.0
3
+
4
+ module Vault
5
+ class PersistentHTTP::TimedStackMulti < ConnectionPool::TimedStack # :nodoc:
6
+
7
+ def initialize(size = 0, &block)
8
+ super
9
+
10
+ @enqueued = 0
11
+ @ques = Hash.new { |h, k| h[k] = [] }
12
+ @lru = {}
13
+ @key = :"connection_args-#{object_id}"
14
+ end
15
+
16
+ def empty?
17
+ (@created - @enqueued) >= @max
18
+ end
19
+
20
+ def length
21
+ @max - @created + @enqueued
22
+ end
23
+
24
+ private
25
+
26
+ def connection_stored? options = {} # :nodoc:
27
+ !@ques[options[:connection_args]].empty?
28
+ end
29
+
30
+ def fetch_connection options = {} # :nodoc:
31
+ connection_args = options[:connection_args]
32
+
33
+ @enqueued -= 1
34
+ lru_update connection_args
35
+ @ques[connection_args].pop
36
+ end
37
+
38
+ def lru_update connection_args # :nodoc:
39
+ @lru.delete connection_args
40
+ @lru[connection_args] = true
41
+ end
42
+
43
+ def shutdown_connections # :nodoc:
44
+ @ques.each_key do |key|
45
+ super connection_args: key
46
+ end
47
+ end
48
+
49
+ def store_connection obj, options = {} # :nodoc:
50
+ @ques[options[:connection_args]].push obj
51
+ @enqueued += 1
52
+ end
53
+
54
+ def try_create options = {} # :nodoc:
55
+ connection_args = options[:connection_args]
56
+
57
+ if @created >= @max && @enqueued >= 1
58
+ oldest, = @lru.first
59
+ @lru.delete oldest
60
+ @ques[oldest].pop
61
+
62
+ @created -= 1
63
+ end
64
+
65
+ if @created < @max
66
+ @created += 1
67
+ lru_update connection_args
68
+ return @create_block.call(connection_args)
69
+ end
70
+ end
71
+
72
+ end
73
+ end