tools: support validating user/custom PKI certs

The virt-pki-validate command can validate the system certificate
directories. The remote driver, however, also supports a standard
per-user certs location, as well as a runtime custom path. This
extends the validation tool to be able to cope with these alternate
locations too.

Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2024-06-07 11:30:35 +01:00
parent 8e97fd4181
commit acb26f22a1
2 changed files with 197 additions and 79 deletions

View File

@ -15,7 +15,7 @@ SYNOPSIS
========
``virt-pki-validate`` [*OPTION*]
``virt-pki-validate`` [*OPTION*] [trust|server|client]
DESCRIPTION
@ -26,6 +26,9 @@ a secure libvirt server or client using the TLS encryption protocol.
It will report any missing certificate or key files on the host. It
should be run as root to ensure it can read all the necessary files
With no arguments it will check the trusted CA config, the server
config and the client config. The optional positional argument can
be used to restrict the checks to just one of these three sets.
OPTIONS
=======

View File

@ -60,11 +60,12 @@ virPKIValidateFile(const char *file,
} while (0)
static bool
virPKIValidateTrust(void)
virPKIValidateTrust(bool system, const char *path)
{
g_autofree char *cacert = NULL, *cacrl = NULL;
bool ok = true;
if (system) {
virNetTLSConfigSystemTrust(&cacert,
&cacrl);
@ -94,6 +95,42 @@ virPKIValidateTrust(void)
0, 0, 0755,
_("The system CA dir %1$s must be accessible to all users. As root, run: chown root.root; chmod 0755 %2$s"),
LIBVIRT_CACERT_DIR, LIBVIRT_CACERT_DIR);
} else if (path) {
virNetTLSConfigCustomTrust(path,
&cacert,
&cacrl);
FILE_REQUIRE_EXISTS("TRUST",
path,
_("Checking if custom PKI base dir exists"),
_("Create the dir %1$s"),
path);
FILE_REQUIRE_ACCESS("TRUST",
path,
_("Checking custom PKI base dir access"),
getuid(), getgid(), 0700,
_("The PKI base dir %1$s must not be accessible to other users. Run: chown %2$d.%3$d %4$s; chmod 0700 %5$s"),
path, getuid(), getgid(), path, path);
} else {
g_autofree char *pkipath = virNetTLSConfigUserPKIBaseDir();
virNetTLSConfigUserTrust(&cacert,
&cacrl);
FILE_REQUIRE_EXISTS("TRUST",
pkipath,
_("Checking if user PKI base dir exists"),
_("Create the dir %1$s"),
pkipath);
FILE_REQUIRE_ACCESS("TRUST",
pkipath,
_("Checking user PKI base dir access"),
getuid(), getgid(), 0700,
_("The PKI base dir %1$s must not be accessible to other users. Run: chown %2$d.%3$d %4$s; chmod 0700 %5$s"),
pkipath, getuid(), getgid(), pkipath, pkipath);
}
FILE_REQUIRE_EXISTS("TRUST",
cacert,
@ -101,25 +138,35 @@ virPKIValidateTrust(void)
_("The machine cannot act as a client or server. See https://libvirt.org/kbase/tlscerts.html#setting-up-a-certificate-authority-ca on how to install %1$s"),
cacert);
if (system) {
FILE_REQUIRE_ACCESS("TRUST",
cacert,
_("Checking CA cert access"),
0, 0, 0644,
_("The CA certificate %1$s must be accessible to all users. As root run: chown root.root %2$s; chmod 0644 %3$s"),
cacert, cacert, cacert);
} else {
FILE_REQUIRE_ACCESS("TRUST",
cacert,
_("Checking CA cert access"),
getuid(), getgid(), 0600,
_("The CA certificate %1$s must not be accessible to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s"),
cacert, getuid(), getgid(), cacert, cacert);
}
done:
return ok;
}
static bool
virPKIValidateIdentity(bool isServer)
virPKIValidateIdentity(bool isServer, bool system, const char *path)
{
g_autofree char *cacert = NULL, *cacrl = NULL;
g_autofree char *cert = NULL, *key = NULL;
bool ok = true;
const char *scope = isServer ? "SERVER" : "CLIENT";
if (system) {
virNetTLSConfigSystemTrust(&cacert,
&cacrl);
virNetTLSConfigSystemIdentity(isServer,
@ -151,6 +198,21 @@ virPKIValidateIdentity(bool isServer)
0, 0, 0755,
_("The system key dir %1$s must be accessible to all users. As root, run: chown root.root; chmod 0755 %2$s"),
LIBVIRT_KEY_DIR, LIBVIRT_PKI_DIR);
} else if (path) {
virNetTLSConfigCustomTrust(path,
&cacert,
&cacrl);
virNetTLSConfigCustomIdentity(path,
isServer,
&cert,
&key);
} else {
virNetTLSConfigUserTrust(&cacert,
&cacrl);
virNetTLSConfigUserIdentity(isServer,
&cert,
&key);
}
FILE_REQUIRE_EXISTS(scope,
key,
@ -160,6 +222,7 @@ virPKIValidateIdentity(bool isServer)
_("The machine cannot act as a client. See https://libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to regenerate %1$s"),
key);
if (system) {
FILE_REQUIRE_ACCESS(scope,
key,
_("Checking key access"),
@ -168,6 +231,16 @@ virPKIValidateIdentity(bool isServer)
_("The server key %1$s must not be accessible to unprivileged users. As root run: chown root.root %2$s; chmod 0600 %3$s") :
_("The client key %1$s must be accessible to all users. As root run: chown root.root %2$s; chmod 0644 %3$s"),
key, key, key);
} else {
FILE_REQUIRE_ACCESS(scope,
key,
_("Checking key access"),
getuid(), getgid(), 0600,
isServer ?
_("The server key %1$s must be not be accessible to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s") :
_("The client key %1$s must be not be accessible to other users. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s"),
key, getuid(), getgid(), key, key);
}
FILE_REQUIRE_EXISTS(scope,
cert,
@ -177,6 +250,7 @@ virPKIValidateIdentity(bool isServer)
_("The machine cannot act as a client. See https://libvirt.org/kbase/tlscerts.html#issuing-client-certificates on how to regenerate %1$s"),
cert);
if (system) {
FILE_REQUIRE_ACCESS(scope,
cert,
_("Checking cert access"),
@ -185,6 +259,16 @@ virPKIValidateIdentity(bool isServer)
_("The server cert %1$s must be accessible to all users. As root run: chown root.root %2$s; chmod 0644 %3$s") :
_("The client cert %1$s must be accessible to all users. As root run: chown root.root %2$s; chmod 0644 %3$s"),
cert, cert, cert);
} else {
FILE_REQUIRE_ACCESS(scope,
cert,
_("Checking cert access"),
getuid(), getgid(), 0600,
isServer ?
_("The server cert %1$s must be restricted to this user. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s") :
_("The client cert %1$s must be restricted to this user. As this user, run: chown %2$d.%3$d %4$s; chmod 0600 %5$s"),
cert, getuid(), getgid(), cert, cert);
}
virValidateCheck(scope, "%s", _("Checking cert properties"));
@ -239,6 +323,9 @@ print_usage(const char *progname,
"Validate TLS certificate configuration\n"
"\n"
"options:\n"
" -s | --system validate system certificates (default)\n"
" -u | --user validate user certificates\n"
" -p DIR | --path DIR validate custom certificate path\n"
" -h | --help display this help and exit\n"
" -v | --version output version information and exit\n"),
progname);
@ -247,6 +334,9 @@ print_usage(const char *progname,
int main(int argc, char **argv)
{
const char *scope = NULL;
bool system = false;
bool user = false;
const char *path = NULL;
bool quiet = false;
int arg = 0;
bool ok = true;
@ -254,6 +344,9 @@ int main(int argc, char **argv)
struct option opt[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ "system", no_argument, NULL, 's' },
{ "user", no_argument, NULL, 'u' },
{ "path", required_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 },
};
@ -262,6 +355,18 @@ int main(int argc, char **argv)
while ((arg = getopt_long(argc, argv, "hvsup:", opt, NULL)) != -1) {
switch (arg) {
case 's':
system = true;
break;
case 'u':
user = true;
break;
case 'p':
path = optarg;
break;
case 'v':
printf("%s\n", PACKAGE_VERSION);
return EXIT_SUCCESS;
@ -292,14 +397,24 @@ int main(int argc, char **argv)
virValidateSetQuiet(quiet);
if ((system && user) ||
(system && path) ||
(user && path)) {
g_printerr("--system, --user & --path are mutually exclusive\n");
return EXIT_FAILURE;
}
if (!system && !user && !path)
system = true;
if ((!scope || g_str_equal(scope, "trust")) &&
!virPKIValidateTrust())
!virPKIValidateTrust(system, path))
ok = false;
if ((!scope || g_str_equal(scope, "server")) &&
!virPKIValidateIdentity(true))
!virPKIValidateIdentity(true, system, path))
ok = false;
if ((!scope || g_str_equal(scope, "client")) &&
!virPKIValidateIdentity(false))
!virPKIValidateIdentity(false, system, path))
ok = false;
if (!ok)