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:
		
							parent
							
								
									75822a12c0
								
							
						
					
					
						commit
						145614a112
					
				
							
								
								
									
										62
									
								
								qemu-nbd.c
									
									
									
									
									
								
							
							
						
						
									
										62
									
								
								qemu-nbd.c
									
									
									
									
									
								
							| @ -42,6 +42,7 @@ | ||||
| #define QEMU_NBD_OPT_DISCARD       3 | ||||
| #define QEMU_NBD_OPT_DETECT_ZEROES 4 | ||||
| #define QEMU_NBD_OPT_OBJECT        5 | ||||
| #define QEMU_NBD_OPT_TLSCREDS      6 | ||||
| 
 | ||||
| static NBDExport *exp; | ||||
| static bool newproto; | ||||
| @ -54,6 +55,7 @@ static int shared = 1; | ||||
| static int nb_fds; | ||||
| static QIOChannelSocket *server_ioc; | ||||
| static int server_watch = -1; | ||||
| static QCryptoTLSCreds *tlscreds; | ||||
| 
 | ||||
| static void usage(const char *name) | ||||
| { | ||||
| @ -342,7 +344,7 @@ static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque) | ||||
|     nb_fds++; | ||||
|     nbd_update_server_watch(); | ||||
|     nbd_client_new(newproto ? NULL : exp, cioc, | ||||
|                    NULL, NULL, nbd_client_closed); | ||||
|                    tlscreds, NULL, nbd_client_closed); | ||||
|     object_unref(OBJECT(cioc)); | ||||
| 
 | ||||
|     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) | ||||
| { | ||||
|     BlockBackend *blk; | ||||
| @ -441,6 +474,7 @@ int main(int argc, char **argv) | ||||
|         { "verbose", 0, NULL, 'v' }, | ||||
|         { "object", 1, NULL, QEMU_NBD_OPT_OBJECT }, | ||||
|         { "export-name", 1, NULL, 'x' }, | ||||
|         { "tls-creds", 1, NULL, QEMU_NBD_OPT_TLSCREDS }, | ||||
|         { NULL, 0, NULL, 0 } | ||||
|     }; | ||||
|     int ch; | ||||
| @ -458,6 +492,7 @@ int main(int argc, char **argv) | ||||
|     BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF; | ||||
|     QDict *options = NULL; | ||||
|     const char *export_name = NULL; | ||||
|     const char *tlscredsid = NULL; | ||||
| 
 | ||||
|     /* The client thread uses SIGTERM to interrupt the server.  A signal
 | ||||
|      * 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); | ||||
|             } | ||||
|         }   break; | ||||
|         case QEMU_NBD_OPT_TLSCREDS: | ||||
|             tlscredsid = optarg; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| @ -650,6 +688,28 @@ int main(int argc, char **argv) | ||||
|         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) { | ||||
|         int nbdfd = open(argv[optind], O_RDWR); | ||||
|         if (nbdfd < 0) { | ||||
|  | ||||
| @ -21,9 +21,10 @@ Export a QEMU disk image using the NBD protocol. | ||||
| @item --object type,id=@var{id},...props... | ||||
| 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 | ||||
| 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 | ||||
| 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} | ||||
| The TCP port to listen on (default @samp{10809}) | ||||
| @item -o, --offset=@var{offset} | ||||
| @ -76,6 +77,10 @@ Don't exit on the last connection | ||||
| @item -x NAME, --export-name=NAME | ||||
| Set the NBD volume export name. This switches the server to use | ||||
| 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 | ||||
| Display extra debugging information | ||||
| @item -h, --help | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Daniel P. Berrange
						Daniel P. Berrange