Integration with Apache2

Arvind Tiwari edited this page Apr 4, 2014 · 6 revisions
Clone this wiki locally
Clone in Desktop

Securing Barbican behind Apache2 HTTPS

Apache2 is a mature web server that has the capability to launch services directly using the Web Service Gateway Interface (WSGI). When a secure connection to Barbican is required, using Apache2 as the front end offloads HTTPS processing onto Apache2. Combining HTTPS and WSGI, the Apache2 server handles the secure incoming network traffic and passes the API request parameters directly to the Barbican service via Barbican's WSGI. The Apache2 server also handles the secure HTTPS outgoing network traffic by placing the returned API response onto the network for Barbican. Using this methodology, the Barbican API requests are never exposed to the network in an insecure format!

How to do it Example (using Ubuntu 12.04)

Make sure Barbican is installed as detailed in the Barbican Quick Start Guide, then install Apache2 and mod_wsgi:

sudo apt-get install apache2 libapache2-mod-wsgi
sudo a2enmod ssl

Create a server certificate for testing:

mkdir /etc/barbican/ssl_keys
cd /etc/barbican/ssl_keys
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

Create the two Barbican API vhost files

Create the barbican-api.conf vhost file:

cd /etc/apache2/sites-available/
vi barbican-api.conf

and add the following content to the file:

Listen *:9311
<VirtualHost *:9311>
    WSGIScriptAlias / /usr/lib/cgi-bin/barbican/barbican-api
    WSGIDaemonProcess barbican-api user=barbican group=barbican processes=3 threads=10 python-path=/home/ubuntu/barbican/barbican:/usr/lib/python2.7
    WSGIProcessGroup barbican-api
    SetEnv nokeepalive ssl-unclean-shutdown
    
    # SSL Config
    SSLEngine on
    SSLCertificateFile /etc/barbican/ssl_keys/server.crt
    SSLCertificateKeyFile /etc/barbican/ssl_keys/server.key
    SSLProtocol all -SSLv2
    SSLVerifyClient none

    ErrorLog /var/log/barbican/barbican-api.log
    LogLevel debug
    CustomLog /var/log/barbican/barbican-api.log combined
</VirtualHost>

Now create the barbican-admin.conf vhost file:

vi barbican-admin.conf

and add the following content:

Listen *:9312
<VirtualHost *:9312>
    WSGIScriptAlias / /usr/lib/cgi-bin/barbican/barbican-admin
    WSGIDaemonProcess barbican-admin user=barbican group=barbican processes=3 threads=10 python-path=/home/ubuntu/barbican/barbican:/usr/lib/python2.7
    WSGIProcessGroup barbican-admin
    SetEnv nokeepalive ssl-unclean-shutdown

    # SSL Config
    SSLEngine on
    SSLCertificateFile /etc/barbican/ssl_keys/server.crt
    SSLCertificateKeyFile /etc/barbican/ssl_keys/server.key
    SSLProtocol all -SSLv2
    SSLVerifyClient none

    ErrorLog /var/log/barbican/barbican-admin.log
    LogLevel debug
    CustomLog /var/log/barbican/barbican-admin.log combined
</VirtualHost>

Now link the vhost files you just created from the sites-available directory to the sites-enabled directory and also create the log file directory:

ln -s /etc/apache2/sites-available/barbican-api.conf /etc/apache2/sites-enabled/barbican-api.conf
ln -s /etc/apache2/sites-available/barbican-admin.conf /etc/apache2/sites-enabled/barbican-admin.conf
mkdir /var/log/barbican

Create the corresponding Barbican WSGI Python scripts

Create file barbican-api:

mkdir /usr/lib/cgi-bin/barbican
vi /usr/lib/cgi-bin/barbican/barbican-api

and add the following content to the file:

from barbican.common import config
from paste import deploy
 
config_files = ['/etc/barbican/barbican-api-paste.ini',  '/etc/barbican/barbican-api.conf']
config.parse_args(default_config_files=config_files)
 
conf = '/etc/barbican/barbican-api-paste.ini'
name = "apiapp"
 
application = deploy.loadapp('config:%s' % conf, name=name)

Now create file barbican-admin

vi /usr/lib/cgi-bin/barbican/barbican-admin

and add the following content:

from barbican.common import config
from paste import deploy
 
config_files = ['/etc/barbican/barbican-admin-paste.ini',  '/etc/barbican/barbican-api.conf']
config.parse_args(default_config_files=config_files)
 
conf = '/etc/barbican/barbican-admin-paste.ini'
name = "adminapp"
 
application = deploy.loadapp('config:%s' % conf, name=name)

I also moved the following file due to a common error that occurs with init.py files that do not contain any executable statements (ImportError: cannot import name normalize):

mv /home/ubuntu/barbican/barbican/locale/_init.py  /home/ubuntu/barbican/barbican/locale/init_.py.bak

Lastly create user "barbican" and restart Apache2 which will also start both the barbican-api and barbican-admin services:

useradd -r -s /bin/false barbican
service apache2 restart

One last connection issue; you may need to use the "Common Name" of the server in the URL that you entered when you created the test certificate. For example:

https://ubuntubarbican.mycompany.net:9311/v1/12345/orders/b755f76b-5866-4a03-8c0e-3368d5e5074f

I also added an entry into my local "/etc/hosts" file for the server on my client computer.

15.253.59.114	ubuntubarbican.mycompany.net

Adding secure HTTPS Keystone Authentication

Keystone Modifications

NOTE: This set of instructions assumes that you first have Keystone installed and running and configured to use UUID token format.

Edit file /etc/keystone/keystone.conf and enable SSL by setting the following directives (NOTE: Set the "cert_subject" directive to match your local server).

[ssl]

# Toggle for SSL support on the keystone eventlet servers.
# (boolean value)
enable=true

# Path of the certfile for SSL. (string value)
certfile=/etc/keystone/ssl/certs/keystone.pem

# Path of the keyfile for SSL. (string value)
keyfile=/etc/keystone/ssl/private/keystonekey.pem

# Path of the ca cert file for SSL. (string value)
ca_certs=/etc/keystone/ssl/certs/ca.pem

# Path of the CA key file for SSL (string value)
ca_key=/etc/keystone/ssl/private/cakey.pem

#  (boolean value)
cert_required=false

# SSL Key Length (in bits) (auto generated certificate)
# (integer value)
key_size=2048

# Days the certificate is valid for once signed (auto
# generated certificate) (integer value)
valid_days=3650

# SSL Certificate Subject (auto generated certificate) (string value)
cert_subject="/C=US/ST=Oregon/L=Corvallis/O=Cloud/CN=ubuntubarbican.mycompany.net"

Now generate sample SSL certificates using the keystone tool (NOTE: If you already have sample Keystone certificates, then you will need to rename directory /etc/keystone/ssl in order to generate new certificates).

keystone-manage ssl_setup

Restart Keystone for these changes to take effect

service keystone restart

Add the following elements to your Keystone server:

  • user "barbican" with password "secret" (I changed the password from "orange" to make sure that we are now authenticating from Keystone).
  • role "admin"
  • project "service"
  • add the "admin" role to user "barbican" for project "service"

Barbican Modifications

To simplify certificate handling, recreate your local Barbican server certificate using the Keystone Certificate Authority file. This way both Keystone and Barbican will accept each others certificates. Enter all of the options below on one continuous line.

openssl ca 
    -in /etc/barbican/ssl_keys/server.csr 
    -out /etc/barbican/ssl_keys/server.crt -config /etc/keystone/ssl/certs/openssl.conf 
    -days 365 
    -cert /etc/keystone/ssl/certs/ca.pem  
    -keyfile /etc/keystone/ssl/private/cakey.pem

Change the "admin_password" in files /etc/barbican/barbican-api-paste.ini and /etc/barbican/barbican-admin-paste.ini to match the password for the barbican user that you entered into Keystone.

admin_password = secret

Edit WSGI file barbican-api:

vi /usr/lib/cgi-bin/barbican/barbican-api

and change the "name" variable from "apiapp" to "barbican-api-keystone" to have it reference the "barbican-api-keystone" pipeline in the "barbican-api-paste.ini" configuration file.

from barbican.common import configfrom barbican.common import config
from paste import deploy
 
config_files = ['/etc/barbican/barbican-api-paste.ini',  '/etc/barbican/barbican-api.conf']
config.parse_args(default_config_files=config_files)
 
conf = '/etc/barbican/barbican-api-paste.ini'
name = "barbican-api-keystone"
#name = "apiapp"
 
application = deploy.loadapp('config:%s' % conf, name=name)   

Also edit WSGI file barbican-admin:

vi /usr/lib/cgi-bin/barbican/barbican-admin

and change the "name" variable from "adminapp" to "barbican-admin-keystone" to have it reference the "barbican-admin-keystone" pipeline in the "barbican-admin-paste.ini" configuration file.

from barbican.common import config
from paste import deploy
 
config_files = ['/etc/barbican/barbican-admin-paste.ini',  '/etc/barbican/barbican-api.conf']
config.parse_args(default_config_files=config_files)
 
conf = '/etc/barbican/barbican-admin-paste.ini'
name = "barbican-admin-keystone"
#name = "adminapp"
 
application = deploy.loadapp('config:%s' % conf, name=name)

Barbican Config File Changes/Examples

I cannot recall all of the changes I made to the three main Barican configuration files so I am including my local/working Barbican config files below. Pay special attention to the "[pipeline:barbican-api-keystone]", "[pipeline:barbican-admin-keystone]", and "[filter:keystone_v3_authtoken]" sections. One directive I found missing from the "keystone_v3_authtoken" filter was the "cafile" directive that the keystoneclient needs for the secure connection from Barbican to Keystone.

File /etc/barbican/barbican-api.conf

[DEFAULT]
# Show more verbose log output (sets INFO log level output)
verbose = True

# Show debugging output in logs (sets DEBUG log level output)
debug = True

# Address to bind the API server
bind_host = 0.0.0.0

# Port to bind the API server to
bind_port = 9311

# Host name, for use in HATEOS-style references
#  Note: Typically this would be the load balanced endpoint that clients would use
#  communicate back with this service.
host_href = https://15.253.59.114:9311

# Log to this file. Make sure you do not set the same log
# file for both the API and registry servers!
#log_file = /var/log/barbican/api.log

# Backlog requests when creating socket
backlog = 4096

# TCP_KEEPIDLE value in seconds when creating socket.
# Not supported on OS X.
#tcp_keepidle = 600

# SQLAlchemy connection string for the reference implementation
# registry server. Any valid SQLAlchemy connection string is fine.
# See: http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/connections.html#sqlalchemy.create_engine
# Uncomment this for local dev, putting db in project directory:
#sql_connection = sqlite:///barbican.sqlite
# Note: For absolute addresses, use '////' slashes after 'sqlite:'
# Uncomment for a more global development environment
sql_connection = sqlite:////var/lib/barbican/barbican.sqlite

# Period in seconds after which SQLAlchemy should reestablish its connection
# to the database.
#
# MySQL uses a default `wait_timeout` of 8 hours, after which it will drop
# idle connections. This can result in 'MySQL Gone Away' exceptions. If you
# notice this, you can lower this value to ensure that SQLAlchemy reconnects
# before MySQL can drop the connection.
sql_idle_timeout = 3600

# Default page size for the 'limit' paging URL parameter.
default_limit_paging = 10

# Maximum page size for the 'limit' paging URL parameter.
max_limit_paging = 100

# Number of Barbican API worker processes to start.
# On machines with more than one CPU increasing this value
# may improve performance (especially if using SSL with
# compression turned on). It is typically recommended to set
# this value to the number of CPUs present on your machine.
workers = 1

# Role used to identify an authenticated user as administrator
#admin_role = admin

# Allow unauthenticated users to access the API with read-only
# privileges. This only applies when using ContextMiddleware.
allow_anonymous_access = False

# Allow access to version 1 of barbican api
#enable_v1_api = True

# Allow access to version 2 of barbican api
#enable_v2_api = True

# ================= SSL Options ===============================

# Certificate file to use when starting API server securely
# cert_file = /etc/keystone/ssl/certs/keystone.pem

# Private key file to use when starting API server securely
# key_file = /etc/keystone/ssl/private/keystonekey.pem

# CA certificate file to use to verify connecting clients
# ca_file = /etc/keystone/ssl/certs/ca.pem
 
# ================= Security Options ==========================

# AES key for encrypting store 'location' metadata, including
# -- if used -- Swift or S3 credentials
# Should be set to a random string of length 16, 24 or 32 bytes
metadata_encryption_key = 12345678901234567890123456789012

# ============ Delayed Delete Options =============================

# Turn on/off delayed delete
delayed_delete = False

# Delayed delete time in seconds
scrub_time = 43200

# Directory that the scrubber will use to remind itself of what to delete
# Make sure this is also set in glance-scrubber.conf
scrubber_datadir = /var/lib/barbican/scrubber

# ======== OpenStack policy integration
# JSON file representing policy (string value)
policy_file=/etc/barbican/policy.json

# Rule checked when requested rule is not found (string value)
policy_default_rule=default

# ================= Queue Options - oslo.messaging ==========================

# Rabbit and HA configuration:
ampq_durable_queues = True
rabbit_userid=guest
rabbit_password=guest
rabbit_ha_queues = True
rabbit_port=5672

# For HA, specify queue nodes in cluster, comma delimited:
#   For example: rabbit_hosts=192.168.50.8:5672, 192.168.50.9:5672
rabbit_hosts=localhost:5672

# For HA, specify queue nodes in cluster as 'user@host:5672', comma delimited, ending with '/offset':
#   For example: transport_url = rabbit://guest@192.168.50.8:5672,guest@192.168.50.9:5672/
#   DO NOT USE THIS, due to '# FIXME(markmc): support multiple hosts' in  oslo/messaging/_drivers/amqpdriver.py
# transport_url = rabbit://guest@localhost:5672/

# ================= Queue Options - Application ==========================

[queue]
# Enable queuing asynchronous messaging.
#   Set false to invoke worker tasks synchronously (i.e. no-queue standalone mode)
enable = False

# Namespace for the queue
namespace = 'barbican'

# Topic for the queue
topic = 'barbican.workers'

# Version for the task API
version = '1.1'

# Server name for RPC service
server_name = 'barbican.queue'

File /etc/barbican/barbican-api-paste.ini

[pipeline:main]
#pipeline = unauthenticated-context apiapp
pipeline = keystone_v3_authtoken context apiapp
####pipeline = simple apiapp

#Use this pipeline to activate a repoze.profile middleware and HTTP port,
#  to provide profiling information for the REST API processing.
[pipeline:barbican-profile]
pipeline = unauthenticated-context egg:Paste#cgitb egg:Paste#httpexceptions profile apiapp

#Use this pipeline for keystone auth
[pipeline:barbican-api-keystone]
pipeline = keystone_v3_authtoken context apiapp

[app:apiapp]
paste.app_factory = barbican.api.app:create_main_app

[filter:simple]
paste.filter_factory = barbican.api.middleware.simple:SimpleFilter.factory

[filter:unauthenticated-context]
paste.filter_factory = barbican.api.middleware.context:UnauthenticatedContextMiddleware.factory

[filter:context]
paste.filter_factory = barbican.api.middleware.context:ContextMiddleware.factory

[filter:keystone_authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
signing_dir = /tmp/barbican/cache
auth_host = ubuntubarbican.mycompany.net
#need ability to re-auth a token, thus admin url
auth_port = 35357
auth_protocol = https
admin_tenant_name = service
admin_user = barbican
admin_password = secret
#admin_password = orange
auth_version = v2.0
#delay failing perhaps to log the unauthorized request in barbican ..
#delay_auth_decision = true

[filter:keystone_v3_authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
signing_dir = /tmp/barbican/cache
auth_host = ubuntubarbican.mycompany.net
#need ability to re-auth a token, thus admin url
auth_port = 35357
auth_protocol = https
admin_tenant_name = service
admin_user = barbican
admin_password = secret
#admin_password = orange
auth_version = v3
#auth_version = v3.0
#delay failing perhaps to log the unauthorized request in barbican ..
#delay_auth_decision = true
cafile = /etc/keystone/ssl/certs/ca.pem

[filter:profile]
use = egg:repoze.profile
log_filename = myapp.profile
cachegrind_filename = cachegrind.out.myapp
discard_first_request = true
path = /__profile__
flush_at_shutdown = true
unwind = false

File /etc/barbican/barbican-admin-paste.ini

[pipeline:main]
#pipeline = unauthenticated-context admin
pipeline = keystone_v3_authtoken context adminapp

[pipeline:barbican-admin-keystone]
pipeline = keystone_v3_authtoken context adminapp

[app:adminapp]
paste.app_factory = barbican.api.app:create_admin_app

#[filter:unauthenticated-context]
#paste.filter_factory = barbican.api.middleware.context:UnauthenticatedContextMiddleware.factory

[filter:keystone_v3_authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
signing_dir = /tmp/barbican/cache
auth_host = ubuntubarbican.mycompany.net
#need ability to re-auth a token, thus admin url
auth_port = 35357
auth_protocol = https
admin_tenant_name = service
admin_user = barbican
admin_password = secret
#admin_password = orange
auth_version = v3
#delay failing perhaps to log the unauthorized request in barbican ..
#delay_auth_decision = true
cafile = /etc/keystone/ssl/certs/ca.pem

[filter:simple]
paste.filter_factory = barbican.api.middleware.simple:SimpleFilter.factory

[filter:context]
paste.filter_factory = barbican.api.middleware.context:ContextMiddleware.factory

[filter:profile]
use = egg:repoze.profile
log_filename = myapp.profile
cachegrind_filename = cachegrind.out.myapp
discard_first_request = true
path = /__profile__
flush_at_shutdown = true
unwind = false

##########################

[filter:unauthenticated-context]
paste.filter_factory = barbican.api.middleware.context:UnauthenticatedContextMiddleware.factory

[filter:keystone_authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
signing_dir = /tmp/barbican/cache
auth_host = ubuntubarbican.mycompany.net
#need ability to re-auth a token, thus admin url
auth_port = 35357
auth_protocol = https
admin_tenant_name = service
admin_user = barbican
admin_password = secret
#admin_password = orange
auth_version = v2.0
#delay failing perhaps to log the unauthorized request in barbican ..
#delay_auth_decision = true

[filter:profile]
use = egg:repoze.profile
log_filename = myapp.profile
cachegrind_filename = cachegrind.out.myapp
discard_first_request = true
path = /__profile__
flush_at_shutdown = true
unwind = false

Lastly restart apache2 for all of your changes to take effect.

service apache2 restart