openstack, python

Enable SSL for an Oslo WSGI service

I recently needed to deploy a REST-based web service for use as a DynamicJSON vendordata provider to OpenStack’s nova metadata service. I settled on Oslo’s WSGI server, mainly due to the fact that the Oslo project’s goal is to provide standard libraries for all OpenStack projects. Plus it made incorporating authentication via Keystone middleware that much easier.

Given the requirement for TLS-everywhere, the next step was to enable SSL encryption of the service. This wasn’t as simple a task as I had hoped.

The Oslo WSGI service is very lightly documented, and while there are documented configuration options for Oslo service’s sslutils library, there is no documentation on how to actually enable it. So in to the source code I went.

Turns out that oslo_service.wsgi.Server accepts a boolean parameter named use_ssl.

self.server = wsgi.Server(CONF, name, self.app, host=self.host,
                          port=self.port, use_ssl=True)

When coupled with the documented sslutils configuration file requirements, our service starts listening over HTTPS. Simple.

[ssl]
cert_file = /etc/pki/tls/certs/vendordata.crt
key_file = /etc/pki/tls/private/vendordata.key

Until of course you try to actually connect to it…

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/eventlet/hubs/poll.py", line 115, in wait
    listener.cb(fileno)
  File "/usr/lib/python2.7/site-packages/eventlet/greenthread.py", line 214, in main
    result = function(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/eventlet/wsgi.py", line 880, in server
    client_socket = sock.accept()
  File "/usr/lib64/python2.7/ssl.py", line 884, in accept
    server_side=True)
  File "/usr/lib64/python2.7/ssl.py", line 348, in wrap_socket
    _context=self)
  File "/usr/lib64/python2.7/ssl.py", line 603, in __init__
    server_hostname, ssl_sock=self)
TypeError: _wrap_socket() argument 1 must be _socket.socket, not GreenSocket
Removing descriptor: 7

Enter eventlet

The Oslo WSGI service relies on several different eventlet libraries for WSGI and SSL utilities. Eventlet is a very efficient way of performing several network-related tasks, however some operations are not compatible with the built-in networking libraries. Eventlet’s solution is to patch these libraries on the fly, known as “monkey patching”. This is not enforced however, as changing the behaviour of another Python module (especially a built-in) is not ideal and, if needed, should be very explicitly requested.

Now for whatever reason (I can only assume it is the same reason), the Oslo service also does not enforce Eventlet’s requirement to monkey patch when wrapping SSL sockets. So, before initiating the WSGI server we need to invoke Eventlet’s patching module.

import eventlet
eventlet.monkey_patch()

This is a little time-consuming (anecdotally it is adding around 30 seconds to server start), so if speed is a factor it is possible to limit which modules are patched.

After restarting the service everything is up and running, encrypted, and working as expected.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.