Vacm
The View Access Control Model is one of the more complex configuration options that Net-SNMP offers.
The Basics
Complete overview
Most folks aren't interested too much in the gory details, but for those who are, here is an external link I found on SNMPv3 View Based Access Control (VACM).
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.
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.