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