While EIP can be used to bind a public IP to a VM that is on a private network, it opens all ports of that EIP to the world; to achieve decent security, users may need to use security group along with EIP. Elastic port forwarding provides another way to this problem; users can selectively bind one or several ports of an public IP to a VM on the private network, and restrict what traffic can access these ports.
In this example, we will initially create a port forwarding rule for one VM, and later rebind it to another VM.
We assume you have followed Quick Installation Guide to install ZStack on a single Linux machine, and the ZStack management node is up and running. To use the command line tool, type below command in your shell terminal:
#zstack-cli
To make things simple, we assume you have only one Linux machine with one network card that can access the internet; besides, there are some other requirements:
sudo su
passwd root
Based on those requirements, we assume below setup information (you should change the IP address and other configurations to align with your local environment.):
open zstack-cli and login with admin/password:
>>> LogInByAccount accountName=admin password=password
create a zone with name 'ZONE1' and description 'zone 1':
>>> CreateZone name=ZONE1 description='zone 1'
create a cluster with name 'CLUSTER1' and hypervisorType 'KVM' under zone 'ZONE1':
QueryZone fields=uuid, name=ZONE1
>>> CreateCluster name=CLUSTER1 hypervisorType=KVM zoneUuid=b5ba18197f7843308cd26f87eab933c5
add KVM Host 'HOST1' under 'CLUSTER1' with correct host IP address and root username and password:
QueryCluster fields=uuid, name=CLUSTER1
>>> AddKVMHost name=HOST1 managementIp=172.20.11.34 username=root password=password clusterUuid=e630ebdb5f7742f3818fd998e91d35a8
add Primary Storagei 'PRIMAYR-STORAGE1' with URI '/zstack_ps' under zone 'ZONE1':
QueryZone fields=uuid, name=ZONE1
>>> AddLocalPrimaryStorage name=PRIMARY-STORAGE1 url=/zstack_ps zoneUuid=b5ba18197f7843308cd26f87eab933c5
attach 'PRIMARY-STORAGE1' to 'CLUSTER1':
QueryCluster fields=uuid, name=CLUSTER1
QueryPrimaryStorage fields=uuid, name=PRIMARY-STORAGE1
>>> AttachPrimaryStorageToCluster primaryStorageUuid=1b952f1e74a747dfb89ef3bdb9e8a821 clusterUuid=e630ebdb5f7742f3818fd998e91d35a8
add sftp Backup Storage 'BACKUP-STORAGE1' with backup storage host IP address('172.20.11.34'), root username('root'), password('password') and sftp folder path('/home/sftpBackupStorage'):
>>> AddSftpBackupStorage name=BACKUP-STORAGE1 hostname=172.20.11.34 username=root password=password url=/zstack_bs
attach new created Backup Storage('BACKUP-STORAGE1') to zone('ZONE1'):
QueryZone fields=uuid, name=ZONE1
QueryBackupStorage fields=uuid, name=BACKUP-STORAGE1
>>> AttachBackupStorageToZone backupStorageUuid=ccc8214bfc2344e5a58c2ec23de3b348 zoneUuid=b5ba18197f7843308cd26f87eab933c5
add Image('image') with format 'qcow2', 'RootVolumeTemplate' type, 'Linux' platform and image URL('http://cdn.zstack.io/product_downloads/images/zstack-image.qcow2') to backup storage ('BACKUP-STORAGE1'):
QueryBackupStorage fields=uuid, name=BACKUP-STORAGE1
>>> AddImage name=image mediaType=RootVolumeTemplate platform=Linux url=http://192.168.200.100/mirror/diskimages/zstack-image-1.4.qcow2 backupStorageUuids=ccc8214bfc2344e5a58c2ec23de3b348 format=qcow2
this image will be used as user VM image.
Add another Image('VRImage') with format 'qcow2' and image URL('http://cdn.zstack.io/product_downloads/images/zstack-image.qcow2') to backup storage ('BACKUP-STORAGE1'):
QueryBackupStorage fields=uuid, name=BACKUP-STORAGE1
http://cdn.zstack.io/product_downloads/vrouter/zstack-vrouter-2.0.0.qcow2
>>> AddImage name=VRImage url=http://192.168.200.100/mirror/diskimages/zstack-vrouter-latest.qcow2 backupStorageUuids=ccc8214bfc2344e5a58c2ec23de3b348 format=qcow2
create No Vlan L2 Network 'PUBLIC-MANAGEMENT-L2' with physical interface as 'eth1' under 'ZONE1':
QueryZone fields=uuid, name=ZONE1
>>> CreateL2NoVlanNetwork name=PUBLIC-MANAGEMENT-L2 physicalInterface=eth0 zoneUuid=b5ba18197f7843308cd26f87eab933c5
attach 'PUBLIC-MANAGEMENT-L2' to 'CLUSTER1':
QueryCluster fields=uuid, name=CLUSTER1
QueryL2Network fields=uuid, name=PUBLIC-MANAGEMENT-L2
>>> AttachL2NetworkToCluster l2NetworkUuid=b4b611280afe4d289c8e3f66aee0393d clusterUuid=e630ebdb5f7742f3818fd998e91d35a8
create new private Vlan L2 network 'PRIVATE-L2' with physical interface as 'eth0' and vlan '100' under 'ZONE1':
QueryZone fields=uuid, name=ZONE1
>>> CreateL2VlanNetwork name=PRIVATE-L2 physicalInterface=eth0 vlan=100 zoneUuid=b5ba18197f7843308cd26f87eab933c5
attach 'PRIVATE-L2' to 'CLUSTER1':
QueryCluster fields=uuid, name=CLUSTER1
QueryL2Network fields=uuid, name=PRIVATE-L2
>>> AttachL2NetworkToCluster l2NetworkUuid=b052b4e080c840f6984c29581b167644 clusterUuid=e630ebdb5f7742f3818fd998e91d35a8
on L2 'PUBLIC-MANAGEMENT-L2', create Public Management L3 'PUBLIC-MANAGEMENT-L3' and set system to 'True':
QueryL2Network fields=uuid, name=PUBLIC-MANAGEMENT-L2
>>> CreateL3Network name=PUBLIC-MANAGEMENT-L3 l2NetworkUuid=b4b611280afe4d289c8e3f66aee0393d system=true
create IP Range for 'PUBLIC-MANAGEMENT-L3':
QueryL3Network fields=uuid, name=PUBLIC-MANAGEMENT-L3
>>> AddIpRange name=PUBLIC-IP-RANGE l3NetworkUuid=5bda71a3ebbd48a5947e325dd24665e5 startIp=10.121.9.40 endIp=10.121.9.100 netmask=255.0.0.0 gateway=10.0.0.1
create a Virtual Router VM instance offering 'VR-OFFERING' with 1 CPU, 512MB memory, management L3 network 'PUBLIC-MANAGEMENT-L3', public L3 network 'PUBLIC-MANAGEMENT-L3' and isDefault 'True':
QueryImage fields=uuid, name=VIRTUAL-ROUTER
QueryL3Network fields=uuid,name, name?=PUBLIC-MANAGEMENT-L3,PRIVATE-L3
QueryZone fields=uuid, name=ZONE1
>>> CreateVirtualRouterOffering name=VR-OFFERING cpuNum=1 imageUuid=090906b0e7de4bf890c677b3bc8f680b managementNetworkUuid=5bda71a3ebbd48a5947e325dd24665e5 publicNetworkUuid=5bda71a3ebbd48a5947e325dd24665e5 zoneUuid=b5ba18197f7843308cd26f87eab933c5 memorySize=536870912
on L2 network 'PRIVATE-L2', create a new guest VM L3 'PRIVATE-L3' with domain 'tutorials.zstack.org':
QueryL2Network fields=uuid, name=PRIVATE-L2
>>> CreateL3Network name=PRIVATE-L3 l2NetworkUuid=b052b4e080c840f6984c29581b167644
create IP Range for 'PRIVATE-L3':
QueryL3Network fields=uuid, name=PRIVATE-L3
>>> AddIpRange name=PRIVATE-RANGE l3NetworkUuid=6a73fdfffb104c79919179af28cba3e3 startIp=192.168.2.2 endIp=192.168.2.254 netmask=255.255.255.0 gateway=192.168.2.1
add DNS for 'PRIVATE-L3':
QueryL3Network fields=uuid name=PRIVATE-L3
>>> AddDnsToL3Network l3NetworkUuid=6a73fdfffb104c79919179af28cba3e3 dns=8.8.8.8
we need to get available network service provider UUID, before add any virtual router service to L3 network:
>>> QueryNetworkServiceProvider
there are 2 available network service providers. In this tutorial, we just need the Virtual Router, which could provide 'DHCP', 'SNAT', 'DNS', 'PortForwarding' and 'Eip'.
attach VirtualRouter services 'DHCP', 'SNAT', 'DNS' and 'PortForwarding' to 'PRIVATE-L3':
QueryL3Network fields=uuid, name=PRIVATE-L3
QueryNetworkServiceProvider fields=uuid, name=VirtualRouter
>>> AttachNetworkServiceToL3Network networkServices="{'61c6f0c18d0240398f29485d64a70e2d':['IPsec','DNS','SNAT','LoadBalancer','PortForwarding','Eip','DHCP']}" l3NetworkUuid=6a73fdfffb104c79919179af28cba3e3
create a guest VM instance offering 'small-instance' with 1 512Mhz CPU and 128MB memory:
>>> CreateInstanceOffering name=small-instance memorySize=134217728 cpuNum=1
create a new guest VM instance with configuration:
QueryInstanceOffering fields=uuid, name=small-instance
QueryImage fields=uuid, name=zs-sample-image
QueryL3Network fields=uuid, name=PRIVATE-L3
>>> CreateVmInstance name=VM1 instanceOfferingUuid=ce994286008d41f6be75e0f804bce47c imageUuid=6874474809df4d2292d3503884e0096e l3NetworkUuids=6a73fdfffb104c79919179af28cba3e3
the new VM has 1 NIC ('585bb3322f444f2296eb12f3f06e4f89') and assigned IP address: 192.168.2.246
create a new VIP 'VIP1' on 'PUBLIC-MANAGEMENT-L3':
QueryL3Network fields=uuid, name=PUBLIC-MANAGEMENT-L3
>>> CreateVip name=VIP1 l3NetworkUuid=5bda71a3ebbd48a5947e325dd24665e5
once it finishes, you should be able to see the new IP address, which will be used in Port Forwarding; in our case, the VIP is '10.121.9.98'.
create a new Port Forwarding 'PORT-FORWARDING1' with 'VIP1' for 'VM1' NIC UUID '585bb3322f444f2296eb12f3f06e4f89' to bind VM1's 22 port with VIP1's 22 port:
QueryVip fields=uuid name=VIP1
QueryVmNic fields=uuid vmInstance.name=VM1
>>> CreatePortForwardingRule name=PORT-FORWARDING1 vipUuid=2bad3299657544418d1cb776cac4493b vmNicUuid=585bb3322f444f2296eb12f3f06e4f89 protocolType=TCP privatePortStart=22 privatePortEnd=22 vipPortStart=22 vipPortEnd=22
use a machine that can reach subnet 10.0.101.0/24 to SSH the IP '10.121.9.98', you should be able to login the VM and see its internal IP address:
QueryVip fields=ip portForwarding.vipPortStart=22
# ssh 10.121.9.98
follow instructions in section 16. Create Virtual Machine to create another VM(VM2) on the private L3 network:
QueryInstanceOffering fields=uuid, name=small-instance
QueryImage fields=uuid, name=zs-sample-image
QueryL3Network fields=uuid, name=PRIVATE-L3
>>> CreateVmInstance name=VM2 instanceOfferingUuid=ce994286008d41f6be75e0f804bce47c imageUuid=6874474809df4d2292d3503884e0096e l3NetworkUuids=6a73fdfffb104c79919179af28cba3e3
then detach 'PORT-FORWARDING1':
QueryPortForwardingRule fields=uuid name=PORT-FORWARDING1
>>> DetachPortForwardingRule uuid=304a788f6b4d48f79713084802b52402
after detaching, attach the 'PORT-FORWARDING1' to VM2 NIC:
QueryPortForwardingRule fields=uuid name=PORT-FORWARDING1
QueryVmNic fields=uuid vmInstance.name=VM2
>>> AttachPortForwardingRule ruleUuid=304a788f6b4d48f79713084802b52402 vmNicUuid=0fb8e2c2c8a7493bb219811e7344adef
SSH login to the '10.0.101.138' again and run command 'hostname; ifconfig', you should see 'VM2' hostname internal network information:
QueryVip fields=ip portForwarding.vipPortStart=22
# ssh 10.121.9.98
create a new Port Forwarding 'PORT-FORWARDING2' with 'VIP1' for 'VM1' NIC UUID '585bb3322f444f2296eb12f3f06e4f89' to bind VM1's 22 port to VIP1's 2222 port:
QueryVip fields=uuid name=VIP1
QueryVmNic fields=uuid vmInstance.name=VM1
>>> CreatePortForwardingRule name=PORT-PORWARDING2 vipUuid=2be82f9f494d4cebb021624563848d6b vmNicUuid=fd05e78c633943b3b9c6836826396571 protocolType=TCP privatePortStart=22 privatePortEnd=22 vipPortStart=2222 vipPortEnd=2222
then PORT-FORWARDING1 and PORT-FORWARDING2 are sharing same VIP1 10.0.101.138 but mapping different ports to different VMs.
QueryVip fields=ip name=VIP1
When ssh 22 port, it will be routed to VM2:
# ssh root@10.121.9.98
when ssh 2222 port, it will be routed to VM1:
# ssh root@10.121.9.98 -p 2222
In this tutorial, we showed you how to create port forwarding rules that allow public traffic to reach specific ports of VMs on the private L3 network. For more details, please visit Elastic Port Forwarding in user manual.