[ovs-dev] [PATCH v2 3/3] ovn-sb: add support for SSL configuration in database

Lance Richardson lrichard at redhat.com
Wed Nov 9 13:59:44 UTC 2016


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 <lrichard at redhat.com>
---
 manpages.mk                  | 10 +++++
 ovn/utilities/ovn-sbctl.8.in | 56 +++++++++++++++++++++++++++
 ovn/utilities/ovn-sbctl.c    | 92 +++++++++++++++++++++++++++++++++++++++++++-
 tests/ovn.at                 | 52 +++++++++++++++++++++++++
 4 files changed, 209 insertions(+), 1 deletion(-)

diff --git a/manpages.mk b/manpages.mk
index 5968444..dbb101c 100644
--- a/manpages.mk
+++ b/manpages.mk
@@ -2,15 +2,25 @@
 
 ovn/utilities/ovn-sbctl.8: \
 	ovn/utilities/ovn-sbctl.8.in \
+	lib/common.man \
 	lib/db-ctl-base.man \
+	lib/ssl-bootstrap.man \
+	lib/ssl-peer-ca-cert.man \
+	lib/ssl.man \
 	lib/table.man \
+	lib/vlog.man \
 	ovsdb/remote-active.man \
 	ovsdb/remote-active.man \
 	ovsdb/remote-passive.man \
 	ovsdb/remote-passive.man
 ovn/utilities/ovn-sbctl.8.in:
+lib/common.man:
 lib/db-ctl-base.man:
+lib/ssl-bootstrap.man:
+lib/ssl-peer-ca-cert.man:
+lib/ssl.man:
 lib/table.man:
+lib/vlog.man:
 ovsdb/remote-active.man:
 ovsdb/remote-active.man:
 ovsdb/remote-passive.man:
diff --git a/ovn/utilities/ovn-sbctl.8.in b/ovn/utilities/ovn-sbctl.8.in
index 1297223..e36b835 100644
--- a/ovn/utilities/ovn-sbctl.8.in
+++ b/ovn/utilities/ovn-sbctl.8.in
@@ -102,6 +102,13 @@ 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
+.so lib/vlog.man
+.so lib/common.man
+.
 .SH COMMANDS
 The commands implemented by \fBovn\-sbctl\fR are described in the
 sections below.
@@ -190,6 +197,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 9b554f9..9a9fc90 100644
--- a/ovn/utilities/ovn-sbctl.c
+++ b/ovn/utilities/ovn-sbctl.c
@@ -314,6 +314,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\
@@ -858,6 +863,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[] = {
@@ -902,6 +985,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}}}
 };
 
@@ -1170,7 +1256,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
 
-- 
2.5.5




More information about the dev mailing list