Skip to content

Commit 116d137

Browse files
committed
* Merge branch 'tls' of github.com:momer/docker-py into momer-tls
* Exported TLS configuration in tls.TLSConfig * Merged exceptions packagee into pre-existing errors module * Flake8 fixes * Bug fixes
2 parents a333a35 + 7ce73de commit 116d137

File tree

6 files changed

+102
-3
lines changed

6 files changed

+102
-3
lines changed

docker/client.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424

2525
from .auth import auth
2626
from .unixconn import unixconn
27+
from .ssladapter import ssladapter
2728
from .utils import utils
2829
from . import errors
30+
from .tls import TLSConfig
2931

3032
if not six.PY3:
3133
import websocket
@@ -37,10 +39,15 @@
3739

3840
class Client(requests.Session):
3941
def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
40-
timeout=DEFAULT_TIMEOUT_SECONDS):
42+
timeout=DEFAULT_TIMEOUT_SECONDS, tls=False):
4143
super(Client, self).__init__()
44+
4245
if base_url is None:
4346
base_url = "http+unix://var/run/docker.sock"
47+
if tls and not base_url.startswith('https://'):
48+
raise errors.TLSParameterError(
49+
'If using TLS, the base_url argument must begin with '
50+
'"https://".')
4451
if 'unix:///' in base_url:
4552
base_url = base_url.replace('unix:/', 'unix:')
4653
if base_url.startswith('unix:'):
@@ -54,7 +61,13 @@ def __init__(self, base_url=None, version=DEFAULT_DOCKER_API_VERSION,
5461
self._timeout = timeout
5562
self._auth_configs = auth.load_config()
5663

57-
self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))
64+
""" Use SSLAdapter for the ability to specify SSL version """
65+
if isinstance(tls, TLSConfig):
66+
tls.configure_client(self)
67+
elif tls:
68+
self.mount('https://', ssladapter.SSLAdapter(self.ssl_version))
69+
else:
70+
self.mount('http+unix://', unixconn.UnixAdapter(base_url, timeout))
5871

5972
def _set_request_timeout(self, kwargs):
6073
"""Prepare the kwargs for an HTTP request by inserting the timeout

docker/errors.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,14 @@ class InvalidConfigFile(DockerException):
6363

6464
class DeprecatedMethod(DockerException):
6565
pass
66+
67+
68+
class TLSParameterError(DockerException):
69+
def __init__(self, msg):
70+
self.msg = msg
71+
72+
def __str__(self):
73+
return self.msg + (". TLS configurations should map the Docker CLI "
74+
"client configurations. See "
75+
"http://docs.docker.com/examples/https/ for "
76+
"API details.")

docker/ssladapter/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .ssladapter import SSLAdapter # flake8: noqa

docker/ssladapter/ssladapter.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
""" Resolves OpenSSL issues in some servers:
2+
https://lukasa.co.uk/2013/01/Choosing_SSL_Version_In_Requests/
3+
https://github.com/kennethreitz/requests/pull/799
4+
"""
5+
from requests.adapters import HTTPAdapter
6+
try:
7+
from requests.packages.urllib3.poolmanager import PoolManager
8+
except ImportError:
9+
from urllib3.poolmanager import PoolManager
10+
11+
12+
class SSLAdapter(HTTPAdapter):
13+
'''An HTTPS Transport Adapter that uses an arbitrary SSL version.'''
14+
def __init__(self, ssl_version=None, **kwargs):
15+
self.ssl_version = ssl_version
16+
super(SSLAdapter, self).__init__(**kwargs)
17+
18+
def init_poolmanager(self, connections, maxsize, block=False):
19+
self.poolmanager = PoolManager(num_pools=connections,
20+
maxsize=maxsize,
21+
block=block,
22+
ssl_version=self.ssl_version)

docker/tls.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import os
2+
3+
from . import errors
4+
from .ssladapter import ssladapter
5+
6+
7+
class TLSConfig(object):
8+
def __init__(self, tls, tls_cert=None, tls_key=None, tls_verify=False,
9+
tls_ca_cert=None, ssl_version=None):
10+
# Argument compatibility/mapping with
11+
# http://docs.docker.com/examples/https/
12+
# This diverges from the Docker CLI in that users can specify 'tls'
13+
# here, but also disable any public/default CA pool verification by
14+
# leaving tls_verify=False
15+
16+
# urllib3 sets a default ssl_version if ssl_version is None
17+
# http://tinyurl.com/kxga8hb
18+
self.ssl_version = ssl_version
19+
20+
# "tls" and "tls_verify" must have both or neither cert/key files
21+
# In either case, Alert the user when both are expected, but any are
22+
# missing.
23+
24+
if tls_cert or tls_key:
25+
if not (tls_cert and tls_key) or (not os.path.isfile(tls_cert) or
26+
not os.path.isfile(tls_key)):
27+
raise errors.TLSParameterError(
28+
'You must provide either both "tls_cert"/"tls_key" files, '
29+
'or neither, in order to use TLS.')
30+
self.cert = (tls_cert, tls_key)
31+
32+
# Either set tls_verify to True (public/default CA checks) or to the
33+
# path of a CA Cert file.
34+
if tls_verify:
35+
if not tls_ca_cert:
36+
self.verify = True
37+
elif os.path.isfile(tls_ca_cert):
38+
self.verify = tls_ca_cert
39+
else:
40+
raise errors.TLSParameterError(
41+
'If "tls_verify" is set, then "tls_ca_cert" must be blank'
42+
' (to check public CA list) OR a path to a Cert File.'
43+
)
44+
else:
45+
self.verify = False
46+
47+
def configure_client(self, client):
48+
client.verify = self.verify
49+
client.ssl_version = self.ssl_version
50+
client.cert = self.cert
51+
self.mount('https://', ssladapter.SSLAdapter(self.ssl_version))

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
name="docker-py",
2323
version=version,
2424
description="Python client for Docker.",
25-
packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils'],
25+
packages=['docker', 'docker.auth', 'docker.unixconn', 'docker.utils',
26+
'docker.ssladapter'],
2627
install_requires=requirements + test_requirements,
2728
zip_safe=False,
2829
test_suite='tests',

0 commit comments

Comments
 (0)