KVM Guests and Remote Desktop Connection

General support questions
Post Reply
ASTONE
Posts: 14
Joined: 2020/05/25 04:08:41

KVM Guests and Remote Desktop Connection

Post by ASTONE » 2020/05/25 04:22:50

To anyone who has experience managing QEMU-KVM Windows Guests using Remote Desktop Connection, normally I would not be using an obsoleted operating system but it's the one my clients uses so I'm stuck with it and doing my best to get my system up and running.

I have an installation of CentOS 6.10 running on a Dell PowerEdge 1950 Server, with a Windows 2012 Guest running on KVM. The Guest is running perfectly and is accessible via the VMM Console but I would rather connect directly to it via RDP from my workstation due to the severe performance limitations of the console.

I'm using Iptables to control ingress and egress of traffic on the virtual network. There is one hardware ethernet interface, one loopback interface and one virtual interface.

The guest has full internet access from inside to outside and can download updates without a problem.

What I can't do is connect to it from my Windows 10 workstation using Remote Desktop Connection.

I've tried installing INPUT rules, NAT rules and FORWARD rules into Iptables but nothing works. In fact, they have had no effect at all. They don't disrupt this existing traffic, nor do they allow my 3389 traffic into the virtual network.

Does anyone have a suggestion?

Thank you in advance for your help.

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: KVM Guests and Remote Desktop Connection

Post by jlehtone » 2020/05/25 10:34:44

If the host routes between VM and outside, then FORWARD must allow that traffic.

If real IP of VM is not known outside, then host must "port forward". A DNAT rule in PREROUTING.
ASTONE wrote:
2020/05/25 04:22:50
I'm using Iptables to control ingress and egress of traffic on the virtual network. There is one hardware ethernet interface, one loopback interface and one virtual interface.
Your description sounds like you have created QEMU-KVM instances without the help of libvirt. If that is true, then I have no idea how your network is set up. More data, please.

Libvirt does have by default a "virtual network" named 'default' that is represented as a bridge 'virbr0' on the host.
The host routes between 'default' and external subnet, and masquerades outgoing traffic. Libvirt adds netfilter rules for that.


I don't use libvirt-created networks; my VMs are bridged or passthrough to outside subnet.
Found one 'default' though, on CentOS 7 host. Libvirtd has prepended its rules directly to FORWARD chain (and POSTROUTING):

Code: Select all

-A FORWARD -d 192.168.122.0/24 -o virbr0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
# normal FORWARD-rules start here
Not sure what CentOS 6's libvirt does.
Trouble here is that ingress is rejected and since libvirt prepends rules at start, it will put that reject before any "allow" rule you add via iptables service on boot.
There was some way to override what libvirt does. Found with Google years ago.

Whoever
Posts: 1357
Joined: 2013/09/06 03:12:10

Re: KVM Guests and Remote Desktop Connection

Post by Whoever » 2020/05/25 16:00:11

1. Performance of Spice display is very good, although this may only be available on CentOS 7 and later (I can't remember).

2. Are you sure that the guest's own firewall isn't blocking access to RDP?

3. Is your guest is inside a NAT setup on your CentOS6 host? Your talk of "virtual network" suggests that it may be. If so you need to ensure that the packets are redirected to the VM guest.

As jlehtone wrote, you need to provide a lot more information on how networking on the guest is configured.

ASTONE
Posts: 14
Joined: 2020/05/25 04:08:41

Re: KVM Guests and Remote Desktop Connection

Post by ASTONE » 2020/05/26 13:41:15

To everyone who took the time to respond to my query, thank you! I wasn't expecting such a rapid response.

To be clear, I'm new to Linux, but I have 30 years experience with Windows an 10 years as a CCNP, so I'm very familiar with routing, switching and firewalling, and the sort. Plus I work with Juniper a lot, which is based on FreeBD so the concepts here not completely foreign to me. What I'm struggling with is not just the proper commands to enter into my iptables file but whether I'm even heading down the right path. I'm limited to CLI in all things due to constraints put upon me by my customer, but if there is another non-iptables method to use for NATing and Firewalling, I'm all ears.

As far as Linux is concerned, I'm self-taught so there is a very good chance I've missed something. CentOS 7 solutions are welcomed, but only if they are known to be applicable to CentOS 6, of course. I'm stuck with CLI because this project is focused on writing scripts to automate the creation, instantiation and management of VMs, which will be tied to a web portal. If there is a non-libvirt / non-virsh method of doing this, I welcome the suggestion, but I have not come across that in my research.

Currently, I have full access to my VMs through the KVM console but no other path. I also have complete, unfettered access to the CentOS CLI through PuTTy, and the CentOS GUI through VNC. What I need is access to manage my VMs from my LAN, through RDP, HTTP, HTTPS, SMB, and other protocols which applications may use. Otherwise, the VMs will serve no purpose and the project will be a failure.

My iptables is as follows:
# cat iptables

=============================================== iptables printout =========================================================
*nat
:PREROUTING ACCEPT [408:22815]
:POSTROUTING ACCEPT [438:31123]
:OUTPUT ACCEPT [438:31123]
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT

*mangle
:PREROUTING ACCEPT [87527:115857611]
:INPUT ACCEPT [87507:115854755]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [47677:3301582]
:POSTROUTING ACCEPT [47677:3301582]
-A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [32:6294]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 5901:5903,6001:6003 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 5901:5903,6001:6003 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
=======================================================================================================================

My NAT table is as follows:
# iptables -t nat -v -L -n --line-number

========================================== iptables -t nat printout ========================================================

Chain PREROUTING (policy ACCEPT 7637 packets, 416K bytes)
num pkts bytes target prot opt in out source destination

Chain POSTROUTING (policy ACCEPT 7347 packets, 526K bytes)
num pkts bytes target prot opt in out source destination
1 0 0 MASQUERADE tcp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
2 0 0 MASQUERADE udp -- * * 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
3 0 0 MASQUERADE all -- * * 192.168.122.0/24 !192.168.122.0/24

Chain OUTPUT (policy ACCEPT 7347 packets, 526K bytes)
num pkts bytes target prot opt in out source destination
=======================================================================================================================

I've tried the following lines, to no effect:

iptables -t nat -I PREROUTING -p tcp -d UNTRUST-IP --dport 3389 -j DNAT --to-destination 192.168.122.x
iptables -t nat -I PREROUTING -I eth0 -p tcp --dport 3389 -j DNAT --to 192.168.122.x:3389
iptables -I FORWARD -I eth0 -p tcp --dport 3389 -d 192.168.122.x -j ACCEPT

The UNTRUST-IP is reachable via vpn, but the 192.168.122.x (which is a VM on the default KVM virtual network) is not reachable by any means, including PING, other than consoling in via the VMM GUI.

A ping from the CentOS host yields "From 192.168.122.x icmp_seq=1 Destination Host Unreachable"

Bottom line: I can open a GUI into my VM (guest) from within the Virtual Machine Manager on my CentOS host, which is accessible only through VNC, but other than that, the VM is useless.

Any CentOS 6 suggestions would be greatly welcomed, including ones that do not involve iptables, as long as they are scriptable.

Thank you All!

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: KVM Guests and Remote Desktop Connection

Post by jlehtone » 2020/05/27 10:50:12

ASTONE wrote:
2020/05/26 13:41:15
I wasn't expecting such a rapid response.
That is a healthy attitude. This is primarily a peer support platform, driven by https://xkcd.com/386/
ASTONE wrote:
2020/05/26 13:41:15
I'm limited to CLI
CLI is not a limit. CLI is raw power. The GUI is a limitation. IMHO
ASTONE wrote:
2020/05/26 13:41:15
non-iptables method to use for NATing and Firewalling, I'm all ears.
There are three meanings/uses for word "iptables":
  1. Linux kernel has subsystem "netfilter"[a]. All the filtering and stateful NAT are in the netfilter. Some call netfilter "iptables".
  2. User tool "iptables" is the only thing that can modify the state of netfilter
  3. Service "iptables" that does load rules from a file (/etc/sysconfig/iptables) to kernel with tool iptables
There are front-ends that have their own config format and who call iptables under the hood. Frankly, I've never used any of those.

I had a blunt script, that recreates rules in netfilter and then saves them to /etc/sysconfig/iptables for persistency. Just many calls to iptables, relying on my logic to do the Right Thing. Scary, isn't it?

[a] Kernel in CentOS 8 has subsystem "nftables" that reuses and replaces "netfilter". Nftables is configured with tool "nft".
ASTONE wrote:
2020/05/26 13:41:15
writing scripts to automate the creation, instantiation and management of VMs, which will be tied to a web portal. If there is a non-libvirt / non-virsh method of doing this, I welcome the suggestion, but I have not come across that in my research.
There are virtualization platforms, like OpenStack, oVirt, OpenNebula. There can be both "web dashboard" and CLI tools for creating/managing a VM. The service can have prebuilt images or you can start with your own. Creation allocates resources (disk, cpu, ram) for the VM and starts it.
Management can be layered: service provider has more admin options than a client, who can only create VM's within quota. This is the "Power button" part.

Another part is the administration of a machine. Software configuration and updates. It is irrelevant, whether machine is a VM or bare metal.
I admin only Linux machines. Partly, because it is "easy". Partly, because MS Windows licenses for VMs require a lawyer.
CentOS installation can be done non-interactively with a kickstart file that lists packages to install and configuration options.
There are tools, like ansible (available in el6 EPEL), that can apply config (e.g. via ssh).
If I create a CentOS VM on OpenStack from image (built by service provide; not quite what I want, but a running system) I then run ansible "play" to apply "necessary" configuration. Time passes ... packages to add, config to tune ... another ansible play.

Apparently it might be possible to use ansible to reconfigure a Windows machine too. Haven't tested.
Ansible is definitely not the only config management option. https://wiki.centos.org/SpecialInterest ... agementSIG
ASTONE wrote:
2020/05/26 13:41:15
My iptables is as follows:
# cat iptables

My NAT table is as follows:
# iptables -t nat -v -L -n --line-number
The file shows what is loaded on boot.
The file has the rules in iptables' syntax.
The file contains the "NAT table" too.

It is possible to show what is in the memory, in iptables' syntax:

Code: Select all

iptables -t mangle -S
iptables -t nat -S
iptables -S
IMHO, the -L formatting is less revealing, except for the counters and line numbers:

Code: Select all

iptables -t mangle --lin -vnL
iptables -t nat --lin -vnL
iptables --lin -vnL
ASTONE wrote:
2020/05/26 13:41:15

Code: Select all

-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -s 192.168.122.0/24 -i virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
The default firewall rules in CentOS 6 have only

Code: Select all

iptables -S FORWARD
-P FORWARD ACCEPT
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
The rules with "virbr0" have all been added by libvirtd service, when it starts and creates the "default" virtual network.
That happens on every boot, and hence those rules are unnecessary in the /etc/sysconfig/iptables.

I know, that is annoying. To update the ruleset and file (cleanly), I have to stop "meddling services", like fail2bans and libvirt, prune their "dynamic rules" out, modify my rules, save to file (service iptables save) and then restart those services.

Libvirt prepends rules to FORWARD (and POSTROUTING). Libvirt adds a REJECT rule.
If we want to allow traffic in, that specific ALLOW must be before the catch-all-to-virbr0 REJECT.
I don't let libvirt create any networks, i.e. add any rules. My VMs are bridged to outside LAN.

However, if libvirt does add firewall rules anyway, it might be able to add rules for port forwarding too.
https://wiki.libvirt.org/page/Networkin ... onnections
That is upstream documentation, but might be supported by the libvirt version in CentOS 6.
ASTONE wrote:
2020/05/26 13:41:15
I've tried the following lines, to no effect:

Code: Select all

iptables -t nat -I PREROUTING -p tcp -d UNTRUST-IP --dport 3389 -j DNAT --to-destination 192.168.122.x
iptables -t nat -I PREROUTING -I eth0 -p tcp --dport 3389 -j DNAT --to 192.168.122.x:3389
iptables -I FORWARD -I eth0 -p tcp --dport 3389 -d 192.168.122.x -j ACCEPT
The hook in libvirt page would create:

Code: Select all

iptables -I FORWARD -o virbr0 -d  192.168.122.x --dport 3389 -j ACCEPT
iptables -t nat -I PREROUTING -p tcp --dport 3389 -j DNAT --to 192.168.122.x:3389
Close, but not identical. IP address of the host is not in these rules.

After adding rules to FORWARD (or PREROUTING) I would check that they are in the right place

Code: Select all

iptables -S FORWARD
iptables -vnL FORWARD
and whether counters for them increment, i.e. some packets do matches.
ASTONE wrote:
2020/05/26 13:41:15
A ping from the CentOS host yields "From 192.168.122.x icmp_seq=1 Destination Host Unreachable"
"the CentOS host"? Do you mean "an another CentOS machine than the host of the VM"?

On the actual host you should be able to ping and its routes would contain something like:

Code: Select all

ip ro
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1
a.b.c.0/24 dev eth0  proto kernel  scope link  src a.b.c.d 
default via a.b.c.e dev eth0
Where a.b.c.d == UNTRUST-IP and a.b.c's prefix might differ.

ASTONE
Posts: 14
Joined: 2020/05/25 04:08:41

Re: KVM Guests and Remote Desktop Connection

Post by ASTONE » 2020/05/29 03:51:31

Thank you for that amazingly detailed response. It was extremely educational and helpful.

I do believe in pruning and I do understand that I have some rules in my netfilter (I hope I'm using that term correctly) that are extraneous but if screw it up, then it's 70 mile drive to the office to roll back the changes at the server, and I'd like to avoid that, if possible.

As of now, everything, for what it's worth is up and running. My iptables printout is:
==================================================================================================================
# Generated by iptables-save v1.4.7 on Tue May 26 09:35:55 2020
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [623:107856]
-A INPUT -i virbr0 -p udp -m udp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 53 -j ACCEPT
-A INPUT -i virbr0 -p udp -m udp --dport 67 -j ACCEPT
-A INPUT -i virbr0 -p tcp -m tcp --dport 67 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 5901:5903,6001:6003 -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -i eth1 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp -m multiport --dports 5901:5903,6001:6003 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -d 192.168.122.0/24 -o virbr0 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j ACCEPT
-A FORWARD -i virbr0 -o virbr0 -j ACCEPT
-A FORWARD -o virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -i virbr0 -j REJECT --reject-with icmp-port-unreachable
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
# Completed on Tue May 26 09:35:55 2020
# Generated by iptables-save v1.4.7 on Tue May 26 09:35:55 2020
*mangle
:PREROUTING ACCEPT [166108:62314743]
:INPUT ACCEPT [165626:62247405]
:FORWARD ACCEPT [33:1872]
:OUTPUT ACCEPT [95611:60597757]
:POSTROUTING ACCEPT [95614:60597909]
-A POSTROUTING -o virbr0 -p udp -m udp --dport 68 -j CHECKSUM --checksum-fill
COMMIT
# Completed on Tue May 26 09:35:55 2020
# Generated by iptables-save v1.4.7 on Tue May 26 09:35:55 2020
*nat
:PREROUTING ACCEPT [6:369]
:POSTROUTING ACCEPT [34:2448]
:OUTPUT ACCEPT [34:2448]
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p tcp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -p udp -j MASQUERADE --to-ports 1024-65535
-A POSTROUTING -s 192.168.122.0/24 ! -d 192.168.122.0/24 -j MASQUERADE
COMMIT
# Completed on Tue May 26 09:35:55 2020
==================================================================================================================

Whichever rules can be eliminated safely, without brining down my connection, I'd like to know.

My new problem is that while my Windows 2012r2 machine is running fine and I can RDP into it from my workstation via vpn, I have been stymied while trying to install a Windowsd 2016 VM using either virt-install, virsh or the Virtual Machine Manager in VNC. I get to the Windows Icon and it hangs permanently. I've tried modifying the configuration, adding the virtio drivers, even just doing a plain vanilla interactive install with the GUI, but nada.

I do recall that ESXi version 4.1 needed to be upgraded to at least 5.0 to support Windows 2016. Does CentOS 6 have the same issue? Is this just a matter of upgrading to CentOS 7 or 8, or is there a way to get a Windows 2016 VM created on 6.10? I only ask because my customer is insisting that they cannot upgrade to 7 or higher yet, so I'm stuck with 6 for now.

Thanks, as always!

User avatar
jlehtone
Posts: 4523
Joined: 2007/12/11 08:17:33
Location: Finland

Re: KVM Guests and Remote Desktop Connection

Post by jlehtone » 2020/05/29 11:04:10

ASTONE wrote:
2020/05/29 03:51:31
if screw it up, then it's 70 mile drive to the office to roll back the changes at the server, and I'd like to avoid that, if possible.
I know that feeling. Not so many miles, but covid-19 has locked doors.

INPUT, OUTPUT and nat rules do affect access to the host server. FORWARD does not.
FORWARD does not affect connecting from host to VM either.
ASTONE wrote:
2020/05/29 03:51:31
As of now, everything, for what it's worth is up and running. My iptables printout is:
As said, that file is loaded by iptables service during boot.
The libvirtd service starts after the iptables service. It probably adds rules.
To check for that:

Code: Select all

iptables -S FORWARD
iptables -t nat -S POSTROUTING
Luckily, having same rules twice is not a terrible error.

I would try the hook script from https://wiki.libvirt.org/page/Networkin ... onnections

User avatar
TrevorH
Site Admin
Posts: 33202
Joined: 2009/09/24 10:40:56
Location: Brighton, UK

Re: KVM Guests and Remote Desktop Connection

Post by TrevorH » 2020/05/29 12:05:00

if screw it up, then it's 70 mile drive to the office to roll back the changes at the server, and I'd like to avoid that, if possible.
You can set up things like a cron to reboot the machine in 10 minutes time, amend the rules and if you get locked out, wait for 11 minutes and it should come back up with the original rules and let you back in. If it works then delete the crontab entry...
The future appears to be RHEL or Debian. I think I'm going Debian.
Info for USB installs on http://wiki.centos.org/HowTos/InstallFromUSBkey
CentOS 5 and 6 are deadest, do not use them.
Use the FAQ Luke

Post Reply