Contrail Security with VNC API
This article means to show a simple way to create custom Firewall Tags for the new Contrail Security concept, apply them to an element (Virtual Network or Virtual Machine Interface == Neutron Port), create a Firewall rule that uses them, attach that rule to a Firewall Policy.
A few theoretical steps:
- create custom tag + value
- attach custom tag + value to port (VMI/Neutron Port)
- read default policy management ID
- create firewall rule attached to parent = default policy management ID
- update firewall policy with the previously created firewall rule
This assumes that later we will map (not present in this article) the firewall policy to the Default Application Policy. To eliminate a bit the confusion, Juniper’s Contrail Security has the following structure:
- Application policy
- Default Application Policy = applies everywhere -> we map here 1 or More Firewall Policies
- Custom Application Policy = applies mentioned Firewall Policies just to the elements (VNs/VMIs/Project/etc) where we put the matching application tags
- Firewall policy List of firewall rules that apply.
- Firewall rules
What is a tag
Tag ID is encoded on 32 bits where the fist 16 bits are reserved for the tag type/name and the last 16 bits for the value. On the config side Tag is divided in 2 resources types:
- tag_type: represents tag type/name (like ‘application’, ’tier’…). For any new tag_type, a unique 16 bits ID is allocated by the config thanks to zookeeper. Contrails pre-allocated 5 tag_types (label, application, tier, deployment and site) and reserved the first 255 IDs for any future requirements.
- tag: represents the Tag (type and value, example: foo=bar). For any new created Tag, a back_ref to its corresponding tag_type is created, a unique 16 bits ID is allocated by the config thanks to zookeeper and the tag ID is composed by the tag_type 16 bits ID plus the 16 bits of the tag ID.
More info directly in the source code: (https://github.com/Juniper/contrail-controller/blob/master/src/bgp/extended-community/tag.cc) Basically it falls exactly where you have also the SOO community or the extended route target.
API examples - using VNC API
We will be using the VNC API already present on one of the Contrail Controllers and ibash
which I installed separately to make things easier to test.
Initializing the VNC library
from vnc_api.vnc_api import *
from vnc_api import vnc_api
vnc = vnc_api.VncApi(username = 'admin',
password = 'fVpuDrAGMpNyb98T8szJxu4B4',
tenant_name = 'admin',
api_server_host = '10.91.121.62',
auth_host = '10.91.121.62',
auth_port = '5000')
Custom Tag Creation
from vnc_api.vnc_api import *
from vnc_api import vnc_api
evil_tag = Tag(tag_type_name='EVIL', tag_value='CUSTOMVALUE')
vnc.tag_create(evil_tag)
Tag Display
This will also show the value of it for BGP ext community.
vnc.tags_list()
#get the ID
my_tag = vnc.tag_read(id='<value from above>')
my.tag.dump()
Tag Assign
-
to VN
vnc.virtual_networks_list() id = 'ccccf55e-b80f-4230-8af0-5db20c483888' vn = vnc.virtual_network_read(id=id) vnc.set_tag(vn, 'evil', 'NIMIC', is_global=True)
-
to VMI / Neutron Port
vnc.virtual_networks_list() #port-id read from before portid = 'fd9d6b00-5ea9-4b73-982b-8d042d8880eb' port = vnc.virtual_machine_interface_read(['default-domain', 'admin', portid]) vnc.set_tag(port, 'evil', 'NIMIC', is_global=True)
-
multiple tags can also be assigned
set_tags(self, obj, tags_dict) method of vnc_api.vnc_api.VncApi instance Associate or disassociate one or mutliple tags to a resource Needs a dict of tags specified. Or via REST API (web) { 'application': { 'is_global': True, 'value': 'production', }, 'label': { 'is_global': False, 'add_values': ['blue', 'grey'], 'delete_values': ['red'], }, 'tier': { 'value': 'backend', }, 'foo': None, }
Create Firewall Rule and attach to existing policy
Needs attaching to a parent object (mandatory parameter). This can be:
-
default policy management
pr=vnc.policy_management_read(['default-policy-management'])
-
project
I saw that the rules I created via GUI were always under “default-policy-management” so proceeded accordingly.
vnc.firewall_rules_list()
# choose the ID for the Firewall Rule you want to see and dump as an example
fwrid = 'e7f338d3-75a5-418b-a1c1-08a412602a23'
a = vnc.firewall_rule_read(id=fwrid)
# see how it looks
a.dump()
# define a new FW rule
rule_obj = FirewallRule(
name='rule-BLA007',
parent_obj=pr,
action_list=ActionListType(simple_action='pass'),
service=FirewallServiceType(protocol='tcp',
dst_ports=PortType(8080, 8082)),
endpoint_1=FirewallRuleEndpointType(tags=['evil=NIMIC',
'tier=TIER-TAG-TST2']),
endpoint_2 = FirewallRuleEndpointType(tags=['site=Binz',
'tier=TIER-TAG-TST']),
direction='<>'
)
vnc.firewall_rule_create(rule_obj)
# attach rule to a FW policy
vnc.policy_managements_list()
fwp = vnc.firewall_policy_read(['default-policy-management', 'LOG_ALL']
fwp.add_firewall_rule(fwp, FirewallSequence(sequence='1.0'))
# update FW policy
vnc.firewall_policy_update(fwp)
Logging for a Firewall rule
Needs an existing SLO defined (or we create it via API).
This just defines the rate at which to export the flows to the Analytics logging engine.
Beware that this SLO needs to be defined in Infrastructure -> Global Config -> Security -> Logging
The one in the Configure -> Networking -> SLO is not global and thus not visible / usable with Contrail Security (rather with the older structure with Security Groups and with Network Policies).
fwrid = 'ca89366b-05fe-4fe5-b51c-b7755e0d5749'
fwr = vnc.firewall_rule_read(id=fwrid)
vnc.security_logging_objects_list()
sloid = '5b6572b1-a390-4459-ba1f-bc80e5727906'
slo = vnc.security_logging_object_read(id=sloid)
# add logging to the FW rule object read before
fwr.set_security_logging_object(ref_obj=slo, ref_data={})
vnc.firewall_rule_update(fwr)
Custom Logging Destination for Firewall Rules
We currently have 3 destinations namely collector, file and syslog. By default the destination is going to be collector (Analytics).
You can change them by specifying in inventory.yaml
during installation (or see below):
Here is the sample contrail_configuration section of inventory.yaml
:
contrail_configuration:
UPGRADE_KERNEL: true
CONTRAIL_VERSION: ocata-master-latest
CLOUD_ORCHESTRATOR: openstack
VROUTER_GATEWAY: 10.84.5.254
RABBITMQ_NODE_PORT: 5673
PHYSICAL_INTERFACE: enp2s0
AUTH_MODE: keystone
KEYSTONE_AUTH_HOST: 10.84.5.27
KEYSTONE_AUTH_URL_VERSION: /v3
SLO_DESTINATION: "file syslog"
SAMPLE_DESTINATION: “”
Modify in the Contrail Container (in Openstack 13 / Queens + Contrail 5.0.1):
ssh heat-admin@<contrail controller IP>
docker exec -it contrail_config_api bash
vi common.sh
## Session logging options
SLO_DESTINATION=${SLO_DESTINATION:-"collector"}
SAMPLE_DESTINATION=${SAMPLE_DESTINATION:-"collector"}
## change these lines, then restart container
exit
docker restart contrail_config_api