Configuration Enforcement for SNMP

This documents describes the SNMP configuration of network devices with saltstack and and napalm.

Configuration Management in the Network

Configuration management in server deployment is widely practised. Key players are puppet, saltstack, or ansible. Administrators developed a whole tool chain with git to speed up the deployment and utilized different environments to improve the quality of deployed configurations.

What proved succesful in server setups should also help to make the life of a network admin easier. In this article I will describe the tool chain of saltstack and napalm to write general valid configurations and to deploy it to in manufacturer dependend device configurations.

Of course, such an automated configuration management also helps to unify your network setups and enable an administrator to take care of a lot more devices.

Napalm and SaltStack

The setup of napalm and saltstack for network configuration management is described on the website of the project. Basically you need a salt-proxy that provides the link between the saltstack configuation management the the device configuration.

As an example the documentation also describes the state and the pillar of the ntp peers on the network devices. The example of the ntp state is somehow hidden in the source code of the napalm-salt module.

But the examples in the next section SNMP do not work as documented. So here is my solution.

The SNMP pillar

In the saltstack environment the pillar is the data store, where configuration data is stored. The saltstack states are the code how to configure things. So code and data are strictly separated by design. Let’s start with the SNMP data:

  contact:   <name>
  email:     <mail address>
  location:  <location>
  community: <community name>

I use SNMPv2c with a community as an example to simplify this documentation. In real life SNMPv3 should be used for better security.

The state File

States tell saltstack how to do things. For the SNMP state of network devices my state file looks like

    - template_name: salt://switch/files/snmp.jinja
      contact: {{ salt['pillar.get']('snmp_config:contact') }}
      email: {{ salt['pillar.get']('snmp_config:email') }}
      location: {{ salt['pillar.get']('snmp_config:location') }}
      community: {{ salt['pillar.get']('snmp_config:community') }}

The Template

The template the state above uses tells saltstack, or better the netconfig.managed function which commands have to be entered on the devices of the various manufacturers. My template looks like

{%- if grains.vendor|lower == 'cisco' %}
  snmp-server community {{ community }} RO
  snmp-server location {{ location }}
  snmp-server contact {{ contact }} <{{ email }}>
{%- elif grains.os|lower == 'junos' %}
  snmp {
      location "{{ location }}";
      contact "{{ contact }} <{{ email }}>";
      community {{ community }} {
        authorization read-only;
{%- endif %}

With this setup and the state file stored in $files_root/switch/snmp.sls, the proxy running then the command

salt <devicename> state.apply switch.snmp

sets the snmp configuration of my network devices as defined on my pillar.


Of course, the ntp state and the snmp state are only the beginning. With the netconfig.managed function of saltstack, you can implement any configuration on the devices you want.

Even better is utilizing the openconfig model that describes standards for defining network components independent of any manufacturer. In one of my next blogs I will describe how to use the netbox tool as the central data store in saltstack.

Michael Schwartzkopff, 15 Feb 2019

   salt    napalm    snmp