acls: Syntax schema, example and docs
First stab at integrating the acl-plugin from VPP. Allow to craft ACLs consisting of one-or-more ACEs (this is ensured by 'terms' being required with min=1), and a rich language to be able to set any L3 and L4 (UDP, ICMP, TCP) matchers that the plugin provides. Explain how the syntax will look like, although for now only YAMALE syntax checking can be performed (semantic validation is next). TESTED: pim@hippo:~/src/vppcfg/vppcfg$ ./vppcfg.py check -c example.yaml [INFO ] root.main: Loading configfile example.yaml [INFO ] vppcfg.config.valid_config: Configuration validated successfully [INFO ] root.main: Configuration is valid
This commit is contained in:
@ -358,3 +358,79 @@ interfaces:
|
||||
dot1q: 200
|
||||
exact-match: False
|
||||
```
|
||||
|
||||
### Access Control Lists
|
||||
|
||||
In VPP, a common firewall function is provided by the `acl-plugin`. The anatomy of this plugin
|
||||
is as follows. First, an ACL consists of one or more Access Control Elements or `ACE`s. These
|
||||
can match on IPv4 or IPv6 source/destination, an IP protocol, and then for TCP/UDP a range
|
||||
of source- and destination ports, and for ICMP a range of ICMP type and codes. Any matching
|
||||
packets then either perform an action of `permit` or `deny` (for stateless) or `permit+reflect`
|
||||
(stateful). The full syntax is as follows:
|
||||
|
||||
* ***description***: A string, no longer than 64 characters, and excluding the single quote '
|
||||
and double quote ". This string is currently not used anywhere, and serves for enduser
|
||||
documentation purposes.
|
||||
* ***terms***: A list of Access Control Elements:
|
||||
* ***action***: What to do upon match, can be either `permit`, `deny` or `permit+reflect`.
|
||||
This is the only required field.
|
||||
* ***family***: Which IP address family to match, can be either `ipv4`, or `ipv6` or `any`,
|
||||
which is the default. If `any` is used, this term will also operate on any source and
|
||||
destination addresses, and it will emit two ACEs, one for each address family.
|
||||
* ***source***: The IPv4 or IPv6 source prefix, eg. `192.0.2.0/24` or `2001:db8::/64`. If
|
||||
left empty, this means any (ie. `0.0.0.0/0` or `::/0`).
|
||||
* ***destination***: Similar to `source`, but for the destination field of the packets.
|
||||
* ***protocol***: The L4 protocol, can be either a numeric value (eg. `6`), or a symbolic
|
||||
string value from `/etc/protocols` (eg. `tcp`). If omitted, only L3 matches are performed.
|
||||
* ***source-port***: When `TCP` or `UDP` are specified, this field specified which source
|
||||
port(s) are matched. It can be either a numeric value (eg. `80`), a symbolic string value
|
||||
from `/etc/services` (eg. `www`), a numeric range with start and/or end ranges (eg. `-1024`
|
||||
for all ports from 0-1024 inclusive; or `1024-` for all ports from 1024-65535 inclusive,
|
||||
or an actual range `49152-65535`). The default keyword `any` is also permitted, which results
|
||||
in range `0-65535`, and is the default if the field is not specified.
|
||||
* ***destination-port***: Similar to `source-port` but for the destination port field in the
|
||||
`TCP` or `UDP` header.
|
||||
* ***icmp-type***: It can be either a numeric value (eg. `3`), a numeric range with start
|
||||
and/or end ranges (eg. `-10` for all types from 0-10 inclusive; or `10-` for all types from
|
||||
10-255 inclusive, or an actual range `10-15`). The default keyword `any` is also permitted,
|
||||
which results in range `0-255`, and is the default if the field is not specified. This field
|
||||
can only be specified if the `protocol` field is `icmp` (or `1`).
|
||||
* ***icmp-code***: Similar to `icmp-type` but for the ICMP code field. This field can only be
|
||||
specified if the `protocol` field is `icmp` (or `1`).
|
||||
|
||||
An example ACL with three ACE terms:
|
||||
```
|
||||
acls:
|
||||
acl01:
|
||||
description: "Test ACL"
|
||||
terms:
|
||||
- description: "Allow a specific IPv6 TCP flow"
|
||||
action: permit
|
||||
source: 2001:db8::/64
|
||||
destination: 2001:db8:1::/64
|
||||
protocol: tcp
|
||||
destination-port: www
|
||||
source-port: "1024-65535"
|
||||
- description: "Allow IPv4 ICMP Destination Unreachable, any code"
|
||||
family: ipv4
|
||||
action: permit
|
||||
protocol: icmp
|
||||
icmp-type: 3
|
||||
icmp-code: any
|
||||
- description: "Deny any IPv4 or IPv6"
|
||||
action: deny
|
||||
```
|
||||
|
||||
One or more of these ACLs are then applied to an interface in either the `input` or the `output`
|
||||
direction:
|
||||
|
||||
```
|
||||
interfaces:
|
||||
GigabitEthernet3/0/0:
|
||||
acls:
|
||||
input: acl01
|
||||
output: [ acl02, acl03 ]
|
||||
```
|
||||
The configuration here is tolerant of either a singleton (a literal string referring to the one
|
||||
ACL that must be applied), or a _list_ of strings to more than one ACL, in which case they will
|
||||
be tested in order (with a first-match return value).
|
||||
|
@ -117,3 +117,23 @@ taps:
|
||||
name: vpp-tap101
|
||||
mtu: 1500
|
||||
bridge: br1
|
||||
|
||||
acls:
|
||||
acl01:
|
||||
description: "Test ACL"
|
||||
terms:
|
||||
- description: "Allow a specific IPv6 TCP flow"
|
||||
action: permit
|
||||
source: 2001:db8::/64
|
||||
destination: 2001:db8:1::/64
|
||||
protocol: tcp
|
||||
destination-port: www
|
||||
source-port: "1024-65535"
|
||||
- description: "Allow IPv4 ICMP Destination Unreachable, any code"
|
||||
family: ipv4
|
||||
action: permit
|
||||
protocol: icmp
|
||||
icmp-type: 3
|
||||
icmp-code: any
|
||||
- description: "Deny any IPv4 or IPv6"
|
||||
action: deny
|
||||
|
@ -4,6 +4,7 @@ loopbacks: map(include('loopback'),key=str(matches='loop[0-9]+'),required=False)
|
||||
bridgedomains: map(include('bridgedomain'),key=str(matches='bd[0-9]+'),required=False)
|
||||
vxlan_tunnels: map(include('vxlan'),key=str(matches='vxlan_tunnel[0-9]+'),required=False)
|
||||
taps: map(include('tap'),key=str(matches='tap[0-9]+'),required=False)
|
||||
acls: map(include('acl'),key=str(matches='[a-z][a-z0-9\-]+'),required=False)
|
||||
---
|
||||
vxlan:
|
||||
description: str(exclude='\'"',len=64,required=False)
|
||||
@ -79,3 +80,24 @@ tap:
|
||||
namespace-create: bool(required=False)
|
||||
rx-ring-size: int(min=8,max=32768,required=False)
|
||||
tx-ring-size: int(min=8,max=32768,required=False)
|
||||
---
|
||||
# Valid: 80 "www" "-1024" "1024-" "1024-65535", and "any"
|
||||
acl-term-port-int-range-symbolic: any(int(min=1,max=65535),str(equals="any"),regex('^([1-9][0-9]*-|-[1-9][0-9]*|[1-9][0-9]*-[1-9][0-9]*)$'),regex('^[a-z][a-z0-9-]*$'))
|
||||
# Valid: 80 "-245" "10-" "10-245", and "any"
|
||||
acl-term-icmp-int-range: any(int(min=0,max=255),str(equals="any"),regex('^([0-9]+-|-[1-9][0-9]*|[0-9]*-[1-9][0-9]*)$'))
|
||||
---
|
||||
acl-term:
|
||||
description: str(exclude='\'"',len=64,required=False)
|
||||
action: enum('permit','deny','permit+reflect')
|
||||
family: enum('ipv4','ipv6','any',required=False)
|
||||
source: ip_interface(required=False)
|
||||
destination: ip_interface(required=False)
|
||||
protocol: any(int(min=1,max=255),regex('^[a-z][a-z0-9-]*$'),required=False)
|
||||
source-port: include('acl-term-port-int-range-symbolic', required=False)
|
||||
destination-port: include('acl-term-port-int-range-symbolic', required=False)
|
||||
icmp-type: include('acl-term-icmp-int-range',required=False)
|
||||
icmp-code: include('acl-term-icmp-int-range',required=False)
|
||||
---
|
||||
acl:
|
||||
description: str(exclude='\'"',len=64,required=False)
|
||||
terms: list(include('acl-term'), min=1, max=100, required=True)
|
||||
|
Reference in New Issue
Block a user