
SNMP4J-AgentX SECURITY README
=============================

AgentX does not implement its own security. Because an AgentX subagent may
significantly interfere with a master agent's operation - it registers MIB
regions, answers requests on the master agent's behalf, and can send
notifications through it - security measures should be taken to allow only
known subagents to connect to the master agent.

SNMP4J-AgentX addresses this with the agent audit policy of SNMP4J-Agent.
The audit policy replaces the two mechanisms that earlier versions of this
file recommended, both of which are obsolete:

  * The Java SecurityManager and the "master.security" policy file. The
    SecurityManager is deprecated for removal since Java 17 (JEP 411) and is
    permanently disabled since Java 24 (JEP 486). On Java 24 and later, the
    JVM refuses to start at all when java.security.manager is set to anything
    other than "disallow":

        Error occurred during initialization of VM
        java.lang.Error: A command line option has attempted to allow or
        enable the Security Manager. Enabling a Security Manager is not
        supported.

    The "master.security" file is kept in this directory for reference only.
    Do not use it with a current JVM.

  * AgentXMasterAgent.setLocalhostSubagentsOnly(true), which is deprecated.
    It only compared the peer address of an incoming connection against the
    loopback address and did nothing else. Use an audit policy instead.


THE AGENT AUDIT POLICY
----------------------

An audit policy answers one question for every security relevant operation
the agent performs: is this operation permitted, and should it be recorded?
It covers three kinds of operation:

  TRANSPORT   listening on an address, sending to and receiving from a peer
  FILE        reading, writing, creating and deleting the agent's files
  OBJECT      access to managed objects (audited only, enforcement stays
              with the VACM)

A policy is an implementation of org.snmp4j.agent.audit.AgentAuditPolicy.
The supplied implementation, DefaultAgentAuditPolicy, takes two arguments:
an AgentPolicyProfile that describes what is allowed, and an AgentAuditLevel
that describes what to do when something is not allowed.

Audit levels (org.snmp4j.agent.audit.AgentAuditLevel):

  OFF         no auditing, everything is permitted.
  LOG         record every decision at INFO level, deny nothing.
  WARN        record violations at WARN level, deny nothing. Use this to
              validate a new profile against real traffic before enforcing it.
  RESTRICT    record violations at WARN level and deny the operation.

Only RESTRICT enforces. Start with WARN, watch the log for "policy violation"
records, adjust the profile until they stop, then switch to RESTRICT.

Policy profile (org.snmp4j.agent.audit.AgentPolicyProfile):

  NetworkAccess             LOOPBACK, SITE_LOCAL_NETWORK,
                            REMOTE_NETWORK_LIMITED, REMOTE_NETWORK_UNLIMITED
  FileAccess                NO_ACCESS, WORKING_DIRECTORY_READONLY,
                            WORKING_DIRECTORY_READWRITE,
                            LIMITED_DIRECTORY_ACCESS, ALL_DIRECTORY_ACCESS
  ManagedObjectAccess       READ, READ_WRITE, READ_WRITE_CREATE, UNRESTRICTED
  minimum SecurityLevel     the least SNMPv3 security level accepted
  allowedFiles              file names permitted in addition to the FileAccess
                            level
  allowedDirectories        directories permitted with LIMITED_DIRECTORY_ACCESS
  allowedAddresses          peer addresses permitted in addition to the
                            NetworkAccess level (used by
                            REMOTE_NETWORK_LIMITED)
  allowedObjects            per-OID overrides of ManagedObjectAccess

For a master agent, NetworkAccess is what restricts which subagents may
connect. SEND and RECEIVE operations are checked against the peer address:
LOOPBACK accepts loopback peers only, SITE_LOCAL_NETWORK also accepts peers
on the local network, and REMOTE_NETWORK_LIMITED accepts loopback peers plus
the addresses listed in allowedAddresses. LISTEN and CLOSE are always
permitted, because they concern the agent's own sockets rather than a peer.

Replacing setLocalhostSubagentsOnly(true) - restrict a master agent to
subagents on the local host and enforce the restriction:

    AgentPolicyProfile profile = new AgentPolicyProfile(
            AgentPolicyProfile.ManagedObjectAccess.UNRESTRICTED,
            AgentPolicyProfile.NetworkAccess.LOOPBACK,
            AgentPolicyProfile.FileAccess.WORKING_DIRECTORY_READWRITE,
            SecurityLevel.authPriv);
    masterAgent.setAuditPolicy(
            new DefaultAgentAuditPolicy(profile, AgentAuditLevel.RESTRICT));

To allow a fixed set of remote subagents in addition to the local ones, use
REMOTE_NETWORK_LIMITED and list their addresses in allowedAddresses.

setAuditPolicy(..) is inherited from AgentConfigManager. Call it before the
agent is initialized - that is, before initialize() or run() - so that the
policy is attached to every transport mapping. It refuses to overwrite an
audit policy that has already been set. A subagent receives its policy
through the AgentXSubagent constructor instead.

An audit record can be written to an OutputStream in addition to the log, by
passing one to the DefaultAgentAuditPolicy constructor - for example a
FileOutputStream for a dedicated audit trail, or System.err.


UNIX DOMAIN SOCKETS
-------------------

A Unix domain socket connection is always local and has no InetAddress, so
the NetworkAccess levels above do not apply to it. Use
UnixDomainAgentProfilePolicy from the SNMP4J-Unix-Transport library
(org.snmp4j.transport.unix.audit) for these: it is a DefaultAgentAuditPolicy
that checks the file system access a Unix domain socket operation needs
instead of the peer's network address. The socket path is matched against
allowedFiles and allowedDirectories, with LISTEN checked as a CREATE, CLOSE
as a DELETE, SEND as a WRITE, and RECEIVE as a READ file operation.
Transport operations of all other address domains are audited unchanged.

    AgentAuditPolicy policy = new UnixDomainAgentProfilePolicy(
            new AgentPolicyProfile(
                    AgentPolicyProfile.ManagedObjectAccess.UNRESTRICTED,
                    AgentPolicyProfile.NetworkAccess.LOOPBACK,
                    AgentPolicyProfile.FileAccess.LIMITED_DIRECTORY_ACCESS,
                    SecurityLevel.authNoPriv,
                    new String[] { "MyAgent.cfg" },
                    new String[] { "/var/agentx" }, null, null),
            AgentAuditLevel.RESTRICT);

With Unix domain sockets, the file system is the access control: the
permissions on the directory that holds the master agent's socket decide who
may connect to it, because connecting requires write permission on the socket
file. Placing the socket in a directory that only the intended users can
reach is the strongest restriction available, and it is enforced by the
operating system rather than by the agent.

See org.snmp4j.agent.agentx.subagent.test.TestSubagent and
org.snmp4j.agent.agentx.master.test.TestMasterAgent for working examples.


OTHER MEASURES
--------------

  * Bind the AgentX master agent to the loopback interface (127.0.0.1) or to
    a Unix domain socket rather than to 0.0.0.0, so that remote hosts cannot
    reach it in the first place. Access control that the operating system
    enforces is preferable to access control the agent enforces.

  * Run the master agent and its subagents under a dedicated, unprivileged
    user account.

  * If AgentX has to cross a host boundary, tunnel it (TLS, SSH, VPN) or
    confine it with a packet filter. AgentX over TCP is neither authenticated
    nor encrypted, so any host that can reach port 705 can register MIB
    regions with the master agent.
