nbd: enable use of TLS with qemu-nbd server

This modifies the qemu-nbd program so that it is possible to
request the use of TLS with the server. It simply adds a new
command line option --tls-creds which is used to provide the
ID of a QCryptoTLSCreds object previously created via the
--object command line option.

For example

  qemu-nbd --object tls-creds-x509,id=tls0,endpoint=server,\
                    dir=/home/berrange/security/qemutls \
           --tls-creds tls0 \
           --exportname default

TLS requires the new style NBD protocol, so if no export name
is set (via --export-name), then we use the default NBD protocol
export name ""

TLS is only supported when using an IPv4/IPv6 socket listener.
It is not possible to use with UNIX sockets, which includes
when connecting the NBD server to a host device.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <1455129674-17255-16-git-send-email-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Daniel P. Berrange 2016-02-10 18:41:13 +00:00 committed by Paolo Bonzini
parent 75822a12c0
commit 145614a112
2 changed files with 68 additions and 3 deletions

View File

@ -42,6 +42,7 @@
#define QEMU_NBD_OPT_DISCARD 3 #define QEMU_NBD_OPT_DISCARD 3
#define QEMU_NBD_OPT_DETECT_ZEROES 4 #define QEMU_NBD_OPT_DETECT_ZEROES 4
#define QEMU_NBD_OPT_OBJECT 5 #define QEMU_NBD_OPT_OBJECT 5
#define QEMU_NBD_OPT_TLSCREDS 6
static NBDExport *exp; static NBDExport *exp;
static bool newproto; static bool newproto;
@ -54,6 +55,7 @@ static int shared = 1;
static int nb_fds; static int nb_fds;
static QIOChannelSocket *server_ioc; static QIOChannelSocket *server_ioc;
static int server_watch = -1; static int server_watch = -1;
static QCryptoTLSCreds *tlscreds;
static void usage(const char *name) static void usage(const char *name)
{ {
@ -342,7 +344,7 @@ static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque)
nb_fds++; nb_fds++;
nbd_update_server_watch(); nbd_update_server_watch();
nbd_client_new(newproto ? NULL : exp, cioc, nbd_client_new(newproto ? NULL : exp, cioc,
NULL, NULL, nbd_client_closed); tlscreds, NULL, nbd_client_closed);
object_unref(OBJECT(cioc)); object_unref(OBJECT(cioc));
return TRUE; return TRUE;
@ -402,6 +404,37 @@ static QemuOptsList qemu_object_opts = {
}; };
static QCryptoTLSCreds *nbd_get_tls_creds(const char *id, Error **errp)
{
Object *obj;
QCryptoTLSCreds *creds;
obj = object_resolve_path_component(
object_get_objects_root(), id);
if (!obj) {
error_setg(errp, "No TLS credentials with id '%s'",
id);
return NULL;
}
creds = (QCryptoTLSCreds *)
object_dynamic_cast(obj, TYPE_QCRYPTO_TLS_CREDS);
if (!creds) {
error_setg(errp, "Object with id '%s' is not TLS credentials",
id);
return NULL;
}
if (creds->endpoint != QCRYPTO_TLS_CREDS_ENDPOINT_SERVER) {
error_setg(errp,
"Expecting TLS credentials with a server endpoint");
return NULL;
}
object_ref(obj);
return creds;
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
BlockBackend *blk; BlockBackend *blk;
@ -441,6 +474,7 @@ int main(int argc, char **argv)
{ "verbose", 0, NULL, 'v' }, { "verbose", 0, NULL, 'v' },
{ "object", 1, NULL, QEMU_NBD_OPT_OBJECT }, { "object", 1, NULL, QEMU_NBD_OPT_OBJECT },
{ "export-name", 1, NULL, 'x' }, { "export-name", 1, NULL, 'x' },
{ "tls-creds", 1, NULL, QEMU_NBD_OPT_TLSCREDS },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
int ch; int ch;
@ -458,6 +492,7 @@ int main(int argc, char **argv)
BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
QDict *options = NULL; QDict *options = NULL;
const char *export_name = NULL; const char *export_name = NULL;
const char *tlscredsid = NULL;
/* The client thread uses SIGTERM to interrupt the server. A signal /* The client thread uses SIGTERM to interrupt the server. A signal
* handler ensures that "qemu-nbd -v -c" exits with a nice status code. * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@ -634,6 +669,9 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
} break; } break;
case QEMU_NBD_OPT_TLSCREDS:
tlscredsid = optarg;
break;
} }
} }
@ -650,6 +688,28 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (tlscredsid) {
if (sockpath) {
error_report("TLS is only supported with IPv4/IPv6");
exit(EXIT_FAILURE);
}
if (device) {
error_report("TLS is not supported with a host device");
exit(EXIT_FAILURE);
}
if (!export_name) {
/* Set the default NBD protocol export name, since
* we *must* use new style protocol for TLS */
export_name = "";
}
tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
if (local_err) {
error_report("Failed to get TLS creds %s",
error_get_pretty(local_err));
exit(EXIT_FAILURE);
}
}
if (disconnect) { if (disconnect) {
int nbdfd = open(argv[optind], O_RDWR); int nbdfd = open(argv[optind], O_RDWR);
if (nbdfd < 0) { if (nbdfd < 0) {

View File

@ -21,9 +21,10 @@ Export a QEMU disk image using the NBD protocol.
@item --object type,id=@var{id},...props... @item --object type,id=@var{id},...props...
Define a new instance of the @var{type} object class identified by @var{id}. Define a new instance of the @var{type} object class identified by @var{id}.
See the @code{qemu(1)} manual page for full details of the properties See the @code{qemu(1)} manual page for full details of the properties
supported. The common object type that it makes sense to define is the supported. The common object types that it makes sense to define are the
@code{secret} object, which is used to supply passwords and/or encryption @code{secret} object, which is used to supply passwords and/or encryption
keys. keys, and the @code{tls-creds} object, which is used to supply TLS
credentials for the qemu-nbd server.
@item -p, --port=@var{port} @item -p, --port=@var{port}
The TCP port to listen on (default @samp{10809}) The TCP port to listen on (default @samp{10809})
@item -o, --offset=@var{offset} @item -o, --offset=@var{offset}
@ -76,6 +77,10 @@ Don't exit on the last connection
@item -x NAME, --export-name=NAME @item -x NAME, --export-name=NAME
Set the NBD volume export name. This switches the server to use Set the NBD volume export name. This switches the server to use
the new style NBD protocol negotiation the new style NBD protocol negotiation
@item --tls-creds=ID
Enable mandatory TLS encryption for the server by setting the ID
of the TLS credentials object previously created with the --object
option.
@item -v, --verbose @item -v, --verbose
Display extra debugging information Display extra debugging information
@item -h, --help @item -h, --help