Description Language for Security Policy and Topology

Table of Contents

Overview

Policies

Network Objects

Service Definitions

Groups

Service Groups

Areas

The topology is build from networks and routers. Networks and routers are connected by interfaces.

An area denotes a part of the topology which is delimited by a set of interfaces. Areas are used to access all networks or security domains of some part of the topology.

Crypto Definition

A crypto definition consists of two parts:
  1. A definition of crypto type (currently IPSec with ISAKMP).
  2. Occurences of hub and spoke attributes at interfaces which define the actual tunnels between many VPN spokes and one (or two redundant) VPN hubs. The referenced crypto type defines the to be used crypto details.
Crypto definitions are very powerful: A large number of crypto tunnels of a hub and spoke topology topology can be defined easily.

Detailed description of network objects

The topology is built from networks and routers. A router and a network are connected by an interface. Networks can have any number of hosts, which are located inside the network.

Routers can be managed or unmanaged. For a managed router, NetSPoC generates access control lists which control what traffic can pass this router and what traffic is blocked. The whole topology is partitioned into different security domains by managed routers.

Special network objects called 'any' objects can be defined which denote all network objects inside a security domain.

General syntax

All network objects and groups have a typed name like <type>:<name>.

<name> is build from one ore more alphanumerical characters together with hyphen and underscore. The current locale settings are used, i.e. accented characters are allowed for European locale settings.

<ip-adr> denotes an IP address. Currently NetSPoC handles IP v4 addresses n.n.n.n with 0 <= n <= 255

<text_to_end_of_line> is any text from current position up to end of line.

<external_name> can contain almost any characters, but not whitespace, no delimiters [;,=] and no quotes ["'].

<int> is an integer

Meta symbols in syntax definitions below:

Network Definition

Syntax

  network:<name> = {
     [[ owner = <external_name>, ... ; ]]
     {{
         ip = <ip-adr><mask>;
	 <network NAT definition> *
         [[ route_hint; ]]
	 [[ subnet_of = network:<name>; ]]
         <host definition> *
     |
         unnumbered
     }}
  }
with
  <network NAT definition> ::=
         nat:<name> = { 
	  ip = <ip-adr>[[<mask>]];
	  [[ dynamic; ]]
	  [[ subnet_of = network:<name>; ]] 
	 }

  <mask> ::= {{/<prefix-lenght> | ; mask = <ip-adr> }}
  <prefix-lenght> ::= {{ 0 | 1 | 2 | ... | 32 }}

Host definition

Syntax

  <host definition> ::=
        host:<name> = { 
          [[ owner = <external_name>, ... ; ]]  
	  {{
	    ip = <ip-adr>;
          |
            range = <ip-adr> - <ip-adr>;
	  }}
          [[ policy_distribution_point; ]]
          <NAT definition> *
        }

  <NAT definition> ::=
        nat:<name> = { ip = <ip-adr>; }

Router definition

Syntax

  <router definition> ::=
  router:<name> = {
     {{
        managed [[ = {{ primary | full | standard | secondary }} ]] ;
        model = <name>;
	[[ no_group_code; ]]
	[[ no_crypto_filter; ]]
	<interface definition> *
     |
        [[ model = <name>; ]]
        {{ 
           <interface definition> 
        | 
           <short interface definition> 
        }} *
     }}
  }

Interface definition

Syntax

  <interface definition> ::= 
    interface:<name> = {
         {{ ip = <ip-adr>, ... ; | unnumbered; | negotiated; }}
	 <secondary interface definition> *
	 [[ <virtual interface definition> ]]
         <NAT definition> *
         [[ <NAT binding> ]]
         [[ hardware = <external_name> ; ]]
	 [[ routing = {{ EIGRP | OSPF | manual }} ; ]]
	 [[ reroute_permit = network:<name>, ... ; ]]
	 [[ loopback ; [[ subnet_of = network:<name>; ]] ]]
         [[ disabled ; ]]
    }

  <secondary interface definition> ::=
    secondary:<name> = { 
         ip = <ip-adr>;
    }

  <virtual interface definition> ::=
    virtual = { 
         ip = <ip-adr>;
         type = {{ VRRP | HSRP }};
         [[ id = <int>; ]]
    }

  <NAT definition> ::=
    nat:<name> = { ip = <ip-adr>; }
  <NAT binding> ::=
    bind_nat = <name>, ... ;

  <short interface definition> ::=
    interface:<name>;
 

'Any' object definition

Syntax

 any:<name> = { 
     [[ owner = <external_name>, ... ; ]]
     link = {{ 
               network:<name>; 
            |  
	       router:<name>; 
            }} 
 }

Area definition

Syntax

  area:<name> = {
   [[ owner = <external_name>, ... ; ]]
   [[ auto_border; ]]
   {{ 
     border = <object set> ; 
   | anchor = network:<name>;
   }}
  }

Referencing single or sets of network objects

Syntax

 <object set> ::= 
    {{ <network object> | <intersection> }} , ...
 <intersection> ::= 
    <network object>  &  <complement> [[ & <complement> ...]]
 <complement> ::=
    [[!]] <network object>

 <network object> ::=
 {{
   host:<name> 
 | network:<name>
 | any:<name> 
 | interface:<name>.<name>[[.<name>]]
 | group:<name> 
 | <auto group>
 }}

Automatic groups

Syntax


 <auto group> ::=
 {{
   interface:<name>.[<selector>]
 | interface:[ [[ managed & ]] <object set with area>].[<selector>]
 | network:[<object set with area>] 
 | any:[<object set with area>]
 }}

 <selector> ::= {{ auto | all }}
 <object set with area> is like <object set> 
   but with additional area:<name> in <network object>

Groups of network objects

Syntax

 group:<name> = <object set>;

Services

Syntax

 service:<name> = 
 {{
   ip 
 | tcp [[[[<range> :]] <range>]]
 | udp [[[[<range> :]] <range>]]
 | icmp [[<int_1>[[/<int_2>]]]] 
 | proto <int> 
 }} [[<service modifier>]] ;

with

 <range> ::= <int_1>[[-<int_2>]]

tcp, udp

icmp

protocol

Service modifiers

One or more <service modifier>'s can optionally be appended to a service definition. A <service modifier> modifies the rule in which the corresponding service is used as follows.
stateless
The rule is only applied to stateless devices.
oneway
At stateless devices, don't automatically generate rules to permit answer packets.
reversed
Source and destination are swapped.
dst_net
If destination of rule is a host or interface, find the enclosing network n and replace destination by n. Exception: hosts having a vpn id and interfaces of manged routers are left unchanged.
dst_any
First apply rules of modifier dst_net above. If afterwards destination of rule is a network, find the enclosing 'any' object a and replace destination by a.
src_net, src_any
Equivalent to dst_* modifiers but applied to source of rule.

Groups of services

Syntax

  servicegroup:<name> = <service>, ... ;

with

  <service> ::= {{ service:<name> | servicegroup:<name> }}

Policies

Syntax

  policy:<name> = {
     [[ description = <text_to_end_of_line> ]]
     user = [[ foreach ]] <object set>;
     <policy_rule> * 
  }

with

  <policy_rule> ::=
  {{ permit | deny }}
        src = <object set with 'user'>;
        dst = <object set with 'user'>;
        srv = <service>, ... ;
 <object set with 'user'> is like <object set> 
   but with additional keyword 'user' allowed in <network object>

Example

policy:ping_local = {
 description = Allow ping to my devices from directly attached network
 user = foreach interface:[group:my_devices].[all];
 permit src = network:[user]; dst = user; srv = service:ping;
}

Path restrictions

Syntax

 
 pathrestriction:<name> = 
   [[ description = <text_to_end_of_line> ]]
   <object set> ;

Global NAT definition

Syntax

 nat:<name> = { 
   ip = <ip-adr><mask>; 
   dynamic;
   [[ subnet_of = network:<name>; ]] 
 }
with <mask> defined as above.

A global NAT definition can be used as a shortcut for applying multiple identical dynamic NAT definitions to all networks in some area. See network address translation for details.

Network address translation (NAT)

Network address translation occurs at routers. At one side of a router, a network object is visible with its original IP address; at another side of the router this address is translated to another address.

Currently, NetSPoC supports static and dynamic NAT for whole networks.

For static NAT, the translated address uses the same netmask as the original network. The translation is automatically applied to all host and interface definitions of the translated network. A separate NAT definition for hosts or interfaces is not possible in this case.

For dynamic NAT, the translated address can use a different netmask than the original network. Typically a smaller network is used for translation. IP addresses are translated dynamically, hence hosts and interfaces of this network are not visible from outside. But a dynamic translation of a network can be augmented with static translations for single hosts or interfaces of this network.

Syntax for NAT is divided into two parts:

  1. A NAT definition denominates the alternate IP address of an network object.
  2. A NAT binding applies a set of NAT definitions to an interface.

Example

Network "extern" has bad IP addresses, which are not usable at network "intern". At router "r_ext" static NAT occurs. The NAT definition and NAT binding tells NetSPoC, that and where NAT occurs.
Hosts "extern_www" and "extern_mail" are visible with addresses 10.7.128.10 and 10.7.128.25 from "intern".
network:extern = {
 ip = 128.1.2.0; mask = 255.255.255.0;
 # static NAT definition
 nat:bad128 = { ip = 10.7.128.0; }
 host:extern_www = { ip = 128.1.2.10; }
 host:extern_mail = { ip = 128.1.2.25; }
}

router:r_ext = {
 interface:extern;
 interface:intern = {
  ip = 10.1.1.1;
  # NAT binding
  bind_nat = bad128;
 }
}

network:intern = { ip = 10.1.1.0; mask = 255.255.255.0; }
All NAT definitions with the same name establish a set of NAT definitions. A set of NAT definition is effective behind that interface where the NAT binding with the same name occurs. We are defining behind an interface as that part of the topology which is seen when looking from the router to that interface.

Multiple NAT definitions can be given for a single network. These are bound to different interfaces to make different NAT definitions effective at different parts of the topology.

Multiple NAT definitions can be bound to single interface. This simplifies definition of NAT for devices with multiple interfaces.

For dynamic NAT, multiple networks can use identical NAT definitions. This is used to masquerade multiple networks to a single address space.

A global NAT definition can be used as a shortcut for applying multiple identical dynamic NAT definitions to all networks located before that interface where the NAT binding with this name occurs.

NetSPoC needs to know about NAT for different reasons:

  1. When generating ACLs for an interface it must use those IP addresses which are visible in the area of this interface.
  2. The same is true when generating static routing entries.
  3. For some types of devices NetSPoC is able to actually generate the NAT translation rules. This is currently true for Cisco ASA and PIX devices.

Secondary packet filters

In a given topology we can get chains of managed packet filters on the path from src to dst. By default, each device filters the same rules again and again.
A secondary packet filter gets a simpler rule set.
A given rule describes traffic starting at src and terminating at dst. If there is at least one none secondary packet filter on the path from src to dst, all secondary packet filters on this path get a simplified ACL line for the current rule. This ACL line allows any IP packets from the src network to the dst network. This simplified filtering assures that the traffic comes from the right src and goes to the right dst.

If, for a given rule, there is a chain of secondary packet filters without a none secondary filter, all devices do standard filtering.

A secondary packet filter is declared with attribute "managed = secondary". This can be useful if a router has not enough memory for storing a complete set of filter rules and most of the packets get fully filtered already by some other managed device.

If a device is marked as "managed = primary", all rules which pass this device, are implemented as secondary filters on other devices which are marked either as "standard" or as "secondary". The effect of "primary" can be overridden by choosing the filter type "full" at an other device.

The default filter type for devices which are simply marked as "managed" is "standard".

Outgoing ACL

Per default, NetSPoC generates incoming access lists at each interface of a managed device. Use the attribute no_in_acl at one interface, to move the incoming ACL from this interface to outgoing ACLs at the other interfaces of the same device.

This is useful for situations like this:

  1. A packet filter connects multiple customers to some central site. Each customer needs to inspect the ACls of 'his' interface, but must not see ACLs of the other customers. Declaring the interface to the central site with 'no_in_acl' adds outgoing ACL to each customer interface.
  2. A packet filter has three interfaces A, B, C. There is a rule permit network:A -> any:[network:B]. With only incoming ACLs, this would allow traffic "network:A -> any:[network:C]" as well. With attribute 'no_in_acl' at interface A we get outgoing ACLs at interface B and C which permit traffic to any:[network:B] but not to any:[network:C].
For IOS there remains a minimal incoming ACL that filters traffic for the device itself.

These restrictions apply:

Outgoing ACLs are supported for model IOS, Linux and ASA. For convenience, the attribute no_in_acl can be added to an 'any' object. It is then inherited by all border interfaces of this 'any' object. Inheritance is stopped for devices which already have an attribute no_in_acl declared at some interface or have an attribute std_in_acl declared at the device level.

Routing

Static and dynamic routing

From its knowledge about the topology, NetSPoC generates static routing entries for each managed device. If an interface of a device has an attribute "routing=<routing protocol>", no static routing entries are generated for networks behind that interface.

Routing entries are only generated for network objects, which are used in some rule. I.e. no routing entries are generated for unused parts of the topology. Even for network objects which are only used as source of a rule, routing entries are generated, since stateful packet filters implicitly allow answer packets back to the source. If an 'any' object is used in a rule, routing entries for all networks part of this 'any' object are generated.

Default route

A default route can be defined for a topology by placing a network with IP address and mask equal 0.0.0.0. Such a network must have an attribute "route_hint".

Alternatively, NetSPoC can automatically define a default route for each managed device as a means to reduce the number of static routing entries.

Optimization

Multiple routing entries for networks which are in a subnet relation, are replaced by a single routing entry.

Rerouting inside of security domains

Internal traffic which flows inside a security domain isn't filtered at all. Sometimes an interface X of a managed (filtering) router is used as a default route for traffic which normally flows inside a security domain. This would cause internal traffic to be routed to X, which would deny this traffic.

NetSPoC is prepared to handle this case by defining an attribute 'reroute_permit' for a managed interface. Value of this attribute is a list of networks, for which any internal traffic should be allowed.

Example

router:x is managed, router:y is unmanaged.
router:x -- network:a -- router:y -- network:b

network:a and network:b are inside one security domain, since router:y isn't managed. If traffic from network:a to network:b is routed via router:x and router:y, router:x would deny this traffic. Use "reroute_permit = network:b" at "interface:x.a" to permit any incoming traffic to network:b.

Virtual interface

A virtual interface defines a shared IP address and type of redundancy protocol at two or more interfaces. Currently, redundancy protocols VRRP and HSRP are supported.

Crosslink network

Add attribute crosslink to a define a crosslink network.

A crosslink network combines two or more routers to a cluster of routers. Filtering occurs only at the outside interfaces of the cluster. The crosslink interfaces permit any traffic, because traffic has already been filtered by some other device of the cluster. These characteristics are enforced for crosslink networks:

Network with isolated ports

For a network with attribute isolated_ports, hosts inside this network are not allowed to talk directly to each other. Instead the traffic must go through an interface which is marked with attribute promiscuous_port. Non promiscuous interfaces are isolated as well; they are handled like hosts.

Disabling part of the topology

An interface can be explicitly marked as disabled. This implicitly marks all network objects as disabled, that are located behind this interface. We are defining behind an interface as that part of the topology which is seen when looking from the router to that interface. All occurrences of disabled network objects in groups and rules are silently discarded.

Encryption

Encrypted VPN tunnels are supported for
  1. remote access by tele worker with software VPN client,
  2. remote access from remote office with hardware VPN client or
  3. LAN to LAN tunnel.
The type of encryption is defined by a crypto definition.

Syntax

  crypto:<name> = {
     [[ description = <text_to_end_of_line> ]]
     type = ipsec:<name>;
     tunnel_all;
  }
  ipsec:<name> = {
     key_exchange = isakmp:<name>;
     esp_encryption = {{ aes | aes192 | aes256 | des | 3des | none }};
     esp_authentication = {{ md5_hmac | sha_hmac | none }};
     ah = {{ md5_hmac | sha_hmac | none }};
     pfs_group = {{ 1 | 2 | 5 | none}};
     lifetime = <number> <timeunit>;
  }
  isakmp:<name> = {
     identity = {{ address | fqdn }};
     nat_traversal = {{ on | additional | off }};
     authentication = {{ preshare | rsasig }};
     encryption = {{ aes | aes192 | aes256 | des | 3des }};
     hash = {{ md5 | sha }};
     group = {{ 1 | 2 | 5 }};
     lifetime = <number> <timeunit>;
  }

with

  <timeunit> ::= 
    {{ sec | min | hour | day | secs | mins | hours | days }};
The actual crypto tunnels are defined by adding hub and spoke definitions to interfaces.
  interface:<name1> = {
    ..
    hub = crypto:<name>
  }

  interface:<name2> = {
    ..
    spoke = crypto:<name>
  }
model= ASA, VPN | VPN3K for remote access with no_check, model = ASA for LAN to LAN

Remote access

Tele worker
Remote office
Both
This concept has been implemented for Cisco ASA and VPN 3000 (VPN3K) devices. VPN3K send authorization request to one or more radius servers. ASA uses a local user database. VPN is build using IPSec tunnels.

Cisco VPN 3000

new router model
model=VPN3K
additional attribute for router
radius_servers=<object set>
additional attributes for interface
additional syntax for hosts
host:id:certificate-name
additional attribute for network
id=<user[[@domain]]>
additional optional attribute at host with id, network with id, network having id hosts and router of type vpn3k
radius_attributes={<key>=<value>;*}

Additional restrictions

Multiple instances if one host:id:<name> can get defined in different networks of a topology. When referencing an id host, one has to append the name of the enclosing newtork to make the reference definite. host:id:<name> is referenced as host:id:<name>.<network>

Special handling of access lists at VPN3K device

Handling of 'any' objects

The meaning of 'any' is different in a NetSPoC rule from that in an ACL. For NetSPoC, any:X means "any network object of the security domain where any:X is located". For an ACL which filters incoming traffic of an interface, any (i.e. 0.0.0.0/0.0.0.0) means "any network object beyond the interface where the ACL is applied to".

as source:
any data object connected directly or indirectly with this interface.
as destination:
any data object located behind the router where the interface belongs to.

PIX security levels

PIX firewalls have a security level associated with each interface. We don't want to expand our syntax to state them explicitly, but instead we try to derive the level from the interface name:

It is not necessary the find the exact level; what we need to know is the relation of the security levels to each other.

Redundant rules

NetSPoC automatically detects and eliminates

Duplicate or redundant rules and elements should be avoided. If you later remove one of two redundant rules, it will be at least surprising that the traffic will still be permitted.

Per default, NetSPoC gives warnings for redundant rules and elements. But the behavior can be adjusted by command line switches and by attributes at policy definitions.

Unenforceable rules

Use command line switch -check_unenforceable=0|1|warn to control the behavior if NetSPoC detects unenforceable rules.

Generated Code

Supported devices

Private configuration context

The configuration for NetSPoC is typically spread to multiple files located inside a directory. For a large topology we might have multiple administrators with responsibility for only part of the topology.

The concept of 'private' configuration contexts allows to partition the configuration files into different areas of responsibility. All definitions inside a directory or a file named 'xxx.private' are marked as private for 'xxx'. All other definitions stay public. Private definitions have some restrictions to prevent inadvertent changes from other parts of a large set of configuration files:

Two private contexts and public context.

Changing default values of command line switches

The behavior of netspoc can be adjusted using command line switches. See man netspoc for details.

You can change values for command line switches permanently for a project by adding a file named "config" in the toplevel directory of the Netspoc configuration.

Format of the "config" file:

Owners and admins

Copyright (c) 2011, Heinz Knutzen heinzknutzen@users.berlios.de