diff --git a/octavia/common/constants.py b/octavia/common/constants.py index 9325850d0a..c4f383591e 100644 --- a/octavia/common/constants.py +++ b/octavia/common/constants.py @@ -768,6 +768,10 @@ RULE_API_READ_QUOTA = 'rule:load-balancer:read-quota' RULE_API_READ_QUOTA_GLOBAL = 'rule:load-balancer:read-quota-global' RULE_API_WRITE_QUOTA = 'rule:load-balancer:write-quota' +# The service user for Aodh needs to be able to list all +# members of a pool to determine which are healthy. +RULE_MEMBER_API_READ = f'{RULE_API_READ} or rule:service' + RBAC_LOADBALANCER = f'{LOADBALANCER_API}:loadbalancer:' RBAC_LISTENER = f'{LOADBALANCER_API}:listener:' RBAC_POOL = f'{LOADBALANCER_API}:pool:' diff --git a/octavia/policies/keystone_default_roles.py b/octavia/policies/keystone_default_roles.py index 6aee011114..b3f8c557a8 100644 --- a/octavia/policies/keystone_default_roles.py +++ b/octavia/policies/keystone_default_roles.py @@ -51,6 +51,11 @@ rules = [ # auth_strategy == noauth configuration setting. # It is equivalent to 'rule:context_is_admin or {auth_strategy == noauth}' + policy.RuleDefault( + name='service', + check_str='role:service', + scope_types=[constants.RBAC_SCOPE_PROJECT]), + policy.RuleDefault( name='load-balancer:global_observer', check_str='role:admin', diff --git a/octavia/policies/member.py b/octavia/policies/member.py index 6cae417e47..e6b98a467e 100644 --- a/octavia/policies/member.py +++ b/octavia/policies/member.py @@ -18,7 +18,7 @@ from octavia.common import constants rules = [ policy.DocumentedRuleDefault( f'{constants.RBAC_MEMBER}{constants.RBAC_GET_ALL}', - constants.RULE_API_READ, + constants.RULE_MEMBER_API_READ, "List Members of a Pool", [{'method': 'GET', 'path': '/v2/lbaas/pools/{pool_id}/members'}] ), diff --git a/octavia/tests/functional/api/v2/test_member.py b/octavia/tests/functional/api/v2/test_member.py index a67f837489..db902f6588 100644 --- a/octavia/tests/functional/api/v2/test_member.py +++ b/octavia/tests/functional/api/v2/test_member.py @@ -169,7 +169,7 @@ class TestMember(base.BaseAPITest): objects = response.json.get(self.root_tag_list) self.assertEqual(len(objects), 0) - def test_get_all_authorized(self): + def _test_get_all_authorized(self, roles, project_id): api_m_1 = self.create_member( self.pool_id, '192.0.2.1', 80).get(self.root_tag) self.set_lb_status(self.lb_id) @@ -195,13 +195,13 @@ class TestMember(base.BaseAPITest): 'is_admin_project': True, 'service_project_domain_id': None, 'service_project_id': None, - 'roles': ['load-balancer_member', 'member'], + 'roles': roles, 'user_id': None, 'is_admin': False, 'service_user_domain_id': None, 'project_domain_id': None, 'service_roles': [], - 'project_id': self.project_id} + 'project_id': project_id} with mock.patch( "oslo_context.context.RequestContext.to_policy_values", return_value=override_credentials): @@ -216,6 +216,15 @@ class TestMember(base.BaseAPITest): for m in [api_m_1, api_m_2]: self.assertIn(m, response) + def test_get_all_authorized(self): + self._test_get_all_authorized( + roles=['load-balancer_member', 'member'], + project_id=self.project_id) + + def test_get_all_authorized_service(self): + self._test_get_all_authorized( + roles=['service'], project_id='services') + def test_get_all_unscoped_token(self): api_m_1 = self.create_member( self.pool_id, '192.0.2.1', 80).get(self.root_tag) diff --git a/releasenotes/notes/aodh-service-api-5c485a172d76fa1a.yaml b/releasenotes/notes/aodh-service-api-5c485a172d76fa1a.yaml new file mode 100644 index 0000000000..abf38994b9 --- /dev/null +++ b/releasenotes/notes/aodh-service-api-5c485a172d76fa1a.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + The ``service`` role now has access to list members in + a pool, this is needed by Aodh to evaluate unhealthy + members in a pool when doing evaluations.