From 93ba95701089420c77b4151d363424dc5a04278e Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Tue, 25 Mar 2025 21:59:34 -0400 Subject: [PATCH] mon/AuthMonitor: add dump-keys and wipe-rotating-service-keys `auth dump-keys` allows examining the key types for each entity and also the rotating session keys. This lets us confirm key upgrades are done as expected. `wipe-rotating-service-keys` clears out existing non-auth service keys so that we do not need to wait for the rotating key expiration. It is not disruptive so long as clients renew their tickets when prompted by the auth epoch change. Signed-off-by: Patrick Donnelly --- src/auth/cephx/CephxKeyServer.cc | 16 ++++++++++++++-- src/auth/cephx/CephxKeyServer.h | 2 +- src/mon/AuthMonitor.cc | 28 +++++++++++++++++++++++++++- src/mon/MonCommands.h | 6 ++++++ src/tools/ceph_monstore_tool.cc | 2 +- 5 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/auth/cephx/CephxKeyServer.cc b/src/auth/cephx/CephxKeyServer.cc index c97297fb9b4..2430c291bfe 100644 --- a/src/auth/cephx/CephxKeyServer.cc +++ b/src/auth/cephx/CephxKeyServer.cc @@ -383,7 +383,7 @@ void KeyServer::encode_plaintext(bufferlist &bl) bl.append(os.str()); } -bool KeyServer::prepare_rotating_update(bufferlist& rotating_bl) +bool KeyServer::prepare_rotating_update(bufferlist& rotating_bl, bool wipe) { std::scoped_lock l{lock}; ldout(cct, 20) << __func__ << " before: data.rotating_ver=" << data.rotating_ver @@ -391,7 +391,19 @@ bool KeyServer::prepare_rotating_update(bufferlist& rotating_bl) KeyServerData pending_data(nullptr); pending_data.rotating_ver = data.rotating_ver + 1; - pending_data.rotating_secrets = data.rotating_secrets; + if (wipe) { + /* Always keep CEPH_ENTITY_TYPE_AUTH: existing auth service keys are needed + * to renew tickets by daemons/clients and the only information in an old + * ticket used is the global_id. Forging tickets is not a significant + * concern. A stolen auth service key is not worthwhile since you would + * be incaapable of generating useful service tickets with the associated + * service key (e.g. "osd"). + */ + RotatingSecrets& r = data.rotating_secrets[CEPH_ENTITY_TYPE_AUTH]; + pending_data.rotating_secrets[CEPH_ENTITY_TYPE_AUTH] = r; + } else { + pending_data.rotating_secrets = data.rotating_secrets; + } int added = 0; added += _rotate_secret(CEPH_ENTITY_TYPE_AUTH, pending_data); diff --git a/src/auth/cephx/CephxKeyServer.h b/src/auth/cephx/CephxKeyServer.h index 5fb7608af67..ffb0e58a29b 100644 --- a/src/auth/cephx/CephxKeyServer.h +++ b/src/auth/cephx/CephxKeyServer.h @@ -345,7 +345,7 @@ public: } } - bool prepare_rotating_update(ceph::buffer::list& rotating_bl); + bool prepare_rotating_update(ceph::buffer::list& rotating_bl, bool wipe); bool get_rotating_encrypted(const EntityName& name, ceph::buffer::list& enc_bl) const; diff --git a/src/mon/AuthMonitor.cc b/src/mon/AuthMonitor.cc index d8b3b83f7c7..4ec1a9c3420 100644 --- a/src/mon/AuthMonitor.cc +++ b/src/mon/AuthMonitor.cc @@ -80,7 +80,7 @@ bool AuthMonitor::check_rotate() { KeyServerData::Incremental rot_inc; rot_inc.op = KeyServerData::AUTH_INC_SET_ROTATING; - if (mon.key_server.prepare_rotating_update(rot_inc.rotating_bl)) { + if (mon.key_server.prepare_rotating_update(rot_inc.rotating_bl, false)) { dout(10) << __func__ << " updating rotating" << dendl; push_cephx_inc(rot_inc); return true; @@ -866,6 +866,8 @@ bool AuthMonitor::preprocess_command(MonOpRequestRef op) cmd_getval(cmdmap, "prefix", prefix); if (prefix == "auth add" || prefix == "auth rotate" || + prefix == "auth dump-keys" || + prefix == "auth wipe-rotating-service-keys" || prefix == "auth del" || prefix == "auth rm" || prefix == "auth get-or-create" || @@ -1900,6 +1902,30 @@ bool AuthMonitor::prepare_command(MonOpRequestRef op) wait_for_commit(op, new Monitor::C_Command(mon, op, 0, rs, rdata, get_last_committed() + 1)); return true; + } else if (prefix == "auth dump-keys") { + if (f) { + f->open_object_section("keys"); + mon.key_server.dump(f.get()); + f->close_section(); + f->flush(ds); + err = 0; + } else { + err = -EINVAL; + } + goto done; + } else if (prefix == "auth wipe-rotating-service-keys") { + /* N.B.: doing this requires all service daemons to restart to get new service keys. */ + /* is this true?? */ + KeyServerData::Incremental rot_inc; + rot_inc.op = KeyServerData::AUTH_INC_SET_ROTATING; + bool modified = mon.key_server.prepare_rotating_update(rot_inc.rotating_bl, true); + ceph_assert(modified); + rs = "wiped rotating service keys!"; + dout(5) << __func__ << " wiped rotating service keys!" << dendl; + push_cephx_inc(rot_inc); + wait_for_commit(op, new Monitor::C_Command(mon, op, 0, rs, rdata, + get_last_committed() + 1)); + return true; } done: rdata.append(ds); diff --git a/src/mon/MonCommands.h b/src/mon/MonCommands.h index 17f12e4af7a..6c520d0ff49 100644 --- a/src/mon/MonCommands.h +++ b/src/mon/MonCommands.h @@ -178,6 +178,12 @@ COMMAND("auth rotate" , "rotate entity key", "auth", "rwx") +COMMAND("auth dump-keys", + "dump keys", + "auth", "rwx") +COMMAND("auth wipe-rotating-service-keys", + "wipe rotating keys", + "auth", "rwx") COMMAND("auth get-or-create-key" " name=entity,type=CephString" " name=caps,type=CephString,n=N,req=false" diff --git a/src/tools/ceph_monstore_tool.cc b/src/tools/ceph_monstore_tool.cc index 31ed80882d3..6b372e67b8f 100644 --- a/src/tools/ceph_monstore_tool.cc +++ b/src/tools/ceph_monstore_tool.cc @@ -507,7 +507,7 @@ static int update_auth(MonitorDBStore& st, const string& keyring_path) KeyServer ks(g_ceph_context, nullptr); KeyServerData::Incremental auth_inc; auth_inc.op = KeyServerData::AUTH_INC_SET_ROTATING; - bool r = ks.prepare_rotating_update(auth_inc.rotating_bl); + bool r = ks.prepare_rotating_update(auth_inc.rotating_bl, false); ceph_assert(r); AuthMonitor::Incremental inc; inc.inc_type = AuthMonitor::AUTH_DATA; -- 2.47.3