From 5971243169c5df863ebe81cff7ebd07f190b840a Mon Sep 17 00:00:00 2001 From: ricolin Date: Sun, 26 Feb 2023 17:30:02 +0800 Subject: [PATCH] Support enables rbac policies new defaults The Magnum service allow enables policies (RBAC) new defaults and scope by default. The Default value of config options ``[oslo_policy] enforce_scope`` and ``[oslo_policy] oslo_policy.enforce_new_defaults`` are both to ``False``, but will change to ``True`` in following cycles. To enable them then modify the below config options value in ``magnum.conf`` file:: [oslo_policy] enforce_new_defaults=True enforce_scope=True reference tc goal for more detail: https://governance.openstack.org/tc/goals/selected/consistent-and-secure-rbac.html Related blueprint secure-rbac Change-Id: I249942a355577c4f1ef51b3988f0cc4979959d0b --- devstack/lib/magnum | 8 + devstack/settings | 4 + magnum/api/hooks.py | 8 +- magnum/common/context.py | 6 +- magnum/common/policies/base.py | 167 +++++++++++++++++- magnum/common/policies/certificate.py | 11 +- magnum/common/policies/cluster.py | 27 ++- magnum/common/policies/cluster_template.py | 20 ++- magnum/common/policies/federation.py | 18 +- magnum/common/policies/nodegroup.py | 15 +- magnum/common/policies/quota.py | 3 +- magnum/common/policies/stats.py | 3 +- magnum/common/policy.py | 12 +- magnum/tests/fakes.py | 2 +- magnum/tests/unit/api/base.py | 16 ++ .../tests/unit/api/controllers/test_root.py | 4 +- .../api/controllers/v1/test_certificate.py | 23 ++- .../unit/api/controllers/v1/test_cluster.py | 34 ++-- .../controllers/v1/test_cluster_actions.py | 48 +++-- .../unit/api/controllers/v1/test_nodegroup.py | 12 +- .../unit/api/controllers/v1/test_quota.py | 2 +- .../unit/api/controllers/v1/test_stats.py | 15 +- magnum/tests/unit/api/test_hooks.py | 10 +- magnum/tests/unit/common/test_context.py | 43 ++--- ...ope-and-new-defaults-7e6e503f74283071.yaml | 13 ++ requirements.txt | 4 +- 26 files changed, 404 insertions(+), 124 deletions(-) create mode 100644 releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml diff --git a/devstack/lib/magnum b/devstack/lib/magnum index 12408965cc..ba090e81d8 100644 --- a/devstack/lib/magnum +++ b/devstack/lib/magnum @@ -153,6 +153,14 @@ function create_magnum_conf { iniset $MAGNUM_CONF oslo_policy policy_file $MAGNUM_POLICY + if [[ "$MAGNUM_ENFORCE_SCOPE" == True ]] ; then + iniset $MAGNUM_CONF oslo_policy enforce_scope true + iniset $MAGNUM_CONF oslo_policy enforce_new_defaults true + else + iniset $MAGNUM_CONF oslo_policy enforce_scope false + iniset $MAGNUM_CONF oslo_policy enforce_new_defaults false + fi + iniset $MAGNUM_CONF keystone_auth auth_type password iniset $MAGNUM_CONF keystone_auth username magnum iniset $MAGNUM_CONF keystone_auth password $SERVICE_PASSWORD diff --git a/devstack/settings b/devstack/settings index 4d6dff966d..ba679659d5 100644 --- a/devstack/settings +++ b/devstack/settings @@ -14,6 +14,10 @@ # PHYSICAL_NETWORK=public # OVS_PHYSICAL_BRIDGE=br-ex +# This option controls whether or not to enforce scope when evaluating policies. Learn more: +# https://docs.openstack.org/oslo.policy/latest/configuration/index.html#oslo_policy.enforce_scope +MAGNUM_ENFORCE_SCOPE=$(trueorfalse False MAGNUM_ENFORCE_SCOPE) + # Enable Magnum services enable_service magnum-api enable_service magnum-cond diff --git a/magnum/api/hooks.py b/magnum/api/hooks.py index e0d36a9a88..f5a9049795 100644 --- a/magnum/api/hooks.py +++ b/magnum/api/hooks.py @@ -52,8 +52,8 @@ class ContextHook(hooks.PecanHook): user_id = headers.get('X-User-Id') project = headers.get('X-Project-Name') project_id = headers.get('X-Project-Id') - domain_id = headers.get('X-User-Domain-Id') - domain_name = headers.get('X-User-Domain-Name') + user_domain_id = headers.get('X-User-Domain-Id') + user_domain_name = headers.get('X-User-Domain-Name') auth_token = headers.get('X-Auth-Token') roles = headers.get('X-Roles', '').split(',') auth_token_info = state.request.environ.get('keystone.token_info') @@ -72,8 +72,8 @@ class ContextHook(hooks.PecanHook): user_id=user_id, project_name=project, project_id=project_id, - domain_id=domain_id, - domain_name=domain_name, + user_domain_id=user_domain_id, + user_domain_name=user_domain_name, roles=roles) diff --git a/magnum/common/context.py b/magnum/common/context.py index 547c9cc9b4..7d6c4011a8 100644 --- a/magnum/common/context.py +++ b/magnum/common/context.py @@ -42,7 +42,7 @@ class RequestContext(context.RequestContext): """ super(RequestContext, self).__init__(auth_token=auth_token, user_id=user_name, - project_id=project_name, + project_id=project_id, is_admin=is_admin, read_only=read_only, show_deleted=show_deleted, @@ -53,8 +53,6 @@ class RequestContext(context.RequestContext): self.user_id = user_id self.project_name = project_name self.project_id = project_id - self.domain_id = domain_id - self.domain_name = domain_name self.user_domain_id = user_domain_id self.user_domain_name = user_domain_name self.auth_url = auth_url @@ -71,8 +69,6 @@ class RequestContext(context.RequestContext): value = super(RequestContext, self).to_dict() value.update({'auth_token': self.auth_token, 'auth_url': self.auth_url, - 'domain_id': self.domain_id, - 'domain_name': self.domain_name, 'user_domain_id': self.user_domain_id, 'user_domain_name': self.user_domain_name, 'user_name': self.user_name, diff --git a/magnum/common/policies/base.py b/magnum/common/policies/base.py index 44c75b7daf..66b7c42806 100644 --- a/magnum/common/policies/base.py +++ b/magnum/common/policies/base.py @@ -13,12 +13,79 @@ # under the License. from oslo_policy import policy -ROLE_ADMIN = 'rule:context_is_admin' + RULE_ADMIN_OR_OWNER = 'rule:admin_or_owner' -RULE_ADMIN_API = 'rule:admin_api' +RULE_ADMIN_API = 'rule:context_is_admin' RULE_ADMIN_OR_USER = 'rule:admin_or_user' RULE_CLUSTER_USER = 'rule:cluster_user' RULE_DENY_CLUSTER_USER = 'rule:deny_cluster_user' +RULE_USER = "rule:is_user" +# Generic check string for checking if a user is authorized on a particular +# project, specifically with the member role. +RULE_PROJECT_MEMBER = 'rule:project_member' +# Generic check string for checking if a user is authorized on a particular +# project but with read-only access. For example, this persona would be able to +# list private images owned by a project but cannot make any writeable changes +# to those images. +RULE_PROJECT_READER = 'rule:project_reader' + +RULE_USER_OR_CLUSTER_USER = ( + 'rule:user_or_cluster_user') +RULE_ADMIN_OR_PROJECT_READER = ( + 'rule:admin_or_project_reader') +RULE_ADMIN_OR_PROJECT_MEMBER = ( + 'rule:admin_or_project_member') +RULE_ADMIN_OR_PROJECT_MEMBER_USER = ( + 'rule:admin_or_project_member_user') +RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER = ( + 'rule:admin_or_project_member_user_or_cluster_user') +RULE_PROJECT_MEMBER_DENY_CLUSTER_USER = ( + 'rule:project_member_deny_cluster_user') +RULE_ADMIN_OR_PROJECT_MEMBER_DENY_CLUSTER_USER = ( + 'rule:admin_or_project_member_deny_cluster_user') +RULE_PROJECT_READER_DENY_CLUSTER_USER = ( + 'rule:project_reader_deny_cluster_user') +RULE_ADMIN_OR_PROJECT_READER_DENY_CLUSTER_USER = ( + 'rule:admin_or_project_reader_deny_cluster_user') +RULE_ADMIN_OR_PROJECT_READER_USER_OR_CLUSTER_USER = ( + 'rule:admin_or_project_reader_user_or_cluster_user') + +# ========================================================== +# Deprecated Since OpenStack 2023.2(Magnum 17.0.0) and should be removed in +# The following cycle. + +DEPRECATED_REASON = """ +The Magnum API now enforces scoped tokens and default reader and member roles. +""" + +DEPRECATED_SINCE = 'OpenStack 2023.2(Magnum 17.0.0)' + + +DEPRECATED_DENY_CLUSTER_USER = policy.DeprecatedRule( + name=RULE_DENY_CLUSTER_USER, + check_str='not domain_id:%(trustee_domain_id)s', + deprecated_reason=DEPRECATED_REASON, + deprecated_since=DEPRECATED_SINCE +) + +DEPRECATED_RULE_ADMIN_OR_OWNER = policy.DeprecatedRule( + name=RULE_ADMIN_OR_OWNER, + check_str='is_admin:True or project_id:%(project_id)s', + deprecated_reason=DEPRECATED_REASON, + deprecated_since=DEPRECATED_SINCE +) + +# Only used for DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER +RULE_ADMIN_OR_USER_OR_CLUSTER_USER = ( + 'rule:admin_or_user_or_cluster_user') + +DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER = policy.DeprecatedRule( + name=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, + check_str=f"(({RULE_ADMIN_API}) or ({RULE_USER_OR_CLUSTER_USER}))", + deprecated_reason=DEPRECATED_REASON, + deprecated_since=DEPRECATED_SINCE +) +# ========================================================== rules = [ policy.RuleDefault( @@ -29,14 +96,14 @@ rules = [ name='admin_or_owner', check_str='is_admin:True or project_id:%(project_id)s' ), - policy.RuleDefault( - name='admin_api', - check_str='rule:context_is_admin' - ), policy.RuleDefault( name='admin_or_user', check_str='is_admin:True or user_id:%(user_id)s' ), + policy.RuleDefault( + name='is_user', + check_str='user_id:%(user_id)s' + ), policy.RuleDefault( name='cluster_user', check_str='user_id:%(trustee_user_id)s' @@ -44,7 +111,93 @@ rules = [ policy.RuleDefault( name='deny_cluster_user', check_str='not domain_id:%(trustee_domain_id)s' - ) + ), + policy.RuleDefault( + name='project_member', + check_str='role:member and project_id:%(project_id)s' + ), + policy.RuleDefault( + name='project_reader', + check_str='role:reader and project_id:%(project_id)s' + ), + policy.RuleDefault( + name='admin_or_project_reader', + check_str=f"({RULE_ADMIN_API}) or ({RULE_PROJECT_READER})", + deprecated_rule=DEPRECATED_RULE_ADMIN_OR_OWNER + ), + policy.RuleDefault( + name='admin_or_project_member', + check_str=f"({RULE_ADMIN_API}) or ({RULE_PROJECT_MEMBER})", + deprecated_rule=DEPRECATED_RULE_ADMIN_OR_OWNER + ), + policy.RuleDefault( + name='admin_or_project_member_user', + check_str=( + f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) and " + f"({RULE_USER}))" + ) + ), + policy.RuleDefault( + name='user_or_cluster_user', + check_str=( + f"(({RULE_USER}) or ({RULE_CLUSTER_USER}))" + ) + ), + policy.RuleDefault( + name='admin_or_user_or_cluster_user', + check_str=( + f"(({RULE_ADMIN_API}) or ({RULE_USER_OR_CLUSTER_USER}))" + ) + ), + policy.RuleDefault( + name='admin_or_project_member_cluster_user', + check_str=( + f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) " + f"and ({RULE_CLUSTER_USER}))" + ) + ), + policy.RuleDefault( + name='admin_or_project_member_user_or_cluster_user', + check_str=( + f"({RULE_ADMIN_API}) or (({RULE_PROJECT_MEMBER}) and " + f"({RULE_USER_OR_CLUSTER_USER}))" + ), + deprecated_rule=DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER + ), + policy.RuleDefault( + name='project_member_deny_cluster_user', + check_str=( + f"(({RULE_PROJECT_MEMBER}) and ({RULE_DENY_CLUSTER_USER}))" + ), + deprecated_rule=DEPRECATED_DENY_CLUSTER_USER + ), + policy.RuleDefault( + name='admin_or_project_member_deny_cluster_user', + check_str=( + f"({RULE_ADMIN_API}) or ({RULE_PROJECT_MEMBER_DENY_CLUSTER_USER})" + ) + ), + policy.RuleDefault( + name='project_reader_deny_cluster_user', + check_str=( + f"(({RULE_PROJECT_READER}) and ({RULE_DENY_CLUSTER_USER}))" + ), + deprecated_rule=DEPRECATED_DENY_CLUSTER_USER + ), + policy.RuleDefault( + name='admin_or_project_reader_deny_cluster_user', + check_str=( + f"({RULE_ADMIN_API}) or ({RULE_PROJECT_READER_DENY_CLUSTER_USER})" + ) + ), + policy.RuleDefault( + name='admin_or_project_reader_user_or_cluster_user', + check_str=( + f"({RULE_ADMIN_API}) or (({RULE_PROJECT_READER}) and " + f"({RULE_USER_OR_CLUSTER_USER}))" + ), + deprecated_rule=DEPRECATED_RULE_ADMIN_OR_USER_OR_CLUSTER_USER + ), ] diff --git a/magnum/common/policies/certificate.py b/magnum/common/policies/certificate.py index 3d385754e8..97ac4cc737 100644 --- a/magnum/common/policies/certificate.py +++ b/magnum/common/policies/certificate.py @@ -16,13 +16,12 @@ from oslo_policy import policy from magnum.common.policies import base CERTIFICATE = 'certificate:%s' -RULE_ADMIN_OR_USER_OR_CLUSTER_USER = base.RULE_ADMIN_OR_USER + " or " + \ - base.RULE_CLUSTER_USER rules = [ policy.DocumentedRuleDefault( name=CERTIFICATE % 'create', - check_str=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER, + scope_types=["project"], description='Sign a new certificate by the CA.', operations=[ { @@ -33,7 +32,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CERTIFICATE % 'get', - check_str=RULE_ADMIN_OR_USER_OR_CLUSTER_USER, + check_str=base.RULE_ADMIN_OR_PROJECT_READER_USER_OR_CLUSTER_USER, + scope_types=["project"], description='Retrieve CA information about the given cluster.', operations=[ { @@ -44,7 +44,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CERTIFICATE % 'rotate_ca', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Rotate the CA certificate on the given cluster.', operations=[ { diff --git a/magnum/common/policies/cluster.py b/magnum/common/policies/cluster.py index 15b63226b2..9bcbf2dd20 100644 --- a/magnum/common/policies/cluster.py +++ b/magnum/common/policies/cluster.py @@ -20,7 +20,8 @@ CLUSTER = 'cluster:%s' rules = [ policy.DocumentedRuleDefault( name=CLUSTER % 'create', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Create a new cluster.', operations=[ { @@ -31,7 +32,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'delete', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Delete a cluster.', operations=[ { @@ -53,7 +55,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'detail', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of clusters with detail.', operations=[ { @@ -75,7 +78,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'get', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve information about the given cluster.', operations=[ { @@ -98,7 +102,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'get_all', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of clusters.', operations=[ { @@ -120,7 +125,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'update', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Update an existing cluster.', operations=[ { @@ -131,7 +137,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'update_health_status', - check_str=base.RULE_ADMIN_OR_USER + " or " + base.RULE_CLUSTER_USER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER_USER_OR_CLUSTER_USER, + scope_types=["project"], description='Update the health status of an existing cluster.', operations=[ { @@ -153,7 +160,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'resize', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Resize an existing cluster.', operations=[ { @@ -164,7 +172,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER % 'upgrade', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Upgrade an existing cluster.', operations=[ { diff --git a/magnum/common/policies/cluster_template.py b/magnum/common/policies/cluster_template.py index d9b51737ad..f6c19de0da 100644 --- a/magnum/common/policies/cluster_template.py +++ b/magnum/common/policies/cluster_template.py @@ -20,18 +20,20 @@ CLUSTER_TEMPLATE = 'clustertemplate:%s' rules = [ policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'create', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Create a new cluster template.', operations=[ { 'path': '/v1/clustertemplates', 'method': 'POST' } - ] + ], ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'delete', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Delete a cluster template.', operations=[ { @@ -65,7 +67,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'detail', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of cluster templates with detail.', operations=[ { @@ -76,7 +79,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'get', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve information about the given cluster template.', operations=[ { @@ -99,7 +103,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'get_all', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of cluster templates.', operations=[ { @@ -121,7 +126,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=CLUSTER_TEMPLATE % 'update', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Update an existing cluster template.', operations=[ { diff --git a/magnum/common/policies/federation.py b/magnum/common/policies/federation.py index b78b1a1b1e..24a65c235e 100644 --- a/magnum/common/policies/federation.py +++ b/magnum/common/policies/federation.py @@ -20,7 +20,8 @@ FEDERATION = 'federation:%s' rules = [ policy.DocumentedRuleDefault( name=FEDERATION % 'create', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Create a new federation.', operations=[ { @@ -31,7 +32,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=FEDERATION % 'delete', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Delete a federation.', operations=[ { @@ -42,7 +44,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=FEDERATION % 'detail', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of federations with detail.', operations=[ { @@ -53,7 +56,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=FEDERATION % 'get', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve information about the given federation.', operations=[ { @@ -64,7 +68,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=FEDERATION % 'get_all', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_READER_DENY_CLUSTER_USER, + scope_types=["project"], description='Retrieve a list of federations.', operations=[ { @@ -75,7 +80,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=FEDERATION % 'update', - check_str=base.RULE_DENY_CLUSTER_USER, + check_str=base.RULE_PROJECT_MEMBER_DENY_CLUSTER_USER, + scope_types=["project"], description='Update an existing federation.', operations=[ { diff --git a/magnum/common/policies/nodegroup.py b/magnum/common/policies/nodegroup.py index 64b2d670ea..25bad88579 100644 --- a/magnum/common/policies/nodegroup.py +++ b/magnum/common/policies/nodegroup.py @@ -24,7 +24,8 @@ NODEGROUP = 'nodegroup:%s' rules = [ policy.DocumentedRuleDefault( name=NODEGROUP % 'get', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_READER, + scope_types=["project"], description='Retrieve information about the given nodegroup.', operations=[ { @@ -35,7 +36,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=NODEGROUP % 'get_all', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_READER, + scope_types=["project"], description='Retrieve a list of nodegroups that belong to a cluster.', operations=[ { @@ -68,7 +70,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=NODEGROUP % 'create', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Create a new nodegroup.', operations=[ { @@ -79,7 +82,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=NODEGROUP % 'delete', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Delete a nodegroup.', operations=[ { @@ -90,7 +94,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=NODEGROUP % 'update', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_MEMBER, + scope_types=["project"], description='Update an existing nodegroup.', operations=[ { diff --git a/magnum/common/policies/quota.py b/magnum/common/policies/quota.py index 4baecf7d84..574857b1a4 100644 --- a/magnum/common/policies/quota.py +++ b/magnum/common/policies/quota.py @@ -42,7 +42,8 @@ rules = [ ), policy.DocumentedRuleDefault( name=QUOTA % 'get', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_READER, + scope_types=["project"], description='Retrieve Quota information for the given project_id.', operations=[ { diff --git a/magnum/common/policies/stats.py b/magnum/common/policies/stats.py index c37164094b..64996443b7 100644 --- a/magnum/common/policies/stats.py +++ b/magnum/common/policies/stats.py @@ -20,7 +20,8 @@ STATS = 'stats:%s' rules = [ policy.DocumentedRuleDefault( name=STATS % 'get_all', - check_str=base.RULE_ADMIN_OR_OWNER, + check_str=base.RULE_ADMIN_OR_PROJECT_READER, + scope_types=["project"], description='Retrieve magnum stats.', operations=[ { diff --git a/magnum/common/policy.py b/magnum/common/policy.py index d4bfff77b5..a79d371e56 100644 --- a/magnum/common/policy.py +++ b/magnum/common/policy.py @@ -17,6 +17,7 @@ import decorator from oslo_config import cfg +from oslo_log import log as logging from oslo_policy import opts from oslo_policy import policy from oslo_utils import importutils @@ -27,6 +28,7 @@ from magnum.common import exception from magnum.common import policies +LOG = logging.getLogger(__name__) _ENFORCER = None CONF = cfg.CONF @@ -105,8 +107,14 @@ def enforce(context, rule=None, target=None, target = {'project_id': context.project_id, 'user_id': context.user_id} add_policy_attributes(target) - return enforcer.enforce(rule, target, credentials, - do_raise=do_raise, exc=exc, *args, **kwargs) + + try: + result = enforcer.enforce(rule, target, credentials, + do_raise=do_raise, exc=exc, *args, **kwargs) + except policy.InvalidScope as ex: + LOG.debug(f"Invalid scope while enforce policy :{str(ex)}") + raise exc(action=rule) + return result def add_policy_attributes(target): diff --git a/magnum/tests/fakes.py b/magnum/tests/fakes.py index 4407975306..3a64078ce8 100644 --- a/magnum/tests/fakes.py +++ b/magnum/tests/fakes.py @@ -25,7 +25,7 @@ fakeAuthTokenHeaders = {'X-User-Id': u'773a902f022949619b5c2f32cd89d419', 'X-Roles': 'role1,role2', 'X-Auth-Url': 'fake_auth_url', 'X-Identity-Status': 'Confirmed', - 'X-User-Domain-Name': 'domain', + 'X-User-Domain-Name': 'user_domain_name', 'X-Project-Domain-Id': 'project_domain_id', 'X-User-Domain-Id': 'user_domain_id', 'OpenStack-API-Version': 'container-infra 1.0' diff --git a/magnum/tests/unit/api/base.py b/magnum/tests/unit/api/base.py index a4dd3fef63..ddf41277e4 100644 --- a/magnum/tests/unit/api/base.py +++ b/magnum/tests/unit/api/base.py @@ -128,6 +128,9 @@ class FunctionalTest(base.DbTestCase): with the request :param status: expected status code of response """ + # Provide member role for put request + if not headers: + headers = {"X-Roles": "member"} return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, @@ -146,6 +149,9 @@ class FunctionalTest(base.DbTestCase): with the request :param status: expected status code of response """ + # Provide member role for post request + if not headers: + headers = {"X-Roles": "member"} return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, @@ -164,6 +170,9 @@ class FunctionalTest(base.DbTestCase): with the request :param status: expected status code of response """ + # Provide member role for patch request + if not headers: + headers = {"X-Roles": "member"} return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, @@ -184,6 +193,9 @@ class FunctionalTest(base.DbTestCase): """ full_path = path_prefix + path print('DELETE: %s' % (full_path)) + # Provide member role for delete request + if not headers: + headers = {"X-Roles": "member"} response = self.app.delete(str(full_path), headers=headers, status=status, @@ -215,6 +227,10 @@ class FunctionalTest(base.DbTestCase): 'q.value': [], 'q.op': [], } + + # Provide reader role for get request + if not headers: + headers = {"X-Roles": "reader"} for query in q: for name in ['field', 'op', 'value']: query_params['q.%s' % name].append(query.get(name, '')) diff --git a/magnum/tests/unit/api/controllers/test_root.py b/magnum/tests/unit/api/controllers/test_root.py index 2430dc29d7..4c58f426de 100644 --- a/magnum/tests/unit/api/controllers/test_root.py +++ b/magnum/tests/unit/api/controllers/test_root.py @@ -132,7 +132,9 @@ class TestRootController(api_base.FunctionalTest): response = app.get('/v1/') self.assertEqual(self.v1_expected, response.json) - response = app.get('/v1/clustertemplates') + response = app.get('/v1/clustertemplates', + headers={"X-Roles": "reader"} + ) self.assertEqual(200, response.status_int) def test_auth_with_no_public_routes(self): diff --git a/magnum/tests/unit/api/controllers/v1/test_certificate.py b/magnum/tests/unit/api/controllers/v1/test_certificate.py index 77f27d4e79..db8ba75f91 100644 --- a/magnum/tests/unit/api/controllers/v1/test_certificate.py +++ b/magnum/tests/unit/api/controllers/v1/test_certificate.py @@ -21,7 +21,14 @@ from magnum.tests.unit.api import utils as api_utils from magnum.tests.unit.objects import utils as obj_utils -HEADERS = {'OpenStack-API-Version': 'container-infra latest'} +READER_HEADERS = { + 'OpenStack-API-Version': 'container-infra latest', + "X-Roles": "reader" +} +HEADERS = { + 'OpenStack-API-Version': 'container-infra latest', + "X-Roles": "member" +} class TestCertObject(base.TestCase): @@ -59,7 +66,7 @@ class TestGetCaCertificate(api_base.FunctionalTest): self.conductor_api.get_ca_certificate.return_value = mock_cert response = self.get_json('/certificates/%s' % self.cluster.uuid, - headers=HEADERS) + headers=READER_HEADERS) self.assertEqual(self.cluster.uuid, response['cluster_uuid']) self.assertEqual(fake_cert['csr'], response['csr']) @@ -72,7 +79,7 @@ class TestGetCaCertificate(api_base.FunctionalTest): self.conductor_api.get_ca_certificate.return_value = mock_cert response = self.get_json('/certificates/%s' % self.cluster.name, - headers=HEADERS) + headers=READER_HEADERS) self.assertEqual(self.cluster.uuid, response['cluster_uuid']) self.assertEqual(fake_cert['csr'], response['csr']) @@ -80,7 +87,8 @@ class TestGetCaCertificate(api_base.FunctionalTest): def test_get_one_by_name_not_found(self): response = self.get_json('/certificates/not_found', - expect_errors=True, headers=HEADERS) + expect_errors=True, + headers=READER_HEADERS) self.assertEqual(404, response.status_int) self.assertEqual('application/json', response.content_type) @@ -93,7 +101,8 @@ class TestGetCaCertificate(api_base.FunctionalTest): uuid=uuidutils.generate_uuid()) response = self.get_json('/certificates/test_cluster', - expect_errors=True, headers=HEADERS) + expect_errors=True, + headers=READER_HEADERS) self.assertEqual(409, response.status_int) self.assertEqual('application/json', response.content_type) @@ -106,7 +115,7 @@ class TestGetCaCertificate(api_base.FunctionalTest): self.conductor_api.get_ca_certificate.return_value = mock_cert response = self.get_json('/certificates/%s' % self.cluster.uuid, - headers=HEADERS) + headers=READER_HEADERS) self.assertIn('links', response.keys()) self.assertEqual(2, len(response['links'])) @@ -244,7 +253,7 @@ class TestCertPolicyEnforcement(api_base.FunctionalTest): self._common_policy_check( "certificate:get", self.get_json, '/certificates/%s' % cluster.uuid, - expect_errors=True, headers=HEADERS) + expect_errors=True, headers=READER_HEADERS) def test_policy_disallow_create(self): cluster = obj_utils.create_test_cluster(self.context) diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster.py b/magnum/tests/unit/api/controllers/v1/test_cluster.py index 3cf0767f10..a5d1256422 100755 --- a/magnum/tests/unit/api/controllers/v1/test_cluster.py +++ b/magnum/tests/unit/api/controllers/v1/test_cluster.py @@ -494,7 +494,9 @@ class TestPatch(api_base.FunctionalTest): '/clusters/%s/?rollback=True' % self.cluster_obj.uuid, [{'path': '/node_count', 'value': node_count, 'op': 'replace'}], - headers={'OpenStack-API-Version': 'container-infra 1.3'}) + headers={'OpenStack-API-Version': 'container-infra 1.3', + "X-Roles": "member" + }) self.mock_cluster_update.assert_called_once_with( mock.ANY, node_count, self.cluster_obj.health_status, @@ -507,7 +509,9 @@ class TestPatch(api_base.FunctionalTest): '/clusters/%s/?rollback=False' % self.cluster_obj.uuid, [{'path': '/node_count', 'value': node_count, 'op': 'replace'}], - headers={'OpenStack-API-Version': 'container-infra 1.3'}) + headers={'OpenStack-API-Version': 'container-infra 1.3', + "X-Roles": "member" + }) self.mock_cluster_update.assert_called_once_with( mock.ANY, node_count, self.cluster_obj.health_status, @@ -520,7 +524,9 @@ class TestPatch(api_base.FunctionalTest): '/clusters/%s' % self.cluster_obj.uuid, [{'path': '/node_count', 'value': node_count, 'op': 'replace'}], - headers={'OpenStack-API-Version': 'container-infra 1.9'}, + headers={'OpenStack-API-Version': 'container-infra 1.9', + "X-Roles": "member" + }, expect_errors=True) self.assertEqual(400, response.status_code) @@ -531,7 +537,9 @@ class TestPatch(api_base.FunctionalTest): '/clusters/%s' % self.cluster_obj.uuid, [{'path': '/node_count', 'value': node_count, 'op': 'replace'}], - headers={'OpenStack-API-Version': 'container-infra 1.10'}) + headers={'OpenStack-API-Version': 'container-infra 1.10', + "X-Roles": "member" + }) self.mock_cluster_update.assert_called_once_with( mock.ANY, node_count, self.cluster_obj.health_status, @@ -708,18 +716,24 @@ class TestPost(api_base.FunctionalTest): def test_create_cluster_with_zero_node_count_fail(self): bdict = apiutils.cluster_post_data() bdict['node_count'] = 0 - response = self.post_json('/clusters', bdict, expect_errors=True, - headers={"Openstack-Api-Version": - "container-infra 1.9"}) + response = self.post_json( + '/clusters', bdict, expect_errors=True, + headers={ + "Openstack-Api-Version": "container-infra 1.9", + "X-Roles": "member" + }) self.assertEqual('application/json', response.content_type) self.assertEqual(400, response.status_int) def test_create_cluster_with_zero_node_count(self): bdict = apiutils.cluster_post_data() bdict['node_count'] = 0 - response = self.post_json('/clusters', bdict, - headers={"Openstack-Api-Version": - "container-infra 1.10"}) + response = self.post_json( + '/clusters', bdict, + headers={ + "Openstack-Api-Version": "container-infra 1.10", + "X-Roles": "member" + }) self.assertEqual('application/json', response.content_type) self.assertEqual(202, response.status_int) diff --git a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py index ba9304fe1b..22baf556ce 100644 --- a/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py +++ b/magnum/tests/unit/api/controllers/v1/test_cluster_actions.py @@ -46,7 +46,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, {"node_count": new_node_count}, headers={"Openstack-Api-Version": - "container-infra 1.7"}) + "container-infra 1.7", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) response = self.get_json('/clusters/%s' % self.cluster_obj.uuid) @@ -69,7 +70,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}) + "container-infra 1.9", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) response = self.get_json('/clusters/%s' % self.cluster_obj.uuid) @@ -89,7 +91,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(400, response.status_code) @@ -106,7 +109,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(400, response.status_code) @@ -123,7 +127,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(400, response.status_code) @@ -140,7 +145,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(400, response.status_code) @@ -157,7 +163,8 @@ class TestClusterResize(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_resize_req, headers={"Openstack-Api-Version": - "container-infra 1.10"}) + "container-infra 1.10", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) @@ -195,7 +202,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.8"}) + "container-infra 1.8", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) def test_upgrade_cluster_as_admin(self): @@ -226,7 +234,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): '/clusters/%s/actions/upgrade' % cluster_uuid, cluster_upgrade_req, - headers={"Openstack-Api-Version": "container-infra 1.8"}) + headers={"Openstack-Api-Version": "container-infra 1.8", + "X-Roles": "member"}) self.assertEqual(202, response.status_int) @@ -239,7 +248,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}) + "container-infra 1.9", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) def test_upgrade_default_master(self): @@ -251,7 +261,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}) + "container-infra 1.9", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) def test_upgrade_non_default_ng(self): @@ -263,7 +274,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}) + "container-infra 1.9", + "X-Roles": "member"}) self.assertEqual(202, response.status_code) def test_upgrade_cluster_not_found(self): @@ -273,7 +285,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): response = self.post_json('/clusters/not_there/actions/upgrade', cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.8"}, + "container-infra 1.8", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(404, response.status_code) @@ -285,7 +298,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.8"}, + "container-infra 1.8", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(404, response.status_code) @@ -298,7 +312,8 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(404, response.status_code) @@ -311,6 +326,7 @@ class TestClusterUpgrade(api_base.FunctionalTest): self.cluster_obj.uuid, cluster_upgrade_req, headers={"Openstack-Api-Version": - "container-infra 1.9"}, + "container-infra 1.9", + "X-Roles": "member"}, expect_errors=True) self.assertEqual(409, response.status_code) diff --git a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py index a6f73d54b2..68304a10f6 100644 --- a/magnum/tests/unit/api/controllers/v1/test_nodegroup.py +++ b/magnum/tests/unit/api/controllers/v1/test_nodegroup.py @@ -47,24 +47,26 @@ class TestNodegroupObject(base.TestCase): class NodeGroupControllerTest(api_base.FunctionalTest): headers = {"Openstack-Api-Version": "container-infra latest"} - def _add_headers(self, kwargs): + def _add_headers(self, kwargs, roles=None): if 'headers' not in kwargs: kwargs['headers'] = self.headers + if roles: + kwargs['headers']['X-Roles'] = ",".join(roles) def get_json(self, *args, **kwargs): - self._add_headers(kwargs) + self._add_headers(kwargs, roles=['reader']) return super(NodeGroupControllerTest, self).get_json(*args, **kwargs) def post_json(self, *args, **kwargs): - self._add_headers(kwargs) + self._add_headers(kwargs, roles=['member']) return super(NodeGroupControllerTest, self).post_json(*args, **kwargs) def delete(self, *args, **kwargs): - self._add_headers(kwargs) + self._add_headers(kwargs, roles=['member']) return super(NodeGroupControllerTest, self).delete(*args, **kwargs) def patch_json(self, *args, **kwargs): - self._add_headers(kwargs) + self._add_headers(kwargs, roles=['member']) return super(NodeGroupControllerTest, self).patch_json(*args, **kwargs) diff --git a/magnum/tests/unit/api/controllers/v1/test_quota.py b/magnum/tests/unit/api/controllers/v1/test_quota.py index b6b47c481a..07e78857ed 100644 --- a/magnum/tests/unit/api/controllers/v1/test_quota.py +++ b/magnum/tests/unit/api/controllers/v1/test_quota.py @@ -207,7 +207,7 @@ class TestQuota(api_base.FunctionalTest): project_id="proj-id-"+str(i)) quota_list.append(quota) - headers = {'X-Project-Id': 'proj-id-2'} + headers = {'X-Project-Id': 'proj-id-2', "X-Roles": "member"} response = self.get_json('/quotas', headers=headers) self.assertEqual(1, len(response['quotas'])) self.assertEqual('proj-id-2', response['quotas'][0]['project_id']) diff --git a/magnum/tests/unit/api/controllers/v1/test_stats.py b/magnum/tests/unit/api/controllers/v1/test_stats.py index bb7aac28f4..2e41222d34 100644 --- a/magnum/tests/unit/api/controllers/v1/test_stats.py +++ b/magnum/tests/unit/api/controllers/v1/test_stats.py @@ -21,7 +21,14 @@ from magnum.tests.unit.objects import utils as obj_utils class TestStatsController(api_base.FunctionalTest): def setUp(self): - self.base_headers = {'OpenStack-API-Version': 'container-infra 1.4'} + self.base_headers = { + "X-Roles": "reader", + "OpenStack-API-Version": "container-infra 1.4" + } + self.base_admin_headers = { + "X-Roles": "admin", + "OpenStack-API-Version": "container-infra 1.4" + } super(TestStatsController, self).setUp() obj_utils.create_test_cluster_template(self.context) @@ -39,7 +46,7 @@ class TestStatsController(api_base.FunctionalTest): obj_utils.create_test_cluster(self.context, project_id=234, uuid='uuid2') - response = self.get_json('/stats', headers=self.base_headers) + response = self.get_json('/stats', headers=self.base_admin_headers) expected = {u'clusters': 2, u'nodes': 12} self.assertEqual(expected, response) @@ -54,7 +61,7 @@ class TestStatsController(api_base.FunctionalTest): uuid='uuid2') self.context.is_admin = True response = self.get_json('/stats?project_id=234', - headers=self.base_headers) + headers=self.base_admin_headers) expected = {u'clusters': 1, u'nodes': 6} self.assertEqual(expected, response) @@ -69,7 +76,7 @@ class TestStatsController(api_base.FunctionalTest): uuid='uuid2') self.context.is_admin = True response = self.get_json('/stats?project_id=34', - headers=self.base_headers) + headers=self.base_admin_headers) expected = {u'clusters': 0, u'nodes': 0} self.assertEqual(expected, response) diff --git a/magnum/tests/unit/api/test_hooks.py b/magnum/tests/unit/api/test_hooks.py index 9332c93120..3cbfde4363 100644 --- a/magnum/tests/unit/api/test_hooks.py +++ b/magnum/tests/unit/api/test_hooks.py @@ -34,7 +34,8 @@ class TestContextHook(base.BaseTestCase): super(TestContextHook, self).setUp() self.app = fakes.FakeApp() - def test_context_hook_before_method(self): + @mock.patch("magnum.common.policy.check_is_admin") + def test_context_hook_before_method(self, m_c): state = mock.Mock(request=fakes.FakePecanRequest()) hook = hooks.ContextHook() hook.before(state) @@ -51,12 +52,13 @@ class TestContextHook(base.BaseTestCase): self.assertEqual(fakes.fakeAuthTokenHeaders['X-Roles'], ','.join(ctx.roles)) self.assertEqual(fakes.fakeAuthTokenHeaders['X-User-Domain-Name'], - ctx.domain_name) + ctx.user_domain_name) self.assertEqual(fakes.fakeAuthTokenHeaders['X-User-Domain-Id'], - ctx.domain_id) + ctx.user_domain_id) self.assertIsNone(ctx.auth_token_info) - def test_context_hook_before_method_auth_info(self): + @mock.patch("magnum.common.policy.check_is_admin") + def test_context_hook_before_method_auth_info(self, c_m): state = mock.Mock(request=fakes.FakePecanRequest()) state.request.environ['keystone.token_info'] = 'assert_this' hook = hooks.ContextHook() diff --git a/magnum/tests/unit/common/test_context.py b/magnum/tests/unit/common/test_context.py index c72c2c763d..aed4d33ebd 100644 --- a/magnum/tests/unit/common/test_context.py +++ b/magnum/tests/unit/common/test_context.py @@ -19,29 +19,30 @@ from magnum.tests import base class ContextTestCase(base.TestCase): def _create_context(self, roles=None): - return magnum_context.RequestContext(auth_token='auth_token1', - auth_url='auth_url1', - domain_id='domain_id1', - domain_name='domain_name1', - user_name='user1', - user_id='user-id1', - project_name='tenant1', - project_id='tenant-id1', - roles=roles, - is_admin=True, - read_only=True, - show_deleted=True, - request_id='request_id1', - trust_id='trust_id1', - auth_token_info='token_info1') + return magnum_context.RequestContext( + auth_token='auth_token1', + auth_url='auth_url1', + user_domain_id='user_domain_id1', + user_domain_name='user_domain_name1', + user_name='user1', + user_id='user-id1', + project_name='tenant1', + project_id='tenant-id1', + roles=roles, + is_admin=True, + read_only=True, + show_deleted=True, + request_id='request_id1', + trust_id='trust_id1', + auth_token_info='token_info1') def test_context(self): ctx = self._create_context() self.assertEqual("auth_token1", ctx.auth_token) self.assertEqual("auth_url1", ctx.auth_url) - self.assertEqual("domain_id1", ctx.domain_id) - self.assertEqual("domain_name1", ctx.domain_name) + self.assertEqual("user_domain_id1", ctx.user_domain_id) + self.assertEqual("user_domain_name1", ctx.user_domain_name) self.assertEqual("user1", ctx.user_name) self.assertEqual("user-id1", ctx.user_id) self.assertEqual("tenant1", ctx.project_name) @@ -59,8 +60,8 @@ class ContextTestCase(base.TestCase): self.assertEqual("auth_token1", ctx.auth_token) self.assertEqual("auth_url1", ctx.auth_url) - self.assertEqual("domain_id1", ctx.domain_id) - self.assertEqual("domain_name1", ctx.domain_name) + self.assertEqual("user_domain_id1", ctx.user_domain_id) + self.assertEqual("user_domain_name1", ctx.user_domain_name) self.assertEqual("user1", ctx.user_name) self.assertEqual("user-id1", ctx.user_id) self.assertEqual("tenant1", ctx.project_name) @@ -80,8 +81,8 @@ class ContextTestCase(base.TestCase): self.assertEqual(ctx.auth_token, ctx2.auth_token) self.assertEqual(ctx.auth_url, ctx2.auth_url) - self.assertEqual(ctx.domain_id, ctx2.domain_id) - self.assertEqual(ctx.domain_name, ctx2.domain_name) + self.assertEqual(ctx.user_domain_id, ctx2.user_domain_id) + self.assertEqual(ctx.user_domain_name, ctx2.user_domain_name) self.assertEqual(ctx.user_name, ctx2.user_name) self.assertEqual(ctx.user_id, ctx2.user_id) self.assertEqual(ctx.project_id, ctx2.project_id) diff --git a/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml b/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml new file mode 100644 index 0000000000..cfb9813b08 --- /dev/null +++ b/releasenotes/notes/enable-enforce-scope-and-new-defaults-7e6e503f74283071.yaml @@ -0,0 +1,13 @@ +--- +upgrade: + - | + The Magnum service now allows enables policies (RBAC) new defaults + and scope checks. These are controlled by the following (default) config + options in ``magnum.conf`` file:: + + [oslo_policy] + enforce_new_defaults=False + enforce_scope=False + + We will change the default to True in 2024.1 (Caracal) cycle. + If you want to enable them then modify both values to True. diff --git a/requirements.txt b/requirements.txt index ce2fc712d0..4efe391fc0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -28,10 +28,10 @@ oslo.config>=8.1.0 # Apache-2.0 oslo.context>=3.1.0 # Apache-2.0 oslo.db>=8.2.0 # Apache-2.0 oslo.i18n>=5.0.0 # Apache-2.0 -oslo.log>=4.2.0 # Apache-2.0 +oslo.log>=4.8.0 # Apache-2.0 oslo.messaging>=14.1.0 # Apache-2.0 oslo.middleware>=4.1.0 # Apache-2.0 -oslo.policy>=3.6.0 # Apache-2.0 +oslo.policy>=3.11.0 # Apache-2.0 oslo.reports>=2.1.0 # Apache-2.0 oslo.serialization>=3.2.0 # Apache-2.0 oslo.service>=2.2.0 # Apache-2.0