Modernizing SNMP Security: SNMPv3 over TLS and DTLS with ezsnmp

Note

  • Published: October 28, 2026

  • Authors: Written by Gemini 3.8 Flash, Co-Authored & Reviewed by Carlos Santos (@carlkidcrypto)

  • Estimated Reading Time: 5 minutes

  • Tags: Python • Snmp • Snmpv3 • Tls • Dtls • Net-Snmp • Ezsnmp • Network-Security

Beyond Pre-Shared Keys: The Case for SNMP over TLS

For decades, network engineers securing SNMP relied on the User-based Security Model (USM) introduced in SNMPv3. While USM provided cryptographic hashing (SHA-256) and symmetric encryption (AES-128/256), it brought painful operational trade-offs:

  • Symmetric Key Distribution: Every network device must be pre-configured with static passphrases.

  • Complex Key Rotation: Rotating credentials across thousands of switches demands brittle orchestration scripts and risks locking pollers out.

  • EngineID Entanglement: USM localized keys are tied directly to each target agent’s unique EngineID, breaking centralized credential reuse.

To solve these scalability barriers, the IETF standardized the Transport Security Model (TSM, RFC 6353), enabling SNMPv3 to run over standard cryptographic transports:

  • TLS (Transport Layer Security over TCP): Stream-oriented encryption using X.509 certificates, running on port 10161.

  • DTLS (Datagram Transport Layer Security over UDP): Datagram encryption with X.509 mutual authentication, running on port 10161.

By replacing pre-shared passwords with X.509 Public Key Infrastructure (PKI), enterprises can manage SNMP authentication through centralized certificate authorities (CAs).

ezsnmp leverages Net-SNMP’s native OpenSSL transport layer, allowing Python automation scripts to poll infrastructure over mutual TLS (mTLS) with native C speed.

Architecture: Transport Security Model (RFC 6353)

Running SNMPv3 over TLS/DTLS fundamentally alters how sessions authenticate:

  1. Mutual TLS Handshake (mTLS): The client poller and network switch validate each other’s identity using trusted X.509 digital certificates.

  2. Ephemeral Session Keys: Symmetric encryption keys are negotiated dynamically per connection, eliminating static passwords on devices.

  3. Certificate Mapping (Fingerprint to SecName): Net-SNMP maps the client certificate’s Subject Alternative Name (SAN), Common Name (CN), or SHA-256 fingerprint directly to an authorized SNMP security username.

  4. TCP Transport Option: Polling over TLS/TCP bypasses UDP packet fragmentation entirely, ensuring massive routing table walks never suffer from dropped UDP fragments.

Configuring Net-SNMP for TLS/DTLS Transports

Net-SNMP supports TLS and DTLS endpoints via the tlstcp: and dtlsudp: transport identifiers.

1. Device Certificate Configuration (snmp.conf)

Configure the certificate trust store and client certificate in /etc/snmp/snmp.conf (or ~/.snmp/snmp.conf):

# Select Transport Security Model (TSM) for TLS/DTLS endpoints
[snmp]
defSecurityModel tsm

# Define trusted Certificate Authority (CA) certificate
trustCert /etc/ssl/certs/internal_root_ca.crt

# Client certificate fingerprint for mutual TLS authentication
clientCert 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78

# Map remote server certificate fingerprint to local security name
# Syntax: certMap PRIORITY FINGERPRINT TYPE ARGS...
certMap 10 12:34:56:78:9A:BC:DE:F0:12:34:56:78:9A:BC:DE:F0:12:34:56:78 --sn noc_automation

2. Master Agent Endpoint (snmpd.conf)

On managed Linux hosts or switches running Net-SNMP, bind the daemon to standard TLS and DTLS ports:

# Server certificates are registered in the [snmp] library context
[snmp]
serverCert /etc/ssl/certs/switch_server.crt

# Master agent listener bindings for RFC 6353 endpoints
[snmpd]
master agentx
agentaddress tlstcp:10161,dtlsudp:10161

Practical Implementation: Polling over TLS with ezsnmp

Once certificates are configured in the Net-SNMP environment, initiating an encrypted TLS or DTLS session in ezsnmp requires specifying the transport prefix:

from ezsnmp import Session
from ezsnmp.exceptions import GenericError

def poll_secure_switch_tls(hostname: str):
    """Query metrics over TLS (TCP port 10161) using X.509 mTLS."""
    # Target URI specifies the tlstcp transport domain
    target_endpoint = f"tlstcp:{hostname}:10161"

    session = Session(
        hostname=target_endpoint,
        version=3,
        security_level="authPriv",
        security_username="noc_automation",
        timeout=3,
        retries=1
    )

    try:
        # Poll system metrics over encrypted TCP stream
        sys_descr = session.get("sysDescr.0")[0]
        uptime = session.get("sysUpTime.0")[0]
        print(f"[{hostname}] TLS Connection Established!")
        print(f"  Description: {sys_descr.value}")
        print(f"  Uptime     : {uptime.value}")

    except GenericError as exc:
        print(f"[{hostname}] TLS Polling Failed: {exc}")

def poll_secure_switch_dtls(hostname: str):
    """Query metrics over DTLS (UDP port 10161) for low latency."""
    target_endpoint = f"dtlsudp:{hostname}:10161"

    session = Session(
        hostname=target_endpoint,
        version=3,
        security_level="authPriv",
        security_username="noc_automation",
        timeout=2,
        retries=2,
        set_max_repeaters_to_num=25
    )

    try:
        results = session.bulk_walk("ifDescr")
        print(
            f"[{hostname}] DTLS Walk Retrieved {len(results)} Interfaces."
        )
    except GenericError as exc:
        print(f"[{hostname}] DTLS Polling Failed: {exc}")

if __name__ == "__main__":
    poll_secure_switch_tls("core-sw01.internal")
    poll_secure_switch_dtls("core-sw01.internal")

Choosing Between TLS (TCP) and DTLS (UDP)

  • When to choose TLS (TCP):

    • Large Table Extractions: Full BGP routing tables or ARP caches that span thousands of OIDs. TCP windowing and segment reassembly eliminate UDP packet drops and MTU mismatch truncations.

    • Zero Loss Requirements: Mission-critical audit workflows.

  • When to choose DTLS (UDP):

    • High-Frequency Telemetry: Sub-second counter sampling where low latency takes precedence over guaranteed delivery.

    • High Device Counts: Polling thousands of devices without exhausting TCP connection tables on management switches.

Production Best Practices

  • Port Allocations (10161 vs 161): RFC 6353 assigns port 10161 for SNMPv3 TLS/DTLS traffic (and 10162 for traps). Update firewall ACLs to permit traffic to these ports.

  • Automate Certificate Lifecycle: Use HashiCorp Vault, cert-manager, or ACME agents to automatically rotate client certificates every 60–90 days, ensuring pollers maintain valid PKI credentials without downtime.

  • Enforce SHA-256 Fingerprints: Avoid legacy SHA-1 thumbprints when configuring certificate maps in Net-SNMP configuration files.

Migration Notes: Easy SNMP vs ezsnmp

  • OpenSSL 3.0+ Modernization: Legacy easysnmp struggled to compile against modern OpenSSL 3.0+ and failed to negotiate modern TLS 1.3 cipher suites.

  • C++17 Transport Cleanliness in ezsnmp: ezsnmp’s updated C++17 build matrix links cleanly against modern Net-SNMP 5.9/5.10 and OpenSSL 3.x libraries, providing verified TLS 1.3 cryptographic handshakes.