From c7ee66c3e54b276b219a0ef26e2475bde8a0fc8b Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 22 Jan 2019 16:59:22 -0600 Subject: [PATCH] auth,msg/async/ProtocolV2: negotiate connection modes The modes are: - crc: crc32c checksums to protect against bit errors. No secrecy or authenticity guarantees, so a MITM could alter traffic in flight. - secure: cryptographic secrecy and authenticity proection (i.e, encrypted and signed). We do not include a 'signed' mode that provides authenticity without secrecy because the cryptographic protocols appear to be faster than SHA-2. New settings: - ms_cluster_mode : mode(s list) for intra-cluster connections - ms_service_mode : mode(s list) for daemons to allow - ms_client_mode : mode(s list) for clients to allow Also, - ms_mon_cluster_mode : mon <-> mon connections - ms_mon_service_mode : mon <-> daemon or client connections The msgr2 protocol is expanded slightly to negotiate a mode. Client shares it's allowed/preferred modes, and server picks one as auth finishes. Negotiation is independent of the authentication, except that the authentiction mode may precluse certain choices. Specifically, AUTH_NONE does not support 'secure', only 'crc'. Signed-off-by: Sage Weil --- doc/dev/msgr2.rst | 10 ++- src/auth/Auth.h | 23 +++---- src/auth/AuthClient.h | 8 ++- src/auth/AuthRegistry.cc | 127 ++++++++++++++++++++++++++++++++---- src/auth/AuthRegistry.h | 23 +++++-- src/auth/AuthServer.h | 11 +++- src/common/options.cc | 34 ++++++++++ src/include/ceph_fs.h | 5 ++ src/mon/MonClient.cc | 25 +++++-- src/mon/MonClient.h | 12 +++- src/mon/Monitor.cc | 13 +++- src/mon/Monitor.h | 8 ++- src/msg/async/ProtocolV2.cc | 114 ++++++++++++++++++++++---------- src/msg/async/ProtocolV2.h | 1 + 14 files changed, 328 insertions(+), 86 deletions(-) diff --git a/doc/dev/msgr2.rst b/doc/dev/msgr2.rst index b71e0d0593f..7cbfe8acefa 100644 --- a/doc/dev/msgr2.rst +++ b/doc/dev/msgr2.rst @@ -108,6 +108,8 @@ Authentication * TAG_AUTH_REQUEST: client->server:: __le32 method; // CEPH_AUTH_{NONE, CEPHX, ...} + __le32 num_preferred_modes; + list<__le32> mode // CEPH_CON_MODE_* method specific payload * TAG_AUTH_BAD_METHOD server -> client: reject client-selected auth method:: @@ -115,7 +117,9 @@ Authentication __le32 method __le32 negative error result code __le32 num_methods - __le32 allowed_methods[num_methods] // CEPH_AUTH_{NONE, CEPHX, ...} + list<__le32> allowed_methods // CEPH_AUTH_{NONE, CEPHX, ...} + __le32 num_modes + list<__le32> allowed_modes // CEPH_CON_MODE_* - Returns the attempted auth method, and error code (-EOPNOTSUPP if the method is unsupported), and the list of allowed authentication @@ -134,9 +138,11 @@ Authentication * TAG_AUTH_DONE: (server->client):: __le64 global_id + __le32 connection mode // CEPH_CON_MODE_* method specific payload - - The server is the one to decide authentication has completed. + - The server is the one to decide authentication has completed and what + the final connection mode will be. Example of authentication phase interaction when the client uses an diff --git a/src/auth/Auth.h b/src/auth/Auth.h index 465d6d8471a..2716a3ddb40 100644 --- a/src/auth/Auth.h +++ b/src/auth/Auth.h @@ -162,21 +162,16 @@ struct AuthConnectionMeta { int auth_mode = 0; ///< AUTH_MODE_* - enum { - CON_MODE_INTEGRITY, // crc: protect against bit errors - CON_MODE_AUTHENTICITY, // secure hash: protect against MITM - CON_MODE_SECRECY, // encrypted - }; - int con_mode = CON_MODE_INTEGRITY; - - bool is_integrity_mode() { - return con_mode == CON_MODE_INTEGRITY; - } - bool is_authenticity_mode() { - return con_mode == CON_MODE_AUTHENTICITY; + /// server: client's preferred con_modes + std::vector preferred_con_modes; + + int con_mode = 0; ///< negotiated mode + + bool is_mode_crc() { + return con_mode == CEPH_CON_MODE_CRC; } - bool is_secrecy_mode() { - return con_mode == CON_MODE_SECRECY; + bool is_mode_secure() { + return con_mode == CEPH_CON_MODE_SECURE; } CryptoKey session_key; ///< per-ticket key diff --git a/src/auth/AuthClient.h b/src/auth/AuthClient.h index aa11e3c29a5..28eae6decce 100644 --- a/src/auth/AuthClient.h +++ b/src/auth/AuthClient.h @@ -14,7 +14,9 @@ public: virtual int get_auth_request( Connection *con, - uint32_t *method, bufferlist *out) = 0; + uint32_t *method, + std::vector *preferred_modes, + bufferlist *out) = 0; virtual int handle_auth_reply_more( Connection *con, const bufferlist& bl, @@ -22,6 +24,7 @@ public: virtual int handle_auth_done( Connection *con, uint64_t global_id, + uint32_t con_mode, const bufferlist& bl, CryptoKey *session_key, CryptoKey *connection_key) = 0; @@ -29,5 +32,6 @@ public: Connection *con, uint32_t old_auth_method, int result, - const std::vector& allowed_methods) = 0; + const std::vector& allowed_methods, + const std::vector& allowed_modes) = 0; }; diff --git a/src/auth/AuthRegistry.cc b/src/auth/AuthRegistry.cc index 0f2752cf55c..a6be5e7b411 100644 --- a/src/auth/AuthRegistry.cc +++ b/src/auth/AuthRegistry.cc @@ -67,6 +67,33 @@ void AuthRegistry::_parse_method_list(const string& s, ldout(cct,20) << __func__ << " " << s << " -> " << *v << dendl; } +void AuthRegistry::_parse_mode_list(const string& s, + std::vector *v) +{ + std::list sup_list; + get_str_list(s, sup_list); + if (sup_list.empty()) { + lderr(cct) << "WARNING: empty auth protocol list" << dendl; + } + for (auto& i : sup_list) { + ldout(cct, 5) << "adding con mode: " << i << dendl; + if (i == "crc") { + v->push_back(CEPH_CON_MODE_CRC); + } else if (i == "secure") { + v->push_back(CEPH_CON_MODE_SECURE); + } else { + v->push_back(CEPH_CON_MODE_UNKNOWN); + lderr(cct) << "WARNING: unknown connection mode " << i << dendl; + } + } + if (v->empty()) { + lderr(cct) << "WARNING: no connection modes defined, use 'crc' by default" + << dendl; + v->push_back(CEPH_CON_MODE_CRC); + } + ldout(cct,20) << __func__ << " " << s << " -> " << *v << dendl; +} + void AuthRegistry::_refresh_config() { if (cct->_conf->auth_supported.size()) { @@ -78,6 +105,16 @@ void AuthRegistry::_refresh_config() _parse_method_list(cct->_conf->auth_service_required, &service_methods); _parse_method_list(cct->_conf->auth_client_required, &client_methods); } + _parse_mode_list(cct->_conf.get_val("ms_mon_cluster_mode"), + &mon_cluster_modes); + _parse_mode_list(cct->_conf.get_val("ms_mon_service_mode"), + &mon_service_modes); + _parse_mode_list(cct->_conf.get_val("ms_cluster_mode"), + &cluster_modes); + _parse_mode_list(cct->_conf.get_val("ms_service_mode"), + &service_modes); + _parse_mode_list(cct->_conf.get_val("ms_client_mode"), + &client_modes); ldout(cct,10) << __func__ << " cluster_methods " << cluster_methods << " service_methods " << service_methods @@ -103,23 +140,68 @@ void AuthRegistry::_refresh_config() } } -void AuthRegistry::get_supported_methods(int peer_type, - std::vector *v) +void AuthRegistry::get_supported_methods( + int peer_type, + std::vector *methods, + std::vector *modes) { - if (cct->get_module_type() == CEPH_ENTITY_TYPE_CLIENT) { - *v = client_methods; + switch (cct->get_module_type()) { + case CEPH_ENTITY_TYPE_CLIENT: + // i am client + if (methods) { + *methods = client_methods; + } + if (modes) { + *modes = client_modes; + } return; - } - switch (peer_type) { case CEPH_ENTITY_TYPE_MON: - case CEPH_ENTITY_TYPE_MGR: - case CEPH_ENTITY_TYPE_MDS: - case CEPH_ENTITY_TYPE_OSD: - *v = cluster_methods; - break; + // i am mon + switch (peer_type) { + case CEPH_ENTITY_TYPE_MON: + // they are mon + if (methods) { + *methods = cluster_methods; + } + if (modes) { + *modes = mon_cluster_modes; + } + break; + default: + // they are anything but mons + if (methods) { + *methods = service_methods; + } + if (modes) { + *modes = mon_service_modes; + } + } + return; default: - *v = service_methods; - break; + // i am a non-mon daemon + switch (peer_type) { + case CEPH_ENTITY_TYPE_MON: + case CEPH_ENTITY_TYPE_MGR: + case CEPH_ENTITY_TYPE_MDS: + case CEPH_ENTITY_TYPE_OSD: + // they are another daemon + if (methods) { + *methods = cluster_methods; + } + if (modes) { + *modes = cluster_modes; + } + break; + default: + // they are a client + if (methods) { + *methods = service_methods; + } + if (modes) { + *modes = service_modes; + } + break; + } } } @@ -137,6 +219,25 @@ bool AuthRegistry::any_supported_methods(int peer_type) return !s.empty(); } +void AuthRegistry::get_supported_modes( + int peer_type, + uint32_t auth_method, + std::vector *modes) +{ + std::vector s; + get_supported_methods(peer_type, nullptr, &s); + if (auth_method == CEPH_AUTH_NONE) { + // filter out all but crc for AUTH_NONE + for (auto mode : s) { + if (mode == CEPH_CON_MODE_CRC) { + modes->push_back(mode); + } + } + } else { + *modes = s; + } +} + AuthAuthorizeHandler *AuthRegistry::get_handler(int peer_type, int method) { std::scoped_lock l{lock}; diff --git a/src/auth/AuthRegistry.h b/src/auth/AuthRegistry.h index 190b615592c..5474355110d 100644 --- a/src/auth/AuthRegistry.h +++ b/src/auth/AuthRegistry.h @@ -20,11 +20,20 @@ class AuthRegistry : public md_config_obs_t { bool _no_keyring_disabled_cephx = false; - std::vector cluster_methods; // CEPH_AUTH_* - std::vector service_methods; // CEPH_AUTH_* - std::vector client_methods; // CEPH_AUTH_* + // CEPH_AUTH_* + std::vector cluster_methods; + std::vector service_methods; + std::vector client_methods; + + // CEPH_CON_MODE_* + std::vector mon_cluster_modes; + std::vector mon_service_modes; + std::vector cluster_modes; + std::vector service_modes; + std::vector client_modes; void _parse_method_list(const string& str, std::vector *v); + void _parse_mode_list(const string& str, std::vector *v); void _refresh_config(); public: @@ -37,10 +46,16 @@ public: _refresh_config(); } - void get_supported_methods(int peer_type, std::vector *v); + void get_supported_methods(int peer_type, + std::vector *methods, + std::vector *modes=nullptr); bool is_supported_method(int peer_type, int method); bool any_supported_methods(int peer_type); + void get_supported_modes(int peer_type, + uint32_t auth_method, + std::vector *modes); + AuthAuthorizeHandler *get_handler(int peer_type, int method); const char** get_tracked_conf_keys() const override; diff --git a/src/auth/AuthServer.h b/src/auth/AuthServer.h index d80c1b0d811..a762dfb2110 100644 --- a/src/auth/AuthServer.h +++ b/src/auth/AuthServer.h @@ -19,8 +19,15 @@ public: virtual void get_supported_auth_methods( int peer_type, - std::vector *methods) { - auth_registry.get_supported_methods(peer_type, methods); + std::vector *methods, + std::vector *modes = nullptr) { + auth_registry.get_supported_methods(peer_type, methods, modes); + } + virtual void get_supported_con_modes( + int peer_type, + uint32_t auth_method, + std::vector *modes) { + auth_registry.get_supported_modes(peer_type, auth_method, modes); } AuthAuthorizeHandler *get_auth_authorize_handler( diff --git a/src/common/options.cc b/src/common/options.cc index 8b3ef4d38e1..1449abf9d51 100644 --- a/src/common/options.cc +++ b/src/common/options.cc @@ -840,6 +840,40 @@ std::vector