Vacm

From Net-SNMP Wiki
Jump to: navigation, search

The View Access Control Model is one of the more complex configuration options that Net-SNMP offers.

The Basics

Check the man page

The Access Control section of the snmp.conf manual page talks about VACM setup, and has the most current information. Check there first.

A Visual Aid

A user-contributed image and text-representation of the relationships can be found on the VACM tutorial page.

We also provide this handy diagram showing how include/exclude functions overlay each other within a "fake" mib tree:

File:Vacm tree.jpeg
Including and Excluding MIB Tree Elements

Living in Denial

In response to the "arrgh, this is too complex for my poor little brain!" types of messages we get about configuring access control, you can avoid it if your needs are simple. So, if you just want to give a user read or write access to the entire MIB tree, you can use the ro and rw configuration options, which specify read-only (ro) or read-write (rw) access.

SNMPv1 and SNMPv2 rocommunity/rwcommunity

These directives allow access for community based requests, optionally restricted to a particular range of source IP addresses, and/or a specific OID. See the snmpd.conf man page for detail, but the general form is:

      rocommunity COMMUNITY [SOURCE [OID]]
      rwcommunity COMMUNITY [SOURCE [OID]]
      rocommunity6 COMMUNITY [SOURCE [OID]]
      rwcommunity6 COMMUNITY [SOURCE [OID]]

With version 5.3 and above, this directive can also restrict access to a named view, using the syntax

      rocommunity COMMUNITY SOURCE -V VIEW
      rwcommunity COMMUNITY SOURCE -V VIEW
      rocommunity6 COMMUNITY SOURCE -V VIEW
      rwcommunity6 COMMUNITY SOURCE -V VIEW

SNMPv3 rouser/rwuser

These directives allow access for SNMPv3 users, optionally requiring a certain access level and restricting the user to a specific OID. See the snmpd.conf man page for detail, but the general form is:

rouser USER [noauth|auth|priv [OID]]
rwuser USER [noauth|auth|priv [OID]]

With version 5.3 and above, this directive can also restrict access to a named view, using the syntax

rouser USER noauth|auth|priv -V NAME
rwuser USER noauth|auth|priv -V NAME

Special Cases and Examples

Here are some examples of more complex configurations, include supporting different views for a SNMPv3 user based on their security level.

VACM Views, or How to restrict access to particular branches in the tree

####
# First, map the community name (COMMUNITY) into a security name
# (local and mynetwork, depending on where the request is coming
# from):

#       sec.name  source          community
com2sec local     localhost       secret42
com2sec custom_sec 192.168.1.0/24  public

####
# Second, map the security names into group names:

#               sec.model  sec.name

group custom_grp v1         custom_sec
group custom_grp v2c        custom_sec

group incremental usm       myuser      # SNMPv3 username == sec.name

####
# Third, create a view for us to let the groups have rights to:

#           incl/excl subtree                              mask
view all    included  .1

view custom_v excluded  .1
view custom_v included  sysUpTime.0
view custom_v included  interfaces.ifTable

view mini_view excluded .1 80
view mini_view included  sysUpTime.0

view if_view excluded .1 80
view if_view included  sysUpTime.0
view if_view included  ifTable


####
# Finally, grant the groups access to their views:

#                context sec.model sec.level match  read     write  notif
access MyRWGroup ""      any       noauth    exact  all      all    none
access custom_grp ""     any       noauth    exact  cust1_v  none   none

access incremental ""    usm       noauth    exact  mini_view none  none
access incremental ""    usm       auth      exact  if_view   none  none
access incremental ""    usm       priv      exact  all_view  none  none

VACM Masks, or How to restrict access to a particular index (row) in a Table

Using the view directive in snmpd.conf, one can limit users to a single row in a table. To do this, the optional mask parameter is specified. Here is an excerpt from the man page:

      view NAME TYPE SUBTREE [MASK]
             The defines the named view. TYPE is either included
             or  excluded.   MASK is a list of hex octets, sepa-
             rated by '.' or ':'.  The MASK defaults to "ff"  if
             not specified.

             The  reason  for the mask is, that it allows you to
             control access to one row in a table,  in  a  rela-
             tively  simple  way.  As  an example, as an ISP you
             might consider giving each customer access  to  his
             or her own interface:

             view cust1 included interfaces.ifTable.ifEntry.ifIndex.1 ff.a0
             view cust2 included interfaces.ifTable.ifEntry.ifIndex.2 ff.a0

             (interfaces.ifTable.ifEntry.ifIndex.1 == .1.3.6.1.2.1.2.2.1.1.1,
             ff.a0 == 11111111.10100000. which nicely covers up and including
             the row index, but lets the user vary the field of the row)

Note: The mask seperator character can be "." or ":".

So, to be a little more visual about it:

.1.3.6.1.2.1.2.2.1.1.1 == interfaces.ifTable.ifEntry.ifIndex.1 
 1 1 1 1 1 1 1 1 1 0 1 (00000) == (ff.a0)
               ^ ^ ^ ^
               | | | |-- the index
               | | |---- the column
               | |------ ifEntry
               |-------- ifTable

So each bit in the mask indicates if the corresponding OID must match or not. In the above example, all parts of the OID except the colum must match. So this view allows access to any column of the first row in the ifTable. So, paired with an exclude row for the ifTable, only row 1 would be accessible to the user.

Now, to bring it all together with the other access control directives. Assuming 2 customers, and each is only connected to a specific interface (eg customer 1 is connected to eth0 and customer 2 is connected to eth1):

####
# First, map the community name (COMMUNITY) into a security name
# (local and mynetwork, depending on where the request is coming
# from):

#       sec.name  source          community
com2sec local     localhost       secret42
com2sec cust1_sec 192.168.1.0/24  public
com2sec cust2_sec 192.168.2.0/24  public

####
# Second, map the security names into group names:

#               sec.model  sec.name
group MyRWGroup v1         local
group MyRWGroup v2c        local

group cust1_grp v1         cust1_sec
group cust1_grp v2c        cust1_sec

group cust2_grp v1         cust2_sec
group cust2_grp v2c        cust2_sec

####
# Third, create a view for us to let the groups have rights to:

#           incl/excl subtree                              mask
view all    included  .1

view cust1_v excluded  .1
view cust1_v included  sysUpTime.0
view cust1_v included  interfaces.ifTable.ifEntry.ifIndex.1 ff.a0

view cust2_v excluded  .1
view cust2_v included  sysUpTime.0
view cust2_v included  interfaces.ifTable.ifEntry.ifIndex.2 ff.a0

####
# Finally, grant the groups access to their views:

#                context sec.model sec.level match  read     write  notif
access MyRWGroup ""      any       noauth    exact  all      all    none
access cust1_grp ""      any       noauth    exact  cust1_v  none   none
access cust2_grp ""      any       noauth    exact  cust2_v  none   none

It is important to note that this works because the customers are on different networks. If all the customers are on the same network, then it is important to note that sniffing network traffic could expose one customer's "community string" to another customer, allowing the second customer to view the first customers interface statistics via SNMP. In this case, you would want to use the encryption capabilities offered by SNMPv3 usm users, instead of SNMPv1 and SNMPv2 community strings.

Using Contexts

SNMPv3 'contexts' can be emulated for SNMPv1 and SNMPv2 communities, as explained on this page for configuring multiple proxies.