Full TLS/SSL options support as provided by Tornado TCPServer.

This commit is contained in:
Dmitry Kuzmenko 2016-11-18 18:31:57 +03:00
parent 3835f91d99
commit e42898f2e3
2 changed files with 43 additions and 27 deletions

View file

@ -914,6 +914,14 @@ VALID_OPTS = {
# Extra modules for Salt Thin
'thin_extra_mods': str,
# TLS/SSL connection options. This could be set to a dictionary containing arguments
# corresponding to python ssl.wrap_socket method. For details see:
# http://www.tornadoweb.org/en/stable/tcpserver.html#tornado.tcpserver.TCPServer
# http://docs.python.org/2/library/ssl.html#ssl.wrap_socket
# Note: to set enum arguments values like `cert_reqs` and `ssl_version` use constant names
# without ssl module prefix: `CERT_REQUIRED` or `PROTOCOL_SSLv23`.
'ssl': dict,
}
# default configurations
@ -1155,6 +1163,7 @@ DEFAULT_MINION_OPTS = {
'proxy_password': '',
'proxy_port': 0,
'minion_jid_queue_hwm': 100,
'ssl': None,
}
DEFAULT_MASTER_OPTS = {
@ -1424,6 +1433,7 @@ DEFAULT_MASTER_OPTS = {
'python3_bin': 'python3',
'cache': 'localfs',
'thin_extra_mods': '',
'ssl': None,
}
@ -3052,6 +3062,26 @@ def get_id(opts, cache_minion_id=False):
return newid, is_ipv4
def _update_ssl_config(opts):
'''
Resolves string names to integer constant in ssl configuration.
'''
if opts['ssl'] is None:
return
import ssl
for key, prefix in (('cert_reqs', 'CERT_'),
('ssl_version', 'PROTOCOL_')):
val = opts['ssl'].get(key)
if val is None:
continue
if not isinstance(val, string_types) or not val.startswith(prefix) or not hasattr(ssl, val):
message = 'SSL option \'{0}\' must be set to one of the following values: \'{1}\'.' \
.format(key, '\', \''.join([val for val in dir(ssl) if val.startswith(prefix)]))
log.error(message)
raise salt.exceptions.SaltConfigurationError(message)
opts['ssl'][key] = getattr(ssl, val)
def apply_minion_config(overrides=None,
defaults=None,
cache_minion_id=False,
@ -3143,6 +3173,9 @@ def apply_minion_config(overrides=None,
# Make sure hash_type is lowercase
opts['hash_type'] = opts['hash_type'].lower()
# Check and update TLS/SSL configuration
_update_ssl_config(opts)
return opts
@ -3296,6 +3329,9 @@ def apply_master_config(overrides=None, defaults=None):
# Make sure hash_type is lowercase
opts['hash_type'] = opts['hash_type'].lower()
# Check and update TLS/SSL configuration
_update_ssl_config(opts)
return opts

View file

@ -576,17 +576,11 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
self.payload_handler = payload_handler
self.io_loop = io_loop
self.serial = salt.payload.Serial(self.opts)
if 'ssl_cert' in self.opts and 'ssl_key' in self.opts:
ssl_options = {
'certfile': self.opts['ssl_cert'],
'keyfile': self.opts['ssl_key'],
}
else:
ssl_options = None
if USE_LOAD_BALANCER:
self.req_server = LoadBalancerWorker(
self.socket_queue, self.handle_message, io_loop=self.io_loop, ssl_options=ssl_options
)
self.req_server = LoadBalancerWorker(self.socket_queue,
self.handle_message,
io_loop=self.io_loop,
ssl_options=self.opts.get('ssl'))
else:
if salt.utils.is_windows():
self._socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -596,7 +590,7 @@ class TCPReqServerChannel(salt.transport.mixins.auth.AESReqServerMixin, salt.tra
self._socket.bind((self.opts['interface'], int(self.opts['ret_port'])))
self.req_server = SaltMessageServer(self.handle_message,
io_loop=self.io_loop,
ssl_options=ssl_options)
ssl_options=self.opts.get('ssl'))
self.req_server.add_socket(self._socket)
self._socket.listen(self.backlog)
salt.transport.mixins.auth.AESReqServerMixin.post_fork(self, payload_handler, io_loop)
@ -837,20 +831,13 @@ class SaltMessageClient(object):
'''
Try to connect for the rest of time!
'''
if 'ssl_cert' in self.opts and 'ssl_key' in self.opts:
ssl_options = {
'certfile': self.opts['ssl_cert'],
'keyfile': self.opts['ssl_key'],
}
else:
ssl_options = None
while True:
if self._closing:
break
try:
self._stream = yield self._tcp_client.connect(self.host,
self.port,
ssl_options=ssl_options)
ssl_options=self.opts.get('ssl'))
self._connecting_future.set_result(True)
break
except Exception as e:
@ -1050,14 +1037,7 @@ class PubServer(tornado.tcpserver.TCPServer, object):
TCP publisher
'''
def __init__(self, opts, io_loop=None):
if 'ssl_cert' in opts and 'ssl_key' in opts:
ssl_options = {
'certfile': opts['ssl_cert'],
'keyfile': opts['ssl_key'],
}
else:
ssl_options = None
super(PubServer, self).__init__(io_loop=io_loop, ssl_options=ssl_options)
super(PubServer, self).__init__(io_loop=io_loop, ssl_options=opts.get('ssl'))
self.opts = opts
self._closing = False
self.clients = set()