
Change-Id: Id71c2a390413d817c8902cc5965a59265978c8df Partially-implements: blueprint fixed-ips-for-pt
508 lines
25 KiB
ReStructuredText
508 lines
25 KiB
ReStructuredText
..
|
|
This work is licensed under a Creative Commons Attribution 3.0 Unported
|
|
License.
|
|
|
|
http://creativecommons.org/licenses/by/3.0/legalcode
|
|
|
|
Group-Based Policy Abstraction
|
|
==============================
|
|
|
|
The OpenStack networking model of networks, ports, subnets, routers,
|
|
and security groups provides the necessary building blocks to build a logical
|
|
network topology for connectivity. However, it does not provide the right level
|
|
of abstraction for an application administrator who understands the
|
|
application's details (like application port numbers), but not the
|
|
infrastructure details likes networks and routes. Not only that, the current
|
|
abstraction puts the burden of maintaining the consistency of the network
|
|
topology on the user. The lack of application developer/administrator focussed
|
|
abstractions supported by a declarative model make it hard for those users
|
|
to consume the existing connectivity layer.
|
|
|
|
The GBP framework complements the OpenStack networking model with the
|
|
notion of policies that can be applied between groups of network endpoints.
|
|
As users look beyond basic connectivity, richer network services with diverse
|
|
implementations and network properties are naturally expressed as policies.
|
|
Examples include service chaining, QoS, path properties, access control, etc.
|
|
|
|
The model allows application administrators to express their networking
|
|
requirements using group and policy abstractions, with the specifics of policy
|
|
enforcement and implementation left to the underlying policy driver. The main
|
|
advantage of the abstractions described here is that they allow for an
|
|
application-centric interface to OpenStack networking.
|
|
|
|
These abstractions achieve the following:
|
|
|
|
* Show clear separation of concerns between application and infrastructure
|
|
administrator.
|
|
|
|
- The application administrator can then deal with a higher level abstraction
|
|
that does not concern itself with networking specifics like
|
|
networks/routers/etc.
|
|
|
|
- The infrastructure administrator will deal with infrastructure specific
|
|
policy abstractions and not have to understand application specific concerns
|
|
like specific ports that have been opened or which of them expect to be
|
|
limited to secure or insecure traffic. The infrastructure admin will also
|
|
have ability to direct which technologies and approaches used in rendering.
|
|
For example, if VLAN or VxLAN is used.
|
|
|
|
- Allow the infrastructure admin to introduce connectivity constraints
|
|
without the application administrator having to be aware of it (e.g. audit
|
|
all traffic between two application tiers).
|
|
|
|
* Allow for independent provider/consumer model with late binding and n-to-m
|
|
relationships between them.
|
|
|
|
* Allow for automatic orchestration that can respond to changes in policy or
|
|
infrastructure without requiring human interaction to translate intent to
|
|
specific actions.
|
|
|
|
* Complement the governance model proposed in the OpenStack Congress project by
|
|
making Policy Tags available for enforcement.
|
|
|
|
Terminology
|
|
-----------
|
|
|
|
**Policy Target (PT):** It is the smallest unit of resource abstraction at
|
|
which policy can be applied.
|
|
|
|
**Policy Target Group (PTG):** A collection of policy targets.
|
|
|
|
**Policy Rule Set (PRS):** It defines how the application services provided by
|
|
a PTG can be accessed. In effect it specifies how a PTG communicates with other
|
|
PTGs. A Policy Rule Set consists of Policy Rules.
|
|
|
|
**Policy Rule (PR):** These are individual rules used to define the communication
|
|
criteria between PTGs. Each rule contains a Filter, Classifier, and Action.
|
|
|
|
**Policy Classifier:** Characterizes the traffic that a particular Policy Rule acts on.
|
|
Corresponding action is taken on traffic that satisfies this classification
|
|
criteria.
|
|
|
|
**Policy Action:** The action that is taken for a matching Policy Rule defined in a
|
|
Policy Rule Set.
|
|
|
|
**L2 Policy (L2P):** Used to define a L2 boundary and impose additional
|
|
constraints (such as no broadcast) within that L2 boundary.
|
|
|
|
**L3 Policy (L3P):** Used to define a non-overlapping IP address space.
|
|
|
|
**Network Service Policy (NSP):** Used to define policies that are used for
|
|
assigning resources in a PTG to be consumed by network services.
|
|
|
|
Resource Model
|
|
---------------
|
|
|
|
.. code-block:: python
|
|
|
|
RESOURCE_ATTRIBUTE_MAP = {
|
|
POLICY_TARGETS: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None}, 'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None}, 'default': '',
|
|
'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'policy_target_group_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'required': True, 'is_visible': True},
|
|
'cluster_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'default': '', 'is_visible': True}
|
|
},
|
|
POLICY_TARGET_GROUPS: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None}, 'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'policy_targets': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'default': None, 'is_visible': True},
|
|
'l2_policy_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'default': None, 'is_visible': True},
|
|
'provided_policy_rule_sets': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:dict_or_none': None},
|
|
'convert_to':
|
|
attr.convert_none_to_empty_dict,
|
|
'default': None, 'is_visible': True},
|
|
'consumed_policy_rule_sets': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:dict_or_none': None},
|
|
'convert_to':
|
|
attr.convert_none_to_empty_dict,
|
|
'default': None, 'is_visible': True},
|
|
'network_service_policy_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'default': None, 'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
'service_management': {'allow_post': True, 'allow_put': True,
|
|
'default': False,
|
|
'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
},
|
|
L2_POLICIES: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None}, 'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'policy_target_groups': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'default': None, 'is_visible': True},
|
|
'l3_policy_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'default': None, 'is_visible': True,
|
|
'required': True},
|
|
'inject_default_route': {'allow_post': True, 'allow_put': True,
|
|
'default': True, 'is_visible': True,
|
|
'convert_to': attr.convert_to_boolean,
|
|
'required': False},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
'required': False},
|
|
},
|
|
L3_POLICIES: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None}, 'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'ip_version': {'allow_post': True, 'allow_put': False,
|
|
'convert_to': attr.convert_to_int,
|
|
'validate': {'type:values': [4, 6]},
|
|
'default': 4, 'is_visible': True},
|
|
'ip_pool': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:subnet': None},
|
|
'default': '10.0.0.0/8', 'is_visible': True},
|
|
'subnet_prefix_length': {'allow_post': True, 'allow_put': True,
|
|
'convert_to': attr.convert_to_int,
|
|
# for ipv4 legal values are 2 to 30
|
|
# for ipv6 legal values are 2 to 127
|
|
'default': 24, 'is_visible': True},
|
|
'l2_policies': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'default': None, 'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
'external_segments': {
|
|
'allow_post': True, 'allow_put': True, 'default': None,
|
|
'validate': {'type:external_dict': None},
|
|
'convert_to': attr.convert_none_to_empty_dict, 'is_visible': True},
|
|
},
|
|
POLICY_CLASSIFIERS: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True, 'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True,
|
|
'is_visible': True},
|
|
'protocol': {'allow_post': True, 'allow_put': True,
|
|
'is_visible': True, 'default': None,
|
|
'convert_to': convert_protocol},
|
|
'port_range': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_port_range': None},
|
|
'convert_to': convert_port_to_string,
|
|
'default': None, 'is_visible': True},
|
|
'direction': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:values': gp_supported_directions},
|
|
'default': gp_constants.GP_DIRECTION_BI,
|
|
'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
},
|
|
POLICY_ACTIONS: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True,
|
|
'is_visible': True},
|
|
'action_type': {'allow_post': True, 'allow_put': False,
|
|
'convert_to': convert_action_to_case_insensitive,
|
|
'validate': {'type:values': gp_supported_actions},
|
|
'is_visible': True, 'default': 'allow'},
|
|
'action_value': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'default': None, 'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
},
|
|
POLICY_RULES: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True, 'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'enabled': {'allow_post': True, 'allow_put': True,
|
|
'default': True, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True},
|
|
'policy_classifier_id': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True, 'required': True},
|
|
'policy_actions': {'allow_post': True, 'allow_put': True,
|
|
'default': None, 'is_visible': True,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
},
|
|
POLICY_RULE_SETS: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '',
|
|
'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True,
|
|
'is_visible': True},
|
|
'parent_id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True},
|
|
'child_policy_rule_sets': {'allow_post': True, 'allow_put': True,
|
|
'default': None, 'is_visible': True,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to':
|
|
attr.convert_none_to_empty_list},
|
|
'policy_rules': {'allow_post': True, 'allow_put': True,
|
|
'default': None, 'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
},
|
|
NETWORK_SERVICE_POLICIES: {
|
|
'id': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid': None}, 'is_visible': True,
|
|
'primary_key': True},
|
|
'name': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:gbp_resource_name': None},
|
|
'default': '', 'is_visible': True},
|
|
'description': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True, 'default': ''},
|
|
'tenant_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True, 'is_visible': True},
|
|
'policy_target_groups': {'allow_post': False, 'allow_put': False,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'default': None, 'is_visible': True},
|
|
'network_service_params': {'allow_post': True, 'allow_put': False,
|
|
'validate':
|
|
{'type:network_service_params': None},
|
|
'default': None, 'is_visible': True},
|
|
attr.SHARED: {'allow_post': True, 'allow_put': True,
|
|
'default': False, 'convert_to': attr.convert_to_boolean,
|
|
'is_visible': True, 'required_by_policy': True,
|
|
'enforce_policy': True},
|
|
}
|
|
|
|
The following defines the mapping to Neutron resources using attribute extension:
|
|
|
|
.. code-block:: python
|
|
|
|
EXTENDED_ATTRIBUTES_2_0 = {
|
|
gp.POLICY_TARGETS: {
|
|
'port_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'is_visible': True, 'default': None},
|
|
'fixed_ips': {'allow_post': True, 'allow_put': True,
|
|
'default': attr.ATTR_NOT_SPECIFIED,
|
|
'convert_list_to': attr.convert_kvp_list_to_dict,
|
|
'validate': {'type:fixed_ips': None},
|
|
'enforce_policy': True,
|
|
'is_visible': True},
|
|
},
|
|
gp.POLICY_TARGET_GROUPS: {
|
|
'subnets': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'is_visible': True, 'default': None},
|
|
},
|
|
gp.L2_POLICIES: {
|
|
'network_id': {'allow_post': True, 'allow_put': False,
|
|
'validate': {'type:uuid_or_none': None},
|
|
'is_visible': True, 'default': None},
|
|
},
|
|
gp.L3_POLICIES: {
|
|
'routers': {'allow_post': True, 'allow_put': True,
|
|
'validate': {'type:uuid_list': None},
|
|
'convert_to': attr.convert_none_to_empty_list,
|
|
'is_visible': True, 'default': None},
|
|
}
|
|
}
|
|
|
|
All resources have the following common attributes:
|
|
* id - standard object uuid
|
|
* name - optional name
|
|
* description - optional annotation
|
|
|
|
The ip_pool in L2Policies is a supernet used for implicitly assigning subnets
|
|
to PTGs.
|
|
|
|
The subnet_prefix_length in L2Policies is the default subnet length used when
|
|
implicitly assigning a subnet to a PTG.
|
|
|
|
The way ip_pool and subnet_prefix_length work is as follows: When
|
|
creating L3Policy a default ip_pool and default_subnet_prefix_length are
|
|
created. If a user creates a PTG, a subnet will be pulled from ip_pool using
|
|
default_subnet_prefix_length.
|
|
|
|
The protocol in PolicyClassifier supports names “tcp”, “icmp”, “udp” and
|
|
protocol numbers 0 to 255 are supported.
|
|
|
|
The port range in PolicyClassifier port range can be a single port number
|
|
or a range (separated by a colon).
|
|
|
|
The direction in PolicyClassifier direction can be “in”, “out”, or “bi”.
|
|
|
|
The type in PolicyAction type can be “allow” or “redirect”.
|
|
|
|
The value in PolicyAction is used only in the case of “redirect” and
|
|
corresponds to a service_chain_spec.
|
|
|
|
The default route injection in VMs can be controlled by using the
|
|
inject_default_route in the L2Policies. This is set to True by default.
|
|
When set to False, the default route propagation is suppressed for all
|
|
the PTGs belonging to a specific L2Policy. This is useful in the cases
|
|
when a VM is associated with more than one PTG, and we want it to get a
|
|
specific default route and suppress others.
|
|
|
|
NetworkServiceParams
|
|
* type - Is one of “ip_single”, “ip_pool”, “string”
|
|
* name - A user-defined string, e.g. vip
|
|
* value - String, e.g. self_subnet or external_subnet when the type is
|
|
ip_single or ip_pool; a string value when the type is string
|
|
The type and value are validated, the name is treated as a literal.
|
|
The name of the param is chosen by the service chain implementation,
|
|
and as such is validated by the service chain provider.
|
|
The supported types are: ip_single, ip_pool, string.
|
|
The supported values are: self_subnet and external_subnet,
|
|
but the values are not validated when the tpye is 'string'.
|
|
Valid combinations are:
|
|
ip_single, self_subnet: Allocate a single IP addr from ptg subnet,
|
|
e.g. VIP (in the private network)
|
|
ip_single, external_subnet: Allocate a single floating-ip addr,
|
|
e.g. Public address for the VIP
|
|
ip_pool, external_subnet: Allocate a floating-ip for every PT in PTG
|
|
|
|
Database models
|
|
---------------
|
|
|
|
Database Objects to support Group-Based Policy:
|
|
|
|
::
|
|
|
|
+----------+ +-------------+
|
|
| | | |
|
|
| Policy | | Policy |
|
|
| Target |1 *| Rule |
|
|
| Groups +--------> Sets |
|
|
| (PTG) | | (PRS) |
|
|
| | | |
|
|
+----------+ +-------------+
|
|
1| 1|
|
|
| |
|
|
|* |*
|
|
+-----v----+ +------v------+ +-------------+
|
|
| | | | | |
|
|
| Policy | | Policy |1 *| Policy |
|
|
| Targets | | Rules +-------> Actions |
|
|
| (PT) | | (PR) | | (PA) |
|
|
| | | | | |
|
|
+----------+ +-------------+ +-------------+
|
|
1|
|
|
|
|
|
|1
|
|
+------v------+
|
|
| |
|
|
| Policy |
|
|
| Classifiers |
|
|
| (PC) |
|
|
| |
|
|
+-------------+
|
|
|
|
* [0..n]
|
|
|
|
Internals
|
|
---------
|
|
|
|
The GBP plugin class is located at `gbpservice/neutron/services/grouppolicy/plugin.py:GroupPolicyPlugin`.
|
|
The GBP plugin driver that maps resources to Neutron is located at `gbpservice/neutron/services/grouppolicy/drivers/resource_mapping.py:ResourceMappingDriver`.
|