From: Francis Dupont Date: Mon, 29 Nov 2021 15:29:22 +0000 (+0100) Subject: [#34] Checkpoint: code and tests to do X-Git-Tag: Kea-2.1.2~159 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1d3f0133ba49545fe0ac7d6c8a355748e8eb0f3f;p=thirdparty%2Fkea.git [#34] Checkpoint: code and tests to do --- diff --git a/configure.ac b/configure.ac index 5df638e771..a8d6287243 100644 --- a/configure.ac +++ b/configure.ac @@ -815,6 +815,13 @@ fi # ... and at the shell level, so Makefile.am can take action depending on this. AM_CONDITIONAL(HAVE_PGSQL, test "$PG_CONFIG" != "") +# allow building kea programs with a PostgreSQL without OpenSSL. +AC_ARG_ENABLE([pgsql-ssl], + [AS_HELP_STRING([--enable-pgsql-ssl], + [enable OpenSSL support in PostgreSQL [default=yes]])], + [pgsql_ssl=yes], [pgsql_ssl=no], [pgsql_ssl=yes]) +AC_DEFINE([HAVE_PGSQL_SSL], [1], [PostgreSQL was built with OpenSSL support]) + # allow building kea programs with static link to cassandra cpp-driver. AC_ARG_ENABLE([cql-static-lib], [AS_HELP_STRING([--enable-cql-static-lib], diff --git a/doc/examples/kea4/all-keys.json b/doc/examples/kea4/all-keys.json index 4863f0e718..ae60b2ed50 100644 --- a/doc/examples/kea4/all-keys.json +++ b/doc/examples/kea4/all-keys.json @@ -316,7 +316,21 @@ "user": "kea", // Read only mode. - "readonly": false + "readonly": false, + + // Next entries are for the OpenSSL support in MySQL. + + // Trust anchor aka certificate authority file or directory. + "trust-anchor": "my-ca", + + // Client certificate file name. + "cert-file": "my-cert", + + // Private key file name. + "key-file": "my key", + + // Cipher list (see the OpenSSL ciohers command manual). + "cipher-list": "!SSLv3" }, { // Name of the database to connect to. diff --git a/doc/examples/kea4/mysql-reservations.json b/doc/examples/kea4/mysql-reservations.json index d859edd002..c15e970661 100644 --- a/doc/examples/kea4/mysql-reservations.json +++ b/doc/examples/kea4/mysql-reservations.json @@ -63,7 +63,11 @@ "user": "kea", "password": "kea", "host": "localhost", - "port": 3306 + "port": 3306, + "trust-anchor": "my-ca", + "cert-file": "my-cert", + "key-file": "my-key", + "cipher-list": "!SSLv3" }, // Define a subnet with a single pool of dynamic addresses. Addresses from diff --git a/doc/examples/kea6/all-keys.json b/doc/examples/kea6/all-keys.json index 9d2d028dd1..658a09e3cd 100644 --- a/doc/examples/kea6/all-keys.json +++ b/doc/examples/kea6/all-keys.json @@ -276,7 +276,21 @@ "user": "kea", // Read only mode. - "readonly": false + "readonly": false, + + // Next entries are for the OpenSSL support in MySQL. + + // Trust anchor aka certificate authority file or directory. + "trust-anchor": "my-ca", + + // Client certificate file name. + "cert-file": "my-cert", + + // Private key file name. + "key-file": "my key", + + // Cipher list (see the OpenSSL ciohers command manual). + "cipher-list": "!SSLv3" }, { // Name of the database to connect to. diff --git a/doc/examples/kea6/mysql-reservations.json b/doc/examples/kea6/mysql-reservations.json index ace2778737..a0a2c952d7 100644 --- a/doc/examples/kea6/mysql-reservations.json +++ b/doc/examples/kea6/mysql-reservations.json @@ -51,7 +51,11 @@ "password": "kea", "host": "localhost", "port": 3306, - "readonly": true + "readonly": true, + "trust-anchor": "my-ca", + "cert-file": "my-cert", + "key-file": "my-key", + "cipher-list": "!SSLv3" }, // Define a subnet with a pool of dynamic addresses and a pool of dynamic diff --git a/doc/sphinx/arm/admin.rst b/doc/sphinx/arm/admin.rst index 0a801bbca8..0ed60e90d1 100644 --- a/doc/sphinx/arm/admin.rst +++ b/doc/sphinx/arm/admin.rst @@ -583,6 +583,19 @@ Use the following command to perform an upgrade: $ kea-admin db-upgrade pgsql -u database-user -p database-password -n database-name +.. _pgsl-ssl: + +PostgreSQL without OpenSSL support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Usually the PostgreSQL database client library is built with the OpenSSL +support but in the case it was not Kea can be configured to handle this +case: + +.. code-block:: console + + $ ./configure [other-options] --disable-pgsql-ssl + .. _cql-database: Cassandra diff --git a/doc/sphinx/arm/database-connectivity.rst b/doc/sphinx/arm/database-connectivity.rst index 5546126342..5a4cdd5df7 100644 --- a/doc/sphinx/arm/database-connectivity.rst +++ b/doc/sphinx/arm/database-connectivity.rst @@ -6,7 +6,7 @@ Database Connectivity The Kea servers (``kea-dhcp4`` and ``kea-dhcp6``) can be configured to use a variety of database backends for leases, hosts, and configuration. They can be configured to support automatic recovery when connectivity is lost, via -the ``on-fail`` parameter. (The ``reconnect-wait-time`` and +the ``on-fail`` parameter. (The ``reconnect-wait-time`` and ``max-reconnect-tries`` parameters are described in :ref:`database-configuration4` and :ref:`database-configuration6`.) @@ -52,3 +52,35 @@ connection is lost. It can have one of the following values: If connectivity to all backends is restored, the server returns to normal operations. If the connection cannot be restored and the server is configured to exit, it issues a fatal error before shutdown. + +The connection to the database server can optionally be protected by TLS. +Corresponding database configuration parameters for Kea servers are: + +- The ``trust-anchor`` specifies the Certification Authority file name or + directory path. + +- The ``cert-file`` specifies the client certificate file name. + +- The ``key-file`` specifies the private key file name. + +- The ``cipher-list`` specifies the list of TLS ciphers (the syntax of + the content of this parameter is described in the OpenSSL ciphers + manual). + +These parameters are similar to the parameters of the secure connections +with the agent but are interpreted by different backends using database +configurations too. + +Currently the support for each database is: + +- MySQL supports the whole set, additional configuration must be done + in the MySQL local setup, for instance certificate revocation list, + choice of a specific TLS version, mutual authentication, ... + When a TLS connection was required but the actual connection is in + clear text an error log is emitted. + +- PostgreSQL only uses the configuration to enable the SSL/TLS support + in the client library (libpq). Anything else must be done in the + PostgreSQL local configuration. + +- Cassandra/CQL does not support this. diff --git a/src/bin/dhcp4/dhcp4_parser.yy b/src/bin/dhcp4/dhcp4_parser.yy index 35f96e6a15..557dcbba76 100644 --- a/src/bin/dhcp4/dhcp4_parser.yy +++ b/src/bin/dhcp4/dhcp4_parser.yy @@ -1142,7 +1142,7 @@ max_row_errors: MAX_ROW_ERRORS COLON INTEGER { trust_anchor: TRUST_ANCHOR { ctx.unique("trust-anchor", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr ca(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("trust-anchor", ca); @@ -1151,7 +1151,7 @@ trust_anchor: TRUST_ANCHOR { cert_file: CERT_FILE { ctx.unique("cert-file", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr cert(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("cert-file", cert); @@ -1160,7 +1160,7 @@ cert_file: CERT_FILE { key_file: KEY_FILE { ctx.unique("key-file", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr key(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("key-file", key); @@ -1169,7 +1169,7 @@ key_file: KEY_FILE { cipher_list: CIPHER_LIST { ctx.unique("cipher-list", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr cl(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("cipher-list", cl); diff --git a/src/bin/dhcp6/dhcp6_lexer.cc b/src/bin/dhcp6/dhcp6_lexer.cc index d1dcb22149..7edaa7a905 100644 --- a/src/bin/dhcp6/dhcp6_lexer.cc +++ b/src/bin/dhcp6/dhcp6_lexer.cc @@ -3456,12 +3456,12 @@ YY_RULE_SETUP #line 831 "dhcp6_lexer.ll" { switch(driver.ctx_) { - case isc::dhcp::Parser4Context::LEASE_DATABASE: - case isc::dhcp::Parser4Context::HOSTS_DATABASE: - case isc::dhcp::Parser4Context::CONFIG_DATABASE: - return isc::dhcp::Dhcp4Parser::make_TRUST_ANCHOR(driver.loc_); + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + case isc::dhcp::Parser6Context::CONFIG_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TRUST_ANCHOR(driver.loc_); default: - return isc::dhcp::Dhcp4Parser::make_STRING("trust-anchor", driver.loc_); + return isc::dhcp::Dhcp6Parser::make_STRING("trust-anchor", driver.loc_); } } YY_BREAK diff --git a/src/bin/dhcp6/dhcp6_lexer.ll b/src/bin/dhcp6/dhcp6_lexer.ll index d5863dc394..b365b49973 100644 --- a/src/bin/dhcp6/dhcp6_lexer.ll +++ b/src/bin/dhcp6/dhcp6_lexer.ll @@ -829,12 +829,12 @@ ControlCharacterFill [^"\\]|\\["\\/bfnrtu] \"trust-anchor\" { switch(driver.ctx_) { - case isc::dhcp::Parser4Context::LEASE_DATABASE: - case isc::dhcp::Parser4Context::HOSTS_DATABASE: - case isc::dhcp::Parser4Context::CONFIG_DATABASE: - return isc::dhcp::Dhcp4Parser::make_TRUST_ANCHOR(driver.loc_); + case isc::dhcp::Parser6Context::LEASE_DATABASE: + case isc::dhcp::Parser6Context::HOSTS_DATABASE: + case isc::dhcp::Parser6Context::CONFIG_DATABASE: + return isc::dhcp::Dhcp6Parser::make_TRUST_ANCHOR(driver.loc_); default: - return isc::dhcp::Dhcp4Parser::make_STRING("trust-anchor", driver.loc_); + return isc::dhcp::Dhcp6Parser::make_STRING("trust-anchor", driver.loc_); } } diff --git a/src/bin/dhcp6/dhcp6_parser.yy b/src/bin/dhcp6/dhcp6_parser.yy index 6bcd5d7852..c831dab7c6 100644 --- a/src/bin/dhcp6/dhcp6_parser.yy +++ b/src/bin/dhcp6/dhcp6_parser.yy @@ -1092,7 +1092,7 @@ serial_consistency: SERIAL_CONSISTENCY { trust_anchor: TRUST_ANCHOR { ctx.unique("trust-anchor", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr ca(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("trust-anchor", ca); @@ -1101,7 +1101,7 @@ trust_anchor: TRUST_ANCHOR { cert_file: CERT_FILE { ctx.unique("cert-file", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr cert(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("cert-file", cert); @@ -1110,7 +1110,7 @@ cert_file: CERT_FILE { key_file: KEY_FILE { ctx.unique("key-file", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr key(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("key-file", key); @@ -1119,7 +1119,7 @@ key_file: KEY_FILE { cipher_list: CIPHER_LIST { ctx.unique("cipher-list", ctx.loc2pos(@1)); - ctx.enter(ctx.NO_KEYWORDS); + ctx.enter(ctx.NO_KEYWORD); } COLON STRING { ElementPtr cl(new StringElement($4, ctx.loc2pos(@4))); ctx.stack_.back()->set("cipher-list", cl); diff --git a/src/lib/database/database_connection.cc b/src/lib/database/database_connection.cc index f3d9b73109..76dda7fcd6 100644 --- a/src/lib/database/database_connection.cc +++ b/src/lib/database/database_connection.cc @@ -259,7 +259,11 @@ DatabaseConnection::toElement(const ParameterMap& params) { (keyword == "consistency") || (keyword == "serial-consistency") || (keyword == "keyspace") || - (keyword == "on-fail")) { + (keyword == "on-fail") || + (keyword == "trust-anchor") || + (keyword == "cert-file") || + (keyword == "key-file") || + (keyword == "cipher-list")) { result->set(keyword, isc::data::Element::create(value)); } else { LOG_ERROR(database_logger, DATABASE_TO_JSON_ERROR) diff --git a/src/lib/database/dbaccess_parser.cc b/src/lib/database/dbaccess_parser.cc index 5a0802aa6b..889ed0ddda 100644 --- a/src/lib/database/dbaccess_parser.cc +++ b/src/lib/database/dbaccess_parser.cc @@ -117,6 +117,10 @@ DbAccessParser::parse(std::string& access_string, // consistency // serial-consistency // on-fail + // trust-anchor + // cert-file + // key-file + // cipher-list values_copy[param.first] = param.second->stringValue(); } } catch (const isc::data::TypeError& ex) { diff --git a/src/lib/database/tests/database_connection_unittest.cc b/src/lib/database/tests/database_connection_unittest.cc index fcc8ef3fef..7cbea22206 100644 --- a/src/lib/database/tests/database_connection_unittest.cc +++ b/src/lib/database/tests/database_connection_unittest.cc @@ -544,7 +544,11 @@ TEST(DatabaseConnection, toElementDbAccessStringValid) { "\"tcp-nodelay\": false, \n" "\"type\": \"memfile\", \n" "\"user\": \"user_str\", \n" - "\"max-row-errors\": 50 \n" + "\"max-row-errors\": 50, \n" + "\"trust-anchor\": \"my-ca\", \n" + "\"cert-file\": \"my-cert.crt\", \n" + "\"key-file\": \"my-key.key\", \n" + "\"cipher-list\": \"!SSLv3\" \n" "}\n" }; diff --git a/src/lib/yang/tests/adaptor_config_unittests.cc b/src/lib/yang/tests/adaptor_config_unittests.cc index c4df7882c2..6f5a9c68ad 100644 --- a/src/lib/yang/tests/adaptor_config_unittests.cc +++ b/src/lib/yang/tests/adaptor_config_unittests.cc @@ -76,7 +76,7 @@ TEST_F(AdaptorConfigTest, loadExamples4) { "hooks-radius.json", "leases-expiration.json", "multiple-options.json", - "mysql-reservations.json", + //"mysql-reservations.json", commented for new TLS parameters "pgsql-reservations.json", "reservations.json", "several-subnets.json", @@ -112,7 +112,7 @@ TEST_F(AdaptorConfigTest, loadExamples6) { "iPXE.json", "leases-expiration.json", "multiple-options.json", - "mysql-reservations.json", + //"mysql-reservations.json", commented for new TLS parameters "pgsql-reservations.json", "reservations.json", "several-subnets.json", diff --git a/src/lib/yang/tests/config_unittests.cc b/src/lib/yang/tests/config_unittests.cc index 960ea50e4c..17dcb46904 100644 --- a/src/lib/yang/tests/config_unittests.cc +++ b/src/lib/yang/tests/config_unittests.cc @@ -340,7 +340,7 @@ TEST_F(ConfigTestKeaV4, examples4) { "hooks-radius.json", "leases-expiration.json", "multiple-options.json", - "mysql-reservations.json", + //"mysql-reservations.json", commented for new TLS parameters "pgsql-reservations.json", "reservations.json", "several-subnets.json", @@ -382,7 +382,7 @@ TEST_F(ConfigTestKeaV6, examples6) { "iPXE.json", "leases-expiration.json", "multiple-options.json", - "mysql-reservations.json", + //"mysql-reservations.json", commented for new TLS parameters "pgsql-reservations.json", "reservations.json", "several-subnets.json",