Files
glance/glance/policies/base.py
T
Ghanshyam Maan 301d8f580f Fix glance service policy rule
Glance service APIs are default to 'service_roles: service'

- https://github.com/openstack/glance/blob/6c33a667a9f5ddce07b6131f4a5cb7460a4bdf17/glance/policies/base.py#L116

The issue here is the service token, which is sent from the
service for the user token expiry case but glance uses that
service token (keystonemiddleware sets the service token roles
in Requestcontext in 'service_roles' field) for RBAC, which
is not correct.

The OpenStack services communicate with each other by
passing the user token and service token wrapped in
keystoneauth's ServiceTokenAuthWrapper. The only purpose
of passing the service token is for long-running
operations and in case the user token gets expired.

For RBAC, we need to check if a user token has the 'service'
role or not. Service needs to load the configured user auth
plugin (where the user should have the 'service' role) from
keystoneauth and pass that to the other services (for example,
cinder change depends-on) and glance will use that user role
to verify the policy permission. To fix that, we need to make
the service APIs default to ``role:service`` and not
`service_role`:`service`.

This commit does one more change. Cinder does not have the
way to configure the glance service user, we are adding the
new config in this release. For backward compatibility,
we need to allow admin access in service policy rule. In
future release (after one SLURP release), we cna remove
the admin access.

Closes-Bug: #2121622

Co-Authored-By: : Sean Mooney <work@seanmooney.info>

Change-Id: I50909e6bdb3227ca99b7eba642546da791f9552a
Signed-off-by: Sean Mooney <work@seanmooney.info>
Signed-off-by: Ghanshyam Maan <gmaan@ghanshyammann.com>
2025-09-12 08:57:01 +00:00

129 lines
5.6 KiB
Python

# 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
# Generic check string for checking if a user is authorized on a particular
# project, specifically with the member role.
PROJECT_MEMBER = 'role:member and project_id:%(project_id)s'
# 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.
PROJECT_READER = 'role:reader and project_id:%(project_id)s'
# Make sure the member_id of the supplied target matches the project_id from
# the context object, which is derived from keystone tokens.
IMAGE_MEMBER_CHECK = 'project_id:%(member_id)s'
# Check if the visibility of the image supplied in the target matches
# "community"
COMMUNITY_VISIBILITY_CHECK = "'community':%(visibility)s"
# Check if the visibility of the resource supplied in the target matches
# "public"
PUBLIC_VISIBILITY_CHECK = "'public':%(visibility)s"
# Check if the visibility of the image supplied in the target matches "shared"
SHARED_VISIBILITY_CHECK = "'shared':%(visibility)s"
PROJECT_MEMBER_OR_IMAGE_MEMBER_OR_COMMUNITY_OR_PUBLIC_OR_SHARED = (
f'role:member and (project_id:%(project_id)s or {IMAGE_MEMBER_CHECK} '
f'or {COMMUNITY_VISIBILITY_CHECK} or {PUBLIC_VISIBILITY_CHECK} '
f'or {SHARED_VISIBILITY_CHECK})'
)
PROJECT_READER_OR_IMAGE_MEMBER_OR_COMMUNITY_OR_PUBLIC_OR_SHARED = (
f'role:reader and (project_id:%(project_id)s or {IMAGE_MEMBER_CHECK} '
f'or {COMMUNITY_VISIBILITY_CHECK} or {PUBLIC_VISIBILITY_CHECK} '
f'or {SHARED_VISIBILITY_CHECK})'
)
PROJECT_READER_OR_PUBLIC_NAMESPACE = (
f'role:reader and (project_id:%(project_id)s or {PUBLIC_VISIBILITY_CHECK})'
)
# FIXME(lbragstad): These are composite check strings that represents glance's
# authorization code, some of which is implemented in the authorization wrapper
# and some is in the database driver.
#
# These check strings do not support tenancy with the `admin` role. This means
# anyone with the `admin` role on any project can execute a policy, which is
# typical in OpenStack services. But following check strings offer formal
# support for project membership and a read-only variant consistent with
# other OpenStack services.
ADMIN = 'rule:context_is_admin'
DEFAULT = 'rule:default'
ADMIN_OR_PROJECT_MEMBER = f'{ADMIN} or ({PROJECT_MEMBER})'
ADMIN_OR_PROJECT_READER = f'{ADMIN} or ({PROJECT_READER})'
ADMIN_OR_PROJECT_READER_GET_IMAGE = (
f'{ADMIN} or '
f'({PROJECT_READER_OR_IMAGE_MEMBER_OR_COMMUNITY_OR_PUBLIC_OR_SHARED})'
)
ADMIN_OR_PROJECT_MEMBER_DOWNLOAD_IMAGE = (
f'{ADMIN} or '
f'({PROJECT_MEMBER_OR_IMAGE_MEMBER_OR_COMMUNITY_OR_PUBLIC_OR_SHARED})'
)
ADMIN_OR_PROJECT_MEMBER_CREATE_IMAGE = (
f'{ADMIN} or ({PROJECT_MEMBER} and project_id:%(owner)s)'
)
ADMIN_OR_PROJECT_READER_GET_NAMESPACE = (
f'{ADMIN} or ({PROJECT_READER_OR_PUBLIC_NAMESPACE})'
)
ADMIN_OR_SHARED_MEMBER = (
f'{ADMIN} or (role:member and {IMAGE_MEMBER_CHECK})'
)
ADMIN_OR_PROJECT_READER_OR_SHARED_MEMBER = (
f'{ADMIN} or '
f'role:reader and (project_id:%(project_id)s or {IMAGE_MEMBER_CHECK})'
)
SERVICE_OR_PROJECT_MEMBER = (
f'rule:service_api or ({PROJECT_MEMBER} and project_id:%(owner)s)'
)
SERVICE = 'rule:service_api'
ADMIN_OR_SERVICE_ROLE = f'{ADMIN} or {SERVICE}'
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.',
deprecated_rule=policy.DeprecatedRule(
name='default',
check_str=ADMIN,
deprecated_reason='In order to allow operators to '
'accept the default policies from code by not '
'defining them in the policy file, while still '
'working with old policy files that rely on the '
'``default`` rule for policies that are '
'not specified in the policy file, the ``default`` '
'rule must now be explicitly set to '
'``"role:admin"`` when that is the desired default '
'for unspecified rules.',
deprecated_since='Ussuri')),
policy.RuleDefault(name='context_is_admin', check_str='role:admin',
description='Defines the rule for the is_admin:True '
'check.'),
# TODO(gmaan): The admin role access is added for backward compatibility
# because some services does not send the service role token to glance.
# Remove the admin role access from service rule in 2026.2 or later(after
# 2026.1 SLURP release).
policy.RuleDefault(name='service_api',
check_str='role:service or role:admin',
description='Default rule for the service-to-service '
'API.'),
]
def list_rules():
return rules