Add keystone authentication of token

Closes-Bug: #1532075
Change-Id: Id45a0babc8e128d02bf648fedb7b66099bc3c7ae
Co-Authored-By: Lubosz "diltram" Kosnik <lubosz.kosnik@intel.com>
Depends-On: Id0deee2714040d271f43a537c27f410e2f4e3ef2
This commit is contained in:
Brandon Logan 2016-01-07 22:11:15 -06:00 committed by Lubosz "diltram" Kosnik
parent 61d8da7d46
commit 1ace351fd8
9 changed files with 57 additions and 9 deletions

View File

@ -7,6 +7,9 @@
# bind_port = 9876 # bind_port = 9876
# api_handler = queue_producer # api_handler = queue_producer
# #
# How should authentication be handled (keystone, noauth)
# auth_strategy = noauth
#
# Plugin options are hot_plug_plugin (Hot-pluggable controller plugin) # Plugin options are hot_plug_plugin (Hot-pluggable controller plugin)
# #
# octavia_plugins = hot_plug_plugin # octavia_plugins = hot_plug_plugin

View File

@ -12,10 +12,14 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from keystonemiddleware import auth_token
from oslo_config import cfg
from oslo_middleware import cors
from oslo_middleware import request_id
import pecan import pecan
from octavia.api import config as app_config from octavia.api import config as app_config
from octavia.api.v1 import hooks from octavia.common import constants
from octavia.common import service as octavia_service from octavia.common import service as octavia_service
@ -29,15 +33,35 @@ def setup_app(pecan_config=None, debug=False, argv=None):
"""Creates and returns a pecan wsgi app.""" """Creates and returns a pecan wsgi app."""
octavia_service.prepare_service(argv) octavia_service.prepare_service(argv)
app_hooks = [hooks.ContextHook()]
if not pecan_config: if not pecan_config:
pecan_config = get_pecan_config() pecan_config = get_pecan_config()
pecan.configuration.set_config(dict(pecan_config), overwrite=True) pecan.configuration.set_config(dict(pecan_config), overwrite=True)
return pecan.make_app( return pecan.make_app(
pecan_config.app.root, pecan_config.app.root,
wrap_app=_wrap_app,
debug=debug, debug=debug,
hooks=app_hooks, hooks=pecan_config.app.hooks,
wsme=pecan_config.wsme wsme=pecan_config.wsme
) )
def _wrap_app(app):
"""Wraps wsgi app with additional middlewares."""
app = request_id.RequestId(app)
if cfg.CONF.auth_strategy == constants.KEYSTONE:
app = auth_token.AuthProtocol(app, {})
# This should be the last middleware in the list (which results in
# it being the first in the middleware chain). This is to ensure
# that any errors thrown by other middleware, such as an auth
# middleware - are annotated with CORS headers, and thus accessible
# by the browser.
app = cors.CORS(app, cfg.CONF)
app.set_latent(
allow_headers=['X-Auth-Token', 'X-Openstack-Request-Id'],
allow_methods=['GET', 'PUT', 'POST', 'DELETE'],
expose_headers=['X-Auth-Token', 'X-Openstack-Request-Id']
)
return app

View File

@ -12,11 +12,14 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from octavia.api.v1 import hooks
# Pecan Application Configurations # Pecan Application Configurations
# See https://pecan.readthedocs.org/en/latest/configuration.html#application-configuration # noqa # See https://pecan.readthedocs.org/en/latest/configuration.html#application-configuration # noqa
app = { app = {
'root': 'octavia.api.root_controller.RootController', 'root': 'octavia.api.root_controller.RootController',
'modules': ['octavia.api'], 'modules': ['octavia.api'],
'hooks': [hooks.ContextHook()],
'debug': False 'debug': False
} }

View File

@ -18,6 +18,7 @@ from octavia.common import context
class ContextHook(hooks.PecanHook): class ContextHook(hooks.PecanHook):
"""Configures a request context and attaches it to the request."""
def on_route(self, state): def on_route(self, state):
context_obj = context.Context.from_environ(state.request.environ) context_obj = context.Context.from_environ(state.request.environ)

View File

@ -35,15 +35,15 @@ core_opts = [
help=_("The host IP to bind to")), help=_("The host IP to bind to")),
cfg.PortOpt('bind_port', default=9876, cfg.PortOpt('bind_port', default=9876,
help=_("The port to bind to")), help=_("The port to bind to")),
cfg.StrOpt('auth_strategy', default=constants.NOAUTH,
choices=[constants.NOAUTH, constants.KEYSTONE],
help=_("The auth strategy for API requests.")),
cfg.StrOpt('api_handler', default='queue_producer', cfg.StrOpt('api_handler', default='queue_producer',
help=_("The handler that the API communicates with")), help=_("The handler that the API communicates with")),
cfg.StrOpt('api_paste_config', default="api-paste.ini", cfg.StrOpt('api_paste_config', default="api-paste.ini",
help=_("The API paste config file to use")), help=_("The API paste config file to use")),
cfg.StrOpt('api_extensions_path', default="", cfg.StrOpt('api_extensions_path', default="",
help=_("The path for API extensions")), help=_("The path for API extensions")),
cfg.StrOpt('auth_strategy', default='keystone',
choices=('noauth', 'keystone'),
help=_("The type of authentication to use")),
cfg.BoolOpt('allow_bulk', default=True, cfg.BoolOpt('allow_bulk', default=True,
help=_("Allow the usage of the bulk API")), help=_("Allow the usage of the bulk API")),
cfg.BoolOpt('allow_pagination', default=False, cfg.BoolOpt('allow_pagination', default=False,

View File

@ -358,3 +358,7 @@ INIT_PROC_COMM_PATH = '/proc/1/comm'
KEEPALIVED_SYSTEMD = 'octavia-keepalived.service' KEEPALIVED_SYSTEMD = 'octavia-keepalived.service'
KEEPALIVED_SYSVINIT = 'octavia-keepalived' KEEPALIVED_SYSVINIT = 'octavia-keepalived'
KEEPALIVED_UPSTART = 'octavia-keepalived.conf' KEEPALIVED_UPSTART = 'octavia-keepalived.conf'
# Authentication
KEYSTONE = 'keystone'
NOAUTH = 'noauth'

View File

@ -25,6 +25,7 @@ class KeystoneSession:
def __init__(self, section=constants.SERVICE_AUTH): def __init__(self, section=constants.SERVICE_AUTH):
self._session = None self._session = None
self.section = section self.section = section
ks_loading.register_auth_conf_options(cfg.CONF, self.section) ks_loading.register_auth_conf_options(cfg.CONF, self.section)
ks_loading.register_session_conf_options(cfg.CONF, self.section) ks_loading.register_session_conf_options(cfg.CONF, self.section)

View File

@ -56,6 +56,7 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
conf.config(api_handler='simulated_handler') conf.config(api_handler='simulated_handler')
conf.config(group="controller_worker", conf.config(group="controller_worker",
network_driver='network_noop_driver') network_driver='network_noop_driver')
conf.config(auth_strategy='noauth')
self.lb_repo = repositories.LoadBalancerRepository() self.lb_repo = repositories.LoadBalancerRepository()
self.listener_repo = repositories.ListenerRepository() self.listener_repo = repositories.ListenerRepository()
self.listener_stats_repo = repositories.ListenerStatisticsRepository() self.listener_stats_repo = repositories.ListenerStatisticsRepository()
@ -74,8 +75,8 @@ class BaseAPITest(base_db_test.OctaviaDBTestBase):
self.addCleanup(reset_pecan) self.addCleanup(reset_pecan)
def _make_app(self): def _make_app(self):
return pecan.testing.load_test_app({'app': pconfig.app, return pecan.testing.load_test_app(
'wsme': pconfig.wsme}) {'app': pconfig.app, 'wsme': pconfig.wsme})
def _get_full_path(self, path): def _get_full_path(self, path):
return ''.join([self.BASE_PATH, path]) return ''.join([self.BASE_PATH, path])

View File

@ -0,0 +1,11 @@
---
prelude: >
Support for Keystone token authentication on frontend Octavia API.
features:
- After setting "auth_strategy = keystone" all incoming requests to Octavia
API will be verified using Keystone are they send by authenticated person.
By default that option is disabled because Neutron LBaaS v2 is not
supporting that functionality properly.
upgrade:
- This feature add new configuration value "auth_strategy" which by default
is set for "noauth".