Ansible SNMP Monitoring Network Devices
SNMP (Simple Network Management Protocol) remains the standard for monitoring network devices — switches, routers, firewalls, UPS systems, and servers. Ansible automates SNMP configuration across your entire fleet, ensuring consistent community strings, SNMPv3 credentials, and trap destinations.
Why Automate SNMP with Ansible
- Consistent security — same SNMPv3 credentials everywhere
- Rapid deployment — configure hundreds of devices at once
- Audit trail — version-controlled SNMP configurations
- Compliance — enforce SNMPv3 (disable v1/v2c) fleet-wide
- Integration — pair with Prometheus SNMP exporter or Zabbix
SNMPv3 Configuration on Linux Servers
---
- name: Configure SNMPv3 on Linux Servers
hosts: all
become: true
vars:
snmp_location: "DataCenter-A Rack-12"
snmp_contact: "ops@example.com"
snmp_v3_users:
- username: monitoring
auth_protocol: SHA-256
auth_password: "{{ vault_snmp_auth_password }}"
priv_protocol: AES-256
priv_password: "{{ vault_snmp_priv_password }}"
access_level: rouser
snmp_trap_receivers:
- host: 10.0.0.50
port: 162
version: 3
username: trap_user
snmp_disable_v1_v2c: true
tasks:
- name: Install SNMP packages
ansible.builtin.package:
name:
- net-snmp
- net-snmp-utils
state: present
when: ansible_os_family == "RedHat"
- name: Install SNMP packages (Debian)
ansible.builtin.package:
name:
- snmpd
- snmp
- libsnmp-dev
state: present
when: ansible_os_family == "Debian"
- name: Stop SNMP before user creation
ansible.builtin.systemd:
name: snmpd
state: stopped
- name: Deploy SNMP configuration
ansible.builtin.template:
src: snmpd.conf.j2
dest: /etc/snmp/snmpd.conf
owner: root
group: root
mode: "0600"
backup: true
notify: Restart SNMPD
- name: Create SNMPv3 users
ansible.builtin.command:
cmd: >
net-snmp-create-v3-user
-ro
-a {{ item.auth_protocol }}
-A '{{ item.auth_password }}'
-x {{ item.priv_protocol }}
-X '{{ item.priv_password }}'
{{ item.username }}
loop: "{{ snmp_v3_users }}"
args:
creates: /var/lib/net-snmp/snmpd.conf
no_log: true
- name: Enable and start SNMPD
ansible.builtin.systemd:
name: snmpd
enabled: true
state: started
- name: Verify SNMPv3 connectivity
ansible.builtin.command:
cmd: >
snmpget -v3
-u {{ snmp_v3_users[0].username }}
-l authPriv
-a {{ snmp_v3_users[0].auth_protocol }}
-A '{{ snmp_v3_users[0].auth_password }}'
-x {{ snmp_v3_users[0].priv_protocol }}
-X '{{ snmp_v3_users[0].priv_password }}'
localhost
sysUpTime.0
register: snmp_test
changed_when: false
no_log: true
failed_when: snmp_test.rc != 0
handlers:
- name: Restart SNMPD
ansible.builtin.systemd:
name: snmpd
state: restarted
SNMPD Configuration Template
templates/snmpd.conf.j2:
# System information
sysLocation {{ snmp_location }}
sysContact {{ snmp_contact }}
sysServices 72
{% if snmp_disable_v1_v2c %}
# Disable SNMPv1 and SNMPv2c (security best practice)
# No rocommunity or rwcommunity directives
{% else %}
# SNMPv2c read-only community (legacy — prefer SNMPv3)
rocommunity {{ snmp_community | default('public') }} {{ snmp_allowed_network | default('127.0.0.1') }}
{% endif %}
# SNMPv3 user access
{% for user in snmp_v3_users %}
{{ user.access_level }} {{ user.username }}
{% endfor %}
# Agent settings
agentAddress udp:161
agentAddress udp6:161
# System view
view systemonly included .1.3.6.1.2.1.1
view systemonly included .1.3.6.1.2.1.25.1
# Full view for authenticated users
view all included .1
# Access control
{% for user in snmp_v3_users %}
{% if user.access_level == 'rouser' %}
rouser {{ user.username }} priv -V all
{% elif user.access_level == 'rwuser' %}
rwuser {{ user.username }} priv -V all
{% endif %}
{% endfor %}
# Trap/inform destinations
{% for receiver in snmp_trap_receivers %}
{% if receiver.version == 3 %}
trapsess -v 3 -u {{ receiver.username }} -l authPriv -a SHA-256 -x AES-256 {{ receiver.host }}:{{ receiver.port }}
{% else %}
trap2sink {{ receiver.host }}:{{ receiver.port }} {{ snmp_community | default('public') }}
{% endif %}
{% endfor %}
# Disk monitoring
disk / 10%
disk /var 10%
# Load monitoring
load 12 10 5
# Process monitoring
{% for proc in snmp_monitored_processes | default([]) %}
proc {{ proc.name }} {{ proc.max | default(0) }} {{ proc.min | default(1) }}
{% endfor %}
# Extend scripts for custom OIDs
{% for extend in snmp_extends | default([]) %}
extend {{ extend.name }} {{ extend.command }}
{% endfor %}
Network Device SNMP Configuration
For Cisco, Arista, and Juniper devices:
- name: Configure SNMP on Cisco IOS devices
hosts: cisco_switches
gather_facts: false
connection: ansible.netcommon.network_cli
vars:
snmp_v3_user: monitoring
snmp_v3_group: MONITOR_GROUP
snmp_trap_host: 10.0.0.50
tasks:
- name: Configure SNMPv3 on Cisco IOS
cisco.ios.ios_config:
lines:
- snmp-server group {{ snmp_v3_group }} v3 priv read FULL_VIEW
- snmp-server user {{ snmp_v3_user }} {{ snmp_v3_group }} v3 auth sha {{ vault_snmp_auth_password }} priv aes 256 {{ vault_snmp_priv_password }}
- snmp-server view FULL_VIEW iso included
- snmp-server location {{ snmp_location }}
- snmp-server contact {{ snmp_contact }}
- snmp-server host {{ snmp_trap_host }} version 3 priv {{ snmp_v3_user }}
- snmp-server enable traps
- no snmp-server community public
- no snmp-server community private
no_log: true
- name: Configure SNMP on Arista EOS
hosts: arista_switches
gather_facts: false
connection: ansible.netcommon.httpapi
tasks:
- name: Configure SNMPv3 on Arista
arista.eos.eos_config:
lines:
- snmp-server view FULL_VIEW iso included
- snmp-server group MONITOR_GROUP v3 priv read FULL_VIEW
- snmp-server user monitoring MONITOR_GROUP v3 auth sha {{ vault_snmp_auth_password }} priv aes {{ vault_snmp_priv_password }}
- snmp-server host {{ snmp_trap_host }} version 3 priv monitoring
- no snmp-server community public
no_log: true
Prometheus SNMP Exporter Integration
- name: Deploy SNMP Exporter for Prometheus
hosts: monitoring_servers
become: true
vars:
snmp_exporter_version: "0.26.0"
snmp_targets:
- name: core-switch-01
address: 10.0.0.1
module: if_mib
- name: core-router-01
address: 10.0.0.2
module: cisco
- name: ups-01
address: 10.0.0.100
module: apcups
tasks:
- name: Download SNMP Exporter
ansible.builtin.get_url:
url: "https://github.com/prometheus/snmp_exporter/releases/download/v{{ snmp_exporter_version }}/snmp_exporter-{{ snmp_exporter_version }}.linux-amd64.tar.gz"
dest: /tmp/snmp_exporter.tar.gz
- name: Extract SNMP Exporter
ansible.builtin.unarchive:
src: /tmp/snmp_exporter.tar.gz
dest: /usr/local/bin/
remote_src: true
extra_opts: ["--strip-components=1"]
- name: Deploy SNMP Exporter configuration
ansible.builtin.template:
src: snmp_exporter.yml.j2
dest: /etc/snmp_exporter/snmp.yml
mode: "0640"
notify: Restart SNMP Exporter
- name: Deploy systemd service
ansible.builtin.copy:
content: |
[Unit]
Description=Prometheus SNMP Exporter
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/snmp_exporter --config.file=/etc/snmp_exporter/snmp.yml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
dest: /etc/systemd/system/snmp_exporter.service
mode: "0644"
notify: Restart SNMP Exporter
- name: Start SNMP Exporter
ansible.builtin.systemd:
name: snmp_exporter
enabled: true
state: started
daemon_reload: true
- name: Add Prometheus scrape config for SNMP targets
ansible.builtin.blockinfile:
path: /etc/prometheus/prometheus.yml
insertafter: "scrape_configs:"
block: |
- job_name: 'snmp'
scrape_interval: 60s
scrape_timeout: 30s
static_configs:
{% for target in snmp_targets %}
- targets: ['{{ target.address }}']
labels:
device: '{{ target.name }}'
module: '{{ target.module }}'
{% endfor %}
metrics_path: /snmp
params:
auth: ['monitoring_v3']
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [module]
target_label: __param_module
- target_label: __address__
replacement: localhost:9116
notify: Restart Prometheus
handlers:
- name: Restart SNMP Exporter
ansible.builtin.systemd:
name: snmp_exporter
state: restarted
- name: Restart Prometheus
ansible.builtin.systemd:
name: prometheus
state: reloaded
SNMP Trap Receiver (snmptrapd)
- name: Configure SNMP Trap Receiver
hosts: monitoring_servers
become: true
tasks:
- name: Install snmptrapd
ansible.builtin.package:
name: net-snmp-utils
state: present
- name: Deploy snmptrapd configuration
ansible.builtin.copy:
content: |
# SNMPv3 user for receiving traps
createUser -e 0x8000000001020304 trap_user SHA-256 "{{ vault_snmp_auth_password }}" AES-256 "{{ vault_snmp_priv_password }}"
authUser log,execute trap_user priv
# Log traps to file
[snmptrapd]
logOption f /var/log/snmptrapd.log
# Forward traps to trap handler script
traphandle default /usr/local/bin/snmp_trap_handler.sh
dest: /etc/snmp/snmptrapd.conf
owner: root
group: root
mode: "0600"
no_log: true
notify: Restart snmptrapd
- name: Deploy trap handler script
ansible.builtin.copy:
content: |
#!/bin/bash
# Forward SNMP traps to alerting system
read host
read ip
while read oid val; do
echo "$(date -Iseconds) $host $ip $oid $val" >> /var/log/snmp_traps.log
# Send to webhook
curl -s -X POST http://alertmanager:9093/api/v1/alerts \
-H "Content-Type: application/json" \
-d "[{\"labels\":{\"alertname\":\"SNMPTrap\",\"device\":\"$host\",\"oid\":\"$oid\"},\"annotations\":{\"value\":\"$val\"}}]"
done
dest: /usr/local/bin/snmp_trap_handler.sh
mode: "0755"
- name: Enable snmptrapd
ansible.builtin.systemd:
name: snmptrapd
enabled: true
state: started
handlers:
- name: Restart snmptrapd
ansible.builtin.systemd:
name: snmptrapd
state: restarted
Security Hardening
- name: SNMP security audit and hardening
hosts: all
become: true
tasks:
- name: Ensure no default community strings
ansible.builtin.lineinfile:
path: /etc/snmp/snmpd.conf
regexp: "^(ro|rw)community\\s+(public|private)"
state: absent
notify: Restart SNMPD
- name: Restrict SNMP to management network
ansible.builtin.iptables:
chain: INPUT
protocol: udp
destination_port: "161"
source: "{{ snmp_management_network }}"
jump: ACCEPT
comment: "Allow SNMP from management network"
- name: Block SNMP from all other sources
ansible.builtin.iptables:
chain: INPUT
protocol: udp
destination_port: "161"
jump: DROP
comment: "Block SNMP from unauthorized sources"
- name: Verify no SNMPv1/v2c access
ansible.builtin.command:
cmd: snmpget -v2c -c public localhost sysUpTime.0
register: v2c_test
changed_when: false
failed_when: v2c_test.rc == 0
ignore_errors: true
Troubleshooting
| Problem | Cause | Solution |
|---|---|---|
| "Timeout: No Response" | Firewall or wrong community | Check UDP 161, verify credentials |
| "Authentication failure" | Wrong auth/priv passwords | Recreate SNMPv3 user |
| "No Such Object" | OID not in view | Expand SNMP view to include OID tree |
| Incomplete walk results | Agent maxGetbulk too low | Increase maxGetbulkRepeats |
| High CPU from SNMP polling | Too frequent polling | Increase scrape_interval to 60s+ |
Related Articles
- Ansible Network Automation Cisco Arista Juniper
- Ansible Prometheus Grafana Monitoring
- Ansible Firewalld UFW Firewall
Conclusion
SNMP monitoring with Ansible gives you consistent, secure, auditable device monitoring across your entire infrastructure. By enforcing SNMPv3, disabling legacy community strings, and integrating with modern monitoring stacks like Prometheus, you get the broad device coverage of SNMP with the security and observability standards of a modern platform.