Port forwarding with ssh for VMs on libvirt NAT network

In my previous post I explored  port forwarding with IPTables to make VMs on a NAT Network (libvirt) accessible to the external world.

The same result can be achieved by using SSH  to forward a port to the VM on the private network(accessible only within the hypervisor). This is specially handy if you don’t have root level access to change IPTables setting on the hypervisor. This is achieved by creating a ssh tunnel to connect a port on the hypervisor to a port on the VM.

Two things to keep in mind to make this work.

  • you must have a ssh login on the VM
  • the port forwarding works as long as the ssh connection is alive

Here is the SSH command that sets up the tunnel between the hypervisor and the VM

ssh -L<hypervisor_ip>:<hypervisor_port>:<vm_ip>:<vm_port> <user_on_vm>@<vm_ip>

an example:


ssh -L0.0.0.0:10022:vm1:22 user1@vm1

I have used 0.0.0.0 as the hypervisor so that the tunnel listen to all the interfaces on the hypervisor.

Execute this command on the hypervisor, this command will open a ssh connection to vm1 and prompt for password for user1. Once the connection is established, the tunnel is created from port 10022 on the hypervisor to port 22(ssh port) on the VM. In this example connecting to port 10022 on the hypervisor will actually access the port 22 on the VM. Users can now SSH to the VM from the external world by connecting to port 10022 on the hypervisor.

Using Cloud images with standalone Hypervisors

Most of the cloud images (centos, ubuntu, fedora) published by Distro builders are now conforming to Cloud-Init based initial configuration.

Cloud-Init is a method of providing configuration to the VM image when it boots up for the first time. It can be used to do initial setup/configuration like provision user login, service configuration, package installation etc. to name a few.

Most of the cloud images do not have any default user password set(to prevent any security risk due to well know password). To login to these Cloud Images on a VM you must provide the user auth configuration during the VM boot up using Cloud init, the same process can also be used to provide data related to the VM itself such as hostname, ip-address etc.

Cloud-init can get this data during the boot process through various sources (called data-sources) like http request to some well know IP, Config-drive etc.

While using these cloud images on a standalone Hypervisors like libvirt or virtualbox, it may not be practical to configure the infrastructure to provide the cloud init data over the network.

Fortunately, Cloud-Init can also use ISO image to get the Configuration Data for the VM

Here is a brief process of creating a ISO image for providing user auth data like ssh key/password and VM metadata using cloud image.

  • Create a ssh key pair

ssh-keygen -f my_ssh_key

  • Create a file named user-data to provide user related settings
#cloud-config
password: mypassword
chpasswd: { expire: False }
ssh_pwauth: True
ssh_authorized_keys:
    - <paste your ssh pub key>
  • Create a file named meta-data to provide VM related data
instance-id: Atomic01
local-hostname: atomic-host-001
  • Create an ISO image

genisoimage -output atomic01-cidata.iso -volid cidata -joliet -rock user-data meta-data

  • Use this ISO image as the CDROM while booting the Cloud Image to provide the configuration to Cloud-Init
  • Now you can login to the VM using the ssh key (my_ssh_key) or password (mypassword) with the default username (e.g.  Ubuntu: use username ubuntu, for Centos: use centos etc.)

A sample ISO and related configuration data is available at this location.

The complete documentation for cloud-init is available here