Update the task policies

At one point, these policies were used to protect actual task API
endpoints. Since then, they have also been used internally within
glance when spawning a task on behalf of the user for long-running
operations (like import).

These policies should not apply to the internal usage, as doing so
prevents the operator from setting them to restrictive values in order
to provide granular access to some roles. In the future we will fix
that by moving those checks out of "the onion" and into the task API
operations themselves, thus decoupling the internal and external uses.

This adds documentation and scope definitions for these policies, as
well as deprecates the "modify_task" policy which is never used and
will be removed in the future. Control over the actual tasks API
remains coarse with the "tasks_api_access" policy until a future
release completes the above decoupling.

Implements: blueprint secure-rbac
Change-Id: I70a58acd78053b54187dba8e35273366f14c47a4
This commit is contained in:
Lance Bragstad 2021-02-25 22:22:20 +00:00 committed by Dan Smith
parent 31414b9f61
commit 165cce6d6e
2 changed files with 85 additions and 5 deletions

View File

@ -449,14 +449,17 @@ class TaskRepoProxy(glance.domain.proxy.TaskRepo):
task_proxy_class=TaskProxy, task_proxy_class=TaskProxy,
task_proxy_kwargs=proxy_kwargs) task_proxy_kwargs=proxy_kwargs)
# TODO(lbragstad): Move this to the tasks api itself
def get(self, task_id): def get(self, task_id):
self.policy.enforce(self.context, 'get_task', {}) self.policy.enforce(self.context, 'get_task', {})
return super(TaskRepoProxy, self).get(task_id) return super(TaskRepoProxy, self).get(task_id)
# TODO(lbragstad): Move this to the tasks api itself
def add(self, task): def add(self, task):
self.policy.enforce(self.context, 'add_task', {}) self.policy.enforce(self.context, 'add_task', {})
super(TaskRepoProxy, self).add(task) super(TaskRepoProxy, self).add(task)
# TODO(lbragstad): Remove this after Xena
def save(self, task): def save(self, task):
self.policy.enforce(self.context, 'modify_task', {}) self.policy.enforce(self.context, 'modify_task', {})
super(TaskRepoProxy, self).save(task) super(TaskRepoProxy, self).save(task)

View File

@ -10,15 +10,92 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_log import versionutils
from oslo_policy import policy from oslo_policy import policy
TASK_DESCRIPTION = """
This granular policy controls access to tasks, both from the tasks API as well
as internal locations in Glance that use tasks (like import). Practically this
cannot be more restrictive than the policy that controls import or things will
break, and changing it from the default is almost certainly not what you want.
Access to the external tasks API should be restricted as desired by the
tasks_api_access policy. This may change in the future.
"""
MODIFY_TASK_DEPRECATION = """
This policy check has never been honored by the API. It will be removed in a
future release.
"""
TASK_ACCESS_DESCRIPTION = """
This is a generic blanket policy for protecting all task APIs. It is not
granular and will not allow you to separate writable and readable task
operations into different roles.
"""
task_policies = [ task_policies = [
policy.RuleDefault(name="get_task", check_str="rule:default"), policy.DocumentedRuleDefault(
policy.RuleDefault(name="get_tasks", check_str="rule:default"), name="get_task",
policy.RuleDefault(name="add_task", check_str="rule:default"), # All policies except tasks_api_access are internal policies that are
policy.RuleDefault(name="modify_task", check_str="rule:default"), # only called by glance as a result of some other operation.
policy.RuleDefault(name="tasks_api_access", check_str="role:admin"), check_str='rule:default',
scope_types=['system', 'project'],
description='Get an image task.\n' + TASK_DESCRIPTION,
operations=[
{'path': '/v2/tasks/{task_id}',
'method': 'GET'}
],
),
policy.DocumentedRuleDefault(
name="get_tasks",
check_str='rule:default',
scope_types=['system', 'project'],
description='List tasks for all images.\n' + TASK_DESCRIPTION,
operations=[
{'path': '/v2/tasks',
'method': 'GET'}
],
),
policy.DocumentedRuleDefault(
name="add_task",
check_str='rule:default',
scope_types=['system', 'project'],
description='List tasks for all images.\n' + TASK_DESCRIPTION,
operations=[
{'path': '/v2/tasks',
'method': 'POST'}
],
),
policy.DocumentedRuleDefault(
name="modify_task",
check_str='rule:default',
scope_types=['system', 'project'],
description="This policy is not used.",
operations=[
{'path': '/v2/tasks/{task_id}',
'method': 'DELETE'}
],
deprecated_for_removal=True,
deprecated_reason=MODIFY_TASK_DEPRECATION,
deprecated_since=versionutils.deprecated.WALLABY,
),
policy.DocumentedRuleDefault(
name="tasks_api_access",
check_str="role:admin",
scope_types=['system', 'project'],
description=TASK_ACCESS_DESCRIPTION,
operations=[
{'path': '/v2/tasks/{task_id}',
'method': 'GET'},
{'path': '/v2/tasks',
'method': 'GET'},
{'path': '/v2/tasks',
'method': 'POST'},
{'path': '/v2/tasks/{task_id}',
'method': 'DELETE'}
],
)
] ]