🤖 Automating My Juniper Switch with Ansible

Network Automation • Configuration Management • Infrastructure as Code

From manual configuration to automated deployment - my journey learning Ansible for Juniper network automation

So after getting my Juniper EX4300 configured manually, I figured I should probably automate this stuff. Got my CCNA and always heard about Ansible but never really messed with it. Time to change that.

This is basically my notes on setting up Ansible to manage Juniper gear. Nothing fancy, just what worked for me.

✅ 1. Prove Connectivity and Collection is Working

This uses the basic ping module to confirm Ansible can log in to your device using the credentials in your inventory, and that the connection type (netconf) is working.

Command to Run Purpose
ansible juniper_switches -i inventory/hosts.yml -m ping Confirms SSH/NETCONF login is successful.
Ansible Connectivity Test - Successful Ping to Juniper Switch

✅ 2. Run an Operational Command

This shows you can execute a specific Junos operational command on the switch, proving you can retrieve real-time data using the junipernetworks.junos.junos_command module.

Command to Run Purpose
ansible juniper_switches -i inventory/hosts.yml -m junipernetworks.junos.junos_command -a "commands='show version'" Demonstrates live data retrieval from the device.
Juniper Show Version Command via Ansible

✅ 3. Run the Automated Backup Playbook

This is the most important demonstration of your work. It proves the playbook logic, file system permissions, and variable usage are correct. Since you documented using Vault, add the secure flag.

Command to Run Purpose
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml --ask-vault-pass Executes the multi-step backup process using the secure Vault password.
Ansible Playbook Backup Execution - Successful Configuration Backup

Why Bother with Ansible?

Look, typing the same commands over and over gets old fast. Plus if I add more switches later, I don't want to configure each one manually. Ansible lets you:

  • Push configs to multiple switches at once
  • Backup configs automatically
  • Roll back if you mess up
  • Actually document what you're doing

Coming from Cisco, I know this stuff matters. Might as well learn it now.


What You Need

Software:

  • Linux (I'm using WSL on Windows)
  • Ansible
  • Python 3
  • Juniper Ansible collection

On the Switch:

  • SSH enabled (already done)
  • NETCONF enabled (comes with SSH on Junos)
  • A user account with permissions

That's it. Pretty straightforward.


Step 1: Installing Ansible

bash
# Update packages
sudo apt update

# Install Ansible
sudo apt install ansible -y

# Verify it worked
ansible --version

You should see something like "ansible 2.x.x" - exact version doesn't matter much.


Step 2: Install Juniper Collection

Ansible needs Juniper-specific modules to talk to JunOS devices.

bash
ansible-galaxy collection install junipernetworks.junos

This downloads all the Juniper stuff you need. Takes a minute.


Step 3: Project Structure

I created a folder called JUNOS to keep everything organized. Here's the structure:

Project Structure
JUNOS/
├── ansible.cfg              # Ansible settings
├── inventory/
│   └── hosts.yml           # List of switches
├── group_vars/
│   └── juniper_switches.yml # Common variables
├── playbooks/
│   ├── backup_config.yml   # Backup playbook
│   ├── deploy_vlans.yml    # VLAN deployment
│   └── check_status.yml    # Status check
├── backups/                # Where backups go
└── templates/              # For future templates

Create it all at once:

bash
mkdir -p ~/JUNOS/{inventory,playbooks,group_vars,backups,templates}
cd ~/JUNOS

Step 4: Ansible Configuration

File: ansible.cfg

ansible.cfg
[defaults]
inventory = ./inventory/hosts.yml
host_key_checking = False
log_path = ./ansible.log
stdout_callback = yaml
timeout = 30

[inventory]
enable_plugins = yaml

This tells Ansible:

  • Where to find your switches
  • Don't bug me about SSH keys
  • Log everything
  • Use YAML output (easier to read)

Step 5: Define Your Switches

File: inventory/hosts.yml

inventory/hosts.yml
---
all:
  children:
    juniper_switches:
      hosts:
        YYY-SWITCH-01:
          ansible_host: XXX.XXX.XXX.XXX
          ansible_network_os: junipernetworks.junos.junos
          ansible_connection: netconf
          ansible_user: YYY-ADMIN
          ansible_ssh_pass: YOUR-PASSWORD-HERE
          
      vars:
        ansible_python_interpreter: /usr/bin/python3

What each line means:

  • YYY-SWITCH-01 - Your switch's name (anything you want)
  • ansible_host - Switch's IP address
  • ansible_network_os - Tells Ansible this is Juniper
  • ansible_connection: netconf - Use NETCONF (better than raw SSH)
  • ansible_user / ansible_ssh_pass - Login credentials

Security note: Yeah, password in plain text sucks. We'll encrypt it later with Ansible Vault. For now, just get it working.


Step 6: Common Variables

File: group_vars/juniper_switches.yml

group_vars/juniper_switches.yml
---
# VLANs configuration
vlans:
  - name: DATA
    vlan_id: 10
    description: "User Data VLAN"
    ip_address: XXX.XXX.10.1/24
  
  - name: VOICE
    vlan_id: 20
    description: "VoIP VLAN"
    ip_address: XXX.XXX.20.1/24
  
  - name: GUEST
    vlan_id: 30
    description: "Guest Network"
    ip_address: XXX.XXX.30.1/24

# Network settings
dhcp_server: XXX.XXX.XXX.XXX
dns_servers:
  - XXX.XXX.XXX.XXX
  - XXX.XXX.XXX.XXX
ntp_servers:
  - 0.pool.ntp.org
  - 1.pool.ntp.org
snmp_community: YOUR-COMMUNITY-HERE
timezone: America/New_York
domain_name: YYY.local

This is where all your network settings live. Change something here, deploy everywhere. Pretty slick.


Step 7: Your First Playbook - Backup

File: playbooks/backup_config.yml

playbooks/backup_config.yml
---
- name: Backup Juniper Switch Configuration
  hosts: juniper_switches
  gather_facts: no
  
  tasks:
    - name: Get current configuration
      junipernetworks.junos.junos_command:
        commands:
          - show configuration | display set
      register: config_output
    
    - name: Save configuration to file
      copy:
        content: "{{ config_output.stdout[0] }}"
        dest: "./backups/{{ inventory_hostname }}_config_{{ ansible_date_time.date }}.txt"
      delegate_to: localhost
    
    - name: Show backup location
      debug:
        msg: "Configuration backed up to ./backups/{{ inventory_hostname }}_config_{{ ansible_date_time.date }}.txt"

What this does:

  1. Connects to your switch
  2. Runs "show configuration | display set"
  3. Saves it to a file with today's date
  4. Tells you where it saved it

Simple, clean, automated.


Step 8: Install Python Dependencies

Before running playbooks, you need some Python libraries:

bash
# Install via apt (recommended)
sudo apt install python3-ncclient python3-paramiko python3-lxml -y

# OR via pip if you prefer
pip3 install ncclient paramiko lxml --break-system-packages

The ncclient library is what lets Ansible talk NETCONF to Juniper switches.


Step 9: Test Connection

Before running playbooks, test if Ansible can reach your switch:

bash
ansible juniper_switches -i inventory/hosts.yml -m ping

If it works, you'll see:

Output
YYY-SWITCH-01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

If you get "pong" - you're golden.


Step 10: Run Your First Backup

bash
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml

You should see:

Output
PLAY [Backup Juniper Switch Configuration]

TASK [Get current configuration]
ok: [YYY-SWITCH-01]

TASK [Save configuration to file]
changed: [YYY-SWITCH-01]

TASK [Show backup location]
ok: [YYY-SWITCH-01]

PLAY RECAP
YYY-SWITCH-01    : ok=3    changed=1    unreachable=0    failed=0

Check your backups folder:

bash
ls backups/
cat backups/YYY-SWITCH-01_config_2025-11-30.txt

Your entire switch config should be there!


VLAN Deployment Playbook

File: playbooks/deploy_vlans.yml

playbooks/deploy_vlans.yml
---
- name: Deploy VLANs to Juniper Switch
  hosts: juniper_switches
  gather_facts: no
  
  tasks:
    - name: Create VLANs
      junipernetworks.junos.junos_vlans:
        config:
          - name: "{{ item.name }}"
            vlan_id: "{{ item.vlan_id }}"
        state: merged
      loop: "{{ vlans }}"
    
    - name: Configure VLAN L3 Interfaces
      junipernetworks.junos.junos_config:
        lines:
          - "set vlans {{ item.name }} l3-interface irb.{{ item.vlan_id }}"
          - "set interfaces irb unit {{ item.vlan_id }} family inet address {{ item.ip_address }}"
      loop: "{{ vlans }}"
    
    - name: Commit configuration
      junipernetworks.junos.junos_config:
        comment: "Ansible VLAN deployment"

This reads your VLANs from group_vars and deploys them automatically. Add a VLAN to the vars file, run the playbook, done.


Status Check Playbook

File: playbooks/check_status.yml

playbooks/check_status.yml
---
- name: Check Juniper Switch Status
  hosts: juniper_switches
  gather_facts: no
  
  tasks:
    - name: Get system information
      junipernetworks.junos.junos_command:
        commands:
          - show version
          - show system uptime
          - show chassis alarms
      register: system_info
    
    - name: Get VLAN information
      junipernetworks.junos.junos_command:
        commands:
          - show vlans
      register: vlan_info
    
    - name: Display results
      debug:
        msg: "{{ system_info.stdout_lines }}"

Run this anytime you want to check on your switch without SSH'ing in.


Securing Passwords with Ansible Vault

Okay, passwords in plain text is bad. Let's fix it.

Encrypt your inventory:

bash
ansible-vault encrypt inventory/hosts.yml

Pick a vault password and remember it.

To edit later:

bash
ansible-vault edit inventory/hosts.yml

Run playbooks with vault:

bash
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml --ask-vault-pass

Now your passwords are encrypted. Much better.


Daily Usage

Morning routine - backup everything:

bash
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml

Check if everything's up:

bash
ansible-playbook -i inventory/hosts.yml playbooks/check_status.yml

Deploy config changes:

bash
# Edit group_vars/juniper_switches.yml
# Add your changes
ansible-playbook -i inventory/hosts.yml playbooks/deploy_vlans.yml

Got multiple switches? Just add them to inventory/hosts.yml and Ansible will configure ALL of them with one command. That's the power of automation.


Troubleshooting

"Module not found" error:

bash
ansible-galaxy collection install junipernetworks.junos --force

"Connection timeout":

bash
# Check if switch is reachable
ping XXX.XXX.XXX.XXX

# Verify NETCONF is enabled
ssh your-user@XXX.XXX.XXX.XXX
show system services

"Permission denied":

  • Check username/password in inventory
  • Verify user has superuser access on switch

"ncclient not found":

bash
sudo apt install python3-ncclient -y

What I Learned

Coming from CCNA and Cisco gear, Ansible on Juniper is actually pretty smooth. The NETCONF connection is way cleaner than screen-scraping Cisco IOS.

Biggest differences from Cisco automation:

  • Juniper uses NETCONF by default (no need for enable and all that)
  • Config is always in "set" format (consistent, predictable)
  • Commit model means you can stage changes without breaking stuff
  • Rollback is built into the OS, not just Ansible

The playbook structure is the same regardless of vendor - you just use different modules. Makes sense once you wrap your head around it.


Next Steps

Things I want to add:

  • Scheduled backups (cron job running the backup playbook)
  • Config drift detection (compare running config vs intended config)
  • Port configuration playbook
  • User management playbook
  • Maybe integrate with Git for version control

For now though, I can backup configs and deploy VLANs automatically. Good enough to get started.


Useful Commands

Quick Reference
# Test connection
ansible juniper_switches -i inventory/hosts.yml -m ping

# Run a single command
ansible juniper_switches -i inventory/hosts.yml -m junipernetworks.junos.junos_command -a "commands='show version'"

# Backup configs
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml

# Deploy VLANs
ansible-playbook -i inventory/hosts.yml playbooks/deploy_vlans.yml

# Check status
ansible-playbook -i inventory/hosts.yml playbooks/check_status.yml

# Edit encrypted files
ansible-vault edit inventory/hosts.yml

# Verbose output (for debugging)
ansible-playbook -i inventory/hosts.yml playbooks/backup_config.yml -vvv

Final Thoughts

Ansible isn't as complicated as I thought it'd be. The hardest part was just figuring out the folder structure and where everything goes. Once you have a working example, you can just modify it for whatever you need.

The YAML syntax takes some getting used to - indentation matters a LOT. Two spaces, not tabs. Mess that up and nothing works.

But overall? Pretty solid tool. Way better than manually configuring stuff, especially when you're dealing with multiple devices.

Glad I took the time to set this up. Should make studying for JNCIA easier too since automation is part of that exam.


Project Structure Recap

Final Structure
JUNOS/
├── ansible.cfg
├── inventory/hosts.yml (encrypted)
├── group_vars/juniper_switches.yml
├── playbooks/
│   ├── backup_config.yml
│   ├── deploy_vlans.yml
│   └── check_status.yml
└── backups/

Clean, organized, automated. That's the goal.

-Ahmed