On Fri, Apr 19, 2024 at 12:12:31PM +0200, Michal Privoznik wrote:
This allows users to SSH into a domain with a VSOCK device:
ssh user@qemu/machineName
So far, only QEMU domains are supported AND qemu:///system is
looked for the first for 'machineName' followed by
qemu:///session. I took an inspiration from SystemD's ssh proxy
[1] [2].
To just work out of the box, it requires (yet unreleased) systemd
to be running inside the guest to set up a socket activated SSHD
on the VSOCK. Alternatively, users can set up the socket
activation themselves, or just run a socat that'll forward vsock
<-> TCP communication.
1:
https://github.com/systemd/systemd/blob/main/src/ssh-generator/ssh-proxy.c
2:
https://github.com/systemd/systemd/blob/main/src/ssh-generator/20-systemd...
Resolves:
https://gitlab.com/libvirt/libvirt/-/issues/579
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
libvirt.spec.in | 27 +++
meson.build | 16 +-
meson_options.txt | 2 +
po/POTFILES | 1 +
tools/meson.build | 2 +
tools/ssh-proxy/30-libvirt-ssh-proxy.conf.in | 10 +
tools/ssh-proxy/meson.build | 25 ++
tools/ssh-proxy/ssh-proxy.c | 233 +++++++++++++++++++
8 files changed, 315 insertions(+), 1 deletion(-)
create mode 100644 tools/ssh-proxy/30-libvirt-ssh-proxy.conf.in
create mode 100644 tools/ssh-proxy/meson.build
create mode 100644 tools/ssh-proxy/ssh-proxy.c
@@ -1017,6 +1018,9 @@ Summary: Client side utilities of the libvirt
library
Requires: libvirt-libs = %{version}-%{release}
# Needed by virt-pki-validate script.
Requires: gnutls-utils
+ %if %{with_ssh_proxy}
+Recommends: libvirt-ssh-proxy = %{version}-%{release}
+ %endif
I wonder if we should also have this present as a stronger 'Requires'
in both libvirt-daemon-kvm & libvirt-daemon-qemu, as those are
convenience RPMs intended to provide a set of RPMs to maxmimise the
featureset.
diff --git a/meson.build b/meson.build
index 1518afa1cb..b19f9b1ed1 100644
--- a/meson.build
+++ b/meson.build
@@ -113,6 +113,11 @@ endif
confdir = sysconfdir / meson.project_name()
pkgdatadir = datadir / meson.project_name()
+sshconfdir = get_option('sshconfdir')
+if sshconfdir == ''
+ sshconfdir = sysconfdir / 'ssh/ssh_config.d'
Lets use the / operator consistently there
sshconfdir = sysconfdir / 'ssh' / 'ssh_config.d'
diff --git a/tools/ssh-proxy/30-libvirt-ssh-proxy.conf.in
b/tools/ssh-proxy/30-libvirt-ssh-proxy.conf.in
new file mode 100644
index 0000000000..9a022826f7
--- /dev/null
+++ b/tools/ssh-proxy/30-libvirt-ssh-proxy.conf.in
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+Host qemu/*
+ ProxyCommand @libexecdir@/libvirt-ssh-proxy %h %p
+ ProxyUseFdpass yes
+ CheckHostIP no
+
+ # Disable all kinds of host identity checks, since these addresses are generally
ephemeral.
+ StrictHostKeyChecking no
+ UserKnownHostsFile /dev/null
I know systemd did this too, but I'm somewhat on the fence over
whether turning this off is a good idea or not.
I would assume it is recording "qemu/guestname" as the entry in
the known hosts file, which is not that ephemeral for traditional
guests ?
I wonder if we should just let the user decide to turn this off
if they so wish rather than forcing a less secure config by
default.
+static int
+processVsock(const char *domname,
+ unsigned int port)
+{
+ const char *uris[] = {"qemu:///system", "qemu:///session"};
We should be skipping the session driver, if running as
root.
+ struct sockaddr_vm sa = {
+ .svm_family = AF_VSOCK,
+ .svm_port = port,
+ };
+ VIR_AUTOCLOSE fd = -1;
+ unsigned long long cid = -1;
+ size_t i;
+
+ for (i = 0; i < G_N_ELEMENTS(uris); i++) {
+ g_autoptr(virConnect) conn = NULL;
+ g_autoptr(virDomain) dom = NULL;
+
+ if (!(dom = lookupDomain(domname, uris[i], &conn)))
+ continue;
+
+ if (extractCID(dom, &cid) >= 0)
+ break;
+ }
+
+ if (cid == -1) {
+ ERROR(_("No usable vsock found"));
+ return -1;
+ }
+
+ sa.svm_cid = cid;
+
+ fd = socket(AF_VSOCK, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ if (fd < 0) {
+ SYS_ERROR(_("Failed to allocate AF_VSOCK socket"));
+ return -1;
+ }
+
+ if (connect(fd, (const struct sockaddr *)&sa, sizeof(sa)) < 0) {
+ SYS_ERROR(_("Failed to connect to vsock (cid=%1$llu port=%2$u)"),
+ cid, port);
+ return -1;
+ }
+
+ /* OpenSSH wants us to send a single byte along with the file descriptor,
+ * hence do so. */
+ if (virSocketSendFD(STDOUT_FILENO, fd) < 0) {
+ SYS_ERROR(_("Failed to send file descriptor %1$d"), fd);
+ return -1;
+ }
+
+ return 0;
+}
With regards,
Daniel
--
|:
https://berrange.com -o-
https://www.flickr.com/photos/dberrange :|
|:
https://libvirt.org -o-
https://fstop138.berrange.com :|
|:
https://entangle-photo.org -o-
https://www.instagram.com/dberrange :|