Connecting to private subnet using python securely and manage the devices

Gopi Narayanaswamy
4 min readMar 14, 2020

--

Assume that you are creating private subnet in your public cloud where you don`t want to provide direct access to external users. There are many ways to restrict access to your private subnet and you have implemented one of them. Later, some of the external users who are developers or system admin who wanted to monitor or do some support work remotely and required to connect to some of these machines using an SSH or Winrm. However, I don’t want to assign an external IP address to any of these machines to avoid various security risks. However, that gives me a new problem. When instances do not have external IP addresses, they can only be reached by some other instances on the network. How to allow them to access these machines over an SSH connection? The most convenient method is to provide an instance in your network to act as a trusted relay for inbound connections. We call that instance a Bastion Host or jump server.

Bastion Host or jump server

Bastion Host or jump server

Ok, now I can connect to my private subnet using jump server manually however my python program wants connect to 1000+ servers in the subnet using passwordless authentication, how to achieve it?

ProxyJump

The ProxyJump, or the -J flag, was introduced in ssh version 7.3. To use it, specify the bastion host to connect through after the -J flag, plus the remote host:

Ssh command with -J options

$ ssh -J host1 host2

If usernames or ports on machines differ,

$ ssh -J username@host1:port username@host2:port

Above example, tells ssh to make a connection to the jump host and then establish a TCP forwarding to the target server

How SSH Agent Forwarding works?

The ssh-agent is a helper program that keeps track of user’s identity keys such as SSH private key. The agent can then use the keys to log into other servers without having the user type in a password. By default, the agent uses SSH keys stored in the .ssh directory under the user’s home directory. the SSH protocol implements agent forwarding by enabling ForwardAgent option as yes on the client and AllowAgentForwarding option set to yes on the server . SSH agent forwarding can easily implement single sign-on to servers on the other side of the world, in cloud services, or at customer premises.

Adding proxy hosts in ~/.ssh/config

The -J flag provides flexibiltiy for easily specifying proxy and remote hosts as needed, but if a specific bastion host is regularly used to connect to a specific remote host, the ProxyJump configuration can be set in ~/.ssh/config to automatically make the connection to the bastion en-route to the remote host:

There is alternative to ProxyJump which is ProxyCommand (old Method) which works by forwarding standard in (stdin) and standard out (stdout) from the remote machine though the proxy or bastion hosts.

The ProxyCommand itself is a specific command used to connect to a remote server — in the case of the earlier example, that would be the manual ssh command used to first connect to the bastion:

$ ssh -o ProxyCommand=”ssh -W %h:%p bastion-host” remote-host

Sample configuration

The ProxyCommand above says that when connecting to any host (besides the jumphost itself) do so by executing ‘ssh jumphost nc %h %p’. In other words, any SSH connection will be proxied through the jumphost (besides the SSH connection to the jumphost itself).

ProxyJump config example

ProxyJump example

How to use in Python?

In many situation, we use netmiko or other ssh libraries for connect to remote host for our automation programs. Below are configuration and sample programs in Python

Let me brief about Netmiko, netmiko is a python library which establishes remote connection and run commands remotely using ssh

Simple remote switch connection program using netmiko

#!/usr/bin/env python

from netmiko import Netmiko # Initiating Netmiko Library

from getpass import getpass # Library for password prompt

net_connect = Netmiko(

“cisco-switch1.example.com”,

username=”auto-developer”,

password=getpass(),

device_type=”cisco_ios”,

) # Providing the remote host details to connect

print(net_connect.find_prompt())

net_connect.disconnect()

Another Example running remote commands in network switch

#!/usr/bin/env python

from __future__ import print_function, unicode_literals

# Netmiko is the same as ConnectHandler

from netmiko import Netmiko

from getpass import getpass

my_device = {

“host”: “cisco-switch1.example.com”,

“username”: “auto-developer”,

“password”: getpass(),

“device_type”: “cisco_ios”,

}

net_connect = Netmiko(**my_device)

cfg_commands = [“logging buffered 10000”, “no logging console”,”show run”]

# send_config_set() will automatically enter/exit config mode

output = net_connect.send_config_set(cfg_commands)

print(output)

net_connect.disconnect()

How to configure ssh in netmiko connection for Bastion host?

#!/usr/bin/env python

from netmiko import ConnectHandler

from getpass import getpass

my_device = {

“host”: “cisco-switch1.example.com”,

“username”: “auto-developer”,

“password”: getpass(),

“device_type”: “cisco_ios”,

‘ssh_config_file’: ‘./ssh_config’,

}

net_connect = ConnectHandler(**device)

output = net_connect.send_command(“show users”)

print(output)

Simply add ssh_config with Proxyjump or Proxycommand in ssh_config file and input to netmiko. Netmiko will connect to remote host via given jump server in ssh_config file

--

--

No responses yet