Implement configurator role RBAC for sysinv API

A RBAC for configurator role is implemented using oslo policy(see
https://docs.openstack.org/neutron/pike/admin/config-rbac.html
https://docs.openstack.org/oslo.policy/latest/user/usage.html#
when-using-oslo-policy)

The new configurator role will have the same privileges as admin
role but blocked access to the following commands
	system ca-certificate-install
        system ca-certificate-uninstall
        system os-certificate-install

the base rules are changed to accommodate the configurator role,
enforce policy implemented for the certificate controller, also
fixed a bug to show forbidden access text on cli when a
configurator role user executes "system ca-certificate-install",
"system os-certificate-install" commands.

PASS: verify execution of following commands is denied for
      configurator role user
	system ca-certificate-install
        system ca-certificate-uninstall
        system os-certificate-install
PASS: execute the following commands as configurator,operator,admin
      role user and expect it to work
       system host-lock / host-unlock
       system host-swact
       system host-power-off / host-power-on
       system host-reboot / host-reset
       system host-update "id" "path=value"
       system host-reinstall "id"
       system host-ptp-instance-assign/host-ptp-instance-remove
       system registry-garbage-collect
PASS: execute the following commands as reader role user and expect
      access denied
       system host-lock / host-unlock
       system host-swact
       system host-power-off / host-power-on
       system host-reboot / host-reset
       system host-update "id" "path=value"
       system host-reinstall "id"
       system host-ptp-instance-assign/host-ptp-instance-remove
       system registry-garbage-collect
PASS: execute the following as configurator,admin,reader,operator
      role user and expect it to work
	system host-list
	system registry-image-list
        system service-parameter-list
PASS: verify that only admin,configurator role user is allowed to
      execute the following
	system registry-image-delete
        system host-delete
PASS: verify that only admin,configurator role user is allowed to
      execute the following
	system service-parameter-add
        system service-parameter-delete
        system service-parameter-apply
PASS: verify access to openstack commands are blocked for
      configurator role user

Story: 2011348
Task: 51956

Change-Id: I779aa473c70abfb5fbd80f0138e9e340cf953d19
Signed-off-by: amantri <ayyappa.mantri@windriver.com>
This commit is contained in:
amantri 2025-04-09 11:24:30 -04:00
parent a6d42645f8
commit fe2fa8135f
10 changed files with 211 additions and 48 deletions

View File

@ -57,6 +57,9 @@ def _install_cert(cc, certificate_file, data):
try:
response = cc.certificate.certificate_install(sec_file, data=data)
err_msg = response.get('error_message')
if err_msg:
raise exc.HTTPForbidden(err_msg)
except exc.HTTPNotFound:
raise exc.CommandError('Certificate not installed %s. No response.' %
certificate_file)

View File

@ -1,23 +1,80 @@
---
# The commented lines below contains the default values for presented rules.
# admin role of admin,services projects
# "admin": "role:admin and (project_name:admin or project_name:services)"
# admin_in_system_projects: role:admin and (project_name:admin or project_name:services)
# reader_or_operator_in_system_projects: (role:reader or role:operator) and
# (project_name:admin or project_name:services)
# admin_or_operator_in_system_projects: (role:admin or role:operator) and
# (project_name:admin or project_name:services)
# admin,configurator roles of admin,services projects
# "admin_or_configurator": "(role:admin or role:configurator) and
# (project_name:admin or project_name:services)"
# config_api:service_parameter:add: rule:admin_in_system_projects
# config_api:service_parameter:apply: rule:admin_in_system_projects
# config_api:service_parameter:delete: rule:admin_in_system_projects
# config_api:service_parameter:get: rule:reader_or_operator_in_system_projects
# config_api:service_parameter:modify: rule:admin_or_operator_in_system_projects
# admin,operator,configurator roles of admin,services projects
# "admin_or_operator_or_configurator": "(role:admin or role:operator or
# role:configurator) and (project_name:admin or project_name:services)"
# config_api:ihosts:add: rule:admin_in_system_projects
# config_api:ihosts:delete: rule:admin_in_system_projects
# config_api:ihosts:get: rule:reader_or_operator_in_system_projects
# config_api:ihosts:modify: rule:admin_or_operator_in_system_projects
# reader,operator,configurator roles of admin,services projects
# "reader_or_operator_or_configurator": "(role:reader or role:operator or
# role:configurator) and (project_name:admin or project_name:services)"
# config_api:registry_image:add: rule:admin_or_operator_in_system_projects
# config_api:registry_image:delete: rule:admin_in_system_projects
# config_api:registry_image:get: "rule:reader_or_operator_in_system_projects
# Add a Service Parameter.
# POST /v1/service_parameter
# "config_api:service_parameter:add": "rule:admin_or_configurator"
# Apply Service Parameters.
# POST /v1/service_parameter/apply
# "config_api:service_parameter:apply": "rule:admin_or_configurator"
# Delete a Service Parameter.
# DELETE /v1/service_parameter/{parameter_id}
# "config_api:service_parameter:delete": "rule:admin_or_configurator"
# Get Service Parameters.
# GET /v1/service_parameter
# GET /v1/service_parameter/{parameter_id}
# "config_api:service_parameter:get": "rule:reader_or_operator_or_configurator"
# Modify Service Parameter value.
# PATCH /v1/service_parameter/{parameter_id}
# "config_api:service_parameter:modify": "rule:admin_or_configurator"
# Add a host Parameter.
# POST /v1/ihosts
# "config_api:ihosts:post": "rule:admin_or_configurator"
# Delete a host Parameter.
# DELETE /v1/ihosts/{parameter_id}
# "config_api:ihosts:delete": "rule:admin_or_configurator"
# Get host Parameters.
# GET /v1/ihosts
# GET /v1/ihosts/{parameter_id}
# "config_api:ihosts:get": "rule:reader_or_operator_or_configurator"
# Modify host value.
# PATCH /v1/ihosts/{parameter_id}
# "config_api:ihosts:patch": "rule:admin_or_operator_or_configurator"
# Run registry garbage collect.
# POST /v1/registry_image
# "config_api:registry_image:add": "rule:admin_or_operator_or_configurator"
# Delete a registry image.
# DELETE /v1/registry_image
# "config_api:registry_image:delete": "rule:admin_or_configurator"
# Get registry images list.
# GET /v1/registry_image
# "config_api:registry_image:get": "rule:reader_or_operator_or_configurator"
# Get certificate
# GET /v1/certificate
# GET /v1/certificate/{parameter_id}
# GET /v1/certificate/get_all_certs
# GET /v1/certificate/get_all_k8s_certs
# "config_api:certificate:get": "rule:reader_or_operator_or_configurator"
# Delete certificate
# DELETE /v1/certificate/{parameter_id}
# "config_api:certificate:delete": "rule:admin"
# install/renew certificate
# POST /v1/certificate/certificate_install
# POST /v1/certificate/certificate_renew
# "config_api:certificate:post": "rule:admin"

View File

@ -39,9 +39,11 @@ from sysinv.api.controllers.v1 import collection
from sysinv.api.controllers.v1 import link
from sysinv.api.controllers.v1 import types
from sysinv.api.controllers.v1 import utils
from sysinv.api.policies import certificate as cert_policy
from sysinv.common import constants
from sysinv.common import exception
from sysinv.common import kubernetes as sys_kube
from sysinv.common import policy
from sysinv.common import utils as cutils
from sysinv.openstack.common.rpc.common import RemoteError
from wsme import types as wtypes
@ -647,6 +649,18 @@ class CertificateController(rest.RestController):
return soon_to_expiry_certs
return cert_data
def enforce_policy(self, method_name, request):
"""Check policy rules for each action of this controller."""
context_dict = request.context.to_dict()
if method_name in ["get_all", "get_one", "get_all_certs", "get_all_k8s_certs"]:
policy.authorize(cert_policy.POLICY_ROOT % "get", {}, context_dict)
elif method_name in ["certificate_install", "certificate_renew"]:
policy.authorize(cert_policy.POLICY_ROOT % "post", {}, context_dict)
elif method_name in ["delete"]:
policy.authorize(cert_policy.POLICY_ROOT % method_name, {}, context_dict)
else:
raise exception.PolicyNotFound()
def _check_endpoint_domain_exists():
# Check that public endpoint FQDN is configured

View File

@ -164,7 +164,7 @@ class ContextHook(hooks.PecanHook):
'project_name': project_name,
'roles': roles
}
is_admin = policy.authorize(base_policy.ADMIN_IN_SYSTEM_PROJECTS, {},
is_admin = policy.authorize(base_policy.ADMIN_OR_CONFIGURATOR, {},
credentials, do_raise=False)
utils.safe_rstrip(state.request.path, '/')
@ -209,12 +209,12 @@ class AccessPolicyHook(hooks.PecanHook):
if method == 'GET':
role = "reader or operator"
has_api_access = policy.authorize(
base_policy.READER_OR_OPERATOR_IN_SYSTEM_PROJECTS, {},
base_policy.READER_OR_OPERATOR_OR_CONFIGURATOR, {},
context.to_dict(), do_raise=False)
else:
role = "admin"
has_api_access = policy.authorize(
base_policy.ADMIN_IN_SYSTEM_PROJECTS, {},
base_policy.ADMIN_OR_CONFIGURATOR, {},
context.to_dict(), do_raise=False)
if not has_api_access:
raise exc.HTTPForbidden("Not allowed/Role " + role + " is needed")

View File

@ -20,6 +20,7 @@ from sysinv.api.policies import base
from sysinv.api.policies import ihosts
from sysinv.api.policies import registry_image
from sysinv.api.policies import service_parameter
from sysinv.api.policies import certificate
def list_rules():
@ -27,5 +28,6 @@ def list_rules():
base.list_rules(),
service_parameter.list_rules(),
ihosts.list_rules(),
registry_image.list_rules()
registry_image.list_rules(),
certificate.list_rules(),
)

View File

@ -16,28 +16,38 @@
from oslo_policy import policy
ADMIN_IN_SYSTEM_PROJECTS = 'admin_in_system_projects'
READER_OR_OPERATOR_IN_SYSTEM_PROJECTS = 'reader_or_operator_in_system_projects'
ADMIN_OR_OPERATOR_IN_SYSTEM_PROJECTS = 'admin_or_operator_in_system_projects'
ADMIN = 'admin'
ADMIN_OR_CONFIGURATOR = 'admin_or_configurator'
READER_OR_OPERATOR_OR_CONFIGURATOR = 'reader_or_operator_or_configurator'
ADMIN_OR_OPERATOR_OR_CONFIGURATOR = 'admin_or_operator_or_configurator'
base_rules = [
policy.RuleDefault(
name=ADMIN_IN_SYSTEM_PROJECTS,
name=ADMIN,
check_str='role:admin and (project_name:admin or ' +
'project_name:services)',
description="Base rule.",
description='admin role of admin,services projects',
),
policy.RuleDefault(
name=ADMIN_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='(role:admin or role:operator) and (project_name:admin or ' +
'project_name:services)',
description="Base rule."
name=ADMIN_OR_CONFIGURATOR,
check_str='(role:admin or role:configurator) and ' +
'(project_name:admin or project_name:services)',
description='admin,configurator roles of admin,services ' +
'projects',
),
policy.RuleDefault(
name=READER_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='(role:reader or role:operator) and (project_name:admin or ' +
'project_name:services)',
description="Base rule."
name=ADMIN_OR_OPERATOR_OR_CONFIGURATOR,
check_str='(role:admin or role:operator or role:configurator) and ' +
'(project_name:admin or project_name:services)',
description='admin,operator,configurator roles of admin,services ' +
'projects',
),
policy.RuleDefault(
name=READER_OR_OPERATOR_OR_CONFIGURATOR,
check_str='(role:reader or role:operator or role:configurator) and ' +
'(project_name:admin or project_name:services)',
description='reader,operator,configurator roles of admin,services ' +
'projects',
)
]

View File

@ -0,0 +1,77 @@
# Copyright (c) 2025 Wind River Systems, Inc.
#
# 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.
#
# SPDX-License-Identifier: Apache-2.0
from oslo_policy import policy
from sysinv.api.policies import base
POLICY_ROOT = 'config_api:certificate:%s'
certificate_rules = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'get',
check_str='rule:' + base.READER_OR_OPERATOR_OR_CONFIGURATOR,
description="Get certificate",
operations=[
{
'method': 'GET',
'path': '/v1/certificate'
},
{
'method': 'GET',
'path': '/v1/certificate/{parameter_id}'
},
{
'method': 'GET',
'path': '/v1/certificate/get_all_certs'
},
{
'method': 'GET',
'path': '/v1/certificate/get_all_k8s_certs'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str='rule:' + base.ADMIN,
description="Delete certificate",
operations=[
{
'method': 'DELETE',
'path': '/v1/certificate/{parameter_id}'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'post',
check_str='rule:' + base.ADMIN,
description="install/renew certificate",
operations=[
{
'method': 'POST',
'path': '/v1/certificate/certificate_install'
},
{
'method': 'POST',
'path': '/v1/certificate/certificate_renew'
},
]
),
]
def list_rules():
return certificate_rules

View File

@ -23,7 +23,7 @@ POLICY_ROOT = 'config_api:ihosts:%s'
ihosts_rules = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'post',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Add a host Parameter.",
operations=[
{
@ -34,7 +34,7 @@ ihosts_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Delete a host Parameter.",
operations=[
{
@ -45,7 +45,7 @@ ihosts_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'get',
check_str='rule:' + base.READER_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.READER_OR_OPERATOR_OR_CONFIGURATOR,
description="Get host Parameters.",
operations=[
{
@ -60,7 +60,7 @@ ihosts_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'patch',
check_str='rule:' + base.ADMIN_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_OPERATOR_OR_CONFIGURATOR,
description="Modify host value.",
operations=[
{

View File

@ -23,7 +23,7 @@ POLICY_ROOT = 'config_api:registry_image:%s'
registry_image_rules = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'add',
check_str='rule:' + base.ADMIN_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_OPERATOR_OR_CONFIGURATOR,
description="Run registry garbage collect.",
operations=[
{
@ -34,7 +34,7 @@ registry_image_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Delete a registry image.",
operations=[
{
@ -45,7 +45,7 @@ registry_image_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'get',
check_str='rule:' + base.READER_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.READER_OR_OPERATOR_OR_CONFIGURATOR,
description="Get registry images list.",
operations=[
{

View File

@ -23,7 +23,7 @@ POLICY_ROOT = 'config_api:service_parameter:%s'
service_parameter_rules = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'add',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Add a Service Parameter.",
operations=[
{
@ -34,7 +34,7 @@ service_parameter_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'apply',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Apply Service Parameters.",
operations=[
{
@ -45,7 +45,7 @@ service_parameter_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'delete',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Delete a Service Parameter.",
operations=[
{
@ -56,7 +56,7 @@ service_parameter_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'get',
check_str='rule:' + base.READER_OR_OPERATOR_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.READER_OR_OPERATOR_OR_CONFIGURATOR,
description="Get Service Parameters.",
operations=[
{
@ -71,7 +71,7 @@ service_parameter_rules = [
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'modify',
check_str='rule:' + base.ADMIN_IN_SYSTEM_PROJECTS,
check_str='rule:' + base.ADMIN_OR_CONFIGURATOR,
description="Modify Service Parameter value.",
operations=[
{