From 354bcbcc17b5d458850709da05f6379202c03c57 Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Fri, 21 Mar 2025 12:56:06 -0400 Subject: [PATCH] mon/AuthMonitor: add key-type switch So it's possible to test with various key-types. Signed-off-by: Patrick Donnelly (cherry picked from commit e8ce247d9267d2a453865c4b3d9692852d979b2a) --- src/auth/Crypto.cc | 9 ++++ src/auth/Crypto.h | 1 + src/common/options/mon.yaml.in | 16 +++++++ src/mon/AuthMonitor.cc | 76 +++++++++++++++++++++++++++------- src/mon/AuthMonitor.h | 19 +++++---- src/mon/MonCommands.h | 45 +++++++++++++------- src/mon/Monitor.cc | 2 +- src/tools/ceph_authtool.cc | 2 +- 8 files changed, 130 insertions(+), 40 deletions(-) diff --git a/src/auth/Crypto.cc b/src/auth/Crypto.cc index d77ceef2fda..8ef4f5ae1f1 100644 --- a/src/auth/Crypto.cc +++ b/src/auth/Crypto.cc @@ -1137,6 +1137,9 @@ int CryptoManager::get_key_type(const std::string& s) { auto l = s; std::transform(l.begin(), l.end(), l.begin(), ::tolower); + if (l == "recommended") { + return CEPH_CRYPTO_AES256KRB5; + } if (l == "aes") { return CEPH_CRYPTO_AES; } @@ -1149,6 +1152,12 @@ int CryptoManager::get_key_type(const std::string& s) return -ENOENT; } +const std::set& CryptoManager::get_secure_key_types() +{ + static const std::set secure_keys{CEPH_CRYPTO_AES256KRB5}; + return secure_keys; +} + bool CryptoManager::crypto_type_supported(int type) const { return supported_crypto_types.find(type) != supported_crypto_types.end(); diff --git a/src/auth/Crypto.h b/src/auth/Crypto.h index b9fbe0a26a5..d3b39a4382c 100644 --- a/src/auth/Crypto.h +++ b/src/auth/Crypto.h @@ -275,6 +275,7 @@ public: } static int get_key_type(const std::string& s); + static const std::set& get_secure_key_types(); bool crypto_type_supported(int type) const; std::shared_ptr get_handler(int type); diff --git a/src/common/options/mon.yaml.in b/src/common/options/mon.yaml.in index b6b7def1918..4384757078d 100644 --- a/src/common/options/mon.yaml.in +++ b/src/common/options/mon.yaml.in @@ -755,6 +755,22 @@ options: services: - mon with_legacy: true +- name: mon_auth_allow_insecure_key + type: bool + level: advanced + desc: Allow the creation of keys with insecure type. + long_desc: > + By default, the Monitors will allow creation of keys with a cipher type + known to be insecure so long as the Monitors also allow that cipher to + authenticate. When that cipher type is removed from the authentication + list, the Monitors will also disable the default value of this + configuration. When disabled, ceph commands can no longer create keys with + an insecure cipher type. + default: false + services: + - mon + flags: + - runtime - name: mon_auth_validate_all_caps type: bool level: advanced diff --git a/src/mon/AuthMonitor.cc b/src/mon/AuthMonitor.cc index bbf32a7c83f..d34681c0c9d 100644 --- a/src/mon/AuthMonitor.cc +++ b/src/mon/AuthMonitor.cc @@ -30,6 +30,7 @@ #include "auth/AuthServiceHandler.h" #include "auth/KeyRing.h" +#include "auth/Crypto.h" #include "include/stringify.h" #include "include/ceph_assert.h" @@ -37,6 +38,11 @@ #include "mgr/MgrCap.h" #include "osd/OSDCap.h" +#include +#include +using namespace std::literals::string_view_literals; +using namespace std::literals::string_literals; + #define dout_subsys ceph_subsys_mon #undef dout_prefix #define dout_prefix _prefix(_dout, mon, get_last_committed()) @@ -1358,6 +1364,22 @@ bool AuthMonitor::valid_caps(const map& caps, ostream *out) return true; } +int AuthMonitor::get_cipher_type(const cmdmap_t& cmdmap, std::ostream& ss) const +{ + std::string key_string_type; + cmd_getval_or(cmdmap, "key_type"sv, key_string_type, "recommended"s); + auto key_type = CryptoManager::get_key_type(key_string_type); + auto&& secure_key_types = CryptoManager::get_secure_key_types(); + if (!secure_key_types.contains(key_type)) { + if (!cct->_conf.get_val("mon_auth_allow_insecure_key")) { + ss << "creating key with insecure key type (\"" << key_string_type << "\") not allowed"; + return -EPERM; + } + } + return key_type; +} + + bool AuthMonitor::prepare_command(MonOpRequestRef op) { auto m = op->get_req(); @@ -1451,6 +1473,11 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) bufferlist bl = m->get_data(); bool has_keyring = (bl.length() > 0); + int key_type = get_cipher_type(cmdmap, ss); + if (key_type < 0) { + goto done; + } + KeyRing new_keyring; if (has_keyring) { auto iter = bl.cbegin(); @@ -1513,7 +1540,7 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) if (!has_keyring) { dout(10) << "AuthMonitor::prepare_command generating random key for " << auth_inc.name << dendl; - new_inc.key.create(g_ceph_context, CEPH_CRYPTO_AES256KRB5); + new_inc.key.create(g_ceph_context, key_type); } new_inc.caps = encoded_caps; @@ -1541,6 +1568,11 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) goto done; } + int key_type = get_cipher_type(cmdmap, ss); + if (key_type < 0) { + goto done; + } + // is there an uncommitted pending_key? (or any change for this entity) for (auto& p : pending_auth) { if (p.inc_type == AUTH_DATA) { @@ -1568,7 +1600,7 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.name = entity; auth_inc.auth = entity_auth; - auth_inc.auth.pending_key.create(g_ceph_context, CEPH_CRYPTO_AES256KRB5); + auth_inc.auth.pending_key.create(g_ceph_context, key_type); push_cephx_inc(auth_inc); kr.add(entity, auth_inc.auth.key, auth_inc.auth.pending_key); push_cephx_inc(auth_inc); @@ -1619,6 +1651,11 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) goto done; } + int key_type = get_cipher_type(cmdmap, ss); + if (key_type < 0) { + goto done; + } + // do we have it? EntityAuth entity_auth; if (mon.key_server.get_auth(entity, entity_auth)) { @@ -1667,7 +1704,7 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) KeyServerData::Incremental auth_inc; auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.name = entity; - auth_inc.auth.key.create(g_ceph_context, CEPH_CRYPTO_AES256KRB5); + auth_inc.auth.key.create(g_ceph_context, key_type); auth_inc.auth.caps = wanted_caps; push_cephx_inc(auth_inc); @@ -1695,6 +1732,11 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) string mds_cap_string, osd_cap_string; string osd_cap_wanted = "r"; + int key_type = get_cipher_type(cmdmap, ss); + if (key_type < 0) { + goto done; + } + const Filesystem* fs = nullptr; if (filesystem != "*" && filesystem != "all") { const auto& fsmap = mon.mdsmon()->get_fsmap(); @@ -1791,7 +1833,7 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) dout(20) << it.first << " cap = \"" << it.second << "\"" << dendl; } - err = _update_caps(entity, newcaps, op, ss, ds, &rdata, f.get()); + err = _update_caps(entity, key_type, newcaps, op, ss, ds, &rdata, f.get()); if (err == 0) { return true; } else { @@ -1799,14 +1841,14 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) } } - err = _create_entity(entity, newcaps, op, ss, ds, &rdata, f.get()); + err = _create_entity(entity, key_type, newcaps, op, ss, ds, &rdata, f.get()); if (err == 0) { return true; } else { goto done; } } else if (prefix == "auth caps" && !entity_name.empty()) { - err = _update_caps(entity, ceph_caps, op, ss, ds, &rdata, f.get()); + err = _update_caps(entity, CEPH_CRYPTO_AES256KRB5, ceph_caps, op, ss, ds, &rdata, f.get()); if (err == 0) { return true; } else { @@ -1833,6 +1875,11 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) goto done; } + int key_type = get_cipher_type(cmdmap, ss); + if (key_type < 0) { + goto done; + } + EntityAuth entity_auth; if (!mon.key_server.get_auth(entity, entity_auth)) { ss << "entity does not exist"; @@ -1840,7 +1887,7 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) goto done; } - entity_auth.key.create(g_ceph_context, CEPH_CRYPTO_AES256KRB5); + entity_auth.key.create(g_ceph_context, key_type); KeyServerData::Incremental auth_inc; auth_inc.op = KeyServerData::AUTH_INC_ADD; @@ -2011,6 +2058,7 @@ int AuthMonitor::_check_and_encode_caps(const map& caps, // Pass both, rdata as well as fmtr, to enable printing of the key after // update int AuthMonitor::_update_or_create_entity(const EntityName& entity, + int key_type, const map& caps, MonOpRequestRef op, stringstream& ss, stringstream& ds, bufferlist* rdata, Formatter* fmtr, bool create_entity) { @@ -2039,7 +2087,7 @@ int AuthMonitor::_update_or_create_entity(const EntityName& entity, auth_inc.op = KeyServerData::AUTH_INC_ADD; auth_inc.auth.caps = encoded_caps; if (create_entity) { - auth_inc.auth.key.create(g_ceph_context, CEPH_CRYPTO_AES256KRB5); + auth_inc.auth.key.create(g_ceph_context, key_type); } push_cephx_inc(auth_inc); @@ -2060,20 +2108,20 @@ int AuthMonitor::_update_or_create_entity(const EntityName& entity, return 0; } -int AuthMonitor::_update_caps(const EntityName& entity, +int AuthMonitor::_update_caps(const EntityName& entity, int key_type, const map& caps, MonOpRequestRef op, stringstream& ss, stringstream& ds, bufferlist* rdata, Formatter* fmtr) { - return _update_or_create_entity(entity, caps, op, ss, ds, rdata, fmtr, - false); + return _update_or_create_entity(entity, key_type, caps, op, ss, + ds, rdata, fmtr, false); } -int AuthMonitor::_create_entity(const EntityName& entity, +int AuthMonitor::_create_entity(const EntityName& entity, int key_type, const map& caps, MonOpRequestRef op, stringstream& ss, stringstream& ds, bufferlist* rdata, Formatter* fmtr) { - return _update_or_create_entity(entity, caps, op, ss, ds, rdata, fmtr, - true); + return _update_or_create_entity(entity, key_type, caps, op, ss, + ds, rdata, fmtr, true); } bool AuthMonitor::prepare_global_id(MonOpRequestRef op) diff --git a/src/mon/AuthMonitor.h b/src/mon/AuthMonitor.h index 0495e20c479..7134612615d 100644 --- a/src/mon/AuthMonitor.h +++ b/src/mon/AuthMonitor.h @@ -102,8 +102,9 @@ public: private: std::vector pending_auth; - uint64_t max_global_id; - uint64_t last_allocated_id; + uint64_t max_global_id = 0; + uint64_t last_allocated_id = 0; + boost::intrusive_ptr cct; // these are protected by mon->auth_lock int mon_num = 0, mon_rank = 0; @@ -174,6 +175,8 @@ private: bool prep_auth(MonOpRequestRef op, bool paxos_writable); bool preprocess_command(MonOpRequestRef op); + + int get_cipher_type(const cmdmap_t& cmdmap, std::ostream& ss) const; bool prepare_command(MonOpRequestRef op); void _encode_keyring(KeyRing& kr, const EntityName& entity, @@ -189,15 +192,15 @@ private: int _check_and_encode_caps(const std::map& caps, std::map& encoded_caps, std::stringstream& ss); - int _update_or_create_entity(const EntityName& entity, + int _update_or_create_entity(const EntityName& entity, int key_type, const std::map& caps, MonOpRequestRef op, std::stringstream& ss, std::stringstream& ds, bufferlist* rdata=nullptr, Formatter* fmtr=nullptr, bool create_entity=false); - int _create_entity(const EntityName& entity, + int _create_entity(const EntityName& entity, int key_type, const std::map& caps, MonOpRequestRef op, std::stringstream& ss, std::stringstream& ds, bufferlist* rdata, Formatter* fmtr); - int _update_caps(const EntityName& entity, + int _update_caps(const EntityName& entity, int key_type, const std::map& caps, MonOpRequestRef op, std::stringstream& ss, std::stringstream& ds, bufferlist* rdata, Formatter* fmtr); @@ -229,10 +232,8 @@ private: const EntityAuth& auth); public: - AuthMonitor(Monitor &mn, Paxos &p, const std::string& service_name) - : PaxosService(mn, p, service_name), - max_global_id(0), - last_allocated_id(0) + AuthMonitor(CephContext* cct, Monitor &mn, Paxos &p, const std::string& service_name) + : PaxosService(mn, p, service_name), cct(cct) {} void pre_auth(MAuth *m); diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 2c0ab671efd..0892c6a1503 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -157,24 +157,36 @@ COMMAND_WITH_FLAG("auth list", "list authentication state", "auth", "rx", COMMAND("auth ls", "list authentication state", "auth", "rx") COMMAND("auth import", "auth import: read keyring file from -i ", "auth", "rwx") -COMMAND("auth add " - "name=entity,type=CephString " - "name=caps,type=CephString,n=N,req=false", +COMMAND("auth add" + " name=entity,type=CephString" + " name=caps,type=CephString,n=N,req=false" + " --" + " name=key_type,type=CephString,req=false" + , "add auth info for from input file, or random key if no " "input is given, and/or any caps specified in the command", "auth", "rwx") -COMMAND("auth rotate " - "name=entity,type=CephString", +COMMAND("auth rotate" + " name=entity,type=CephString" + " --" + " name=key_type,type=CephString,req=false" + , "rotate entity key", "auth", "rwx") -COMMAND("auth get-or-create-key " - "name=entity,type=CephString " - "name=caps,type=CephString,n=N,req=false", +COMMAND("auth get-or-create-key" + " name=entity,type=CephString" + " name=caps,type=CephString,n=N,req=false" + " --" + " name=key_type,type=CephString,req=false" + , "get, or add, key for from system/caps pairs specified in the command. If key already exists, any given caps must match the existing caps for that key.", "auth", "rwx") -COMMAND("auth get-or-create " - "name=entity,type=CephString " - "name=caps,type=CephString,n=N,req=false", +COMMAND("auth get-or-create" + " name=entity,type=CephString" + " name=caps,type=CephString,n=N,req=false" + " --" + " name=key_type,type=CephString,req=false" + , "add auth info for from input file, or random key if no input given, and/or any caps specified in the command", "auth", "rwx") COMMAND("auth get-or-create-pending " @@ -189,10 +201,13 @@ COMMAND("auth commit-pending " "name=entity,type=CephString", "rotate pending key into active position", "auth", "rwx") -COMMAND("fs authorize " - "name=filesystem,type=CephString " - "name=entity,type=CephString " - "name=caps,type=CephString,n=N", +COMMAND("fs authorize" + " name=filesystem,type=CephString" + " name=entity,type=CephString" + " name=caps,type=CephString,n=N" + " --" + " name=key_type,type=CephString,req=false" + , "add auth for to access file system based on following directory and permissions pairs", "auth", "rwx") COMMAND("auth caps " diff --git a/src/mon/Monitor.cc b/src/mon/Monitor.cc index f6495c7535f..2a940044012 100644 --- a/src/mon/Monitor.cc +++ b/src/mon/Monitor.cc @@ -241,7 +241,7 @@ Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s, paxos_service[PAXOS_MONMAP].reset(new MonmapMonitor(*this, *paxos, "monmap")); paxos_service[PAXOS_OSDMAP].reset(new OSDMonitor(cct, *this, *paxos, "osdmap")); paxos_service[PAXOS_LOG].reset(new LogMonitor(*this, *paxos, "logm")); - paxos_service[PAXOS_AUTH].reset(new AuthMonitor(*this, *paxos, "auth")); + paxos_service[PAXOS_AUTH].reset(new AuthMonitor(cct, *this, *paxos, "auth")); paxos_service[PAXOS_MGR].reset(new MgrMonitor(*this, *paxos, "mgr")); paxos_service[PAXOS_MGRSTAT].reset(new MgrStatMonitor(*this, *paxos, "mgrstat")); paxos_service[PAXOS_HEALTH].reset(new HealthMonitor(*this, *paxos, "health")); diff --git a/src/tools/ceph_authtool.cc b/src/tools/ceph_authtool.cc index dd5bff7e5f1..e53f3afa128 100644 --- a/src/tools/ceph_authtool.cc +++ b/src/tools/ceph_authtool.cc @@ -66,7 +66,7 @@ int main(int argc, const char **argv) map caps; std::string fn; - int key_type = CEPH_CRYPTO_AES256KRB5; + int key_type = CryptoManager::get_key_type("recommended"); if (args.empty()) { cerr << argv[0] << ": -h or --help for usage" << std::endl; -- 2.39.5