Salt-Minion for Automation
Salt-Minion integrates VyOS with SaltStack for centralized configuration management and automation of network devices.
Overview
What is SaltStack
SaltStack is a configuration management and orchestration system:
- IT infrastructure automation
- Remote command execution
- Configuration management
- Infrastructure as Code approach
- Event-driven architecture
- Python-based solution
Salt Architecture
Salt Master:
- Central management server
- Stores states and pillars
- Manages minions
- Performs orchestration
Salt Minion:
- Agent on the managed device
- Executes commands from the Master
- Sends data and events
- Applies configurations
Salt Proxy Minion:
- For devices that cannot run an agent
- Uses SSH/NETCONF/API
- Support for network devices
- Netmiko for VyOS
Capabilities for VyOS
- Operational commands - running show commands
- Configuration management - applying configurations
- Batch operations - bulk changes
- Event monitoring - tracking events
- Inventory management - hardware accounting
- Compliance checking - verifying compliance
Installing Salt Master
Installation on the Management Server
Ubuntu/Debian:
# Add SaltStack repository
curl -fsSL https://packages.broadcom.com/artifactory/api/gpg/key/public | sudo tee /etc/apt/keyrings/salt-archive-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/salt-archive-keyring.gpg arch=amd64] https://packages.broadcom.com/artifactory/saltproject-deb/ stable main" | sudo tee /etc/apt/sources.list.d/salt.list
# Install Salt Master
sudo apt update
sudo apt install salt-master salt-minion salt-ssh
# Start service
sudo systemctl enable salt-master
sudo systemctl start salt-masterCentOS/RHEL:
# Add repository
sudo yum install https://repo.saltproject.io/salt/py3/redhat/8/x86_64/latest/salt-repo-latest.el8.noarch.rpm
# Install
sudo yum install salt-master salt-minion
# Start
sudo systemctl enable salt-master
sudo systemctl start salt-masterBasic Master Configuration
/etc/salt/master:
interface: 0.0.0.0
auto_accept: False
file_roots:
base:
- /srv/salt/states
pillar_roots:
base:
- /srv/salt/pillarsCreating the directory structure:
sudo mkdir -p /srv/salt/{states,pillars}
sudo systemctl restart salt-masterConfiguring Salt-Minion on VyOS
Basic Setup
Minimal configuration:
set service salt-minion id 'vyos-router-01'
set service salt-minion master '192.0.2.250'
commit
saveParameters:
id- unique minion identifiermaster- IP or hostname of the Salt Master
Advanced Configuration
set service salt-minion id 'vyos-edge-router'
set service salt-minion master '192.0.2.250'
set service salt-minion hash md5
set service salt-minion interval 60
commit
saveParameters:
hash- hashing algorithm (md5, sha256)interval- Master check interval (seconds)
Multiple Masters
set service salt-minion id 'vyos-router-01'
set service salt-minion master '192.0.2.250'
set service salt-minion master '192.0.2.251'
commit
saveAccepting Keys on the Master
Viewing Pending Keys
On the Salt Master:
sudo salt-key -LOutput:
Accepted Keys:
Denied Keys:
Unaccepted Keys:
vyos-router-01
Rejected Keys:Accepting a Key
Accept a specific key:
sudo salt-key -a vyos-router-01Accept all keys (use with caution!):
sudo salt-key -ARemoving a Key
sudo salt-key -d vyos-router-01Verifying the Connection
sudo salt 'vyos-router-01' test.pingOutput:
vyos-router-01:
TrueSalt Proxy Minion for VyOS
What is a Proxy Minion
A Proxy Minion is used when:
- An agent cannot be installed on the device
- Management via SSH/API is required
- Network devices lack Salt support
Configuring the Netmiko Proxy
Installing Netmiko on the Salt Master:
sudo pip3 install netmikoCreating a Pillar for the device:
/srv/salt/pillars/vyos-proxy.sls:
proxy:
proxytype: netmiko
device_type: vyos
host: 192.0.2.10
username: vyos
password: vyos_password
secret: enable_passwordTop file for Pillars:
/srv/salt/pillars/top.sls:
base:
'vyos-proxy-01':
- vyos-proxyStarting the Proxy Minion
sudo salt-proxy --proxyid=vyos-proxy-01 -dOr via systemd:
/etc/systemd/system/salt-proxy@.service:
[Unit]
Description=Salt Proxy Minion %i
After=network.target
[Service]
Type=notify
NotifyAccess=all
ExecStart=/usr/bin/salt-proxy --proxyid=%i
Restart=always
[Install]
WantedBy=multi-user.targetStartup:
sudo systemctl enable salt-proxy@vyos-proxy-01
sudo systemctl start salt-proxy@vyos-proxy-01Accepting the Proxy Minion Key
sudo salt-key -a vyos-proxy-01Basic Operations
Verifying the Connection
All minions:
sudo salt '*' test.pingA specific minion:
sudo salt 'vyos-router-01' test.pingBy glob pattern:
sudo salt 'vyos-*' test.pingRetrieving Information
System version:
sudo salt 'vyos-router-01' test.versionNetwork interfaces:
sudo salt 'vyos-router-01' network.interfacesInterface details:
sudo salt 'vyos-router-01' network.interface eth0Executing Commands
Shell commands:
sudo salt 'vyos-router-01' cmd.run 'show version'Multiple commands:
sudo salt 'vyos-router-01' cmd.run 'show interfaces; show system uptime'Managing VyOS Configuration
Via Proxy Minion with Netmiko
Sending a configuration command:
sudo salt 'vyos-proxy-01' netmiko.send_config config_commands="['set interfaces ethernet eth0 description WAN_Link']" commit=TrueMultiple commands:
sudo salt 'vyos-proxy-01' netmiko.send_config \
config_commands="['set system host-name vyos-edge', 'set system domain-name example.com']" \
commit=TrueStates for Configuration
Creating a State file:
/srv/salt/states/vyos-basic.sls:
configure_hostname:
netmiko.send_config:
- config_commands:
- set system host-name vyos-router-01
- set system domain-name corp.local
- commit: True
configure_ntp:
netmiko.send_config:
- config_commands:
- set system ntp server 0.pool.ntp.org
- set system ntp server 1.pool.ntp.org
- commit: True
configure_dns:
netmiko.send_config:
- config_commands:
- set system name-server 8.8.8.8
- set system name-server 8.8.4.4
- commit: TrueApplying the State:
sudo salt 'vyos-proxy-01' state.apply vyos-basicBatch Configuration
File with commands:
/srv/salt/states/commands.txt:
set interfaces ethernet eth1 description LAN
set interfaces ethernet eth1 address 192.168.1.1/24
set service ssh port 22
set service ssh listen-address 0.0.0.0State to apply it:
/srv/salt/states/vyos-config.sls:
apply_config_from_file:
netmiko.send_config:
- config_file: salt://commands.txt
- commit: TrueApplication:
sudo salt 'vyos-proxy-01' state.apply vyos-configAutomation Examples
Example 1: Basic System Setup
/srv/salt/states/vyos-system.sls:
system_hostname:
netmiko.send_config:
- config_commands:
- set system host-name {{ pillar['hostname'] }}
- commit: True
system_timezone:
netmiko.send_config:
- config_commands:
- set system time-zone {{ pillar['timezone'] }}
- commit: True
system_users:
netmiko.send_config:
- config_commands:
- set system login user admin authentication plaintext-password {{ pillar['admin_password'] }}
- set system login user admin level admin
- commit: True/srv/salt/pillars/vyos-router-01.sls:
hostname: vyos-edge-01
timezone: Europe/Moscow
admin_password: SecurePassword123!Example 2: Interface Configuration
/srv/salt/states/vyos-interfaces.sls:
{% for iface, config in pillar['interfaces'].items() %}
configure_{{ iface }}:
netmiko.send_config:
- config_commands:
- set interfaces ethernet {{ iface }} description '{{ config.description }}'
{% if config.address %}
- set interfaces ethernet {{ iface }} address {{ config.address }}
{% endif %}
{% if config.dhcp %}
- set interfaces ethernet {{ iface }} address dhcp
{% endif %}
- commit: True
{% endfor %}/srv/salt/pillars/vyos-router-01.sls:
interfaces:
eth0:
description: "WAN Interface"
dhcp: true
eth1:
description: "LAN Interface"
address: "192.168.1.1/24"
eth2:
description: "DMZ Interface"
address: "192.168.100.1/24"Example 3: Firewall Configuration
/srv/salt/states/vyos-firewall.sls:
firewall_wan_local:
netmiko.send_config:
- config_commands:
- set firewall ipv4 name WAN_LOCAL default-action drop
- set firewall ipv4 name WAN_LOCAL rule 10 action accept
- set firewall ipv4 name WAN_LOCAL rule 10 state established
- set firewall ipv4 name WAN_LOCAL rule 10 state related
- set firewall ipv4 name WAN_LOCAL rule 20 action drop
- set firewall ipv4 name WAN_LOCAL rule 20 state invalid
- set firewall ipv4 name WAN_LOCAL rule 30 action accept
- set firewall ipv4 name WAN_LOCAL rule 30 protocol icmp
- set interfaces ethernet eth0 firewall in name WAN_LOCAL
- commit: TrueExample 4: NAT Deployment
/srv/salt/states/vyos-nat.sls:
configure_nat:
netmiko.send_config:
- config_commands:
- set nat source rule 100 outbound-interface name eth0
- set nat source rule 100 source address 192.168.1.0/24
- set nat source rule 100 translation address masquerade
- commit: TrueExample 5: DHCP Server
/srv/salt/states/vyos-dhcp.sls:
configure_dhcp_server:
netmiko.send_config:
- config_commands:
- set service dhcp-server shared-network-name LAN subnet 192.168.1.0/24 option default-router 192.168.1.1
- set service dhcp-server shared-network-name LAN subnet 192.168.1.0/24 option name-server 192.168.1.1
- set service dhcp-server shared-network-name LAN subnet 192.168.1.0/24 range 0 start 192.168.1.100
- set service dhcp-server shared-network-name LAN subnet 192.168.1.0/24 range 0 stop 192.168.1.200
- set service dhcp-server shared-network-name LAN subnet 192.168.1.0/24 subnet-id 1
- commit: TrueRetrieving Information from VyOS
Operational Commands
Via proxy minion:
# Show version
sudo salt 'vyos-proxy-01' netmiko.send_command command="show version"
# Show configuration
sudo salt 'vyos-proxy-01' netmiko.send_command command="show configuration"
# Show interfaces
sudo salt 'vyos-proxy-01' netmiko.send_command command="show interfaces"
# Show route table
sudo salt 'vyos-proxy-01' netmiko.send_command command="show ip route"Grains (Facts System)
Retrieving all grains:
sudo salt 'vyos-router-01' grains.itemsA specific grain:
sudo salt 'vyos-router-01' grains.get osMonitoring and Events
Event Bus
Subscribing to events:
sudo salt-run state.event pretty=TrueReactor System
Automatic actions in response to events:
/etc/salt/master.d/reactor.conf:
reactor:
- 'salt/minion/*/start':
- /srv/salt/reactors/minion-start.sls/srv/salt/reactors/minion-start.sls:
send_notification:
local.cmd.run:
- tgt: salt-master
- arg:
- echo "Minion {{ data['id'] }} started" | mail -s "Minion Start" admin@example.comOperational Commands
On VyOS
Checking salt-minion status:
show service salt-minionRestarting salt-minion:
restart salt-minionOn the Salt Master
List of all keys:
sudo salt-key -LList of minions:
sudo salt '*' test.pingApplying a state:
sudo salt 'vyos-router-01' state.applyHighstate (all states):
sudo salt 'vyos-router-01' state.highstateTroubleshooting
Minion Does Not Connect
Problem: The minion does not appear in the key list.
Diagnostics:
On VyOS:
show service salt-minion
show log | grep saltOn the Master:
sudo systemctl status salt-master
sudo tail -f /var/log/salt/masterSolution:
# Check Master reachability
ping 192.0.2.250
# Check ports (4505, 4506)
telnet 192.0.2.250 4505
telnet 192.0.2.250 4506
# Firewall on the Master
sudo firewall-cmd --add-port=4505-4506/tcp --permanent
sudo firewall-cmd --reloadKey Is Not Accepted
Problem: salt-key does not show the minion.
Solution:
Restart the minion on VyOS:
restart salt-minionOn the Master:
# Remove the old key
sudo salt-key -d vyos-router-01
# Wait for the new one
sudo salt-key -LCommands Do Not Run
Problem: salt 'minion' test.ping returns no result.
Diagnostics:
# Check that the key is accepted
sudo salt-key -L
# Verbose mode
sudo salt 'vyos-router-01' test.ping -l debugSolution:
# Restart the master
sudo systemctl restart salt-master
# Restart the minion
restart salt-minion # on VyOSProxy Minion Issues
Problem: The proxy minion does not connect to VyOS.
Diagnostics:
# Check the logs
sudo journalctl -u salt-proxy@vyos-proxy-01 -f
# Test SSH
ssh vyos@192.0.2.10Solution:
# Check the pillar
sudo salt 'vyos-proxy-01' pillar.items
# Verify the credentials in the pillar
# Make sure netmiko is installed
sudo pip3 install --upgrade netmikoNetmiko Errors
Problem: “Authentication failed” or “Connection timeout”.
Solution:
Check the Pillar:
sudo salt 'vyos-proxy-01' pillar.get proxyUpdate the credentials:
# /srv/salt/pillars/vyos-proxy.sls
proxy:
proxytype: netmiko
device_type: vyos
host: 192.0.2.10
username: correct_user
password: correct_passwordRefresh the pillar:
sudo salt 'vyos-proxy-01' saltutil.refresh_pillarSecurity
Security Recommendations
- Protecting the Master:
# /etc/salt/master
auto_accept: False
client_acl:
admin:
- .*
publisher_acl:
admin:
- .*- Firewall on the Master:
# Only from known networks
sudo firewall-cmd --add-rich-rule='rule family="ipv4" source address="192.0.2.0/24" port protocol="tcp" port="4505-4506" accept' --permanent
sudo firewall-cmd --reload- Encrypting Pillars:
# Generate the key
sudo salt-key --gen-keys=master
# /etc/salt/master
pillar_opts: False
gpg_keydir: /etc/salt/gpgkeys- Key Rotation:
# Remove the old key
sudo salt-key -d vyos-router-01
# The minion will generate a new one on restart
restart salt-minion- Action Auditing:
# /etc/salt/master
return_job: True
job_cache: True
keep_jobs: 24- Restricting Commands:
# /etc/salt/master
publisher_acl:
operator:
- test.ping
- network.interface
admin:
- .*Best Practices
Use Pillars for secrets:
- Store passwords in pillars
- Encrypt sensitive data
- Restrict access to pillars
Version control for States:
- Keep states in Git
- Code review changes
- Test before applying
Testing before production:
# Test mode
sudo salt 'vyos-router-01' state.apply test=True
# Single minion first
sudo salt 'vyos-router-01' state.apply vyos-config
# Then batch
sudo salt 'vyos-*' state.apply vyos-config- Backup before changes:
# Save config before applying a state
sudo salt 'vyos-proxy-01' netmiko.send_command command="save /config/backup-$(date +%Y%m%d).config"- Monitoring results:
# Check job results
sudo salt-run jobs.list_jobs
# Specific job
sudo salt-run jobs.lookup_jid <job_id>Documentation:
- Describe your states
- Comment your pillars
- Maintain a changelog
File organization:
/srv/salt/
├── states/
│ ├── base/
│ │ ├── init.sls
│ │ └── packages.sls
│ ├── network/
│ │ ├── vyos-interfaces.sls
│ │ ├── vyos-firewall.sls
│ │ └── vyos-nat.sls
│ └── services/
│ ├── vyos-dhcp.sls
│ └── vyos-dns.sls
└── pillars/
├── top.sls
├── network/
│ └── vyos-devices.sls
└── secrets/
└── credentials.sls- Regular updates:
- Update the Salt Master
- Update the Minions
- Watch for security bulletins
Integration with Other Systems
Gitlab CI/CD
.gitlab-ci.yml:
stages:
- test
- deploy
test_state:
stage: test
script:
- salt 'vyos-test' state.apply vyos-config test=True
deploy_production:
stage: deploy
script:
- salt 'vyos-prod-*' state.apply vyos-config
only:
- main
when: manualAnsible + Salt
Using Salt as an execution engine for Ansible:
# playbook.yml
- hosts: localhost
tasks:
- name: Apply Salt state to VyOS
command: salt 'vyos-*' state.apply vyos-configPrometheus Monitoring
Salt for collecting metrics:
# Custom grain for metrics
sudo salt 'vyos-*' grains.set monitoring:enabled TrueConclusion
Salt-Minion provides powerful capabilities for automating VyOS:
- Centralized management - a single point of control
- Configuration as Code - configuration versioning
- Scalability - managing many devices at once
- Flexibility - support for both direct minion and proxy minion
- Event-driven - event-based automation
- Integration - integration with the CI/CD pipeline
Key use cases:
- Bulk configuration deployment
- Standardizing settings
- Automating routine tasks
- Compliance checking
- Centralized management of network infrastructure
A proper Salt setup enables efficient management of VyOS routers at enterprise scale and simplifies operations in cloud environments.