bolt 1.34.0 → 1.35.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bolt might be problematic. Click here for more details.

@@ -1,206 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Bolt
4
- class Plugin
5
- class Vault
6
- class VaultHTTPError < Bolt::Error
7
- def initialize(response)
8
- err = JSON.parse(response.body)['errors']
9
- m = String.new("#{response.code} \"#{response.msg}\"")
10
- m << ": #{err.join(';')}" unless err.nil?
11
- super(m, 'bolt.plugin/vault-http-error')
12
- end
13
- end
14
-
15
- attr_reader :config
16
-
17
- # All requests for secrets must have a token in the request header
18
- TOKEN_HEADER = "X-Vault-Token"
19
-
20
- # Default header for all requests, including auth methods
21
- DEFAULT_HEADER = {
22
- "Content-Type" => "application/json",
23
- "Accept" => "application/json"
24
- }.freeze
25
-
26
- # Make sure no unexpected keys are in the config
27
- def validate_config(config)
28
- known_keys = %w[server_url auth cacert]
29
-
30
- config.each do |key, _v|
31
- next if known_keys.include?(key)
32
- raise Bolt::ValidationError, "Unexpected key in Vault plugin config: #{key}"
33
- end
34
- end
35
-
36
- # Make sure no unexpected keys are in the inventory config and
37
- # that required keys are present
38
- def validate_options(opts)
39
- known_keys = %w[_plugin server_url auth path field version cacert]
40
- required_keys = %w[path]
41
-
42
- opts.each do |key, _v|
43
- next if known_keys.include?(key)
44
- raise Bolt::ValidationError, "Unexpected key in inventory config: #{key}"
45
- end
46
-
47
- required_keys.each do |key|
48
- next if opts[key]
49
- raise Bolt::ValidationError, "Expected key in inventory config: #{key}"
50
- end
51
- end
52
-
53
- def name
54
- 'vault'
55
- end
56
-
57
- def hooks
58
- [:resolve_reference]
59
- end
60
-
61
- def initialize(config:, **_opts)
62
- validate_config(config)
63
- @config = config
64
- @logger = Logging.logger[self]
65
- end
66
-
67
- def resolve_reference(opts)
68
- validate_options(opts)
69
-
70
- header = {
71
- TOKEN_HEADER => token(opts)
72
- }
73
-
74
- response = request(:Get, uri(opts), opts, nil, header)
75
-
76
- parse_response(response, opts)
77
- end
78
-
79
- # Request uri - built up from Vault server url and secrets path
80
- def uri(opts, path = nil)
81
- url = opts['server_url'] || config['server_url'] || ENV['VAULT_ADDR']
82
-
83
- # Handle the different versions of the API
84
- if opts['version'] == 2
85
- mount, store = opts['path'].split('/', 2)
86
- opts['path'] = [mount, 'data', store].join('/')
87
- end
88
-
89
- path ||= opts['path']
90
-
91
- URI.parse(File.join(url, "v1", path))
92
- end
93
-
94
- # Configure the http/s client
95
- def client(uri, opts)
96
- client = Net::HTTP.new(uri.host, uri.port)
97
-
98
- if uri.scheme == 'https'
99
- cacert = opts['cacert'] || config['cacert'] || ENV['VAULT_CACERT']
100
-
101
- unless cacert
102
- raise Bolt::ValidationError, "Expected cacert to be set when using https"
103
- end
104
-
105
- client.use_ssl = true
106
- client.ssl_version = :TLSv1_2
107
- client.ca_file = cacert
108
- client.verify_mode = OpenSSL::SSL::VERIFY_PEER
109
- end
110
-
111
- client
112
- end
113
-
114
- # Auth token to vault server
115
- def token(opts)
116
- if (auth = opts['auth'] || config['auth'])
117
- request_token(auth, opts)
118
- else
119
- ENV['VAULT_TOKEN']
120
- end
121
- end
122
-
123
- def request(verb, uri, opts, data, header = {})
124
- # Add on any header options
125
- header = DEFAULT_HEADER.merge(header)
126
-
127
- # Create the HTTP request
128
- client = client(uri, opts)
129
- request = Net::HTTP.const_get(verb).new(uri.request_uri, header)
130
-
131
- # Attach any data
132
- request.body = data if data
133
-
134
- # Send the request
135
- begin
136
- response = client.request(request)
137
- rescue StandardError => e
138
- raise Bolt::Error.new(
139
- "Failed to connect to #{uri}: #{e.message}",
140
- 'CONNECT_ERROR'
141
- )
142
- end
143
-
144
- case response
145
- when Net::HTTPOK
146
- JSON.parse(response.body)
147
- else
148
- raise VaultHTTPError, response
149
- end
150
- end
151
-
152
- def parse_response(response, opts)
153
- data = case opts['version']
154
- when 2
155
- response['data']['data']
156
- else
157
- response['data']
158
- end
159
-
160
- if opts['field']
161
- unless data[opts['field']]
162
- raise Bolt::ValidationError, "Unknown secrets field: #{opts['field']}"
163
- end
164
- data[opts['field']]
165
- else
166
- data
167
- end
168
- end
169
-
170
- # Request a token from Vault using one of the auth methods
171
- def request_token(auth, opts)
172
- case auth['method']
173
- when 'token'
174
- auth_token(auth)
175
- when 'userpass'
176
- auth_userpass(auth, opts)
177
- else
178
- raise Bolt::ValidationError, "Unknown auth method: #{auth['method']}"
179
- end
180
- end
181
-
182
- def validate_auth(auth, required_keys)
183
- required_keys.each do |key|
184
- next if auth[key]
185
- raise Bolt::ValidationError, "Expected key in #{auth['method']} auth method: #{key}"
186
- end
187
- end
188
-
189
- # Authenticate with Vault using the 'Token' auth method
190
- def auth_token(auth)
191
- validate_auth(auth, %w[token])
192
- auth['token']
193
- end
194
-
195
- # Authenticate with Vault using the 'Userpass' auth method
196
- def auth_userpass(auth, opts)
197
- validate_auth(auth, %w[user pass])
198
- path = "auth/userpass/login/#{auth['user']}"
199
- uri = uri(opts, path)
200
- data = { "password" => auth['pass'] }.to_json
201
-
202
- request(:Post, uri, opts, data)['auth']['client_token']
203
- end
204
- end
205
- end
206
- end