Fail to start if authorization and policy is misconfigured
This informs operators of glance's support status for secure RBAC as of the Wallaby release. Eventually, this message will be removed when glance adopts more support for secure RBAC personas. This also forces glance to fail if it's configured improperly. This is done to explicitly prevent ambiguity with authoritative decisions. Related: blueprint secure-rbac Change-Id: I06293de08dd3fdfbd60b9a65501d1198f40ff434
This commit is contained in:
parent
bdbad59dc9
commit
bf838242ac
@ -15,6 +15,7 @@
|
||||
function configure_enforce_scope {
|
||||
iniset $GLANCE_CONF_DIR/glance-api.conf oslo_policy enforce_scope true
|
||||
iniset $GLANCE_CONF_DIR/glance-api.conf oslo_policy enforce_new_defaults true
|
||||
iniset $GLANCE_CONF_DIR/glance-api.conf DEFAULT enforce_secure_rbac true
|
||||
sudo systemctl restart devstack@g-api
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@ from oslo_policy import policy
|
||||
|
||||
from glance.common import exception
|
||||
import glance.domain.proxy
|
||||
from glance.i18n import _
|
||||
from glance.i18n import _, _LW
|
||||
from glance import policies
|
||||
|
||||
|
||||
@ -48,6 +48,15 @@ class Enforcer(policy.Enforcer):
|
||||
def __init__(self):
|
||||
super(Enforcer, self).__init__(CONF, use_conf=True, overwrite=False)
|
||||
self.register_defaults(policies.list_rules())
|
||||
if CONF.enforce_secure_rbac and CONF.oslo_policy.enforce_new_defaults:
|
||||
LOG.warning(_LW(
|
||||
"Deploying glance with secure RBAC personas enabled via "
|
||||
"`glance-api.conf [DEFAULT] enforce_secure_rbac=True` and "
|
||||
"`glance-api.conf [oslo_policy] enforce_new_defaults=True` "
|
||||
"is marked as EXPERIMENTAL in Wallaby. The status of this "
|
||||
"feature will graduate to SUPPORTED as glance adopts more "
|
||||
"personas, specifically for system-scope."
|
||||
))
|
||||
|
||||
def add_rules(self, rules):
|
||||
"""Add new rules to the Rules object"""
|
||||
|
@ -108,6 +108,14 @@ def main():
|
||||
host=CONF.bind_host
|
||||
)
|
||||
|
||||
if CONF.enforce_secure_rbac != CONF.oslo_policy.enforce_new_defaults:
|
||||
fail_message = (
|
||||
"[DEFAULT] enforce_secure_rbac does not match "
|
||||
"[oslo_policy] enforce_new_defaults. Please set both to "
|
||||
"True to enable secure RBAC personas. Otherwise, make sure "
|
||||
"both are False.")
|
||||
raise exception.ServerError(fail_message)
|
||||
|
||||
# NOTE(danms): Configure system-wide threading model to use eventlet
|
||||
glance.async_.set_threadpool_model('eventlet')
|
||||
|
||||
|
@ -566,6 +566,31 @@ Related options:
|
||||
|
||||
Related options:
|
||||
* [DEFAULT]/node_staging_uri""")),
|
||||
cfg.BoolOpt('enforce_secure_rbac', default=False,
|
||||
deprecated_for_removal=True,
|
||||
deprecated_reason=_("""
|
||||
This option has been introduced to require operators to opt into enforcing
|
||||
authorization based on common RBAC personas, which is EXPERIMENTAL as of the
|
||||
Wallaby release. This behavior will be the default and STABLE in a future
|
||||
release, allowing this option to be removed.
|
||||
"""),
|
||||
deprecated_since='Wallaby',
|
||||
help=_("""
|
||||
Enforce API access based on common persona definitions used across OpenStack.
|
||||
Enabling this option formalizes project-specific read/write operations, like
|
||||
creating private images or updating the status of shared image, behind the
|
||||
`member` role. It also formalizes a read-only variant useful for
|
||||
project-specific API operations, like listing private images in a project,
|
||||
behind the `reader` role.
|
||||
|
||||
Operators should take an opportunity to understand glance's new image policies,
|
||||
audit assignments in their deployment, and update permissions using the default
|
||||
roles in keystone (e.g., `admin`, `member`, and `reader`).
|
||||
|
||||
Related options:
|
||||
* [oslo_policy]/enforce_new_defaults
|
||||
|
||||
""")),
|
||||
]
|
||||
|
||||
wsgi_opts = [
|
||||
|
@ -21,6 +21,7 @@ import osprofiler.initializer
|
||||
from glance.api import common
|
||||
import glance.async_
|
||||
from glance.common import config
|
||||
from glance.common import exception
|
||||
from glance.common import store_utils
|
||||
from glance.i18n import _
|
||||
from glance import notifier
|
||||
@ -69,6 +70,16 @@ def _setup_os_profiler():
|
||||
host=CONF.bind_host)
|
||||
|
||||
|
||||
def _validate_policy_enforcement_configuration():
|
||||
if CONF.enforce_secure_rbac != CONF.oslo_policy.enforce_new_defaults:
|
||||
fail_message = (
|
||||
"[DEFAULT] enforce_secure_rbac does not match "
|
||||
"[oslo_policy] enforce_new_defaults. Please set both to "
|
||||
"True to enable secure RBAC personas. Otherwise, make sure "
|
||||
"both are False.")
|
||||
raise exception.ServerError(fail_message)
|
||||
|
||||
|
||||
def drain_threadpools():
|
||||
# NOTE(danms): If there are any other named pools that we need to
|
||||
# drain before exit, they should be in this list.
|
||||
@ -112,4 +123,5 @@ def init_app():
|
||||
glance_store.verify_default_store()
|
||||
|
||||
_setup_os_profiler()
|
||||
_validate_policy_enforcement_configuration()
|
||||
return config.load_paste_app('glance-api')
|
||||
|
@ -18,6 +18,7 @@ from unittest import mock
|
||||
|
||||
from glance.api import common
|
||||
import glance.async_
|
||||
from glance.common import exception
|
||||
from glance.common import wsgi_app
|
||||
from glance.tests import utils as test_utils
|
||||
|
||||
@ -63,3 +64,37 @@ class TestWsgiAppInit(test_utils.BaseTestCase):
|
||||
# Make sure that shutdown() was called on the tasks_pool
|
||||
# ThreadPoolExecutor
|
||||
mock_shutdown.assert_called_once_with()
|
||||
|
||||
@mock.patch('glance.common.config.load_paste_app')
|
||||
@mock.patch('glance.async_.set_threadpool_model')
|
||||
@mock.patch('glance.common.wsgi_app._get_config_files')
|
||||
def test_policy_enforcement_kills_service_if_misconfigured(
|
||||
self, mock_load_app, mock_set, mock_config_files):
|
||||
self.config(enforce_new_defaults=True, group='oslo_policy')
|
||||
self.config(enforce_secure_rbac=False)
|
||||
self.assertRaises(exception.ServerError, wsgi_app.init_app)
|
||||
|
||||
self.config(enforce_new_defaults=False, group='oslo_policy')
|
||||
self.config(enforce_secure_rbac=True)
|
||||
self.assertRaises(exception.ServerError, wsgi_app.init_app)
|
||||
|
||||
@mock.patch('glance.common.config.load_paste_app')
|
||||
@mock.patch('glance.async_.set_threadpool_model')
|
||||
@mock.patch('glance.common.wsgi_app._get_config_files')
|
||||
def test_policy_enforcement_valid_truthy_configuration(
|
||||
self, mock_load_app, mock_set, mock_config_files):
|
||||
self.config(enforce_new_defaults=True, group='oslo_policy')
|
||||
self.config(enforce_secure_rbac=True)
|
||||
self.assertTrue(wsgi_app.init_app())
|
||||
|
||||
@mock.patch('glance.common.config.load_paste_app')
|
||||
@mock.patch('glance.async_.set_threadpool_model')
|
||||
@mock.patch('glance.common.wsgi_app._get_config_files')
|
||||
def test_policy_enforcement_valid_falsy_configuration(
|
||||
self, mock_load_app, mock_set, mock_config_files):
|
||||
# This is effectively testing the default values, but we're doing that
|
||||
# to make sure nothing bad happens at runtime in the default case when
|
||||
# validating policy enforcement configuration.
|
||||
self.config(enforce_new_defaults=False, group='oslo_policy')
|
||||
self.config(enforce_secure_rbac=False)
|
||||
self.assertTrue(wsgi_app.init_app())
|
||||
|
@ -373,6 +373,27 @@ class TestPolicyEnforcer(base.IsolatedUnitTest):
|
||||
enforcer.check(context, 'foo', {})
|
||||
mock_enforcer.assert_called_once_with('foo', {}, context)
|
||||
|
||||
def test_ensure_experimental_warning_is_logged_for_secure_rbac(self):
|
||||
self.config(enforce_new_defaults=True, group='oslo_policy')
|
||||
self.config(enforce_secure_rbac=True)
|
||||
expected_log_string = (
|
||||
"Deploying glance with secure RBAC personas enabled via "
|
||||
"`glance-api.conf [DEFAULT] enforce_secure_rbac=True` and "
|
||||
"`glance-api.conf [oslo_policy] enforce_new_defaults=True` "
|
||||
"is marked as EXPERIMENTAL in Wallaby. The status of this "
|
||||
"feature will graduate to SUPPORTED as glance adopts more "
|
||||
"personas, specifically for system-scope."
|
||||
)
|
||||
with mock.patch.object(glance.api.policy, 'LOG') as mock_log:
|
||||
glance.api.policy.Enforcer()
|
||||
mock_log.warning.assert_called_once_with(expected_log_string)
|
||||
|
||||
def test_ensure_experimental_warning_is_not_logged_for_legacy_rbac(self):
|
||||
self.config(enforce_new_defaults=False, group='oslo_policy')
|
||||
with mock.patch.object(glance.api.policy, 'LOG') as mock_log:
|
||||
glance.api.policy.Enforcer()
|
||||
mock_log.warning.assert_not_called()
|
||||
|
||||
|
||||
class TestPolicyEnforcerNoFile(base.IsolatedUnitTest):
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user