cluster-conf:
global:
auth service cipher: aes
- cephx preferred cipher: aes
mon:
mon auth allow insecure key: true
cephx:
{
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;
}
#undef dout_prefix
#define dout_prefix *_dout << "cephx keyserver: "
-
+#define cct kscct.get()
KeyServer::KeyServer(CephContext *cct_, KeyRing *extra_secrets)
- : cct(cct_),
+ : kscct(cct_),
data(extra_secrets),
lock{ceph::make_mutex("KeyServer::lock")}
{
}
+
int KeyServer::start_server()
{
std::scoped_lock l{lock};
double const auth_mon_ticket_ttl = cct->_conf.get_val<double>("auth_mon_ticket_ttl");
double const auth_service_ticket_ttl= cct->_conf.get_val<double>("auth_service_ticket_ttl");
- auto const auth_service_cipher = cct->_conf.get_val<string>("auth_service_cipher");
- const int auth_service_cipher_key_type = CryptoManager::get_key_type(auth_service_cipher);
+ auto const auth_service_cipher_key_type = get_service_cipher();
+ auto auth_service_cipher = CryptoManager::get_key_type_name(auth_service_cipher_key_type);
+ //const int auth_service_cipher_key_type = CryptoManager::get_key_type(auth_service_cipher);
ldout(cct, 10) << __func__
<< ": auth_mon_ticket_ttl=" << auth_mon_ticket_ttl
#include <map>
#include <string>
+#include <boost/intrusive_ptr.hpp>
+
#include "auth/KeyRing.h"
#include "CephxProtocol.h"
#include "common/ceph_json.h"
class KeyServer : public KeyStore {
- CephContext *cct;
+ boost::intrusive_ptr<CephContext> kscct;
KeyServerData data;
std::map<EntityName, CryptoKey> used_pending_keys;
mutable ceph::mutex lock;
{ return data.secrets_begin(); }
std::map<EntityName, EntityAuth>::iterator secrets_end()
{ return data.secrets_end(); }
+
+ virtual int get_service_cipher() const {
+ return CEPH_CRYPTO_AES256KRB5;
+ }
+ virtual bool is_cipher_allowed(int cipher) const {
+ return cipher == CEPH_CRYPTO_AES256KRB5;
+ }
+ virtual std::vector<int> get_ciphers_allowed() const {
+ return {CEPH_CRYPTO_AES256KRB5};
+ }
};
WRITE_CLASS_ENCODER(KeyServer)
using ceph::encode;
CephxServiceHandler::CephxServiceHandler(CephContext *cct_, KeyServer *ks)
- : AuthServiceHandler(cct_), key_server(ks), server_challenge(0) {
- cct->_conf.add_observer(this);
- init_conf(cct->_conf);
-}
-
-std::vector<std::string> CephxServiceHandler::get_tracked_keys() const noexcept
+ : AuthServiceHandler(cct_)
+ , key_server(ks)
{
- static constexpr auto as_sv = std::to_array<std::string_view>({
- "cephx_allowed_ciphers",
- });
- static_assert(std::is_sorted(as_sv.begin(), as_sv.end()), "keys are not sorted!");
- return {as_sv.begin(), as_sv.end()};
-}
-
-void CephxServiceHandler::init_conf(const ConfigProxy& conf) {
- std::unique_lock wl(lock);
- auto s = conf.get_val<std::string>("cephx_allowed_ciphers");
-
- std::vector<std::string> v;
- get_str_vec(s, ", ", v);
-
- for (auto& cipher : v) {
- int cipher_type = CryptoManager::get_key_type(cipher);
- if (cipher_type > 0) {
- allowed_ciphers.insert(cipher_type);
- }
- }
}
bool CephxServiceHandler::cipher_is_allowed(int cipher)
{
std::shared_lock rl(lock);
- return (allowed_ciphers.find(cipher) != allowed_ciphers.end());
+ return key_server->is_cipher_allowed(cipher);
}
int CephxServiceHandler::do_start_session(
}
if (!cipher_is_allowed(eauth.key.get_type())) {
- ldout(cct, 20) << __func__ << " authentication failed due to unallowed cipher type: " << eauth.key.get_type() << dendl;
+ ldout(cct, 20) << __func__
+ << " authentication failed due to unallowed cipher type: "
+ << CryptoManager::get_key_type_name(eauth.key.get_type()) << dendl;
+ ldout(cct, 30);
+ std::shared_lock rl(lock);
+ auto ciphers = key_server->get_ciphers_allowed();
+ dout_prefix << __func__
+ << ": ciphers are:";
+ for (auto& cipher : ciphers) {
+ dout_prefix << " " << CryptoManager::get_key_type_name(cipher);
+ }
+ dout_prefix << dendl;
ret = -EACCES;
break;
}
#include "auth/Auth.h"
#include "common/ceph_mutex.h"
-#include "common/config_obs.h"
class KeyServer;
struct CephXAuthenticate;
struct CephXServiceTicketInfo;
-class CephxServiceHandler : public AuthServiceHandler, md_config_obs_t {
+class CephxServiceHandler : public AuthServiceHandler {
KeyServer *key_server;
- uint64_t server_challenge;
+ uint64_t server_challenge = 0;
- std::set<int> allowed_ciphers;
ceph::shared_mutex lock = ceph::make_shared_mutex("CephxServiceHandler::lock");
public:
void build_cephx_response_header(int request_type, int status,
ceph::buffer::list& bl);
- std::vector<std::string> get_tracked_keys() const noexcept final;
-
- void init_conf(const ConfigProxy& conf);
- void handle_conf_change(const ConfigProxy& conf,
- const std::set <std::string> &changed) override {
- init_conf(conf);
- }
-
bool cipher_is_allowed(int type);
};
Ceph services. Valid settings are ``cephx`` or ``none``.
default: cephx
with_legacy: true
-- name: auth_service_cipher
- type: str
- level: advanced
- desc: cipher type that is used to encrypt service tickets.
- fmt_desc: When service tickets are being generaeted, this would
- be the cipher that will be used to encrypt them. This requires
- that all the services support the specific cipher. Valid settings
- are ``aes` or ``aes256k``.
- default: aes
- services:
- - mon
- enum_values:
- - aes
- - aes256k
- with_legacy: false
- flags:
- - runtime
# what clients require of daemons
- name: auth_client_required
type: str
fmt_desc: If the Ceph version supports message signing, Ceph will sign
all messages so they are more difficult to spoof.
with_legacy: true
-- name: cephx_preferred_cipher
- type: str
- level: dev
- desc: preferred cipher to use for new authentication keys
- default: recommended
- flags:
- - runtime
-- name: cephx_allowed_ciphers
- type: str
- level: advanced
- desc: list of allowed ciphers in cephx authentication
- fmt_desc: This can be used to enable/disable specific key types
- that are being used for connecting different entities to the
- cluster.
- default: aes, aes256k
- with_legacy: false
- flags:
- - runtime
- name: auth_mon_ticket_ttl
type: float
level: advanced
{
KeyServerData::Incremental rot_inc;
rot_inc.op = KeyServerData::AUTH_INC_SET_ROTATING;
- if (mon.key_server.prepare_rotating_update(rot_inc.rotating_bl, false)) {
+ if (mon.prepare_rotating_update(rot_inc.rotating_bl, false)) {
dout(10) << __func__ << " updating rotating" << dendl;
push_cephx_inc(rot_inc);
return true;
inc.op = KeyServerData::AUTH_INC_ADD;
inc.name = name;
- mon.key_server.get_auth(name, inc.auth);
+ mon.get_auth(name, inc.auth);
for (auto& p : pending_auth) {
if (p.inc_type == AUTH_DATA) {
KeyServerData::Incremental auth_inc;
}
if (mon.monmap->min_mon_release >= ceph_release_t::quincy) {
- auto used_pending_keys = mon.key_server.get_used_pending_keys();
+ auto used_pending_keys = mon.get_used_pending_keys();
if (!used_pending_keys.empty()) {
dout(10) << __func__ << " " << used_pending_keys.size() << " used pending_keys"
<< dendl;
if (!mon.is_leader())
return;
- mon.key_server.start_server();
- mon.key_server.clear_used_pending_keys();
+ mon.start_server();
+ mon.clear_used_pending_keys();
if (is_writeable()) {
bool propose = false;
dout(10) << "create_initial -- creating initial map" << dendl;
// initialize rotating keys
- mon.key_server.clear_secrets();
+ mon.clear_secrets();
check_rotate();
ceph_assert(pending_auth.size() == 1);
dout(10) << __func__ << dendl;
version_t version = get_last_committed();
- version_t keys_ver = mon.key_server.get_ver();
+ version_t keys_ver = mon.get_ver();
if (version == keys_ver)
return;
ceph_assert(version > keys_ver);
__u8 struct_v;
decode(struct_v, p);
decode(max_global_id, p);
- decode(mon.key_server, p);
- mon.key_server.set_ver(latest_full);
+ decode(mon, p);
+ mon.set_ver(latest_full);
keys_ver = latest_full;
}
- dout(10) << __func__ << " key server version " << mon.key_server.get_ver() << dendl;
+ dout(10) << __func__ << " key server version " << mon.get_ver() << dendl;
// walk through incrementals
while (version > keys_ver) {
// keys in here temporarily for bootstrapping that we need to
// clear out.
if (keys_ver == 0)
- mon.key_server.clear_secrets();
+ mon.clear_secrets();
dout(20) << __func__ << " walking through version " << (keys_ver+1)
<< " len " << bl.length() << dendl;
KeyServerData::Incremental auth_inc;
auto iter = inc.auth_data.cbegin();
decode(auth_inc, iter);
- mon.key_server.apply_data_incremental(auth_inc);
+ mon.apply_data_incremental(auth_inc);
break;
}
}
}
keys_ver++;
- mon.key_server.set_ver(keys_ver);
+ mon.set_ver(keys_ver);
if (keys_ver == 1 && mon.is_keyring_required()) {
auto t(std::make_shared<MonitorDBStore::Transaction>());
<< " format_version " << format_version
<< dendl;
- mon.key_server.dump();
+ mon.dump();
}
bool AuthMonitor::_should_increase_max_global_id()
auto const& secure_key_types = CryptoManager::get_secure_key_types();
{
- auto allowed_ciphers = cct->_conf.get_val<std::string>("cephx_allowed_ciphers");
+ auto allowed_ciphers = mon.monmap->auth_allowed_ciphers;
std::vector<std::string> details;
for (auto& c : allowed_ciphers) {
if (!secure_key_types.contains(c)) {
}
{
- auto service_key_type_name = cct->_conf.get_val<std::string>("auth_service_cipher");
- auto service_key_type = CryptoManager::get_key_type(service_key_type_name);
+ auto service_key_type = mon.monmap->auth_service_cipher;
if (!secure_key_types.contains(service_key_type)) {
next.add("AUTH_INSECURE_SERVICE_TICKETS", HEALTH_WARN, "Monitors are configured to issue insecure service key types", 1);
}
std::map<std::string,std::list<std::string>> bad_caps_detail; // entity -> details
std::map<EntityName, std::string> bad_key_client_detail;
std::map<EntityName, std::string> bad_key_service_detail;
- for (auto const& [entity, auth] : mon.key_server.get_secrets()) {
+ for (auto const& [entity, auth] : mon.get_secrets()) {
for (auto& p : auth.caps) {
ostringstream ss;
if (!valid_caps(p.first, p.second, &ss)) {
}
std::vector<std::string> bad_rotating_service_keys;
- for (auto const& [entity_type, secrets] : mon.key_server.get_rotating_secrets()) {
+ for (auto const& [entity_type, secrets] : mon.get_rotating_secrets()) {
auto entity_name = EntityName::ceph_entity_type_to_str(entity_type);
dout(20) << __func__ << ": examining " << entity_name << " for insecure rotating keys" << dendl;
if (entity_type == CEPH_ENTITY_TYPE_AUTH) {
void AuthMonitor::encode_full(MonitorDBStore::TransactionRef t)
{
- version_t version = mon.key_server.get_ver();
+ version_t version = mon.get_ver();
// do not stash full version 0 as it will never be removed nor read
if (version == 0)
return;
ceph_assert(get_last_committed() == version);
bufferlist full_bl;
- std::scoped_lock l{mon.key_server.get_lock()};
+ std::scoped_lock l{mon.get_lock()};
dout(20) << __func__ << " key server has "
- << (mon.key_server.has_secrets() ? "" : "no ")
+ << (mon.has_secrets() ? "" : "no ")
<< "secrets!" << dendl;
__u8 v = 1;
encode(v, full_bl);
encode(max_global_id, full_bl);
- encode(mon.key_server, full_bl);
+ encode(mon, full_bl);
put_version_full(t, version, full_bl);
put_version_latest_full(t, version);
else
type = mon.auth_service_required.pick(supported);
- s->auth_handler = get_auth_service_handler(type, g_ceph_context, &mon.key_server);
+ s->auth_handler = get_auth_service_handler(type, g_ceph_context, &mon);
if (!s->auth_handler) {
dout(1) << "client did not provide supported auth type" << dendl;
ret = -ENOTSUP;
}
} else if (prefix == "auth get" && !entity_name.empty()) {
EntityAuth entity_auth;
- if (!mon.key_server.get_auth(entity, entity_auth)) {
+ if (!mon.get_auth(entity, entity_auth)) {
ss << "failed to find " << entity_name << " in keyring";
r = -ENOENT;
} else {
prefix == "auth print_key" ||
prefix == "auth get-key") {
EntityAuth auth;
- if (!mon.key_server.get_auth(entity, auth)) {
+ if (!mon.get_auth(entity, auth)) {
ss << "don't have " << entity;
r = -ENOENT;
goto done;
} else if (prefix == "auth list" ||
prefix == "auth ls") {
if (f) {
- mon.key_server.encode_formatted("auth", f.get(), rdata);
+ mon.encode_formatted("auth", f.get(), rdata);
} else {
- mon.key_server.encode_plaintext(rdata);
+ mon.encode_plaintext(rdata);
}
r = 0;
goto done;
void AuthMonitor::export_keyring(KeyRing& keyring)
{
- mon.key_server.export_keyring(keyring);
+ mon.export_keyring(keyring);
}
int AuthMonitor::import_keyring(KeyRing& keyring)
int AuthMonitor::remove_entity(const EntityName &entity)
{
dout(10) << __func__ << " " << entity << dendl;
- if (!mon.key_server.contains(entity))
+ if (!mon.contains(entity))
return -ENOENT;
KeyServerData::Incremental auth_inc;
EntityAuth existing_auth;
// does entry already exist?
- if (mon.key_server.get_auth(name, existing_auth)) {
+ if (mon.get_auth(name, existing_auth)) {
// key match?
if (has_secret) {
if (existing_auth.key.get_secret().cmp(auth.key.get_secret())) {
return -EINVAL;
}
- if (!mon.key_server.contains(cephx_entity) &&
- !mon.key_server.contains(lockbox_entity)) {
+ if (!mon.contains(cephx_entity) &&
+ !mon.contains(lockbox_entity)) {
return -ENOENT;
}
// we must have validated before reaching this point.
// if keys exist, then this means they also match; otherwise we would
// have failed before calling this function.
- bool cephx_exists = mon.key_server.contains(cephx_entity.name);
+ bool cephx_exists = mon.contains(cephx_entity.name);
if (!cephx_exists) {
int err = add_entity(cephx_entity.name, cephx_entity.auth);
}
if (has_lockbox &&
- !mon.key_server.contains(lockbox_entity.name)) {
+ !mon.contains(lockbox_entity.name)) {
int err = add_entity(lockbox_entity.name, lockbox_entity.auth);
ceph_assert(0 == err);
}
int AuthMonitor::get_cipher_type(const cmdmap_t& cmdmap, std::ostream& ss) const
{
+ static const std::string PREFERRED = "preferred";
std::string key_string_type;
- cmd_getval_or<std::string>(cmdmap, "key_type"sv, key_string_type, "recommended"s);
- auto key_type = CryptoManager::get_key_type(key_string_type);
+ std::string cmd_key_string_type;
+ cmd_getval_or<std::string>(cmdmap, "key_type"sv, cmd_key_string_type, PREFERRED);
+ int key_type;
+ if (cmd_key_string_type == PREFERRED) {
+ key_type = mon.monmap->auth_preferred_cipher;
+ key_string_type = fmt::format("`preferred' AKA {}", CryptoManager::get_key_type_name(key_type));
+ } else {
+ key_type = CryptoManager::get_key_type(cmd_key_string_type);
+ if (key_type < 0) {
+ ss << "invalid key type: " << cmd_key_string_type;
+ return -EINVAL;
+ }
+ key_string_type = CryptoManager::get_key_type_name(key_type);
+ }
auto&& secure_key_types = CryptoManager::get_secure_key_types();
if (!secure_key_types.contains(key_type)) {
if (!cct->_conf.get_val<bool>("mon_auth_allow_insecure_key")) {
return -EPERM;
}
}
+ auto& allowed_ciphers = mon.monmap->auth_allowed_ciphers;
+ if (auto it = std::find(allowed_ciphers.begin(), allowed_ciphers.end(), key_type); it == allowed_ciphers.end()) {
+ ss << "refusing to create key with type ("
+ << key_string_type
+ << ") that cannot be used for auth (auth_allowed_ciphers)";
+ return -EPERM;
+ }
return key_type;
}
int key_type = get_cipher_type(cmdmap, ss);
if (key_type < 0) {
+ err = -EINVAL;
goto done;
}
}
EntityAuth entity_auth;
- if (!mon.key_server.get_auth(entity, entity_auth)) {
+ if (!mon.get_auth(entity, entity_auth)) {
ss << "entity " << entity << " does not exist";
err = -ENOENT;
goto done;
int key_type = get_cipher_type(cmdmap, ss);
if (key_type < 0) {
+ err = -EINVAL;
goto done;
}
int key_type = get_cipher_type(cmdmap, ss);
if (key_type < 0) {
+ err = -EINVAL;
goto done;
}
// do we have it?
EntityAuth entity_auth;
- if (mon.key_server.get_auth(entity, entity_auth)) {
+ if (mon.get_auth(entity, entity_auth)) {
for (const auto &sys_cap : wanted_caps) {
if (entity_auth.caps.count(sys_cap.first) == 0 ||
!entity_auth.caps[sys_cap.first].contents_equal(sys_cap.second)) {
int key_type = get_cipher_type(cmdmap, ss);
if (key_type < 0) {
+ err = -EINVAL;
goto done;
}
}
EntityAuth entity_auth;
- if (mon.key_server.get_auth(entity, entity_auth)) {
+ if (mon.get_auth(entity, entity_auth)) {
int rv = _gen_wanted_caps(entity_auth, newcaps, ss);
ceph_assert(rv == CAPS_UPDATE_REQD or rv == CAPS_UPDATE_NOT_REQD or
rv == CAPS_PARSING_ERR);
!entity_name.empty()) {
KeyServerData::Incremental auth_inc;
auth_inc.name = entity;
- if (!mon.key_server.contains(auth_inc.name)) {
+ if (!mon.contains(auth_inc.name)) {
err = 0;
goto done;
}
int key_type = get_cipher_type(cmdmap, ss);
if (key_type < 0) {
+ err = -EINVAL;
goto done;
}
EntityAuth entity_auth;
- if (!mon.key_server.get_auth(entity, entity_auth)) {
+ if (!mon.get_auth(entity, entity_auth)) {
ss << "entity does not exist";
err = -ENOENT;
goto done;
} else if (prefix == "auth dump-keys") {
if (f) {
f->open_object_section("keys");
- mon.key_server.dump(f.get());
+ mon.dump(f.get());
f->close_section();
f->flush(ds);
err = 0;
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);
+ bool modified = mon.prepare_rotating_update(rot_inc.rotating_bl, true);
ceph_assert(modified);
rs = "wiped rotating service keys!";
dout(5) << __func__ << " wiped rotating service keys!" << dendl;
// if entity to be created is already present.
if (create_entity &&
- mon.key_server.get_auth(auth_inc.name, auth_inc.auth)) {
+ mon.get_auth(auth_inc.name, auth_inc.auth)) {
ss << "entity already exists" << auth_inc.name;
return -EEXIST;
}
// if entity to be updated is absent.
if (!create_entity &&
- !mon.key_server.get_auth(auth_inc.name, auth_inc.auth)) {
+ !mon.get_auth(auth_inc.name, auth_inc.auth)) {
ss << "couldn't find entry " << auth_inc.name;
return -ENOENT;
}
bool changed = false;
map<EntityName, EntityAuth>::iterator p;
- for (p = mon.key_server.secrets_begin();
- p != mon.key_server.secrets_end();
+ for (p = mon.secrets_begin();
+ p != mon.secrets_end();
++p) {
// grab mon caps, if any
string mon_caps;
bool changed = false;
map<EntityName, EntityAuth>::iterator p;
- for (p = mon.key_server.secrets_begin();
- p != mon.key_server.secrets_end();
+ for (p = mon.secrets_begin();
+ p != mon.secrets_end();
++p) {
string n = p->first.to_str();
EntityName bootstrap_mgr_name;
int r = bootstrap_mgr_name.from_str("client.bootstrap-mgr");
ceph_assert(r);
- if (!mon.key_server.contains(bootstrap_mgr_name)) {
+ if (!mon.contains(bootstrap_mgr_name)) {
EntityName name = bootstrap_mgr_name;
EntityAuth auth;
bool changed = false;
for (auto &p : auth_lst) {
- if (mon.key_server.contains(p.first)) {
+ if (mon.contains(p.first)) {
continue;
}
int err = add_entity(p.first, p.second);
f->open_object_section("auth");
f->dump_unsigned("first_committed", get_first_committed());
f->dump_unsigned("last_committed", get_last_committed());
- f->dump_unsigned("num_secrets", mon.key_server.get_num_secrets());
+ f->dump_unsigned("num_secrets", mon.get_num_secrets());
f->close_section();
}
"name=args,type=CephString,n=N,goodchars=[A-Za-z0-9-_.=]",
"specify location <args> for the monitor <name>, using CRUSH bucket names", \
"mon", "rw")
+COMMAND("mon set " \
+ "name=name,type=CephString "
+ "name=value,type=CephString",
+ "set mon configuration", \
+ "mon", "rw")
COMMAND("mon enable_stretch_mode " \
"name=tiebreaker_mon,type=CephString, "
"name=new_crush_rule,type=CephString, "
#include "common/Formatter.h"
+#include "include/ceph_fs.h"
#include "include/ceph_features.h"
#include "include/addr_parsing.h"
+#include "auth/Crypto.h"
#include "common/ceph_argparse.h"
#include "common/ceph_json.h"
#include "common/dns_resolve.h"
encode(tiebreaker_mon, blist);
encode(stretch_marked_down_mons, blist);
encode(auth_epoch, blist);
+ encode(auth_service_cipher, blist);
+ encode(auth_allowed_ciphers, blist);
+ encode(auth_preferred_cipher, blist);
ENCODE_FINISH(blist);
}
}
if (struct_v >= 10) {
decode(auth_epoch, p);
+ decode(auth_service_cipher, p);
+ decode(auth_allowed_ciphers, p);
+ decode(auth_preferred_cipher, p);
+ } else {
+ /* When decoding an old MonMap, choose defaults reasonable for an existing
+ * cluster:
+ */
+ auth_epoch = 0;
+ auth_service_cipher = CEPH_CRYPTO_AES;
+ auth_allowed_ciphers = {CEPH_CRYPTO_AES, CEPH_CRYPTO_AES256KRB5};
+ auth_preferred_cipher = CEPH_CRYPTO_AES;
}
calc_addr_mons();
DECODE_FINISH(p);
out << "\n";
}
out << "auth_epoch " << auth_epoch << "\n";
+ out << "auth_service_cipher " << CryptoManager::get_key_type_name(auth_service_cipher) << "\n";
+ {
+ out << "auth_allowed_ciphers ";
+ bool first = true;
+ for (auto& c : auth_allowed_ciphers) {
+ if (!first) out << ", ";
+ out << CryptoManager::get_key_type_name(c);
+ first = false;
+ }
+ out << "\n";
+ }
+ out << "auth_preferred_cipher " << CryptoManager::get_key_type_name(auth_preferred_cipher) << "\n";
}
void MonMap::dump(Formatter *f) const
{
f->dump_unsigned("epoch", epoch);
f->dump_unsigned("auth_epoch", auth_epoch);
+
+ f->open_object_section("auth_service_cipher");
+ f->dump_string("name", CryptoManager::get_key_type_name(auth_service_cipher));
+ f->dump_int("value", auth_service_cipher);
+ f->close_section();
+
+ f->open_array_section("auth_allowed_ciphers");
+ for (auto const& k : auth_allowed_ciphers) {
+ f->open_object_section("key_type");
+ f->dump_string("name", CryptoManager::get_key_type_name(k));
+ f->dump_int("value", k);
+ f->close_section();
+ }
+ f->close_section();
+
+ f->open_object_section("auth_preferred_cipher");
+ f->dump_string("name", CryptoManager::get_key_type_name(auth_preferred_cipher));
+ f->dump_int("value", auth_preferred_cipher);
+ f->close_section();
+
f->dump_stream("fsid") << fsid;
last_changed.gmtime(f->dump_stream("modified"));
created.gmtime(f->dump_stream("created"));
});
}
+MonMap::MonMap()
+ : auth_service_cipher(CEPH_CRYPTO_NONE)
+ , auth_allowed_ciphers{CEPH_CRYPTO_NONE}
+ , auth_preferred_cipher(CEPH_CRYPTO_NONE)
+{
+}
+
seastar::future<> MonMap::build_initial(const crimson::common::ConfigProxy& conf, bool for_mkfs)
{
/* an invalid epoch so the real monmap doesn't trigger rotation */
auth_epoch = std::numeric_limits<decltype(auth_epoch)>::max();
+ if (for_mkfs) {
+ auth_service_cipher = CEPH_CRYPTO_AES256KRB5;
+ auth_allowed_ciphers = {CEPH_CRYPTO_AES256KRB5};
+ auth_preferred_cipher = CEPH_CRYPTO_AES256KRB5;
+ } else {
+ /* wait for real monmap */
+ auth_service_cipher = CEPH_CRYPTO_NONE;
+ auth_allowed_ciphers = {CEPH_CRYPTO_NONE};
+ auth_preferred_cipher = CEPH_CRYPTO_NONE;
+ }
// mon_host_override?
if (maybe_init_with_mon_host(conf.get_val<std::string>("mon_host_override"),
#else // WITH_CRIMSON
+MonMap::MonMap()
+ : auth_service_cipher(CEPH_CRYPTO_NONE)
+ , auth_allowed_ciphers{CEPH_CRYPTO_NONE}
+ , auth_preferred_cipher(CEPH_CRYPTO_NONE)
+{
+}
+
int MonMap::init_with_monmap(const std::string& monmap, std::ostream& errout)
{
int r;
/* an invalid epoch so the real monmap doesn't trigger rotation */
auth_epoch = std::numeric_limits<decltype(auth_epoch)>::max();
+ if (for_mkfs) {
+ auth_service_cipher = CEPH_CRYPTO_AES256KRB5;
+ auth_allowed_ciphers = {CEPH_CRYPTO_AES256KRB5};
+ auth_preferred_cipher = CEPH_CRYPTO_AES256KRB5;
+ } else {
+ /* wait for real monmap */
+ auth_service_cipher = CEPH_CRYPTO_NONE;
+ auth_allowed_ciphers = {CEPH_CRYPTO_NONE};
+ auth_preferred_cipher = CEPH_CRYPTO_NONE;
+ }
// mon_host_override?
auto mon_host_override = conf.get_val<std::string>("mon_host_override");
class MonMap {
public:
- epoch_t epoch; // what epoch/version of the monmap
+ epoch_t epoch = 0; // what epoch/version of the monmap
+ epoch_t auth_epoch = 0;
+ int auth_service_cipher;
+ std::vector<int> auth_allowed_ciphers;
+ int auth_preferred_cipher;
uuid_d fsid;
utime_t last_changed;
utime_t created;
std::string tiebreaker_mon;
std::set<std::string> stretch_marked_down_mons; // can't be leader or taken proposal in CONNECTIVITY
// seriously until fully recovered
-
- epoch_t auth_epoch = 0;
-
public:
void calc_legacy_ranks();
void calc_addr_mons() {
}
}
- MonMap()
- : epoch(0) {
- }
+ MonMap();
uuid_d& get_fsid() { return fsid; }
Monitor::Monitor(CephContext* cct_, string nm, MonitorDBStore *s,
Messenger *m, Messenger *mgr_m, MonMap *map) :
Dispatcher(cct_),
+ KeyServer(cct, &keyring),
AuthServer(cct_),
name(nm),
rank(-1),
logger(NULL), cluster_logger(NULL), cluster_logger_registered(false),
monmap(map),
log_client(cct_, messenger, monmap, LogClient::FLAG_MON),
- key_server(cct, &keyring),
auth_cluster_required(cct,
cct->_conf->auth_supported.empty() ?
cct->_conf->auth_cluster_required : cct->_conf->auth_supported),
// Attempt to decode and extract keyring only if it is found.
KeyRing keyring;
auto p = bl.cbegin();
- decode(keyring, p);
+ ::decode(keyring, p);
extract_save_mon_key(keyring);
}
}
EntityName mon_name;
mon_name.set_type(CEPH_ENTITY_TYPE_MON);
EntityAuth mon_key;
- if (key_server.get_auth(mon_name, mon_key)) {
+ if (get_auth(mon_name, mon_key)) {
dout(1) << "copying mon. key from old db to external keyring" << dendl;
keyring.add(mon_name, mon_key);
bufferlist bl;
if (r >= 0) {
try {
auto p = bl.cbegin();
- decode(fingerprint, p);
+ ::decode(fingerprint, p);
}
catch (ceph::buffer::error& e) {
dout(10) << __func__ << " failed to decode cluster_fingerprint" << dendl;
sync_providers.erase(sp.cookie);
}
- encode(*tx, reply->chunk_bl);
+ ::encode(*tx, reply->chunk_bl);
m->get_connection()->send_message(reply);
}
// do that anyway for other reasons, though.
MonitorDBStore::TransactionRef t = paxos->get_pending_transaction();
bufferlist bl;
- encode(m, bl);
+ ::encode(m, bl);
t->put(MONITOR_STORE_PREFIX, "last_metadata", bl);
}
elector.process_pending_pings();
f->close_section();
stringstream ss;
f->flush(ss);
- encode(ss.str(), payload);
+ ::encode(ss.str(), payload);
reply->set_payload(payload);
dout(10) << __func__ << " reply payload len " << reply->get_payload().length() << dendl;
m->get_connection()->send_message(reply);
if (r)
return r;
auto it = bl.cbegin();
- decode(mon_metadata, it);
+ ::decode(mon_metadata, it);
pending_metadata = mon_metadata;
return 0;
dout(10) << __func__ << " proposing cluster_fingerprint " << nf << dendl;
bufferlist bl;
- encode(nf, bl);
+ ::encode(nf, bl);
t->put(MONITOR_NAME, "cluster_fingerprint", bl);
}
CryptoKey key_server_secret;
CryptoKey keyring_secret;
- bool ksb = key_server.get_secret(name, key_server_secret);
+ bool ksb = get_secret(name, key_server_secret);
if (ksb) {
dout(30) << __func__ << ": keyserver found secret=" << key_server_secret << dendl;
}
dout(0) << " couldn't get secret for mon service from keyring or keyserver"
<< dendl;
stringstream ss, ds;
- int err = key_server.list_secrets(ds);
+ int err = list_secrets(ds);
if (err < 0)
ss << "no installed auth entries!";
else
secret = keyring_secret;
}
- ret = key_server.build_session_auth_info(
+ ret = build_session_auth_info(
service_id, auth_ticket_info.ticket, secret, (uint64_t)-1, secret.get_type(), info);
if (ret < 0) {
dout(0) << __func__ << " failed to build mon session_auth_info "
}
} else if (service_id == CEPH_ENTITY_TYPE_MGR) {
// mgr
- ret = key_server.build_session_auth_info(
+ ret = build_session_auth_info(
service_id, auth_ticket_info.ticket, std::nullopt, info);
if (ret < 0) {
derr << __func__ << " failed to build mgr service session_auth_info "
return false;
}
bufferlist ticket_data;
- encode(blob, ticket_data);
+ ::encode(blob, ticket_data);
auto iter = ticket_data.cbegin();
CephXTicketHandler handler(g_ceph_context, service_id);
- decode(handler.ticket, iter);
+ ::decode(handler.ticket, iter);
handler.session_key = info.session_key;
dout(20) << __func__ << ": verify authorizer was_challenge=" << was_challenge << dendl;
bool isvalid = ah->verify_authorizer(
cct,
- use_mon_keyring ? static_cast<KeyStore&>(keyring) : static_cast<KeyStore&>(key_server),
+ use_mon_keyring ? static_cast<KeyStore&>(keyring) : static_cast<KeyStore&>(*this),
payload,
auth_meta->get_connection_secret_length(),
reply,
// handler?
unique_ptr<AuthServiceHandler> auth_handler{get_auth_service_handler(
- auth_method, g_ceph_context, &key_server)};
+ auth_method, g_ceph_context, this)};
if (!auth_handler) {
dout(1) << __func__ << " auth_method " << auth_method << " not supported"
<< dendl;
EntityName entity_name;
try {
- decode(mode, p);
+ ::decode(mode, p);
if (mode < AUTH_MODE_MON ||
mode > AUTH_MODE_MON_MAX) {
dout(1) << __func__ << " invalid mode " << (int)mode << dendl;
return -EACCES;
}
ceph_assert(mode >= AUTH_MODE_MON && mode <= AUTH_MODE_MON_MAX);
- decode(entity_name, p);
- decode(con->peer_global_id, p);
+ ::decode(entity_name, p);
+ ::decode(con->peer_global_id, p);
} catch (ceph::buffer::error& e) {
dout(1) << __func__ << " failed to decode, " << e.what() << dendl;
return -EACCES;
bufferlist::const_iterator p = caps_info.caps.cbegin();
string str;
try {
- decode(str, p);
+ ::decode(str, p);
} catch (const ceph::buffer::error &err) {
derr << __func__ << " corrupt cap data for " << con->get_peer_entity_name()
<< " in auth db" << dendl;
}
}
set_elector_disallowed_leaders(can_change_external_state);
+
+ {
+ std::lock_guard lock{cipher_mutex};
+ my_service_cipher = monmap->auth_service_cipher;
+ dout(20) << __func__ << ": my_service_cipher now " << my_service_cipher << dendl;
+ my_allowed_ciphers = monmap->auth_allowed_ciphers;
+ dout(20) << __func__ << ": auth_allowed_ciphers now " << my_allowed_ciphers << dendl;
+ }
}
void Monitor::set_elector_disallowed_leaders(bool allow_election)
session_stretch_allowed(*j, blank);
}
}
+
+int Monitor::get_service_cipher() const
+{
+ dout(30) << __func__ << dendl;
+ int cipher;
+ {
+ std::lock_guard lock{cipher_mutex};
+ cipher = my_service_cipher;
+ }
+ dout(30) << __func__ << ": = " << cipher << dendl;
+ return cipher;
+}
+
+bool Monitor::is_cipher_allowed(int cipher) const
+{
+ dout(30) << __func__ << ": " << CryptoManager::get_key_type_name(cipher) << dendl;
+ bool found;
+ {
+ std::lock_guard lock{cipher_mutex};
+ auto it = std::find(my_allowed_ciphers.begin(), my_allowed_ciphers.end(), cipher);
+ found = (it != my_allowed_ciphers.end());
+ }
+ dout(30) << __func__ << ": = " << found << dendl;
+ return found;
+}
+
+std::vector<int> Monitor::get_ciphers_allowed() const
+{
+ dout(30) << __func__ << dendl;
+ std::vector<int> ciphers;
+ {
+ std::lock_guard lock{cipher_mutex};
+ ciphers = my_allowed_ciphers;
+ }
+ dout(30) << __func__ << ": = " << ciphers << dendl;
+ return ciphers;
+}
#define COMPAT_SET_LOC "feature_set"
class Monitor : public Dispatcher,
+ public KeyServer,
public AuthClient,
public AuthServer,
public md_config_obs_t {
LogChannelRef clog;
LogChannelRef audit_clog;
KeyRing keyring;
- KeyServer key_server;
AuthMethodList auth_cluster_required;
AuthMethodList auth_service_required;
uint64_t mgr_proxy_bytes = 0; // in-flight proxied mgr command message bytes
std::string gss_ktfile_client{};
+private:
+ mutable ceph::mutex cipher_mutex = ceph::make_mutex("Monitor::cipher_mutex");
+ std::vector<int> my_allowed_ciphers;
+ int my_service_cipher = -1;
+public:
+ int get_service_cipher() const override;
+ bool is_cipher_allowed(int cipher) const override;
+ std::vector<int> get_ciphers_allowed() const override;
+
private:
void new_tick();
pending_map.stretch_marked_down_mons.clear();
pending_map.last_changed = ceph_clock_now();
request_proposal(mon.osdmon());
+ } else if (prefix == "mon set") {
+ std::string name;
+ cmd_getval(cmdmap, "name", name);
+ std::string value;
+ cmd_getval(cmdmap, "value", value);
+ if (name == "auth_service_cipher") {
+ int c = CryptoManager::get_key_type(value);
+ if (c < 0) {
+ err = -EINVAL;
+ goto reply_no_propose;
+ }
+ pending_map.auth_service_cipher = c;
+ } else if (name == "auth_allowed_ciphers") {
+ std::vector<std::string> v;
+ std::vector<int> ciphers;
+ get_str_vec(value, ", ", v);
+ for (auto& cipher : v) {
+ int c = CryptoManager::get_key_type(cipher);
+ if (c < 0) {
+ err = -EINVAL;
+ goto reply_no_propose;
+ }
+ ciphers.push_back(c);
+ }
+ pending_map.auth_allowed_ciphers = std::move(ciphers);
+ } else if (name == "auth_preferred_cipher") {
+ int c = CryptoManager::get_key_type(value);
+ if (c < 0) {
+ err = -EINVAL;
+ goto reply_no_propose;
+ }
+ pending_map.auth_preferred_cipher = c;
+ } else {
+ ss << "unknown name " << name;
+ err = -EINVAL;
+ }
} else {
ss << "unknown command " << prefix;
err = -EINVAL;
pool_name = &osdmap.get_pool_name(m->pool);
}
- if (!is_unmanaged_snap_op_permitted(cct, mon.key_server,
+ if (!is_unmanaged_snap_op_permitted(cct, mon,
session->entity_name, session->caps,
session->get_peer_socket_addr(),
pool_name)) {
EntityName ename(g_conf()->name);
if (key_type < 0) {
- auto cephx_preferred_cipher = g_conf().get_val<std::string>("cephx_preferred_cipher");
- cerr << "using key type: " << cephx_preferred_cipher << std::endl;
- key_type = CryptoManager::get_key_type(cephx_preferred_cipher);
+ key_type = CEPH_CRYPTO_AES256KRB5;
}
// Enforce the use of gen-key or add-key when creating to avoid ending up
monmap.epoch = 0;
monmap.created = ceph_clock_now();
monmap.last_changed = monmap.created;
+ monmap.auth_service_cipher = CEPH_CRYPTO_AES256KRB5;
+ monmap.auth_allowed_ciphers = {CEPH_CRYPTO_AES256KRB5};
+ monmap.auth_preferred_cipher = CEPH_CRYPTO_AES256KRB5;
srand(getpid() + time(0));
if (g_conf().get_val<uuid_d>("fsid").is_zero()) {
monmap.generate_fsid();