Ansible libssh Connection Plugin: Replacing Paramiko for Better SSH Performance and Security
By Luca Berton · Published 2024-01-01 · Category: installation
Migrate from Paramiko to the libssh connection plugin in Ansible for faster, more secure SSH connections in network automation.
Red Hat has introduced the ansible.netcommon.libssh connection plugin as the recommended replacement for Paramiko in Ansible network automation. This addresses long-standing performance and security concerns with the Paramiko SSH library.
Source: Red Hat Developer article
Why Replace Paramiko?
Paramiko has been Ansible's default SSH library for network devices since the beginning, but it has significant drawbacks:
Security Vulnerabilities
Paramiko has accumulated multiple CVEs over the years:
| CVE | Severity | Issue | |---|---|---| | CVE-2023-48795 | High | Terrapin attack — SSH prefix truncation | | CVE-2024-10963 | Medium | PAM authentication bypass | | CVE-2025-26465 | High | Machine-in-the-middle via VerifyHostKeyDNS |
Performance Limitations
• Pure Python implementation — slower than C-based alternatives • No hardware acceleration for crypto operations • Higher CPU usage during bulk SSH sessions • Slower key exchange and channel operationsMaintenance Burden
• Separate SSH implementation from the system's OpenSSH • Different behavior thanssh command-line tool
• Inconsistent host key verification
See also: Paramiko Deprecated for network_cli: Migrate to libssh (ansible-pylibssh)
The libssh Solution
The ansible.netcommon.libssh plugin uses libssh (a C-based SSH library) via the ansible-pylibssh Python binding, providing:
• System-level SSH — uses the same crypto libraries as OpenSSH
• Better performance — C implementation with hardware acceleration
• Fewer CVEs — benefits from OpenSSH ecosystem security patches
• Consistent behavior — matches ssh command behavior
Migration Guide
Step 1: Install ansible-pylibssh
pip install ansible-pylibssh
Step 2: Install the netcommon collection
ansible-galaxy collection install ansible.netcommon
Step 3: Update connection type
Change your inventory or playbook connection from paramiko or network_cli to use the libssh transport:
# inventory.ini
[switches]
switch01 ansible_host=192.168.1.10
[switches:vars]
ansible_connection=ansible.netcommon.libssh
ansible_network_os=cisco.ios.ios
ansible_user=admin
ansible_password={{ vault_switch_password }}
Or in ansible.cfg:
[defaults]
# For network devices, use libssh instead of paramiko
Or per-playbook:
---
- name: Configure network devices via libssh
hosts: switches
connection: ansible.netcommon.libssh
gather_facts: false
tasks:
- name: Get device facts
cisco.ios.ios_facts:
gather_subset: min
- name: Display hostname
ansible.builtin.debug:
msg: "Device: {{ ansible_net_hostname }} running {{ ansible_net_version }}"
Step 4: Verify connectivity
ansible switches -m ping -c ansible.netcommon.libssh
See also: Ansible NETCONF Connection Plugin: Network Configuration Protocol Complete Guide
Paramiko vs libssh Comparison
| Feature | Paramiko | libssh |
|---|---|---|
| Language | Pure Python | C (via pylibssh binding) |
| Performance | Slower | Faster (hardware crypto) |
| Security patches | Independent | Aligned with system libraries |
| Known CVEs | Multiple active | Fewer, faster patching |
| SSH agent support | Yes | Yes |
| Key types | RSA, DSA, ECDSA, Ed25519 | RSA, ECDSA, Ed25519 |
| ProxyCommand | Limited | Full support |
| Host key checking | Custom implementation | System-consistent |
| Collection | Built-in | ansible.netcommon |
Common Use Cases
Network Device Management
---
- name: Backup network configurations
hosts: network_devices
connection: ansible.netcommon.libssh
gather_facts: false
vars:
backup_dir: /tmp/network-backups
tasks:
- name: Backup running config (Cisco IOS)
cisco.ios.ios_config:
backup: true
backup_options:
dir_path: "{{ backup_dir }}"
when: ansible_network_os == 'cisco.ios.ios'
- name: Backup running config (Juniper)
junipernetworks.junos.junos_config:
backup: true
dir_path: "{{ backup_dir }}"
when: ansible_network_os == 'junipernetworks.junos.junos'
Large-Scale Network Automation
For environments with hundreds of devices, libssh's performance advantage is significant:
# ansible.cfg for large-scale deployments
[defaults]
forks = 50
timeout = 30
[persistent_connection]
connect_timeout = 30
command_timeout = 30
See also: Ansible Network Automation: Configure Cisco, Arista, and Juniper at Scale
Troubleshooting
| Issue | Solution |
|---|---|
| ModuleNotFoundError: ansible-pylibssh | pip install ansible-pylibssh |
| libssh not found | Install system package: dnf install libssh-devel (RHEL) or apt install libssh-dev (Debian) |
| Host key verification fails | Add host key: ssh-keyscan -t ed25519 switch01 >> ~/.ssh/known_hosts |
| Connection timeout | Increase connect_timeout in [persistent_connection] |
| kex error | Update libssh system package to latest version |
FIPS Compliance for Network Automation
For public sector and regulated industries, FIPS (Federal Information Processing Standards) compliance is mandatory. This is where libssh becomes critical.
The Problem with Paramiko in FIPS Mode
Many teams rely on standard SSH transports for NETCONF-based automation. But if your devices are locked down in FIPS mode, Paramiko's pure Python crypto may not use FIPS-compliant algorithms — creating a massive compliance gap.
The Solution: use_libssh for NETCONF
Starting with ansible.netcommon v8.4.0, the use_libssh option enables FIPS-compliant SSH transport for NETCONF connections:
# Enable libssh for NETCONF (FIPS-compliant)
- name: Configure device via FIPS-compliant NETCONF
hosts: junos_firewalls
connection: ansible.netcommon.netconf
vars:
ansible_netconf_ssh_type: libssh
gather_facts: false
tasks:
- name: Get running configuration
ansible.netcommon.netconf_get:
source: running
register: config
Key Benefits for Regulated Environments
• FIPS compliance — encrypted, FIPS-compliant SSH transport for NETCONF • Scale at speed — integrated with Execution Nodes and Automation Mesh for massive footprints • No security vs automation trade-offs — no need to disable FIPS on SRX firewalls to run playbooks • Consistent auditing — every NETCONF config change wrapped in FIPS-compliant encryption • Streamlined Automation Mesh — libssh is more efficient, letting Execution Nodes manage larger Juniper fabrics without legacy Python SSH overheadJuniper Customers and YANG/NETCONF Vendors
For network vendors using YANG + NETCONF (Juniper SRX, MX, QFX; Cisco IOS-XR; Nokia SR OS), this update means: No need to disable FIPS on firewalls just to run Ansible playbooks Larger fabric management per Execution Node (less SSH overhead) Every configuration push satisfies rigorous security audits
Official Deprecation Notice
Paramiko is now officially deprecated for network_cli connections. Key resources:
• Deprecation notice: Paramiko Deprecated for network_cli
• Migration guide: Migrating to ssh_type libssh
• Red Hat Developer article: New libssh connection plug
FAQ
Is Paramiko being removed from Ansible?
Not immediately. Paramiko remains available but is no longer the recommended choice for new deployments. Migration to libssh is encouraged.
Does libssh work with all network platforms?
Yes. The libssh connection plugin works with any network OS supported by Ansible: Cisco IOS/NX-OS/ASA, Juniper Junos, Arista EOS, and more.
Do I need to rewrite my playbooks?
No. Only the connection type changes. All existing modules (ios_config, junos_command, etc.) work identically with libssh.
What about the standard ansible.builtin.ssh connection?
The built-in SSH connection (used for Linux hosts) already uses system OpenSSH. The libssh plugin addresses network device connections that previously required Paramiko.
Does libssh support SSH keys and ssh-agent?
Yes. libssh supports SSH keys (RSA, ECDSA, Ed25519), ssh-agent forwarding, and ProxyCommand — all aligned with system OpenSSH behavior.
Related Articles
• Ansible Connection Types: SSH, WinRM, Local, Docker, Network Guide • Ansible Network Automation: Cisco, Arista, Juniper at Scale • Ansible SSH Password Authentication with sshpass • Red Hat Ansible Automation Platform 2.7: What's NewCategory: installation