From ff883486e62e394b03ed7c6e6911ca082e599586 Mon Sep 17 00:00:00 2001 From: Lance Bragstad Date: Wed, 18 Nov 2020 21:16:05 +0000 Subject: [PATCH] Implement system scoped RBAC for node and driver passthru This commit updates the policies for baremetal passthru policies to understand scope checking and account for a read-only role. This is part of a broader series of changes across OpenStack to provide a consistent RBAC experience and improve security. Change-Id: I31a258e0ce7db7e931e62f2a06e610857dabdd47 --- ironic/common/policy.py | 92 +++++++++++++------ ironic/tests/unit/api/test_rbac_legacy.yaml | 30 ++++++ .../unit/api/test_rbac_system_scoped.yaml | 30 ------ ...coped-authentication-28e3651de250bea8.yaml | 2 +- 4 files changed, 93 insertions(+), 61 deletions(-) diff --git a/ironic/common/policy.py b/ironic/common/policy.py index 05039f3534..8c8631bda6 100644 --- a/ironic/common/policy.py +++ b/ironic/common/policy.py @@ -956,39 +956,71 @@ driver_policies = [ ), ] +deprecated_node_passthru = policy.DeprecatedRule( + name='baremetal:node:vendor_passthru', + check_str='rule:is_admin' +) +deprecated_driver_passthru = policy.DeprecatedRule( + name='baremetal:driver:vendor_passthru', + check_str='rule:is_admin' +) +deprecated_vendor_reason = """ +The baremetal vendor passthru API is now aware of system scope and default +roles. +""" + vendor_passthru_policies = [ policy.DocumentedRuleDefault( - 'baremetal:node:vendor_passthru', - 'rule:is_admin', - 'Access vendor-specific Node functions', - [{'path': 'nodes/{node_ident}/vendor_passthru/methods', - 'method': 'GET'}, - {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', - 'method': 'GET'}, - {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', - 'method': 'PUT'}, - {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', - 'method': 'POST'}, - {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', - 'method': 'PATCH'}, - {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', - 'method': 'DELETE'}]), + name='baremetal:node:vendor_passthru', + check_str=SYSTEM_ADMIN, + scope_types=['system'], + description='Access vendor-specific Node functions', + operations=[ + {'path': 'nodes/{node_ident}/vendor_passthru/methods', + 'method': 'GET'}, + {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', + 'method': 'GET'}, + {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', + 'method': 'PUT'}, + {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', + 'method': 'POST'}, + {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', + 'method': 'PATCH'}, + {'path': 'nodes/{node_ident}/vendor_passthru?method={method_name}', + 'method': 'DELETE'}, + ], + deprecated_rule=deprecated_node_passthru, + deprecated_reason=deprecated_vendor_reason, + deprecated_since=versionutils.deprecated.WALLABY + ), policy.DocumentedRuleDefault( - 'baremetal:driver:vendor_passthru', - 'rule:is_admin', - 'Access vendor-specific Driver functions', - [{'path': 'drivers/{driver_name}/vendor_passthru/methods', - 'method': 'GET'}, - {'path': 'drivers/{driver_name}/vendor_passthru?method={method_name}', - 'method': 'GET'}, - {'path': 'drivers/{driver_name}/vendor_passthru?method={method_name}', - 'method': 'PUT'}, - {'path': 'drivers/{driver_name}/vendor_passthru?method={method_name}', - 'method': 'POST'}, - {'path': 'drivers/{driver_name}/vendor_passthru?method={method_name}', - 'method': 'PATCH'}, - {'path': 'drivers/{driver_name}/vendor_passthru?method={method_name}', - 'method': 'DELETE'}]), + name='baremetal:driver:vendor_passthru', + check_str=SYSTEM_ADMIN, + scope_types=['system'], + description='Access vendor-specific Driver functions', + operations=[ + {'path': 'drivers/{driver_name}/vendor_passthru/methods', + 'method': 'GET'}, + {'path': 'drivers/{driver_name}/vendor_passthru?' + 'method={method_name}', + 'method': 'GET'}, + {'path': 'drivers/{driver_name}/vendor_passthru?' + 'method={method_name}', + 'method': 'PUT'}, + {'path': 'drivers/{driver_name}/vendor_passthru?' + 'method={method_name}', + 'method': 'POST'}, + {'path': 'drivers/{driver_name}/vendor_passthru?' + 'method={method_name}', + 'method': 'PATCH'}, + {'path': 'drivers/{driver_name}/vendor_passthru?' + 'method={method_name}', + 'method': 'DELETE'} + ], + deprecated_rule=deprecated_driver_passthru, + deprecated_reason=deprecated_vendor_reason, + deprecated_since=versionutils.deprecated.WALLABY + ), ] utility_policies = [ diff --git a/ironic/tests/unit/api/test_rbac_legacy.yaml b/ironic/tests/unit/api/test_rbac_legacy.yaml index 0b37b8d8ec..f4842999b1 100644 --- a/ironic/tests/unit/api/test_rbac_legacy.yaml +++ b/ironic/tests/unit/api/test_rbac_legacy.yaml @@ -520,90 +520,105 @@ nodes_vendor_passthru_methods_get_admin: method: get headers: *admin_headers assert_status: 503 + deprecated: true nodes_vendor_passthru_methods_get_member: path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get headers: *member_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_methods_get_observer: path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get headers: *observer_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_get_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *admin_headers assert_status: 503 + deprecated: true nodes_vendor_passthru_get_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *member_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_get_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *observer_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_post_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *admin_headers assert_status: 503 + deprecated: true nodes_vendor_passthru_post_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *member_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_post_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *observer_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_put_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *admin_headers assert_status: 503 + deprecated: true nodes_vendor_passthru_put_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *member_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_put_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *observer_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_delete_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *admin_headers assert_status: 503 + deprecated: true nodes_vendor_passthru_delete_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *member_headers assert_status: 403 + deprecated: true nodes_vendor_passthru_delete_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *observer_headers assert_status: 403 + deprecated: true # Node Traits - https://docs.openstack.org/api-ref/baremetal/#node-traits-nodes @@ -1631,72 +1646,84 @@ drivers_vendor_passthru_methods_get_admin: method: get headers: *admin_headers assert_status: 404 + deprecated: true drivers_vendor_passthru_methods_get_member: path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get headers: *member_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_methods_get_observer: path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get headers: *observer_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_get_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *admin_headers assert_status: 404 + deprecated: true drivers_vendor_passthru_get_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *member_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_get_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *observer_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_post_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *admin_headers assert_status: 404 + deprecated: true drivers_vendor_passthru_post_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *member_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_post_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *observer_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_put_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *admin_headers assert_status: 404 + deprecated: true drivers_vendor_passthru_put_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *member_headers assert_status: 403 + deprecated: true drivers_vendor_passthru_put_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *observer_headers assert_status: 403 + deprecated: true # NOTE(TheJulia): Returns an error due to the driver name # not matching, but this should be pass policy checking. @@ -1706,18 +1733,21 @@ drivers_vendor_passthru_delete_admin: method: delete headers: *admin_headers assert_status: 404 + skip_reason: not updated for scope testing drivers_vendor_passthru_delete_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: delete headers: *member_headers assert_status: 403 + skip_reason: not updated for scope testing drivers_vendor_passthru_delete_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: delete headers: *observer_headers assert_status: 403 + skip_reason: not updated for scope testing # Node Bios - https://docs.openstack.org/api-ref/baremetal/#node-bios-nodes diff --git a/ironic/tests/unit/api/test_rbac_system_scoped.yaml b/ironic/tests/unit/api/test_rbac_system_scoped.yaml index 69140205ad..e9c10fa4c5 100644 --- a/ironic/tests/unit/api/test_rbac_system_scoped.yaml +++ b/ironic/tests/unit/api/test_rbac_system_scoped.yaml @@ -455,105 +455,90 @@ nodes_vendor_passthru_methods_get_admin: method: get headers: *admin_headers assert_status: 503 - skip_reason: policy not implemented yet nodes_vendor_passthru_methods_get_member: path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get headers: *scoped_member_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_methods_get_observer: path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get headers: *observer_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_get_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *admin_headers assert_status: 503 - skip_reason: policy not implemented yet nodes_vendor_passthru_get_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *scoped_member_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_get_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: get headers: *observer_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_post_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *admin_headers assert_status: 503 - skip_reason: policy not implemented yet nodes_vendor_passthru_post_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *scoped_member_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_post_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post headers: *observer_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_put_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *admin_headers assert_status: 503 - skip_reason: policy not implemented yet nodes_vendor_passthru_put_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *scoped_member_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_put_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put headers: *observer_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_delete_admin: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *admin_headers assert_status: 503 - skip_reason: policy not implemented yet nodes_vendor_passthru_delete_member: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *scoped_member_headers assert_status: 403 - skip_reason: policy not implemented yet nodes_vendor_passthru_delete_observer: path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete headers: *observer_headers assert_status: 403 - skip_reason: policy not implemented yet # Node Traits - https://docs.openstack.org/api-ref/baremetal/#node-traits-nodes @@ -1523,84 +1508,72 @@ drivers_vendor_passthru_methods_get_admin: method: get headers: *admin_headers assert_status: 404 - skip_reason: not updated for scope testing drivers_vendor_passthru_methods_get_member: path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get headers: *scoped_member_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_methods_get_observer: path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get headers: *observer_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_get_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *admin_headers assert_status: 404 - skip_reason: not updated for scope testing drivers_vendor_passthru_get_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *scoped_member_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_get_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: get headers: *observer_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_post_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *admin_headers assert_status: 404 - skip_reason: not updated for scope testing drivers_vendor_passthru_post_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *scoped_member_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_post_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post headers: *observer_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_put_admin: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *admin_headers assert_status: 404 - skip_reason: not updated for scope testing drivers_vendor_passthru_put_member: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *scoped_member_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_put_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put headers: *observer_headers assert_status: 403 - skip_reason: not updated for scope testing # NOTE(TheJulia): Returns an error due to the driver name # not matching, but this should be pass policy checking. @@ -1610,21 +1583,18 @@ drivers_vendor_passthru_delete_admin: method: delete headers: *admin_headers assert_status: 404 - skip_reason: not updated for scope testing drivers_vendor_passthru_delete_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: delete headers: *scoped_member_headers assert_status: 403 - skip_reason: not updated for scope testing drivers_vendor_passthru_delete_observer: path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: delete headers: *observer_headers assert_status: 403 - skip_reason: not updated for scope testing # Node Bios - https://docs.openstack.org/api-ref/baremetal/#node-bios-nodes diff --git a/releasenotes/notes/system-scoped-authentication-28e3651de250bea8.yaml b/releasenotes/notes/system-scoped-authentication-28e3651de250bea8.yaml index 20ff567dad..d6bf799995 100644 --- a/releasenotes/notes/system-scoped-authentication-28e3651de250bea8.yaml +++ b/releasenotes/notes/system-scoped-authentication-28e3651de250bea8.yaml @@ -3,7 +3,7 @@ features: - | The Baremetal API, provided by the ironic-api process, now supports use of ``system`` scoped ``keystone`` authentication for the following endpoints: - nodes, ports, portgroups, chassis, drivers + nodes, ports, portgroups, chassis, drivers, vendor passthru. upgrade: - | Deprecated policy rules are not expressed via a default policy file