Imagine you have been asked to deploy OpenStack with public facing API endpoints. Your major requirement is to ensure that any service facing the public must be wrapped in SSL to protect user credentials and transactions between the user and the cloud. Unfortunately, you don’t have access to any hardware to terminate the SSL connection and your budget is fairly small.
On the surface this seems like a pretty straightforward request. As an operations or systems person you deploy SSL services in your sleep. However, in the case of the OpenStack Compute API services, this isn’t quite as straightforward as enabling an option in the configuration file for the API service. One option is to use a software loadbalancer on another server in the environment, but this leaves the communication between the loadbalancer and the API service unencrypted. You could run the load balancer on the same server as the API and take the performance hit, but this may not be ideal depending on the load.
Fortunately there is another option, but let me first give you some background on why SSL cannot simply be enabled. In the nova configuration file, there is a performance tax that is paid when Python is required to handle the SSL transaction. Since there is plenty of hardware and software that can handle these transactions, and the API service needs to respond quickly, there really is not a good reason to build it in. Additionally, the Nova API code has been written as a Web Server Gateway Interface (WSGI, PEP 333), which, for the non-Python folks in the room, is basically a specification for running Python code from web or application servers.
That brings us to running a web server like Apache or Nginx to provide the OpenStack API, rather than running it directly from the Python server it uses by default. I’ve put together the following reference configuration for Apache to run the OpenStack API code – identical approaches can be taken for the EC2 compatibility API, the volume API and the metadata services. Keep in mind that the following steps assume apache2 has been installed and the mod_ssl is enabled. With all of that said, let’s get started.
First enable the wsgi module provided with apache2.
a2enmod mod_wsgi restart apache2
Now create the wsgi file that will be used to tie Apache to the nova-api service. This script simply pulls in some configuration information and Nova modules to mod_wsgi. Because Nova makes use of the paste deploy system in Python, this script is very straightforward and uses the configuration information that already exists when nova is setup initially. If you need an api-paste.ini for OpenStack compute you can find one on github. You can store this wsgi anywhere on your system, for example /opt/wsgi/osapi.wsgi, as long as Apache can read and execute it from that location. I’ve also added some comments in the script itself to help describe what’s happening.
import os import sys from nova import log from nova import utils from paste.deploy.loadwsgi import loadapp sys.path.insert(0,(os.path.dirname(os.path.realpath(__file__)))) sys.stdout = sys.stderr # Read nova configuration options and pick the default configuration file # Typically /etc/nova/nova.conf flags = utils.default_flagfile() # Import nova gflags information for ease of use from nova import flags flags.FLAGS(sys.argv) log.setup() # Location of the paste-deploy configuration file config = '/etc/nova/api-paste.ini' # Application that mod_wsgi will be deploying application = loadapp('config:%s' % config, name = 'osapi_compute')
Then create a new site/virtualhost definition file in /etc/apache2/sites-available/osapi:
Listen 8774 <VirtualHost *:8774> WSGIScriptAlias / /opt/wsgi/osapi/osapi.wsgi WSGIDaemonProcess nova-osapi user=nova group=nogroup processes=3 threads=10 python-path=/usr/share/pyshared/nova WSGIProcessGroup nova-osapi # SSL Config SSLEngine on SSLCertificateFile /etc/ssl/certs/server.crt SSLCertificateKeyFile /etc/ssl/private/server.key ErrorLog /var/log/nova/osapi.log LogLevel info CustomLog /var/log/nova/osapi.log combined </VirtualHost>
There are a couple of modifications you will need to make to match your environment:
- WSGIScriptAlias / /path/to/wsgi
This is the wsgi file that we created in the earlier code block to ease the deployment of the service via Python paste deployment.
- WSGIDaemonProcess nova-osapi and WSGIProcessGroup nova-osapi must match
- WSGIDaemonProcess path=/usr/share/pyshared/nova must match the location of nova as it is installed on your system.
- The SSL cert must be a valid certificate, meaning there must be a CA that the server is aware of and that any clients you are using must be aware of. For information on creating your own CA, Ubuntu provides some good documentation with links to more general OpenSSL usage.
That’s it! At this point stop the nova-api process if any is running on the server, restart Apache and you will have the OpenStack API running out of Apache and all requests will be handled on port 8774 with SSL. As I mentioned earlier, it is possible to take all of the services provided by nova-api and wrap them the exact same way, and the api-paste.ini provided with nova will already contain configuration information for them.
As I mentioned, this is simply a reference configuration that I put together. I’d love to hear how others would approach this. Please leave your comments below!
(All code contained in this post is covered by the Apache 2.0 license, http://www.apache.org/licenses/LICENSE-2.0.)