Skip to content

Commit 7ca12ae

Browse files
authored
Add optional tls_verify_peer flag for HTTPS Docker API client (#17)
* Add tls_verify_peer option for HTTPS transport * Document tls_verify_peer option in README
1 parent 44e6821 commit 7ca12ae

File tree

11 files changed

+67
-9
lines changed

11 files changed

+67
-9
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,15 @@ docker = DockerEngineRuby::Client.new(
132132
)
133133
```
134134

135+
By default, peer verification is enabled. You can disable it explicitly:
136+
137+
```ruby
138+
docker = DockerEngineRuby::Client.new(
139+
base_url: "https://localhost:2376",
140+
tls_verify_peer: false
141+
)
142+
```
143+
135144
You can also configure these through environment variables:
136145

137146
- `DOCKER_TLS_CA_CERT_PATH`

lib/docker_engine_ruby/client.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ class Client < DockerEngineRuby::Internal::Transport::BaseClient
1515
# Default max retry delay in seconds.
1616
DEFAULT_MAX_RETRY_DELAY = 8.0
1717

18+
# Whether to verify server TLS certificate chain.
19+
DEFAULT_TLS_VERIFY_PEER = true
20+
1821
# rubocop:disable Style/MutableConstant
1922
# @type [Hash{Symbol=>String}]
2023
ENVIRONMENTS = {production: "http://localhost:2375", production_tls: "https://localhost:2376"}
@@ -106,6 +109,8 @@ class Client < DockerEngineRuby::Internal::Transport::BaseClient
106109
# @param initial_retry_delay [Float]
107110
#
108111
# @param max_retry_delay [Float]
112+
#
113+
# @param tls_verify_peer [Boolean] Whether to verify server TLS certificate chain.
109114
def initialize(
110115
tls_ca_cert_path: ENV["DOCKER_TLS_CA_CERT_PATH"],
111116
tls_client_cert_path: ENV["DOCKER_TLS_CLIENT_CERT_PATH"],
@@ -115,10 +120,12 @@ def initialize(
115120
max_retries: self.class::DEFAULT_MAX_RETRIES,
116121
timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
117122
initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
118-
max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
123+
max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY,
124+
tls_verify_peer: self.class::DEFAULT_TLS_VERIFY_PEER
119125
)
120126
base_url ||= DockerEngineRuby::Client::ENVIRONMENTS.fetch(environment&.to_sym || :production) do
121-
message = "environment must be one of #{DockerEngineRuby::Client::ENVIRONMENTS.keys}, got #{environment}"
127+
message = "environment must be one of " \
128+
"#{DockerEngineRuby::Client::ENVIRONMENTS.keys}, got #{environment}"
122129
raise ArgumentError.new(message)
123130
end
124131

@@ -132,6 +139,7 @@ def initialize(
132139
max_retries: max_retries,
133140
initial_retry_delay: initial_retry_delay,
134141
max_retry_delay: max_retry_delay,
142+
tls_verify_peer: tls_verify_peer,
135143
tls_ca_cert_path: @tls_ca_cert_path,
136144
tls_client_cert_path: @tls_client_cert_path,
137145
tls_client_key_path: @tls_client_key_path

lib/docker_engine_ruby/internal/transport/base_client.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ def reap_connection!(status, stream:)
197197
# @param max_retry_delay [Float]
198198
# @param headers [Hash{String=>String, Integer, Array<String, Integer, nil>, nil}]
199199
# @param idempotency_header [String, nil]
200+
# @param tls_verify_peer [Boolean]
200201
# @param tls_ca_cert_path [String, nil]
201202
# @param tls_client_cert_path [String, nil]
202203
# @param tls_client_key_path [String, nil]
@@ -208,6 +209,7 @@ def initialize(
208209
max_retry_delay: 0.0,
209210
headers: {},
210211
idempotency_header: nil,
212+
tls_verify_peer: true,
211213
tls_ca_cert_path: nil,
212214
tls_client_cert_path: nil,
213215
tls_client_key_path: nil
@@ -219,6 +221,7 @@ def initialize(
219221
end
220222
@requester = DockerEngineRuby::Internal::Transport::PooledNetRequester.new(
221223
unix_socket_path: @unix_socket_path,
224+
tls_verify_peer: tls_verify_peer,
222225
tls_ca_cert_path: tls_ca_cert_path,
223226
tls_client_cert_path: tls_client_cert_path,
224227
tls_client_key_path: tls_client_key_path

lib/docker_engine_ruby/internal/transport/pooled_net_requester.rb

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ class << self
3737
# @param tls_cert [OpenSSL::X509::Certificate, nil]
3838
# @param tls_key [OpenSSL::PKey::PKey, nil]
3939
# @param unix_socket_path [String, nil]
40+
# @param tls_verify_peer [Boolean]
4041
# @param url [URI::Generic]
4142
#
4243
# @return [Net::HTTP]
43-
def connect(cert_store:, tls_cert:, tls_key:, unix_socket_path:, url:)
44+
def connect(cert_store:, tls_cert:, tls_key:, unix_socket_path:, tls_verify_peer:, url:)
4445
if unix_socket_path
4546
return UnixSocketHTTP.new(unix_socket_path).tap do
4647
_1.use_ssl = false
@@ -65,6 +66,7 @@ def connect(cert_store:, tls_cert:, tls_key:, unix_socket_path:, url:)
6566
_1.cert_store = cert_store
6667
_1.cert = tls_cert if tls_cert
6768
_1.key = tls_key if tls_key
69+
_1.verify_mode = tls_verify_peer ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
6870
end
6971
end
7072
end
@@ -141,6 +143,7 @@ def build_request(request, &blk)
141143
tls_cert: @tls_cert,
142144
tls_key: @tls_key,
143145
unix_socket_path: unix_socket_path,
146+
tls_verify_peer: @tls_verify_peer,
144147
url: url
145148
)
146149
end
@@ -236,22 +239,27 @@ def execute(request)
236239
# @param tls_client_cert_path [String, nil]
237240
# @param tls_client_key_path [String, nil]
238241
# @param unix_socket_path [String, nil]
242+
# @param tls_verify_peer [Boolean]
239243
def initialize(
240244
size: self.class::DEFAULT_MAX_CONNECTIONS,
241245
unix_socket_path: nil,
246+
tls_verify_peer: true,
242247
tls_ca_cert_path: nil,
243248
tls_client_cert_path: nil,
244249
tls_client_key_path: nil
245250
)
246251
@mutex = Mutex.new
247252
@size = size
248253
@default_unix_socket_path = unix_socket_path
254+
@tls_verify_peer = tls_verify_peer
249255
@cert_store = OpenSSL::X509::Store.new.tap(&:set_default_paths)
250256
@cert_store.add_file(tls_ca_cert_path) if tls_ca_cert_path
251257

252258
if tls_client_cert_path || tls_client_key_path
253259
if tls_client_cert_path.nil? || tls_client_key_path.nil?
254-
raise ArgumentError.new("Both tls_client_cert_path and tls_client_key_path must be provided together.")
260+
raise ArgumentError.new(
261+
"Both tls_client_cert_path and tls_client_key_path must be provided together."
262+
)
255263
end
256264

257265
@tls_cert = OpenSSL::X509::Certificate.new(File.read(tls_client_cert_path))

rbi/docker_engine_ruby/client.rbi

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ module DockerEngineRuby
1010

1111
DEFAULT_MAX_RETRY_DELAY = T.let(8.0, Float)
1212

13+
DEFAULT_TLS_VERIFY_PEER = T.let(T.unsafe(nil), T::Boolean)
14+
1315
ENVIRONMENTS =
1416
T.let(
1517
{
@@ -88,7 +90,8 @@ module DockerEngineRuby
8890
max_retries: Integer,
8991
timeout: Float,
9092
initial_retry_delay: Float,
91-
max_retry_delay: Float
93+
max_retry_delay: Float,
94+
tls_verify_peer: T::Boolean
9295
).returns(T.attached_class)
9396
end
9497
def self.new(
@@ -115,7 +118,8 @@ module DockerEngineRuby
115118
max_retries: DockerEngineRuby::Client::DEFAULT_MAX_RETRIES,
116119
timeout: DockerEngineRuby::Client::DEFAULT_TIMEOUT_IN_SECONDS,
117120
initial_retry_delay: DockerEngineRuby::Client::DEFAULT_INITIAL_RETRY_DELAY,
118-
max_retry_delay: DockerEngineRuby::Client::DEFAULT_MAX_RETRY_DELAY
121+
max_retry_delay: DockerEngineRuby::Client::DEFAULT_MAX_RETRY_DELAY,
122+
tls_verify_peer: DockerEngineRuby::Client::DEFAULT_TLS_VERIFY_PEER
119123
)
120124
end
121125
end

rbi/docker_engine_ruby/internal/transport/base_client.rbi

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ module DockerEngineRuby
166166
)
167167
],
168168
idempotency_header: T.nilable(String),
169+
tls_verify_peer: T::Boolean,
169170
tls_ca_cert_path: T.nilable(String),
170171
tls_client_cert_path: T.nilable(String),
171172
tls_client_key_path: T.nilable(String)
@@ -179,6 +180,7 @@ module DockerEngineRuby
179180
max_retry_delay: 0.0,
180181
headers: {},
181182
idempotency_header: nil,
183+
tls_verify_peer: true,
182184
tls_ca_cert_path: nil,
183185
tls_client_cert_path: nil,
184186
tls_client_key_path: nil

rbi/docker_engine_ruby/internal/transport/pooled_net_requester.rbi

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,13 @@ module DockerEngineRuby
3131
cert_store: OpenSSL::X509::Store,
3232
tls_cert: T.nilable(OpenSSL::X509::Certificate),
3333
tls_key: T.nilable(OpenSSL::PKey::PKey),
34+
tls_verify_peer: T::Boolean,
3435
url: URI::Generic
3536
).returns(
3637
Net::HTTP
3738
)
3839
end
39-
def connect(cert_store:, tls_cert:, tls_key:, url:)
40+
def connect(cert_store:, tls_cert:, tls_key:, tls_verify_peer:, url:)
4041
end
4142

4243
# @api private
@@ -81,13 +82,15 @@ module DockerEngineRuby
8182
sig do
8283
params(
8384
size: Integer,
85+
tls_verify_peer: T::Boolean,
8486
tls_ca_cert_path: T.nilable(String),
8587
tls_client_cert_path: T.nilable(String),
8688
tls_client_key_path: T.nilable(String)
8789
).returns(T.attached_class)
8890
end
8991
def self.new(
9092
size: DockerEngineRuby::Internal::Transport::PooledNetRequester::DEFAULT_MAX_CONNECTIONS,
93+
tls_verify_peer: true,
9194
tls_ca_cert_path: nil,
9295
tls_client_cert_path: nil,
9396
tls_client_key_path: nil

sig/docker_engine_ruby/client.rbs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ module DockerEngineRuby
88

99
DEFAULT_MAX_RETRY_DELAY: Float
1010

11+
DEFAULT_TLS_VERIFY_PEER: bool
12+
1113
ENVIRONMENTS: {
1214
production: "http://localhost:2375",
1315
production_tls: "https://localhost:2376"
@@ -58,7 +60,8 @@ module DockerEngineRuby
5860
?max_retries: Integer,
5961
?timeout: Float,
6062
?initial_retry_delay: Float,
61-
?max_retry_delay: Float
63+
?max_retry_delay: Float,
64+
?tls_verify_peer: bool
6265
) -> void
6366
end
6467
end

sig/docker_engine_ruby/internal/transport/base_client.rbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ module DockerEngineRuby
8383
| Integer
8484
| ::Array[(String | Integer)?])?],
8585
?idempotency_header: String?,
86+
?tls_verify_peer: bool,
8687
?tls_ca_cert_path: String?,
8788
?tls_client_cert_path: String?,
8889
?tls_client_key_path: String?

sig/docker_engine_ruby/internal/transport/pooled_net_requester.rbs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ module DockerEngineRuby
2121
cert_store: OpenSSL::X509::Store,
2222
tls_cert: OpenSSL::X509::Certificate?,
2323
tls_key: OpenSSL::PKey::PKey?,
24+
tls_verify_peer: bool,
2425
url: URI::Generic
2526
) -> top
2627

@@ -45,6 +46,7 @@ module DockerEngineRuby
4546

4647
def initialize: (
4748
?size: Integer,
49+
?tls_verify_peer: bool,
4850
?tls_ca_cert_path: String?,
4951
?tls_client_cert_path: String?,
5052
?tls_client_key_path: String?

0 commit comments

Comments
 (0)