setup

How to Restrict SNMP OIDs with a VACM Allowlist

Use net-snmp VACM views to expose only the OID subtrees a manager needs, so a leaked community or credential reveals almost nothing.

By the SNMP Monitoring team · Reviewed July 2026

A read-only SNMP agent still hands over its entire MIB tree by default — inventory, interface tables, running config details, the lot. Least privilege says otherwise: expose only the handful of subtrees your poller actually reads, and nothing else. That's what a VACM allowlist does. Build one and a leaked community or a compromised credential reveals a few metrics instead of a full device profile. This is the how-to — define a view, bind it to access, and prove that out-of-view OIDs return nothing.

Parent: setup. Related: snmpd.conf, community string, SNMPv3.

What VACM is

VACM — the View-based Access Control Model — is net-snmp's mechanism for deciding which OIDs a given requester may read. Instead of "this community can read everything," VACM lets you say "this group may read only these subtrees." You describe a view as a set of OID subtrees, each either included or excluded, and then attach that view to a security group. A request for an OID inside the view returns data; a request for anything outside it returns no such object. VACM is standardised as part of the SNMP framework and implemented directly by net-snmp's view/access directives.

Why allowlist OIDs

The point is blast-radius reduction. Even with a random community and a source-IP restriction, anything that can talk to the agent can still walk the whole tree unless you scope it. An allowlist caps the damage:

  • A leaked community string then dumps only your chosen metrics, not the full MIB.
  • A compromised v3 credential is similarly limited to its authorised view.
  • Reconnaissance is starved — an attacker can't enumerate software, routes, or ARP tables you never exposed.
  • Accidental over-collection is prevented — your poller sees exactly what it's meant to.

An allowlist is the difference between "read-only" and "read-only, and only these three subtrees." The second is the one you want.

Step 1: Define a view

A view line names an allowlist and adds one subtree to it. List each subtree your monitoring needs:

view monitoring included 1.3.6.1.2.1.1
view monitoring included 1.3.6.1.2.1.25
view monitoring included 1.3.6.1.2.1.2

To build a view methodically:

  1. Start empty — nothing is visible until you include it.
  2. Add the system group (1.3.6.1.2.1.1) so sysDescr/sysUpTime work.
  3. Add each MIB subtree your poller reads — host-resources (...25), interfaces (...2), and so on.
  4. Use excluded to carve a sensitive leaf back out of an otherwise-included subtree.

Each line is additive. An optional trailing hex mask lets you match specific table columns, but for most allowlists whole-subtree includes are enough.

Step 2: Bind the view to access

A view does nothing until a group is bound to it. net-snmp's chain maps a community (or user) to a group, then a group to a view:

DirectiveRole
com2secMap a community + source to a security name
groupPut that security name into a named group
viewDefine the allowed OID subtrees
accessBind the group to the view with a permission

Written out:

com2sec monnet 10.0.0.5 S3cr3tR0str1ng
group   mongroup v2c monnet
access  mongroup "" any noauth exact monitoring none none

The access line reads: group mongroup, any security model, no auth required, exact-match, read using the monitoring view, no write, no notify. For the shorthand, net-snmp also accepts a view directly on the community line:

rocommunity S3cr3tR0str1ng 10.0.0.5 -V monitoring

The -V monitoring binds that community to the same view without spelling out the full chain — simpler when you only need one community scoped to one allowlist.

Step 3: Verify

Restart snmpd, then test both an in-view and an out-of-view OID. An allowed subtree returns data:

snmpwalk -v2c -c S3cr3tR0str1ng <host> 1.3.6.1.2.1.1
SNMPv2-MIB::sysDescr.0 = STRING: Linux edge01 5.15.0-generic x86_64
SNMPv2-MIB::sysUpTime.0 = Timeticks: (98765432) 11 days, 10:20:54.32

Now query something you did not include — say the ARP/routing area — and confirm it's invisible:

snmpget -v2c -c S3cr3tR0str1ng <host> 1.3.6.1.2.1.4.22.1.2.2.10.0.0.1
SNMPv2-MIB::... = No Such Object available on this agent at this OID

Data on the allowed subtree and No Such Object on the excluded one means the allowlist is working. That "no such object" is VACM doing its job — the OID may well exist on the box, but it's outside the view, so the agent behaves as though it isn't there.

Example: a monitoring allowlist

A typical server poller needs surprisingly few subtrees. A sensible default allowlist:

  • 1.3.6.1.2.1.1 — system group (identity, uptime, contact).
  • 1.3.6.1.2.1.25 — host-resources (CPU, storage, running processes).
  • 1.3.6.1.2.1.2 and 1.3.6.1.2.1.31 — interfaces (traffic, errors).

That covers the bread-and-butter of server and network monitoring while leaving routing tables, ARP caches, and the full software inventory unexposed. Add only what a real dashboard queries; if you're unsure what an OID is, the glossary and the sensor index map metrics to their subtrees.

How ostr.io uses this

An allowlist is exactly the pattern an external checker should rely on. ostr.io recommends exposing only a narrow OID allowlist for its off-box SNMPv2c polling, so the agent surfaces just the health metrics it needs and nothing sensitive — a good fit because an external, agentless path should have the least possible visibility into the host. See external monitoring for how that off-box check fits alongside on-box hardening.

Frequently asked questions

How do I restrict which SNMP OIDs are readable?

Define a VACM view listing the subtrees to expose — view <name> included <oid> — then bind it to a group with an access line (or use rocommunity <string> <source> -V <view> for the short form). Restart snmpd; anything outside the view returns no such object.

What is VACM?

VACM is the View-based Access Control Model, net-snmp's way of controlling which OID subtrees a requester may read. You group OIDs into a named view using included/excluded subtrees and attach that view to a security group, so each community or user sees only its authorised slice of the MIB.

How do I limit a community to a view?

The quickest way is rocommunity <string> <source> -V <viewname>, which binds that community to the named view. For finer control use the full com2secgroupaccess chain and reference the view in the access line's read column.

What happens when I query an OID that's out of view?

The agent returns No Such Object (or no response), exactly as if the OID didn't exist — even though it may be present on the device. VACM filters the response, so an out-of-view query yields no data, which is the whole point of the allowlist.

Key takeaways

  • A read-only agent still exposes its whole tree — scope it with a VACM allowlist.
  • Build a view from included subtrees; carve exceptions with excluded.
  • Bind it via com2sec/group/access, or the shorthand -V <view> on rocommunity.
  • Verify both ways: in-view returns data, out-of-view returns No Such Object.
  • A typical poller needs only system, host-resources, and interface subtrees.
  • The ostr.io external check leans on exactly this allowlist pattern — see external monitoring.

Monitor it from outside the network

SNMP only tells you a box is healthy while something is still asking. ostr.io polls your endpoints externally and fires email + SMS alerts the moment a reading crosses your line — or the agent goes silent.