Merge "Move policy defaults into code"
This commit is contained in:
commit
c632586ef3
3
.gitignore
vendored
3
.gitignore
vendored
@ -22,6 +22,9 @@ tests.sqlite
|
||||
glance/versioninfo
|
||||
subunit.log
|
||||
|
||||
# generated policy file
|
||||
etc/policy.yaml.sample
|
||||
|
||||
# Swap files range from .saa to .swp
|
||||
*.s[a-w][a-p]
|
||||
|
||||
|
3
etc/glance-policy-generator.conf
Normal file
3
etc/glance-policy-generator.conf
Normal file
@ -0,0 +1,3 @@
|
||||
[DEFAULT]
|
||||
namespace = glance
|
||||
output_file = etc/policy.yaml.sample
|
@ -1,63 +1,2 @@
|
||||
{
|
||||
"context_is_admin": "role:admin",
|
||||
"default": "role:admin",
|
||||
|
||||
"add_image": "",
|
||||
"delete_image": "",
|
||||
"get_image": "",
|
||||
"get_images": "",
|
||||
"modify_image": "",
|
||||
"publicize_image": "role:admin",
|
||||
"communitize_image": "",
|
||||
"copy_from": "",
|
||||
|
||||
"download_image": "",
|
||||
"upload_image": "",
|
||||
|
||||
"delete_image_location": "",
|
||||
"get_image_location": "",
|
||||
"set_image_location": "",
|
||||
|
||||
"add_member": "",
|
||||
"delete_member": "",
|
||||
"get_member": "",
|
||||
"get_members": "",
|
||||
"modify_member": "",
|
||||
|
||||
"manage_image_cache": "role:admin",
|
||||
|
||||
"get_task": "",
|
||||
"get_tasks": "",
|
||||
"add_task": "",
|
||||
"modify_task": "",
|
||||
"tasks_api_access": "role:admin",
|
||||
|
||||
"deactivate": "",
|
||||
"reactivate": "",
|
||||
|
||||
"get_metadef_namespace": "",
|
||||
"get_metadef_namespaces":"",
|
||||
"modify_metadef_namespace":"",
|
||||
"add_metadef_namespace":"",
|
||||
|
||||
"get_metadef_object":"",
|
||||
"get_metadef_objects":"",
|
||||
"modify_metadef_object":"",
|
||||
"add_metadef_object":"",
|
||||
|
||||
"list_metadef_resource_types":"",
|
||||
"get_metadef_resource_type":"",
|
||||
"add_metadef_resource_type_association":"",
|
||||
|
||||
"get_metadef_property":"",
|
||||
"get_metadef_properties":"",
|
||||
"modify_metadef_property":"",
|
||||
"add_metadef_property":"",
|
||||
|
||||
"get_metadef_tag":"",
|
||||
"get_metadef_tags":"",
|
||||
"modify_metadef_tag":"",
|
||||
"add_metadef_tag":"",
|
||||
"add_metadef_tags":""
|
||||
|
||||
}
|
||||
|
@ -32,34 +32,26 @@ from oslo_policy import policy
|
||||
from glance.common import exception
|
||||
import glance.domain.proxy
|
||||
from glance.i18n import _
|
||||
from glance import policies
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = cfg.CONF
|
||||
_ENFORCER = None
|
||||
|
||||
DEFAULT_RULES = policy.Rules.from_dict({
|
||||
'context_is_admin': 'role:admin',
|
||||
'default': 'role:admin',
|
||||
'manage_image_cache': 'role:admin',
|
||||
})
|
||||
|
||||
|
||||
class Enforcer(policy.Enforcer):
|
||||
"""Responsible for loading and enforcing rules"""
|
||||
|
||||
def __init__(self):
|
||||
if CONF.find_file(CONF.oslo_policy.policy_file):
|
||||
kwargs = dict(rules=None, use_conf=True)
|
||||
else:
|
||||
kwargs = dict(rules=DEFAULT_RULES, use_conf=False)
|
||||
super(Enforcer, self).__init__(CONF, overwrite=False, **kwargs)
|
||||
super(Enforcer, self).__init__(CONF, use_conf=True, overwrite=False)
|
||||
self.register_defaults(policies.list_rules())
|
||||
|
||||
def add_rules(self, rules):
|
||||
"""Add new rules to the Rules object"""
|
||||
self.set_rules(rules, overwrite=False, use_conf=self.use_conf)
|
||||
|
||||
def enforce(self, context, action, target):
|
||||
def enforce(self, context, action, target, registered=True):
|
||||
"""Verifies that the action is valid on the target in this context.
|
||||
|
||||
:param context: Glance request context
|
||||
@ -68,13 +60,15 @@ class Enforcer(policy.Enforcer):
|
||||
:raises: `glance.common.exception.Forbidden`
|
||||
:returns: A non-False value if access is allowed.
|
||||
"""
|
||||
if registered and action not in self.registered_rules:
|
||||
raise policy.PolicyNotRegistered(action)
|
||||
return super(Enforcer, self).enforce(action, target,
|
||||
context.to_policy_values(),
|
||||
do_raise=True,
|
||||
exc=exception.Forbidden,
|
||||
action=action)
|
||||
|
||||
def check(self, context, action, target):
|
||||
def check(self, context, action, target, registered=True):
|
||||
"""Verifies that the action is valid on the target in this context.
|
||||
|
||||
:param context: Glance request context
|
||||
@ -82,6 +76,8 @@ class Enforcer(policy.Enforcer):
|
||||
:param target: Dictionary representing the object of the action.
|
||||
:returns: A non-False value if access is allowed.
|
||||
"""
|
||||
if registered and action not in self.registered_rules:
|
||||
raise policy.PolicyNotRegistered(action)
|
||||
return super(Enforcer, self).enforce(action,
|
||||
target,
|
||||
context.to_policy_values())
|
||||
|
@ -209,7 +209,7 @@ class PropertyRules(object):
|
||||
def _check_policy(self, property_exp, action, context):
|
||||
try:
|
||||
action = ":".join([property_exp, action])
|
||||
self.policy_enforcer.enforce(context, action, {})
|
||||
self.policy_enforcer.enforce(context, action, {}, registered=False)
|
||||
except exception.Forbidden:
|
||||
return False
|
||||
return True
|
||||
|
27
glance/policies/__init__.py
Normal file
27
glance/policies/__init__.py
Normal file
@ -0,0 +1,27 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import itertools
|
||||
|
||||
from glance.policies import base
|
||||
from glance.policies import image
|
||||
from glance.policies import metadef
|
||||
from glance.policies import tasks
|
||||
|
||||
|
||||
def list_rules():
|
||||
return itertools.chain(
|
||||
base.list_rules(),
|
||||
image.list_rules(),
|
||||
tasks.list_rules(),
|
||||
metadef.list_rules(),
|
||||
)
|
28
glance/policies/base.py
Normal file
28
glance/policies/base.py
Normal file
@ -0,0 +1,28 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_policy import policy
|
||||
|
||||
|
||||
rules = [
|
||||
policy.RuleDefault(name='default', check_str='',
|
||||
description='Defines the default rule used for '
|
||||
'policies that historically had an empty '
|
||||
'policy in the supplied policy.json file.'),
|
||||
policy.RuleDefault(name='context_is_admin', check_str='role:admin',
|
||||
description='Defines the rule for the is_admin:True '
|
||||
'check.'),
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return rules
|
47
glance/policies/image.py
Normal file
47
glance/policies/image.py
Normal file
@ -0,0 +1,47 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_policy import policy
|
||||
|
||||
|
||||
image_policies = [
|
||||
policy.RuleDefault(name="add_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="delete_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_images", check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="publicize_image", check_str="role:admin"),
|
||||
policy.RuleDefault(name="communitize_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="copy_from", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="download_image", check_str="rule:default"),
|
||||
policy.RuleDefault(name="upload_image", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="delete_image_location", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_image_location", check_str="rule:default"),
|
||||
policy.RuleDefault(name="set_image_location", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="add_member", check_str="rule:default"),
|
||||
policy.RuleDefault(name="delete_member", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_member", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_members", check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_member", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="manage_image_cache", check_str="role:admin"),
|
||||
|
||||
policy.RuleDefault(name="deactivate", check_str="rule:default"),
|
||||
policy.RuleDefault(name="reactivate", check_str="rule:default"),
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return image_policies
|
52
glance/policies/metadef.py
Normal file
52
glance/policies/metadef.py
Normal file
@ -0,0 +1,52 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_policy import policy
|
||||
|
||||
|
||||
metadef_policies = [
|
||||
policy.RuleDefault(name="get_metadef_namespace", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_metadef_namespaces",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_metadef_namespace",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_namespace", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="get_metadef_object", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_metadef_objects", check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_metadef_object", check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_object", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="list_metadef_resource_types",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_metadef_resource_type",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_resource_type_association",
|
||||
check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="get_metadef_property", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_metadef_properties",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_metadef_property",
|
||||
check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_property", check_str="rule:default"),
|
||||
|
||||
policy.RuleDefault(name="get_metadef_tag", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_metadef_tags", check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_metadef_tag", check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_tag", check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_metadef_tags", check_str="rule:default"),
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return metadef_policies
|
26
glance/policies/tasks.py
Normal file
26
glance/policies/tasks.py
Normal file
@ -0,0 +1,26 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_policy import policy
|
||||
|
||||
|
||||
task_policies = [
|
||||
policy.RuleDefault(name="get_task", check_str="rule:default"),
|
||||
policy.RuleDefault(name="get_tasks", check_str="rule:default"),
|
||||
policy.RuleDefault(name="add_task", check_str="rule:default"),
|
||||
policy.RuleDefault(name="modify_task", check_str="rule:default"),
|
||||
policy.RuleDefault(name="tasks_api_access", check_str="role:admin"),
|
||||
]
|
||||
|
||||
|
||||
def list_rules():
|
||||
return task_policies
|
@ -162,6 +162,22 @@ class TaskFactoryStub(object):
|
||||
|
||||
class TestPolicyEnforcer(base.IsolatedUnitTest):
|
||||
|
||||
def test_policy_enforce_unregistered(self):
|
||||
enforcer = glance.api.policy.Enforcer()
|
||||
context = glance.context.RequestContext(roles=[])
|
||||
|
||||
self.assertRaises(glance.api.policy.policy.PolicyNotRegistered,
|
||||
enforcer.enforce,
|
||||
context, 'wibble', {})
|
||||
|
||||
def test_policy_check_unregistered(self):
|
||||
enforcer = glance.api.policy.Enforcer()
|
||||
context = glance.context.RequestContext(roles=[])
|
||||
|
||||
self.assertRaises(glance.api.policy.policy.PolicyNotRegistered,
|
||||
enforcer.check,
|
||||
context, 'wibble', {})
|
||||
|
||||
def test_policy_file_default_rules_default_location(self):
|
||||
enforcer = glance.api.policy.Enforcer()
|
||||
|
||||
|
22
releasenotes/notes/policy-in-code-7e0c6c070d32d136.yaml
Normal file
22
releasenotes/notes/policy-in-code-7e0c6c070d32d136.yaml
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
upgrade:
|
||||
- |
|
||||
Policy defaults are now defined in code, as they already were in other
|
||||
OpenStack services. After upgrading there is no need to provide a
|
||||
``policy.json`` file (and you should not do so) unless you want to override
|
||||
the default policies, and only policies you want to override need be
|
||||
mentioned in the file. You should no longer rely on the ``default`` rule,
|
||||
and especially not the default value of the rule (which has been relaxed),
|
||||
to assign a non-default policy to rules not explicitly specified in the
|
||||
policy file.
|
||||
security:
|
||||
- |
|
||||
If the existing ``policy.json`` file relies on the ``default`` rule for
|
||||
some policies (i.e. not all policies are explicitly specified in the file)
|
||||
then the ``default`` rule must be explicitly set (e.g. to
|
||||
``"role:admin"``) in the file. The new default value for the ``default``
|
||||
rule is ``""``, whereas since the Queens release it has been
|
||||
``"role:admin"`` (prior to Queens it was ``"@"``, which allows everything).
|
||||
After upgrading to this release, the policy file should be replaced by one
|
||||
that overrides only policies that need to be different from the defaults,
|
||||
without relying on the ``default`` rule.
|
@ -66,6 +66,8 @@ glance.database.metadata_backend =
|
||||
|
||||
oslo.policy.enforcer =
|
||||
glance = glance.api.policy:get_enforcer
|
||||
oslo.policy.policies =
|
||||
glance = glance.policies:list_rules
|
||||
|
||||
glance.flows =
|
||||
api_image_import = glance.async_.flows.api_image_import:get_flow
|
||||
|
5
tox.ini
5
tox.ini
@ -62,6 +62,11 @@ commands = {[testenv:functional]commands}
|
||||
setenv = {[testenv:functional]setenv}
|
||||
commands = {[testenv:functional]commands}
|
||||
|
||||
[testenv:genpolicy]
|
||||
basepython = python3
|
||||
commands =
|
||||
oslopolicy-sample-generator --config-file=etc/glance-policy-generator.conf
|
||||
|
||||
[testenv:gateonly]
|
||||
# NOTE(rosmaita): these tests catch configuration problems for some code
|
||||
# constants that must be maintained manually; we have them separated out
|
||||
|
Loading…
x
Reference in New Issue
Block a user