[policy in code] part 4

Add service rule, resource rules, actions rules, build_info rules,
events rules.
Partially-Implements: bp policy-in-code

Change-Id: I497f4d02b5ea8399265dedc548214e4eca6b6a35
This commit is contained in:
ricolin 2017-10-06 18:45:16 +08:00
parent 46f0e16d11
commit 51e4f04693
12 changed files with 263 additions and 29 deletions

View File

@ -25,16 +25,6 @@
"cloudwatch:PutMetricData": "", "cloudwatch:PutMetricData": "",
"cloudwatch:SetAlarmState": "rule:deny_stack_user", "cloudwatch:SetAlarmState": "rule:deny_stack_user",
"actions:action": "rule:deny_stack_user",
"build_info:build_info": "rule:deny_stack_user",
"events:index": "rule:deny_stack_user",
"events:show": "rule:deny_stack_user",
"resource:index": "rule:deny_stack_user",
"resource:metadata": "",
"resource:signal": "",
"resource:mark_unhealthy": "rule:deny_stack_user",
"resource:show": "rule:deny_stack_user",
"software_configs:global_index": "rule:deny_everybody", "software_configs:global_index": "rule:deny_everybody",
"software_configs:index": "rule:deny_stack_user", "software_configs:index": "rule:deny_stack_user",
"software_configs:create": "rule:deny_stack_user", "software_configs:create": "rule:deny_stack_user",
@ -45,7 +35,5 @@
"software_deployments:show": "rule:deny_stack_user", "software_deployments:show": "rule:deny_stack_user",
"software_deployments:update": "rule:deny_stack_user", "software_deployments:update": "rule:deny_stack_user",
"software_deployments:delete": "rule:deny_stack_user", "software_deployments:delete": "rule:deny_stack_user",
"software_deployments:metadata": "", "software_deployments:metadata": ""
"service:index": "rule:context_is_admin"
} }

View File

@ -26,7 +26,8 @@ class ActionController(object):
Implements the API for stack actions Implements the API for stack actions
""" """
# Define request scope (must match what is in policy.json) # Define request scope (must match what is in policy.json or policies in
# code)
REQUEST_SCOPE = 'actions' REQUEST_SCOPE = 'actions'
ACTIONS = ( ACTIONS = (
@ -41,7 +42,7 @@ class ActionController(object):
self.options = options self.options = options
self.rpc_client = rpc_client.EngineClient() self.rpc_client = rpc_client.EngineClient()
@util.identified_stack @util.registered_identified_stack
def action(self, req, identity, body=None): def action(self, req, identity, body=None):
"""Performs a specified action on a stack. """Performs a specified action on a stack.

View File

@ -24,14 +24,15 @@ class BuildInfoController(object):
Returns build information for current app. Returns build information for current app.
""" """
# Define request scope (must match what is in policy.json) # Define request scope (must match what is in policy.json or policies in
# code)
REQUEST_SCOPE = 'build_info' REQUEST_SCOPE = 'build_info'
def __init__(self, options): def __init__(self, options):
self.options = options self.options = options
self.rpc_client = rpc_client.EngineClient() self.rpc_client = rpc_client.EngineClient()
@util.policy_enforce @util.registered_policy_enforce
def build_info(self, req): def build_info(self, req):
engine_revision = self.rpc_client.get_revision(req.context) engine_revision = self.rpc_client.get_revision(req.context)
build_info = { build_info = {

View File

@ -84,7 +84,8 @@ class EventController(object):
Implements the API actions. Implements the API actions.
""" """
# Define request scope (must match what is in policy.json) # Define request scope (must match what is in policy.json or policies in
# code)
REQUEST_SCOPE = 'events' REQUEST_SCOPE = 'events'
def __init__(self, options): def __init__(self, options):
@ -106,7 +107,7 @@ class EventController(object):
return [format_event(req, e, keys) for e in events] return [format_event(req, e, keys) for e in events]
@util.identified_stack @util.registered_identified_stack
def index(self, req, identity, resource_name=None): def index(self, req, identity, resource_name=None):
"""Lists summary information for all events.""" """Lists summary information for all events."""
whitelist = { whitelist = {
@ -149,7 +150,7 @@ class EventController(object):
return {'events': events} return {'events': events}
@util.identified_stack @util.registered_identified_stack
def show(self, req, identity, resource_name, event_id): def show(self, req, identity, resource_name, event_id):
"""Gets detailed information for an event.""" """Gets detailed information for an event."""

View File

@ -75,7 +75,8 @@ class ResourceController(object):
Implements the API actions. Implements the API actions.
""" """
# Define request scope (must match what is in policy.json) # Define request scope (must match what is in policy.json or policies in
# code)
REQUEST_SCOPE = 'resource' REQUEST_SCOPE = 'resource'
def __init__(self, options): def __init__(self, options):
@ -92,7 +93,7 @@ class ResourceController(object):
else: else:
return default return default
@util.identified_stack @util.registered_identified_stack
def index(self, req, identity): def index(self, req, identity):
"""Lists information for all resources.""" """Lists information for all resources."""
@ -131,7 +132,7 @@ class ResourceController(object):
return {'resources': [format_resource(req, res) for res in res_list]} return {'resources': [format_resource(req, res) for res in res_list]}
@util.identified_stack @util.registered_identified_stack
def show(self, req, identity, resource_name): def show(self, req, identity, resource_name):
"""Gets detailed information for a resource.""" """Gets detailed information for a resource."""
@ -146,7 +147,7 @@ class ResourceController(object):
return {'resource': format_resource(req, res)} return {'resource': format_resource(req, res)}
@util.identified_stack @util.registered_identified_stack
def metadata(self, req, identity, resource_name): def metadata(self, req, identity, resource_name):
"""Gets metadata information for a resource.""" """Gets metadata information for a resource."""
@ -156,14 +157,14 @@ class ResourceController(object):
return {rpc_api.RES_METADATA: res[rpc_api.RES_METADATA]} return {rpc_api.RES_METADATA: res[rpc_api.RES_METADATA]}
@util.identified_stack @util.registered_identified_stack
def signal(self, req, identity, resource_name, body=None): def signal(self, req, identity, resource_name, body=None):
self.rpc_client.resource_signal(req.context, self.rpc_client.resource_signal(req.context,
stack_identity=identity, stack_identity=identity,
resource_name=resource_name, resource_name=resource_name,
details=body) details=body)
@util.identified_stack @util.registered_identified_stack
def mark_unhealthy(self, req, identity, resource_name, body): def mark_unhealthy(self, req, identity, resource_name, body):
"""Mark a resource as healthy or unhealthy.""" """Mark a resource as healthy or unhealthy."""
data = dict() data = dict()

View File

@ -25,14 +25,15 @@ from heat.rpc import client as rpc_client
class ServiceController(object): class ServiceController(object):
"""WSGI controller for reporting the heat engine status in Heat v1 API.""" """WSGI controller for reporting the heat engine status in Heat v1 API."""
# Define request scope (must match what is in policy.json) # Define request scope (must match what is in policy.json or policies in
# code)
REQUEST_SCOPE = 'service' REQUEST_SCOPE = 'service'
def __init__(self, options): def __init__(self, options):
self.options = options self.options = options
self.rpc_client = rpc_client.EngineClient() self.rpc_client = rpc_client.EngineClient()
@util.policy_enforce @util.registered_policy_enforce
def index(self, req): def index(self, req):
try: try:
services = self.rpc_client.list_services(req.context) services = self.rpc_client.list_services(req.context)

View File

@ -13,14 +13,24 @@
import itertools import itertools
from heat.policies import actions
from heat.policies import base from heat.policies import base
from heat.policies import build_info
from heat.policies import events
from heat.policies import resource
from heat.policies import resource_types from heat.policies import resource_types
from heat.policies import service
from heat.policies import stacks from heat.policies import stacks
def list_rules(): def list_rules():
return itertools.chain( return itertools.chain(
base.list_rules(), base.list_rules(),
stacks.list_rules(), actions.list_rules(),
build_info.list_rules(),
events.list_rules(),
resource.list_rules(),
resource_types.list_rules(), resource_types.list_rules(),
service.list_rules(),
stacks.list_rules(),
) )

37
heat/policies/actions.py Normal file
View File

@ -0,0 +1,37 @@
# 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
from heat.policies import base
POLICY_ROOT = 'actions:%s'
actions_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'action',
check_str=base.RULE_DENY_STACK_USER,
description='Performs non-lifecycle operations on the stack '
'(Snapshot, Resume, Cancel update, or check stack resources).',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'actions',
'method': 'POST'
}
]
)
]
def list_rules():
return actions_policies

View File

@ -0,0 +1,35 @@
# 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
from heat.policies import base
POLICY_ROOT = 'build_info:%s'
build_info_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'build_info',
check_str=base.RULE_DENY_STACK_USER,
description='Show build information.',
operations=[
{
'path': '/v1/{tenant_id}/build_info',
'method': 'GET'
}
]
)
]
def list_rules():
return build_info_policies

48
heat/policies/events.py Normal file
View File

@ -0,0 +1,48 @@
# 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
from heat.policies import base
POLICY_ROOT = 'events:%s'
events_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
description='List events.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'events',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
description='Show event.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources/{resource_name}/events/{event_id}',
'method': 'GET'
}
]
)
]
def list_rules():
return events_policies

84
heat/policies/resource.py Normal file
View File

@ -0,0 +1,84 @@
# 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
from heat.policies import base
POLICY_ROOT = 'resource:%s'
resource_policies = [
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_DENY_STACK_USER,
description='List resources.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'metadata',
check_str=base.RULE_ALLOW_EVERYBODY,
description='Show resource metadata.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources/{resource_name}/metadata',
'method': 'GET'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'signal',
check_str=base.RULE_ALLOW_EVERYBODY,
description='Signal resource.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources/{resource_name}/signal',
'method': 'POST'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'mark_unhealthy',
check_str=base.RULE_DENY_STACK_USER,
description='Mark resource as unhealthy.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources/{resource_name_or_physical_id}',
'method': 'PATCH'
}
]
),
policy.DocumentedRuleDefault(
name=POLICY_ROOT % 'show',
check_str=base.RULE_DENY_STACK_USER,
description='Show resource.',
operations=[
{
'path': '/v1/{tenant_id}/stacks/{stack_name}/{stack_id}/'
'resources/{resource_name}',
'method': 'GET'
}
]
)
]
def list_rules():
return resource_policies

27
heat/policies/service.py Normal file
View File

@ -0,0 +1,27 @@
# 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
from heat.policies import base
POLICY_ROOT = 'service:%s'
service_policies = [
policy.RuleDefault(
name=POLICY_ROOT % 'index',
check_str=base.RULE_CONTEXT_IS_ADMIN)
]
def list_rules():
return service_policies