VPP/SecurityGroups

From fd.io
< VPP
Revision as of 09:41, 17 November 2016 by Ayourtch (Talk | contribs)

Jump to: navigation, search

VPP Security Groups

Introduction

Features are tracked as they are developed in the following VPP-427.

Initial development is done on github: ACL branch

ACL Node architecture

Requirements

  • Support classifiers/filters on any interface type (bridged / routed)
  • Filter on IP-addresses with address mask or prefix length (IPv4 and IPv6)
  • Filter on source and destination TCP/UDP port ranges
  • Filter on source and destination L2 MAC addresses
  • Support IPv6 with extension headers present
  • Support fragmented packets and unknown transport layer headers
  • Combinations of the above filters (e.g. MAC + IP)
  • Filters on ingress and egress interfaces
  • Stateful firewall. No application layer filtering.

Work list

Task Owner Priority Status Description
API definition Ole 0 WIP VPP-513
Connection tracker Andrew 0 WIP VPP-514
Stateful ACLs 0 VPP-515
ACL policy matching node (MVP) Andrew 0 Done input output
Direct classifier policy matching -
Control Plane test code (new framework) Pavel 0 WIP
Data Plane tests (performance + scale) 0


 1. Python tests/examples -> Ole + Pavel
 2a. IPv4 matching in all plugin -> Andrew - done.
 2b. make it “deny by default” -> Andrew - done.
 2c. port range support -> Andrew - done.
 2d. ICMP type/code matching -> Andrew - ***WIP***.
 3. Performance testing -> Pavel ?
 --- MVP ---
 4a. Plumbing for stateful sessions from ACL plugin (to be able to specify “match and track” (“permit and create the forward/return session”) -> Andrew - done.
 4b. Stateful session tracking - timeouts -> Andrew - Done
 4c. Stateful session tracking - TCP state -> Andrew - ***WIP***
 5. MACIP(L2) rules -> Andrew - done.
 
 PHASE2:
 6. ACL/Sessions support for L3 (routed) mode - (big)!
 7. Can we implement the ACL match purely in terms of classifier tables ? How expensive/(in)efficient that would be ?
 8. Extension header handling during the slow path lookup - easy in ACL plugin
 9. classifier match for the sessions with extension headers - currently no extension headers supported

API

API file as implemented

MACIP (formerly "L2") API

MACIP (renamed to avoid confusion) is an ingress-only ACL which permits the traffic based on a mix of MAC and IP address matches.

The use of this mechanism is to prevent spoofing.

API file as implemented

API as implemented supports MAC address masks and prefixes, however, be aware: the current implementation is done using chained classifier tables, so each variation of the masks/prefix lengths means an extra table and hence the performance impact.

These filters are per-packet so you will want to care for performance.

For best performance, use the exact match MAC mask (ff:ff:ff:ff:ff:ff) and the maximum prefix length (/32 for IPv4 and /128 for IPv6).

Design and prototyping

The ACL matching is implemented in this phase as a simple array search, under the assumption that given the rules are per-port, the rule list will be small.

The redirection of the traffic to the node performing the ACL match is done by installing an empty L2 classifier table whose "miss-next" index diverts the traffic to the node.

The ACL match node can also redirect the traffic to the stateful-session setup node (by having a "permit" = 2 in the ACE), which will create the session on that interface.

...TBD: more details...

CLI

Every activity with the ACL must be done via the API. The plugins do not add any CLI at this point.

Examples

YANG model

Open Issues

Closed Issues

  • Security Group use case specific API. Done in a plugin. Two plugins, to be exact - one to ACL match, one to track sessions.

Existing functionality

The existing functionality has a classifier (https://wiki.fd.io/view/VPP/Introduction_To_N-tuple_Classifiers) matching.

As the above document explains, the classifier is a series of chained tables, with each table having a specific mask, but this mask is the same for all entries.

This has been tested to happen in the L2 bridged case (test case: http://stdio.be/vpp/t/aytest-bridge-tap-py.txt).

Therefore, if we have an example policy:

 nova secgroup-create test-secgroup test
 nova secgroup-add-rule test-secgroup icmp -1 -1 0.0.0.0/0
 nova secgroup-add-rule test-secgroup tcp 22 22 0.0.0.0/0

So, assuming we match with offset 0 (from the beginning of the packet) the mask will look like this for the first line:

 000000000000 000000000000 0000 00 00 0000 0000 0000 00 FF 0000 00000000 00000000  00 00 0000 0000 
   eth dst      eth src    et   ihl t  len id    fo ttl pr  cs   ip4src   ip4dst    t  c  cs   id
   +-------- L2 ---------------+----------- L3 IPv4 ------------------------------+--------L4 ICMP -----+

For the TCP matching on port 22 it will look as follows:

 000000000000 000000000000 0000 00 00 0000 0000 0000 00 FF 0000 00000000 00000000  0000 FFFF 00000000 00000000 0000 0000 0000 0000
   eth dst      eth src    et   ihl t  len id    fo ttl pr  cs   ip4src   ip4dst    sp  dp    seq      ack      fl  win   cs   urg
   +-------- L2 ---------------+----------- L3 IPv4 ------------------------------+--------L4 TCP ---------------------------------+


(One would need to round up the number of bytes to the nearest 16-byte boundary that makes sense)

For IPv6 assuming no extension headers, it will look similar, with the L3 header being the IPv6 one:


 000000000000 000000000000 0000 0 00 00000 0000 FF 00 00000000000000000000000000000000 00000000000000000000000000000000 00 00 0000 0000 
   eth dst      eth src    et   v TC  fll  len  nh hl             ipv6 src                   ipv dst                    t  c  cs   id
   +-------- L2 ---------------+----------- L3 IPv6 --------------------------------------------------------------------+--------L4 ICMP -----+

For the TCP matching on port 22 it will look as follows:

 000000000000 000000000000 0000 0 00 00000 0000 FF 00 00000000000000000000000000000000 00000000000000000000000000000000 0000 FFFF 00000000 00000000 0000 0000 0000 0000
   eth dst      eth src    et   v TC  fll  len  nh hl             ipv6 src                   ipv dst                      sp  dp    seq      ack      fl  win   cs   urg
   +-------- L2 ---------------+----------- L3 IPv6 --------------------------------------------------------------------+--------L4 TCP ---------------------------------


Then using these masks one would create 4 tables, by using the API call:

 classify_add_del_table(is_add=1, skip_n_vectors=0, mask=<MMMM>, match_n_vectors=<NNNN>,nbuckets=32,memory_size=20000, next_table_index=-1, miss_next_index=-1)

Let's call these tables "IPv4PROTO", "IPv4PROTO_TCPDPORT", "IPv6PROTO", "IPv6PROTO_TCPDPORT".

One would mention "IPv4PROTO" table as "next_table_index" table for "IPv4PROTO_TCPDPORT", and "IPv6PROTO" as "next_table_index" table for IPv6PROTO_TCPDPORT table.

Then one needs to populate the tables with the correct matches for "ICMP" and "tcp dst port 22". That can be done using API call:

 classify_add_del_session(is_add=1, table_index=<XXXX>, match=<bytes-to-match>, hit-next-index -1)

The bytes "XXXX" above would be the match of one or several vectors, corresponding to the packet contents with the desired value.

WARNING: if the "skip" is nonzero in the table configuration, the match is still the entire bitstring, without skipping any leading bytes !!!

Then one would apply the IPv4PROTO_TCPDPORT and IPv6PROTO_TCPDPORT as l2 input classify tables.

The CLI for that is set interface l2 output classify intfc <name> ip[46]-table <tableid>.

The API for this is

  classify_set_interface_l2_tables(sw_if_index=<INTFC>, ip4_table_index=<IPv4PROTO_TCPDPORT>, ip6_table_index=<IPv6PROTO_TCPDPORT>, other_table_index=-1, is_input=0)


This would allow to create a unidirectional policy, assuming the other policy is "permit all" it would be fine. If not - then a mirror table entries will need to be created using the same logic.

The full script showing this process in detail using the python API is at http://stdio.be/vpp/t/classifier_script_simple_policy.txt

The Java API is located in $ROOT/vpp-api/java..

References