From patchwork Mon Nov 14 16:21:23 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lance Richardson X-Patchwork-Id: 694607 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3tHbQf3Dlgz9s9Y for ; Tue, 15 Nov 2016 03:22:34 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id CE4E7C78; Mon, 14 Nov 2016 16:21:30 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 0E0C2BCD for ; Mon, 14 Nov 2016 16:21:27 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 172992A0 for ; Mon, 14 Nov 2016 16:21:26 +0000 (UTC) Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9CAF18FCF8 for ; Mon, 14 Nov 2016 16:21:25 +0000 (UTC) Received: from thinkcentre.redhat.com (ovpn-116-16.rdu2.redhat.com [10.10.116.16]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id uAEGLNMh010825 for ; Mon, 14 Nov 2016 11:21:25 -0500 From: Lance Richardson To: dev@openvswitch.org Date: Mon, 14 Nov 2016 11:21:23 -0500 Message-Id: <1479140483-24778-4-git-send-email-lrichard@redhat.com> In-Reply-To: <1479140483-24778-1-git-send-email-lrichard@redhat.com> References: <1479140483-24778-1-git-send-email-lrichard@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.27 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Mon, 14 Nov 2016 16:21:25 +0000 (UTC) X-Spam-Status: No, score=-9.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v3 3/3] ovn-sb: add support for SSL configuration in database X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org Add SSL configuration to the southbound database schema and add commands to ovn-sbctl to allow management of these entries. Added commands: Print SSL configuration: ovn-sbctl get-ssl Delete SSL configuration: ovn-sbctl del-ssl Set SSL configuration: ovn-sbctl [--bootstrap] set-ssl PRIV-KEY CERT CA-CERT Signed-off-by: Lance Richardson --- manpages.mk | 6 +++ ovn/utilities/ovn-sbctl.8.in | 54 ++++++++++++++++++++++++++ ovn/utilities/ovn-sbctl.c | 92 +++++++++++++++++++++++++++++++++++++++++++- tests/ovn.at | 52 +++++++++++++++++++++++++ 4 files changed, 203 insertions(+), 1 deletion(-) diff --git a/manpages.mk b/manpages.mk index e019179..ebe654e 100644 --- a/manpages.mk +++ b/manpages.mk @@ -3,6 +3,9 @@ ovn/utilities/ovn-sbctl.8: \ ovn/utilities/ovn-sbctl.8.in \ lib/db-ctl-base.man \ + lib/ssl-bootstrap.man \ + lib/ssl-peer-ca-cert.man \ + lib/ssl.man \ lib/table.man \ ovsdb/remote-active.man \ ovsdb/remote-active.man \ @@ -10,6 +13,9 @@ ovn/utilities/ovn-sbctl.8: \ ovsdb/remote-passive.man ovn/utilities/ovn-sbctl.8.in: lib/db-ctl-base.man: +lib/ssl-bootstrap.man: +lib/ssl-peer-ca-cert.man: +lib/ssl.man: lib/table.man: ovsdb/remote-active.man: ovsdb/remote-active.man: diff --git a/ovn/utilities/ovn-sbctl.8.in b/ovn/utilities/ovn-sbctl.8.in index 5545b2e..55621d9 100644 --- a/ovn/utilities/ovn-sbctl.8.in +++ b/ovn/utilities/ovn-sbctl.8.in @@ -98,6 +98,11 @@ These options control the format of output from the \fBlist\fR and \fBfind\fR commands. .so lib/table.man . +.SS "Public Key Infrastructure Options" +.so lib/ssl.man +.so lib/ssl-bootstrap.man +.so lib/ssl-peer-ca-cert.man +. .SH COMMANDS The commands implemented by \fBovn\-sbctl\fR are described in the sections below. @@ -186,6 +191,55 @@ be preceded by an optional access-specifier (\fBread\-only\fR or If provided, the effect of the access specifier persists for subsequent targets until changed by another access specifier. . +.SS "SSL Configuration" +When \fBovsdb\-server\fR is configured to connect using SSL, the +following parameters are required: +.TP +\fIprivate-key\fR +Specifies a PEM file containing the private key used for SSL connections. +.TP +\fIcertificate\fR +Specifies a PEM file containing a certificate, signed by the +certificate authority (CA) used by the connection peers, that +certifies the private key, identifying a trustworthy peer. +.TP +\fIca-cert\fR +Specifies a PEM file containing the CA certificate used to verify that +the connection peers are trustworthy. +.PP +These SSL settings apply to all SSL connections made by the southbound +database server. +. +.IP "\fBget\-ssl\fR" +Prints the SSL configuration. +. +.IP "\fBdel\-ssl\fR" +Deletes the current SSL configuration. +. +.IP "[\fB\-\-bootstrap\fR] \fBset\-ssl\fR \fIprivate-key\fR \fIcertificate\fR \fIca-cert\fR" +Sets the SSL configuration. The \fB\-\-bootstrap\fR option is described +below. +. +.ST "CA Certificate Bootstrap" +.PP +Ordinarily, all of the files named in the SSL configuration must exist +before SSL connectivity can be used. However, if the \fIca-cert\fR file +does not exist and the \fB\-\-bootstrap\fR +option is given, then \fBovsdb\-server\fR will attempt to obtain the +CA certificate from the target on its first SSL connection and +save it to the named PEM file. If it is successful, it will +immediately drop the connection and reconnect, and from then on all +SSL connections must be authenticated by a certificate signed by the +CA certificate thus obtained. +.PP +\fBThis option exposes the SSL connection to a man-in-the-middle +attack obtaining the initial CA certificate\fR, but it may be useful +for bootstrapping. +.PP +This option is only useful if the SSL peer sends its CA certificate +as part of the SSL certificate chain. The SSL protocol does not +require the controller to send the CA certificate. +. .so lib/db-ctl-base.man .SH "EXIT STATUS" .IP "0" diff --git a/ovn/utilities/ovn-sbctl.c b/ovn/utilities/ovn-sbctl.c index 516b024..92ae3e5 100644 --- a/ovn/utilities/ovn-sbctl.c +++ b/ovn/utilities/ovn-sbctl.c @@ -313,6 +313,11 @@ Connection commands:\n\ del-connection delete the connections\n\ set-connection TARGET... set the list of connections to TARGET...\n\ \n\ +SSL commands:\n\ + get-ssl print the SSL configuration\n\ + del-ssl delete the SSL configuration\n\ + set-ssl PRIV-KEY CERT CA-CERT set the SSL configuration\n\ +\n\ %s\ \n\ Options:\n\ @@ -857,6 +862,84 @@ cmd_set_connection(struct ctl_context *ctx) insert_connections(ctx, &ctx->argv[1], n); } +static void +pre_cmd_get_ssl(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl); + + ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_private_key); + ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_certificate); + ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_ca_cert); + ovsdb_idl_add_column(ctx->idl, &sbrec_ssl_col_bootstrap_ca_cert); +} + +static void +cmd_get_ssl(struct ctl_context *ctx) +{ + const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl); + const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl); + + sbrec_sb_global_verify_ssl(sb_global); + if (ssl) { + sbrec_ssl_verify_private_key(ssl); + sbrec_ssl_verify_certificate(ssl); + sbrec_ssl_verify_ca_cert(ssl); + sbrec_ssl_verify_bootstrap_ca_cert(ssl); + + ds_put_format(&ctx->output, "Private key: %s\n", ssl->private_key); + ds_put_format(&ctx->output, "Certificate: %s\n", ssl->certificate); + ds_put_format(&ctx->output, "CA Certificate: %s\n", ssl->ca_cert); + ds_put_format(&ctx->output, "Bootstrap: %s\n", + ssl->bootstrap_ca_cert ? "true" : "false"); + } +} + +static void +pre_cmd_del_ssl(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl); +} + +static void +cmd_del_ssl(struct ctl_context *ctx) +{ + const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl); + const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl); + + if (ssl) { + sbrec_sb_global_verify_ssl(sb_global); + sbrec_ssl_delete(ssl); + sbrec_sb_global_set_ssl(sb_global, NULL); + } +} + +static void +pre_cmd_set_ssl(struct ctl_context *ctx) +{ + ovsdb_idl_add_column(ctx->idl, &sbrec_sb_global_col_ssl); +} + +static void +cmd_set_ssl(struct ctl_context *ctx) +{ + bool bootstrap = shash_find(&ctx->options, "--bootstrap"); + const struct sbrec_sb_global *sb_global = sbrec_sb_global_first(ctx->idl); + const struct sbrec_ssl *ssl = sbrec_ssl_first(ctx->idl); + + sbrec_sb_global_verify_ssl(sb_global); + if (ssl) { + sbrec_ssl_delete(ssl); + } + ssl = sbrec_ssl_insert(ctx->txn); + + sbrec_ssl_set_private_key(ssl, ctx->argv[1]); + sbrec_ssl_set_certificate(ssl, ctx->argv[2]); + sbrec_ssl_set_ca_cert(ssl, ctx->argv[3]); + + sbrec_ssl_set_bootstrap_ca_cert(ssl, bootstrap); + + sbrec_sb_global_set_ssl(sb_global, ssl); +} static const struct ctl_table_class tables[] = { @@ -901,6 +984,9 @@ static const struct ctl_table_class tables[] = { {{&sbrec_table_connection, NULL, NULL}, {NULL, NULL, NULL}}}, + {&sbrec_table_ssl, + {{&sbrec_table_sb_global, NULL, &sbrec_sb_global_col_ssl}}}, + {NULL, {{NULL, NULL, NULL}, {NULL, NULL, NULL}}} }; @@ -1169,7 +1255,11 @@ static const struct ctl_command_syntax sbctl_commands[] = { {"set-connection", 1, INT_MAX, "TARGET...", pre_connection, cmd_set_connection, NULL, "", RW}, - /* SSL commands (To Be Added). */ + /* SSL commands. */ + {"get-ssl", 0, 0, "", pre_cmd_get_ssl, cmd_get_ssl, NULL, "", RO}, + {"del-ssl", 0, 0, "", pre_cmd_del_ssl, cmd_del_ssl, NULL, "", RW}, + {"set-ssl", 3, 3, "PRIVATE-KEY CERTIFICATE CA-CERT", pre_cmd_set_ssl, + cmd_set_ssl, NULL, "--bootstrap", RW}, {NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, RO}, }; diff --git a/tests/ovn.at b/tests/ovn.at index 6ae4247..39d2af8 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -5555,6 +5555,58 @@ AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ OVS_APP_EXIT_AND_WAIT([ovsdb-server]) AT_CLEANUP +AT_SETUP([ovn -- sb connection/ssl commands]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +AT_SKIP_IF([test "$HAVE_OPENSSL" = no]) +PKIDIR="$(cd $abs_top_builddir/tests && pwd)" +AT_SKIP_IF([expr "$PKIDIR" : ".*[ '\" +\\]"]) + +: > .$1.db.~lock~ +ovsdb-tool create ovn-sb.db "$abs_top_srcdir"/ovn/ovn-sb.ovsschema + +# Start sb db server using db connection/ssl entries (unpopulated initially) +start_daemon ovsdb-server --remote=punix:ovnsb_db.sock \ + --remote=db:OVN_Southbound,SB_Global,connections \ + --private-key=db:OVN_Southbound,SSL,private_key \ + --certificate=db:OVN_Southbound,SSL,certificate \ + --ca-cert=db:OVN_Southbound,SSL,ca_cert \ + ovn-sb.db + +# Populate SSL configuration entries in sb db +AT_CHECK( + [ovn-sbctl set-ssl $PKIDIR/testpki-privkey.pem \ + $PKIDIR/testpki-cert.pem \ + $PKIDIR/testpki-cacert.pem], [0], [stdout], [ignore]) + +# Populate a passive SSL connection in sb db +AT_CHECK([ovn-sbctl set-connection pssl:0:127.0.0.1], [0], [stdout], [ignore]) + +PARSE_LISTENING_PORT([ovsdb-server.log], [TCP_PORT]) + +# Verify SSL connetivity to sb db server +AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ + --private-key=$PKIDIR/testpki-privkey.pem \ + --certificate=$PKIDIR/testpki-cert.pem \ + --ca-cert=$PKIDIR/testpki-cacert.pem \ + list SB_Global], + [0], [stdout], [ignore]) +AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ + --private-key=$PKIDIR/testpki-privkey.pem \ + --certificate=$PKIDIR/testpki-cert.pem \ + --ca-cert=$PKIDIR/testpki-cacert.pem \ + list Connection], + [0], [stdout], [ignore]) +AT_CHECK([ovn-sbctl --db=ssl:127.0.0.1:$TCP_PORT \ + --private-key=$PKIDIR/testpki-privkey.pem \ + --certificate=$PKIDIR/testpki-cert.pem \ + --ca-cert=$PKIDIR/testpki-cacert.pem \ + get-connection], + [0], [stdout], [ignore]) + +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +AT_CLEANUP + AT_SETUP([ovn -- nested containers]) ovn_start