diff --git a/designate/common/policies/__init__.py b/designate/common/policies/__init__.py new file mode 100644 index 000000000..a76d4a0b5 --- /dev/null +++ b/designate/common/policies/__init__.py @@ -0,0 +1,26 @@ +# All Rights Reserved. +# +# 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. +# +# Borrowed from Zun + + +import itertools + +from designate.common.policies import base + + +def list_rules(): + return itertools.chain( + base.list_rules() + ) diff --git a/designate/common/policies/base.py b/designate/common/policies/base.py new file mode 100644 index 000000000..d5d0f2cb4 --- /dev/null +++ b/designate/common/policies/base.py @@ -0,0 +1,60 @@ +# All Rights Reserved. +# +# 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 + + +RULE_ADMIN_OR_OWNER = 'rule:admin_or_owner' +RULE_ADMIN = 'rule:admin' +RULE_ZONE_PRIMARY_OR_ADMIN = "('PRIMARY':%(zone_type)s and rule:admin_or_owner)\ + OR ('SECONDARY':%(zone_type)s AND is_admin:True)" +RULE_ANY = "@" + +rules = [ + policy.RuleDefault( + name="admin", + check_str="role:admin or is_admin:True"), + policy.RuleDefault( + name="primary_zone", + check_str="target.zone_type:SECONDARY"), + policy.RuleDefault( + name="owner", + check_str="tenant:%(tenant_id)s"), + policy.RuleDefault( + name="admin_or_owner", + check_str="rule:admin or rule:owner"), + policy.RuleDefault( + name="default", + check_str="rule:admin_or_owner"), + policy.RuleDefault( + name="target", + check_str="tenant:%(target_tenant_id)s"), + policy.RuleDefault( + name="owner_or_target", + check_str="rule:target or rule:owner"), + policy.RuleDefault( + name="admin_or_owner_or_target", + check_str="rule:owner_or_target or rule:admin"), + policy.RuleDefault( + name="admin_or_target", + check_str="rule:admin or rule:target"), + policy.RuleDefault( + name="zone_primary_or_admin", + check_str=RULE_ZONE_PRIMARY_OR_ADMIN) +] + + +def list_rules(): + return rules diff --git a/designate/policy.py b/designate/policy.py index 309e5fa92..b9f4df5e1 100644 --- a/designate/policy.py +++ b/designate/policy.py @@ -19,9 +19,8 @@ from oslo_policy import policy from oslo_policy import opts from designate.i18n import _ -from designate.i18n import _LI -from designate import utils from designate import exceptions +from designate.common import policies CONF = cfg.CONF @@ -62,25 +61,12 @@ def set_rules(data, default_rule=None, overwrite=True): _ENFORCER.set_rules(rules, overwrite=overwrite) -def init(default_rule=None): - policy_files = utils.find_config(CONF['oslo_policy'].policy_file) - - if len(policy_files) == 0: - msg = 'Unable to determine appropriate policy json file' - raise exceptions.ConfigurationError(msg) - - LOG.info(_LI('Using policy_file found at: %s'), policy_files[0]) - - with open(policy_files[0]) as fh: - policy_string = fh.read() - rules = policy.Rules.load_json(policy_string, default_rule=default_rule) - +def init(default_rule=None, policy_file=None): global _ENFORCER if not _ENFORCER: LOG.debug("Enforcer is not present, recreating.") - _ENFORCER = policy.Enforcer(CONF) - - _ENFORCER.set_rules(rules) + _ENFORCER = policy.Enforcer(CONF, policy_file=policy_file) + _ENFORCER.register_defaults(policies.list_rules()) def check(rule, ctxt, target=None, do_raise=True, exc=exceptions.Forbidden): diff --git a/designate/tests/fixtures.py b/designate/tests/fixtures.py index dfc7ba555..bb43a3052 100644 --- a/designate/tests/fixtures.py +++ b/designate/tests/fixtures.py @@ -32,6 +32,7 @@ from designate import policy from designate import network_api from designate import rpc from designate.network_api import fake as fake_network_api +from designate import utils from designate.sqlalchemy import utils as sqlalchemy_utils """Test fixtures @@ -104,6 +105,8 @@ class ServiceFixture(fixtures.Fixture): class PolicyFixture(fixtures.Fixture): def setUp(self): super(PolicyFixture, self).setUp() + policy.init(policy_file=utils.find_config( + cfg.CONF.oslo_policy.policy_file)[0]) self.addCleanup(policy.reset) diff --git a/designate/tests/unit/test_pool_manager/test_service.py b/designate/tests/unit/test_pool_manager/test_service.py index d51a1fdae..492423fcb 100644 --- a/designate/tests/unit/test_pool_manager/test_service.py +++ b/designate/tests/unit/test_pool_manager/test_service.py @@ -96,7 +96,8 @@ class PoolManagerInitTest(test.BaseTestCase): def test_init(self): Service() - def test_start(self): + @patch.object(pm_module.DesignateContext, 'get_admin_context') + def test_start(self, *mock): with patch.object(objects.Pool, 'from_config', return_value=Mock()): pm = Service() @@ -218,6 +219,7 @@ class PoolManagerTest(test.BaseTestCase): self.assertEqual(1, self.pm.pool_manager_api.create_zone.call_count) self.assertEqual(0, self.pm.pool_manager_api.update_zone.call_count) + @patch.object(pm_module.DesignateContext, 'get_admin_context') def test_periodic_sync(self, *mocks): def mock_fetch_healthy_zones(ctx): return [ diff --git a/etc/designate/designate-policy-generator.conf b/etc/designate/designate-policy-generator.conf new file mode 100644 index 000000000..e9dae7d1f --- /dev/null +++ b/etc/designate/designate-policy-generator.conf @@ -0,0 +1,3 @@ +[DEFAULT] +output_file = etc/designate/policy.yaml.sample +namespace = designate \ No newline at end of file diff --git a/etc/designate/policy.json b/etc/designate/policy.json index 0eeb7a1d4..3378825a0 100644 --- a/etc/designate/policy.json +++ b/etc/designate/policy.json @@ -1,18 +1,4 @@ { - "admin": "role:admin or is_admin:True", - "primary_zone": "target.zone_type:SECONDARY", - - "owner": "tenant:%(tenant_id)s", - "admin_or_owner": "rule:admin or rule:owner", - "target": "tenant:%(target_tenant_id)s", - "owner_or_target":"rule:target or rule:owner", - "admin_or_owner_or_target":"rule:owner_or_target or rule:admin", - "admin_or_target":"rule:admin or rule:target", - - "zone_primary_or_admin": "('PRIMARY':%(zone_type)s and rule:admin_or_owner) OR ('SECONDARY':%(zone_type)s AND is_admin:True)", - - "default": "rule:admin_or_owner", - "all_tenants": "rule:admin", "edit_managed_records" : "rule:admin", diff --git a/setup.cfg b/setup.cfg index d164b114e..6fc17b1d6 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,9 @@ oslo.config.opts = oslo.config.opts.defaults = designate.api = designate.common.config:set_defaults +oslo.policy.policies = + designate = designate.common.policies:list_rules + console_scripts = designate-rootwrap = oslo_rootwrap.cmd:main designate-api = designate.cmd.api:main diff --git a/tox.ini b/tox.ini index c847ab836..8179f1b5b 100644 --- a/tox.ini +++ b/tox.ini @@ -71,6 +71,9 @@ commands = sh tools/pretty_flake8.sh [testenv:genconfig] commands = oslo-config-generator --config-file=etc/designate/designate-config-generator.conf +[testenv:genpolicy] +commands = oslopolicy-sample-generator --config-file etc/designate/designate-policy-generator.conf + [testenv:bashate] deps = bashate whitelist_externals = bash