1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
17 #include "mon/AuthMonitor.h"
18 #include "mon/Monitor.h"
19 #include "mon/MonitorDBStore.h"
20 #include "mon/ConfigKeyService.h"
21 #include "mon/OSDMonitor.h"
22 #include "mon/MDSMonitor.h"
24 #include "messages/MMonCommand.h"
25 #include "messages/MAuth.h"
26 #include "messages/MAuthReply.h"
27 #include "messages/MMonGlobalID.h"
28 #include "msg/Messenger.h"
30 #include "auth/AuthServiceHandler.h"
31 #include "auth/KeyRing.h"
32 #include "include/stringify.h"
33 #include "include/assert.h"
35 #include "mds/MDSAuthCaps.h"
36 #include "osd/OSDCap.h"
38 #define dout_subsys ceph_subsys_mon
40 #define dout_prefix _prefix(_dout, mon, get_last_committed())
41 static ostream
& _prefix(std::ostream
*_dout
, Monitor
*mon
, version_t v
) {
42 return *_dout
<< "mon." << mon
->name
<< "@" << mon
->rank
43 << "(" << mon
->get_state_name()
44 << ").auth v" << v
<< " ";
47 ostream
& operator<<(ostream
&out
, const AuthMonitor
&pm
)
52 bool AuthMonitor::check_rotate()
54 KeyServerData::Incremental rot_inc
;
55 rot_inc
.op
= KeyServerData::AUTH_INC_SET_ROTATING
;
56 if (!mon
->key_server
.updated_rotating(rot_inc
.rotating_bl
, last_rotating_ver
))
58 dout(10) << __func__
<< " updated rotating" << dendl
;
59 push_cephx_inc(rot_inc
);
64 Tick function to update the map based on performance every N seconds
67 void AuthMonitor::tick()
69 if (!is_active()) return;
71 dout(10) << *this << dendl
;
73 if (!mon
->is_leader()) return;
79 void AuthMonitor::on_active()
81 dout(10) << "AuthMonitor::on_active()" << dendl
;
83 if (!mon
->is_leader())
85 mon
->key_server
.start_server();
88 void AuthMonitor::create_initial()
90 dout(10) << "create_initial -- creating initial map" << dendl
;
92 // initialize rotating keys
93 last_rotating_ver
= 0;
95 assert(pending_auth
.size() == 1);
97 if (mon
->is_keyring_required()) {
100 int ret
= mon
->store
->get("mkfs", "keyring", bl
);
101 // fail hard only if there's an error we're not expecting to see
102 assert((ret
== 0) || (ret
== -ENOENT
));
104 // try importing only if there's a key
107 bufferlist::iterator p
= bl
.begin();
109 ::decode(keyring
, p
);
110 import_keyring(keyring
);
114 max_global_id
= MIN_GLOBAL_ID
;
117 inc
.inc_type
= GLOBAL_ID
;
118 inc
.max_global_id
= max_global_id
;
119 pending_auth
.push_back(inc
);
124 void AuthMonitor::update_from_paxos(bool *need_bootstrap
)
126 dout(10) << __func__
<< dendl
;
127 version_t version
= get_last_committed();
128 version_t keys_ver
= mon
->key_server
.get_ver();
129 if (version
== keys_ver
)
131 assert(version
> keys_ver
);
133 version_t latest_full
= get_version_latest_full();
135 dout(10) << __func__
<< " version " << version
<< " keys ver " << keys_ver
136 << " latest " << latest_full
<< dendl
;
138 if ((latest_full
> 0) && (latest_full
> keys_ver
)) {
139 bufferlist latest_bl
;
140 int err
= get_version_full(latest_full
, latest_bl
);
142 assert(latest_bl
.length() != 0);
143 dout(7) << __func__
<< " loading summary e " << latest_full
<< dendl
;
144 dout(7) << __func__
<< " latest length " << latest_bl
.length() << dendl
;
145 bufferlist::iterator p
= latest_bl
.begin();
147 ::decode(struct_v
, p
);
148 ::decode(max_global_id
, p
);
149 ::decode(mon
->key_server
, p
);
150 mon
->key_server
.set_ver(latest_full
);
151 keys_ver
= latest_full
;
154 dout(10) << __func__
<< " key server version " << mon
->key_server
.get_ver() << dendl
;
156 // walk through incrementals
157 while (version
> keys_ver
) {
159 int ret
= get_version(keys_ver
+1, bl
);
163 // reset if we are moving to initial state. we will normally have
164 // keys in here temporarily for bootstrapping that we need to
167 mon
->key_server
.clear_secrets();
169 dout(20) << __func__
<< " walking through version " << (keys_ver
+1)
170 << " len " << bl
.length() << dendl
;
172 bufferlist::iterator p
= bl
.begin();
178 switch (inc
.inc_type
) {
180 max_global_id
= inc
.max_global_id
;
185 KeyServerData::Incremental auth_inc
;
186 bufferlist::iterator iter
= inc
.auth_data
.begin();
187 ::decode(auth_inc
, iter
);
188 mon
->key_server
.apply_data_incremental(auth_inc
);
195 mon
->key_server
.set_ver(keys_ver
);
197 if (keys_ver
== 1 && mon
->is_keyring_required()) {
198 auto t(std::make_shared
<MonitorDBStore::Transaction
>());
199 t
->erase("mkfs", "keyring");
200 mon
->store
->apply_transaction(t
);
204 if (last_allocated_id
== 0)
205 last_allocated_id
= max_global_id
;
207 dout(10) << "update_from_paxos() last_allocated_id=" << last_allocated_id
208 << " max_global_id=" << max_global_id
209 << " format_version " << format_version
213 void AuthMonitor::increase_max_global_id()
215 assert(mon
->is_leader());
217 max_global_id
+= g_conf
->mon_globalid_prealloc
;
218 dout(10) << "increasing max_global_id to " << max_global_id
<< dendl
;
220 inc
.inc_type
= GLOBAL_ID
;
221 inc
.max_global_id
= max_global_id
;
222 pending_auth
.push_back(inc
);
225 bool AuthMonitor::should_propose(double& delay
)
227 return (!pending_auth
.empty());
230 void AuthMonitor::create_pending()
232 pending_auth
.clear();
233 dout(10) << "create_pending v " << (get_last_committed() + 1) << dendl
;
236 void AuthMonitor::encode_pending(MonitorDBStore::TransactionRef t
)
238 dout(10) << __func__
<< " v " << (get_last_committed() + 1) << dendl
;
244 vector
<Incremental
>::iterator p
;
245 for (p
= pending_auth
.begin(); p
!= pending_auth
.end(); ++p
)
246 p
->encode(bl
, mon
->get_quorum_con_features());
248 version_t version
= get_last_committed() + 1;
249 put_version(t
, version
, bl
);
250 put_last_committed(t
, version
);
253 void AuthMonitor::encode_full(MonitorDBStore::TransactionRef t
)
255 version_t version
= mon
->key_server
.get_ver();
256 // do not stash full version 0 as it will never be removed nor read
260 dout(10) << __func__
<< " auth v " << version
<< dendl
;
261 assert(get_last_committed() == version
);
264 Mutex::Locker
l(mon
->key_server
.get_lock());
265 dout(20) << __func__
<< " key server has "
266 << (mon
->key_server
.has_secrets() ? "" : "no ")
267 << "secrets!" << dendl
;
269 ::encode(v
, full_bl
);
270 ::encode(max_global_id
, full_bl
);
271 ::encode(mon
->key_server
, full_bl
);
273 put_version_full(t
, version
, full_bl
);
274 put_version_latest_full(t
, version
);
277 version_t
AuthMonitor::get_trim_to()
279 unsigned max
= g_conf
->paxos_max_join_drift
* 2;
280 version_t version
= get_last_committed();
281 if (mon
->is_leader() && (version
> max
))
282 return version
- max
;
286 bool AuthMonitor::preprocess_query(MonOpRequestRef op
)
288 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
289 dout(10) << "preprocess_query " << *m
<< " from " << m
->get_orig_source_inst() << dendl
;
290 switch (m
->get_type()) {
291 case MSG_MON_COMMAND
:
293 return preprocess_command(op
);
295 catch (const bad_cmd_get
& e
) {
297 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
302 return prep_auth(op
, false);
304 case MSG_MON_GLOBAL_ID
:
313 bool AuthMonitor::prepare_update(MonOpRequestRef op
)
315 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
316 dout(10) << "prepare_update " << *m
<< " from " << m
->get_orig_source_inst() << dendl
;
317 switch (m
->get_type()) {
318 case MSG_MON_COMMAND
:
320 return prepare_command(op
);
322 catch (const bad_cmd_get
& e
) {
324 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
327 case MSG_MON_GLOBAL_ID
:
328 return prepare_global_id(op
);
330 return prep_auth(op
, true);
337 uint64_t AuthMonitor::assign_global_id(MonOpRequestRef op
, bool should_increase_max
)
339 MAuth
*m
= static_cast<MAuth
*>(op
->get_req());
340 int total_mon
= mon
->monmap
->size();
341 dout(10) << "AuthMonitor::assign_global_id m=" << *m
<< " mon=" << mon
->rank
<< "/" << total_mon
342 << " last_allocated=" << last_allocated_id
<< " max_global_id=" << max_global_id
<< dendl
;
344 uint64_t next_global_id
= last_allocated_id
+ 1;
345 int remainder
= next_global_id
% total_mon
;
347 remainder
= total_mon
- remainder
;
348 next_global_id
+= remainder
+ mon
->rank
;
349 dout(10) << "next_global_id should be " << next_global_id
<< dendl
;
351 // if we can't bump the max, bail out now on an out-of-bounds gid
352 if (next_global_id
> max_global_id
&&
353 (!mon
->is_leader() || !should_increase_max
)) {
357 // can we return a gid?
358 bool return_next
= (next_global_id
<= max_global_id
);
361 while (mon
->is_leader() &&
362 (max_global_id
< g_conf
->mon_globalid_prealloc
||
363 next_global_id
>= max_global_id
- g_conf
->mon_globalid_prealloc
/ 2)) {
364 increase_max_global_id();
368 last_allocated_id
= next_global_id
;
369 return next_global_id
;
376 bool AuthMonitor::prep_auth(MonOpRequestRef op
, bool paxos_writable
)
378 MAuth
*m
= static_cast<MAuth
*>(op
->get_req());
379 dout(10) << "prep_auth() blob_size=" << m
->get_auth_payload().length() << dendl
;
381 MonSession
*s
= op
->get_session();
383 dout(10) << "no session, dropping" << dendl
;
388 AuthCapsInfo caps_info
;
390 bufferlist response_bl
;
391 bufferlist::iterator indata
= m
->auth_payload
.begin();
392 __u32 proto
= m
->protocol
;
394 EntityName entity_name
;
397 if (m
->protocol
== 0 && !s
->auth_handler
) {
398 set
<__u32
> supported
;
402 ::decode(struct_v
, indata
);
403 ::decode(supported
, indata
);
404 ::decode(entity_name
, indata
);
405 ::decode(s
->global_id
, indata
);
406 } catch (const buffer::error
&e
) {
407 dout(10) << "failed to decode initial auth message" << dendl
;
412 // do we require cephx signatures?
414 if (!m
->get_connection()->has_feature(CEPH_FEATURE_MSG_AUTH
)) {
415 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
416 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
417 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
418 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
) {
419 if (g_conf
->cephx_cluster_require_signatures
||
420 g_conf
->cephx_require_signatures
) {
421 dout(1) << m
->get_source_inst()
422 << " supports cephx but not signatures and"
423 << " 'cephx [cluster] require signatures = true';"
424 << " disallowing cephx" << dendl
;
425 supported
.erase(CEPH_AUTH_CEPHX
);
428 if (g_conf
->cephx_service_require_signatures
||
429 g_conf
->cephx_require_signatures
) {
430 dout(1) << m
->get_source_inst()
431 << " supports cephx but not signatures and"
432 << " 'cephx [service] require signatures = true';"
433 << " disallowing cephx" << dendl
;
434 supported
.erase(CEPH_AUTH_CEPHX
);
437 } else if (!m
->get_connection()->has_feature(CEPH_FEATURE_CEPHX_V2
)) {
438 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
439 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
440 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
441 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
) {
442 if (g_conf
->cephx_cluster_require_version
>= 2 ||
443 g_conf
->cephx_require_version
>= 2) {
444 dout(1) << m
->get_source_inst()
445 << " supports cephx but not v2 and"
446 << " 'cephx [cluster] require version >= 2';"
447 << " disallowing cephx" << dendl
;
448 supported
.erase(CEPH_AUTH_CEPHX
);
451 if (g_conf
->cephx_service_require_version
>= 2 ||
452 g_conf
->cephx_require_version
>= 2) {
453 dout(1) << m
->get_source_inst()
454 << " supports cephx but not v2 and"
455 << " 'cephx [service] require version >= 2';"
456 << " disallowing cephx" << dendl
;
457 supported
.erase(CEPH_AUTH_CEPHX
);
463 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
464 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
465 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
466 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
)
467 type
= mon
->auth_cluster_required
.pick(supported
);
469 type
= mon
->auth_service_required
.pick(supported
);
471 s
->auth_handler
= get_auth_service_handler(type
, g_ceph_context
, &mon
->key_server
);
472 if (!s
->auth_handler
) {
473 dout(1) << "client did not provide supported auth type" << dendl
;
478 } else if (!s
->auth_handler
) {
479 dout(10) << "protocol specified but no s->auth_handler" << dendl
;
484 /* assign a new global_id? we assume this should only happen on the first
485 request. If a client tries to send it later, it'll screw up its auth
488 s
->global_id
= assign_global_id(op
, paxos_writable
);
491 delete s
->auth_handler
;
492 s
->auth_handler
= NULL
;
494 if (mon
->is_leader() && paxos_writable
) {
495 dout(10) << "increasing global id, waitlisting message" << dendl
;
496 wait_for_active(op
, new C_RetryMessage(this, op
));
500 if (!mon
->is_leader()) {
501 dout(10) << "not the leader, requesting more ids from leader" << dendl
;
502 int leader
= mon
->get_leader();
503 MMonGlobalID
*req
= new MMonGlobalID();
504 req
->old_max_id
= max_global_id
;
505 mon
->messenger
->send_message(req
, mon
->monmap
->get_inst(leader
));
506 wait_for_finished_proposal(op
, new C_RetryMessage(this, op
));
510 assert(!paxos_writable
);
520 // always send the latest monmap.
521 if (m
->monmap_epoch
< mon
->monmap
->get_epoch())
522 mon
->send_latest_monmap(m
->get_connection().get());
524 proto
= s
->auth_handler
->start_session(entity_name
, indata
, response_bl
, caps_info
);
526 if (caps_info
.allow_all
)
527 s
->caps
.set_allow_all();
530 ret
= s
->auth_handler
->handle_request(indata
, response_bl
, s
->global_id
, caps_info
, &auid
);
533 wait_for_active(op
, new C_RetryMessage(this,op
));
536 if (caps_info
.caps
.length()) {
537 bufferlist::iterator p
= caps_info
.caps
.begin();
541 } catch (const buffer::error
&err
) {
542 derr
<< "corrupt cap data for " << entity_name
<< " in auth db" << dendl
;
545 s
->caps
.parse(str
, NULL
);
548 } catch (const buffer::error
&err
) {
550 dout(0) << "caught error when trying to handle auth request, probably malformed request" << dendl
;
554 reply
= new MAuthReply(proto
, &response_bl
, ret
, s
->global_id
);
555 mon
->send_reply(op
, reply
);
560 bool AuthMonitor::preprocess_command(MonOpRequestRef op
)
562 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
567 map
<string
, cmd_vartype
> cmdmap
;
568 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
569 // ss has reason for failure
570 string rs
= ss
.str();
571 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
576 cmd_getval_throws(g_ceph_context
, cmdmap
, "prefix", prefix
);
577 if (prefix
== "auth add" ||
578 prefix
== "auth del" ||
579 prefix
== "auth rm" ||
580 prefix
== "auth get-or-create" ||
581 prefix
== "auth get-or-create-key" ||
582 prefix
== "fs authorize" ||
583 prefix
== "auth import" ||
584 prefix
== "auth caps") {
588 MonSession
*session
= m
->get_session();
590 mon
->reply_command(op
, -EACCES
, "access denied", rdata
, get_last_committed());
594 // entity might not be supplied, but if it is, it should be valid
596 cmd_getval_throws(g_ceph_context
, cmdmap
, "entity", entity_name
);
598 if (!entity_name
.empty() && !entity
.from_str(entity_name
)) {
599 ss
<< "invalid entity_auth " << entity_name
;
600 mon
->reply_command(op
, -EINVAL
, ss
.str(), get_last_committed());
605 cmd_getval_throws(g_ceph_context
, cmdmap
, "format", format
, string("plain"));
606 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
608 if (prefix
== "auth export") {
610 export_keyring(keyring
);
611 if (!entity_name
.empty()) {
613 if (keyring
.get_auth(entity
, eauth
)) {
615 kr
.add(entity
, eauth
);
617 kr
.encode_formatted("auth", f
.get(), rdata
);
619 kr
.encode_plaintext(rdata
);
620 ss
<< "export " << eauth
;
623 ss
<< "no key for " << eauth
;
628 keyring
.encode_formatted("auth", f
.get(), rdata
);
630 keyring
.encode_plaintext(rdata
);
632 ss
<< "exported master keyring";
635 } else if (prefix
== "auth get" && !entity_name
.empty()) {
637 EntityAuth entity_auth
;
638 if(!mon
->key_server
.get_auth(entity
, entity_auth
)) {
639 ss
<< "failed to find " << entity_name
<< " in keyring";
642 keyring
.add(entity
, entity_auth
);
644 keyring
.encode_formatted("auth", f
.get(), rdata
);
646 keyring
.encode_plaintext(rdata
);
647 ss
<< "exported keyring for " << entity_name
;
650 } else if (prefix
== "auth print-key" ||
651 prefix
== "auth print_key" ||
652 prefix
== "auth get-key") {
654 if (!mon
->key_server
.get_auth(entity
, auth
)) {
655 ss
<< "don't have " << entity
;
660 auth
.key
.encode_formatted("auth", f
.get(), rdata
);
662 auth
.key
.encode_plaintext(rdata
);
665 } else if (prefix
== "auth list" ||
666 prefix
== "auth ls") {
668 mon
->key_server
.encode_formatted("auth", f
.get(), rdata
);
670 mon
->key_server
.encode_plaintext(rdata
);
671 if (rdata
.length() > 0)
672 ss
<< "installed auth entries:" << std::endl
;
674 ss
<< "no installed auth entries!" << std::endl
;
679 ss
<< "invalid command";
686 getline(ss
, rs
, '\0');
687 mon
->reply_command(op
, r
, rs
, rdata
, get_last_committed());
691 void AuthMonitor::export_keyring(KeyRing
& keyring
)
693 mon
->key_server
.export_keyring(keyring
);
696 int AuthMonitor::import_keyring(KeyRing
& keyring
)
698 for (map
<EntityName
, EntityAuth
>::iterator p
= keyring
.get_keys().begin();
699 p
!= keyring
.get_keys().end();
701 if (p
->second
.caps
.empty()) {
702 dout(0) << "import: no caps supplied" << dendl
;
705 int err
= add_entity(p
->first
, p
->second
);
711 int AuthMonitor::remove_entity(const EntityName
&entity
)
713 dout(10) << __func__
<< " " << entity
<< dendl
;
714 if (!mon
->key_server
.contains(entity
))
717 KeyServerData::Incremental auth_inc
;
718 auth_inc
.name
= entity
;
719 auth_inc
.op
= KeyServerData::AUTH_INC_DEL
;
720 push_cephx_inc(auth_inc
);
725 bool AuthMonitor::entity_is_pending(EntityName
& entity
)
727 // are we about to have it?
728 for (auto& p
: pending_auth
) {
729 if (p
.inc_type
== AUTH_DATA
) {
730 KeyServerData::Incremental inc
;
731 bufferlist::iterator q
= p
.auth_data
.begin();
733 if (inc
.op
== KeyServerData::AUTH_INC_ADD
&&
734 inc
.name
== entity
) {
742 int AuthMonitor::exists_and_matches_entity(
743 const auth_entity_t
& entity
,
747 return exists_and_matches_entity(entity
.name
, entity
.auth
,
748 entity
.auth
.caps
, has_secret
, ss
);
751 int AuthMonitor::exists_and_matches_entity(
752 const EntityName
& name
,
753 const EntityAuth
& auth
,
754 const map
<string
,bufferlist
>& caps
,
759 dout(20) << __func__
<< " entity " << name
<< " auth " << auth
760 << " caps " << caps
<< " has_secret " << has_secret
<< dendl
;
762 EntityAuth existing_auth
;
763 // does entry already exist?
764 if (mon
->key_server
.get_auth(name
, existing_auth
)) {
767 if (existing_auth
.key
.get_secret().cmp(auth
.key
.get_secret())) {
768 ss
<< "entity " << name
<< " exists but key does not match";
774 if (caps
.size() != existing_auth
.caps
.size()) {
775 ss
<< "entity " << name
<< " exists but caps do not match";
778 for (auto& it
: caps
) {
779 if (existing_auth
.caps
.count(it
.first
) == 0 ||
780 !existing_auth
.caps
[it
.first
].contents_equal(it
.second
)) {
781 ss
<< "entity " << name
<< " exists but cap "
782 << it
.first
<< " does not match";
793 int AuthMonitor::add_entity(
794 const EntityName
& name
,
795 const EntityAuth
& auth
)
799 KeyServerData::Incremental auth_inc
;
800 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
801 auth_inc
.name
= name
;
802 auth_inc
.auth
= auth
;
804 dout(10) << " importing " << auth_inc
.name
<< dendl
;
805 dout(30) << " " << auth_inc
.auth
<< dendl
;
806 push_cephx_inc(auth_inc
);
810 int AuthMonitor::validate_osd_destroy(
813 EntityName
& cephx_entity
,
814 EntityName
& lockbox_entity
,
817 assert(paxos
->is_plugged());
819 dout(10) << __func__
<< " id " << id
<< " uuid " << uuid
<< dendl
;
821 string cephx_str
= "osd." + stringify(id
);
822 string lockbox_str
= "client.osd-lockbox." + stringify(uuid
);
824 if (!cephx_entity
.from_str(cephx_str
)) {
825 dout(10) << __func__
<< " invalid cephx entity '"
826 << cephx_str
<< "'" << dendl
;
827 ss
<< "invalid cephx key entity '" << cephx_str
<< "'";
831 if (!lockbox_entity
.from_str(lockbox_str
)) {
832 dout(10) << __func__
<< " invalid lockbox entity '"
833 << lockbox_str
<< "'" << dendl
;
834 ss
<< "invalid lockbox key entity '" << lockbox_str
<< "'";
838 if (!mon
->key_server
.contains(cephx_entity
) &&
839 !mon
->key_server
.contains(lockbox_entity
)) {
846 int AuthMonitor::do_osd_destroy(
847 const EntityName
& cephx_entity
,
848 const EntityName
& lockbox_entity
)
850 assert(paxos
->is_plugged());
852 dout(10) << __func__
<< " cephx " << cephx_entity
853 << " lockbox " << lockbox_entity
<< dendl
;
855 bool removed
= false;
857 int err
= remove_entity(cephx_entity
);
858 if (err
== -ENOENT
) {
859 dout(10) << __func__
<< " " << cephx_entity
<< " does not exist" << dendl
;
864 err
= remove_entity(lockbox_entity
);
865 if (err
== -ENOENT
) {
866 dout(10) << __func__
<< " " << lockbox_entity
<< " does not exist" << dendl
;
872 dout(10) << __func__
<< " entities do not exist -- no-op." << dendl
;
876 // given we have paxos plugged, this will not result in a proposal
877 // being triggered, but it will still be needed so that we get our
878 // pending state encoded into the paxos' pending transaction.
883 bufferlist
_encode_cap(const string
& cap
)
893 const map
<string
,bufferlist
>& caps
)
898 auth
.key
.decode_base64(key
);
899 } catch (buffer::error
& e
) {
906 int AuthMonitor::validate_osd_new(
909 const string
& cephx_secret
,
910 const string
& lockbox_secret
,
911 auth_entity_t
& cephx_entity
,
912 auth_entity_t
& lockbox_entity
,
916 dout(10) << __func__
<< " osd." << id
<< " uuid " << uuid
<< dendl
;
918 map
<string
,bufferlist
> cephx_caps
= {
919 { "osd", _encode_cap("allow *") },
920 { "mon", _encode_cap("allow profile osd") },
921 { "mgr", _encode_cap("allow profile osd") }
923 map
<string
,bufferlist
> lockbox_caps
= {
924 { "mon", _encode_cap("allow command \"config-key get\" "
925 "with key=\"dm-crypt/osd/" +
930 bool has_lockbox
= !lockbox_secret
.empty();
932 string cephx_name
= "osd." + stringify(id
);
933 string lockbox_name
= "client.osd-lockbox." + stringify(uuid
);
935 if (!cephx_entity
.name
.from_str(cephx_name
)) {
936 dout(10) << __func__
<< " invalid cephx entity '"
937 << cephx_name
<< "'" << dendl
;
938 ss
<< "invalid cephx key entity '" << cephx_name
<< "'";
943 if (!lockbox_entity
.name
.from_str(lockbox_name
)) {
944 dout(10) << __func__
<< " invalid cephx lockbox entity '"
945 << lockbox_name
<< "'" << dendl
;
946 ss
<< "invalid cephx lockbox entity '" << lockbox_name
<< "'";
951 if (entity_is_pending(cephx_entity
.name
) ||
952 (has_lockbox
&& entity_is_pending(lockbox_entity
.name
))) {
953 // If we have pending entities for either the cephx secret or the
954 // lockbox secret, then our safest bet is to retry the command at
955 // a later time. These entities may be pending because an `osd new`
956 // command has been run (which is unlikely, due to the nature of
957 // the operation, which will force a paxos proposal), or (more likely)
958 // because a competing client created those entities before we handled
959 // the `osd new` command. Regardless, let's wait and see.
963 if (!is_valid_cephx_key(cephx_secret
)) {
964 ss
<< "invalid cephx secret.";
968 if (has_lockbox
&& !is_valid_cephx_key(lockbox_secret
)) {
969 ss
<< "invalid cephx lockbox secret.";
973 int err
= _create_auth(cephx_entity
.auth
, cephx_secret
, cephx_caps
);
976 bool cephx_is_idempotent
= false, lockbox_is_idempotent
= false;
977 err
= exists_and_matches_entity(cephx_entity
, true, ss
);
979 if (err
!= -ENOENT
) {
984 cephx_is_idempotent
= true;
988 err
= _create_auth(lockbox_entity
.auth
, lockbox_secret
, lockbox_caps
);
990 err
= exists_and_matches_entity(lockbox_entity
, true, ss
);
991 if (err
!= -ENOENT
) {
996 lockbox_is_idempotent
= true;
1000 if (cephx_is_idempotent
&& (!has_lockbox
|| lockbox_is_idempotent
)) {
1007 int AuthMonitor::do_osd_new(
1008 const auth_entity_t
& cephx_entity
,
1009 const auth_entity_t
& lockbox_entity
,
1012 assert(paxos
->is_plugged());
1014 dout(10) << __func__
<< " cephx " << cephx_entity
.name
1017 *_dout
<< lockbox_entity
.name
;
1023 // we must have validated before reaching this point.
1024 // if keys exist, then this means they also match; otherwise we would
1025 // have failed before calling this function.
1026 bool cephx_exists
= mon
->key_server
.contains(cephx_entity
.name
);
1028 if (!cephx_exists
) {
1029 int err
= add_entity(cephx_entity
.name
, cephx_entity
.auth
);
1034 !mon
->key_server
.contains(lockbox_entity
.name
)) {
1035 int err
= add_entity(lockbox_entity
.name
, lockbox_entity
.auth
);
1039 // given we have paxos plugged, this will not result in a proposal
1040 // being triggered, but it will still be needed so that we get our
1041 // pending state encoded into the paxos' pending transaction.
1046 bool AuthMonitor::valid_caps(const vector
<string
>& caps
, ostream
*out
)
1048 for (vector
<string
>::const_iterator p
= caps
.begin();
1049 p
!= caps
.end(); p
+= 2) {
1050 if ((p
+1) == caps
.end()) {
1051 *out
<< "cap '" << *p
<< "' has no value";
1054 if (*p
== "mon" || *p
== "mgr") {
1056 if (!tmp
.parse(*(p
+1), out
)) {
1059 } else if (*p
== "osd") {
1061 if (!ocap
.parse(*(p
+1), out
)) {
1064 } else if (*p
== "mds") {
1066 if (!mdscap
.parse(g_ceph_context
, *(p
+1), out
)) {
1070 *out
<< "unknown cap type '" << *p
<< "'";
1077 bool AuthMonitor::prepare_command(MonOpRequestRef op
)
1079 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
1080 stringstream ss
, ds
;
1085 map
<string
, cmd_vartype
> cmdmap
;
1086 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
1087 // ss has reason for failure
1088 string rs
= ss
.str();
1089 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
1094 vector
<string
>caps_vec
;
1098 cmd_getval_throws(g_ceph_context
, cmdmap
, "prefix", prefix
);
1101 cmd_getval_throws(g_ceph_context
, cmdmap
, "format", format
, string("plain"));
1102 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
1104 MonSession
*session
= m
->get_session();
1106 mon
->reply_command(op
, -EACCES
, "access denied", rdata
, get_last_committed());
1110 cmd_getval_throws(g_ceph_context
, cmdmap
, "caps", caps_vec
);
1111 if ((caps_vec
.size() % 2) != 0) {
1112 ss
<< "bad capabilities request; odd number of arguments";
1117 cmd_getval_throws(g_ceph_context
, cmdmap
, "entity", entity_name
);
1118 if (!entity_name
.empty() && !entity
.from_str(entity_name
)) {
1119 ss
<< "bad entity name";
1124 if (prefix
== "auth import") {
1125 bufferlist bl
= m
->get_data();
1126 if (bl
.length() == 0) {
1127 ss
<< "auth import: no data supplied";
1129 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
1132 bufferlist::iterator iter
= bl
.begin();
1135 ::decode(keyring
, iter
);
1136 } catch (const buffer::error
&ex
) {
1137 ss
<< "error decoding keyring" << " " << ex
.what();
1141 err
= import_keyring(keyring
);
1143 ss
<< "auth import: no caps supplied";
1145 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
1148 ss
<< "imported keyring";
1151 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1152 get_last_committed() + 1));
1154 } else if (prefix
== "auth add" && !entity_name
.empty()) {
1155 /* expected behavior:
1156 * - if command reproduces current state, return 0.
1157 * - if command adds brand new entity, handle it.
1158 * - if command adds new state to existing entity, return error.
1160 KeyServerData::Incremental auth_inc
;
1161 auth_inc
.name
= entity
;
1162 bufferlist bl
= m
->get_data();
1163 bool has_keyring
= (bl
.length() > 0);
1164 map
<string
,bufferlist
> new_caps
;
1166 KeyRing new_keyring
;
1168 bufferlist::iterator iter
= bl
.begin();
1170 ::decode(new_keyring
, iter
);
1171 } catch (const buffer::error
&ex
) {
1172 ss
<< "error decoding keyring";
1178 if (!valid_caps(caps_vec
, &ss
)) {
1183 // are we about to have it?
1184 if (entity_is_pending(entity
)) {
1185 wait_for_finished_proposal(op
,
1186 new Monitor::C_Command(mon
, op
, 0, rs
, get_last_committed() + 1));
1190 // build new caps from provided arguments (if available)
1191 for (vector
<string
>::iterator it
= caps_vec
.begin();
1192 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1196 ::encode(*(it
+1), cap
);
1197 new_caps
[sys
] = cap
;
1200 // pull info out of provided keyring
1203 if (!new_keyring
.get_auth(auth_inc
.name
, new_inc
)) {
1204 ss
<< "key for " << auth_inc
.name
1205 << " not found in provided keyring";
1209 if (!new_caps
.empty() && !new_inc
.caps
.empty()) {
1210 ss
<< "caps cannot be specified both in keyring and in command";
1214 if (new_caps
.empty()) {
1215 new_caps
= new_inc
.caps
;
1219 err
= exists_and_matches_entity(auth_inc
.name
, new_inc
,
1220 new_caps
, has_keyring
, ss
);
1221 // if entity/key/caps do not exist in the keyring, just fall through
1222 // and add the entity; otherwise, make sure everything matches (in
1223 // which case it's a no-op), because if not we must fail.
1224 if (err
!= -ENOENT
) {
1236 dout(10) << "AuthMonitor::prepare_command generating random key for "
1237 << auth_inc
.name
<< dendl
;
1238 new_inc
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1240 new_inc
.caps
= new_caps
;
1242 err
= add_entity(auth_inc
.name
, new_inc
);
1245 ss
<< "added key for " << auth_inc
.name
;
1247 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1248 get_last_committed() + 1));
1250 } else if ((prefix
== "auth get-or-create-key" ||
1251 prefix
== "auth get-or-create") &&
1252 !entity_name
.empty()) {
1253 // auth get-or-create <name> [mon osdcapa osd osdcapb ...]
1255 if (!valid_caps(caps_vec
, &ss
)) {
1260 // Parse the list of caps into a map
1261 std::map
<std::string
, bufferlist
> wanted_caps
;
1262 for (vector
<string
>::const_iterator it
= caps_vec
.begin();
1263 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1265 const std::string
&sys
= *it
;
1267 ::encode(*(it
+1), cap
);
1268 wanted_caps
[sys
] = cap
;
1272 EntityAuth entity_auth
;
1273 if (mon
->key_server
.get_auth(entity
, entity_auth
)) {
1274 for (const auto &sys_cap
: wanted_caps
) {
1275 if (entity_auth
.caps
.count(sys_cap
.first
) == 0 ||
1276 !entity_auth
.caps
[sys_cap
.first
].contents_equal(sys_cap
.second
)) {
1277 ss
<< "key for " << entity
<< " exists but cap " << sys_cap
.first
1278 << " does not match";
1284 if (prefix
== "auth get-or-create-key") {
1286 entity_auth
.key
.encode_formatted("auth", f
.get(), rdata
);
1288 ds
<< entity_auth
.key
;
1292 kr
.add(entity
, entity_auth
.key
);
1294 kr
.set_caps(entity
, entity_auth
.caps
);
1295 kr
.encode_formatted("auth", f
.get(), rdata
);
1297 kr
.encode_plaintext(rdata
);
1304 // ...or are we about to?
1305 for (vector
<Incremental
>::iterator p
= pending_auth
.begin();
1306 p
!= pending_auth
.end();
1308 if (p
->inc_type
== AUTH_DATA
) {
1309 KeyServerData::Incremental auth_inc
;
1310 bufferlist::iterator q
= p
->auth_data
.begin();
1311 ::decode(auth_inc
, q
);
1312 if (auth_inc
.op
== KeyServerData::AUTH_INC_ADD
&&
1313 auth_inc
.name
== entity
) {
1314 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1315 get_last_committed() + 1));
1322 KeyServerData::Incremental auth_inc
;
1323 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1324 auth_inc
.name
= entity
;
1325 auth_inc
.auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1326 auth_inc
.auth
.caps
= wanted_caps
;
1328 push_cephx_inc(auth_inc
);
1330 if (prefix
== "auth get-or-create-key") {
1332 auth_inc
.auth
.key
.encode_formatted("auth", f
.get(), rdata
);
1334 ds
<< auth_inc
.auth
.key
;
1338 kr
.add(entity
, auth_inc
.auth
.key
);
1340 kr
.set_caps(entity
, wanted_caps
);
1341 kr
.encode_formatted("auth", f
.get(), rdata
);
1343 kr
.encode_plaintext(rdata
);
1349 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
, rdata
,
1350 get_last_committed() + 1));
1352 } else if (prefix
== "fs authorize") {
1354 cmd_getval_throws(g_ceph_context
, cmdmap
, "filesystem", filesystem
);
1355 string mds_cap_string
, osd_cap_string
;
1356 string osd_cap_wanted
= "r";
1358 if (!valid_caps(caps_vec
, &ss
)) {
1363 for (auto it
= caps_vec
.begin();
1364 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1366 const string
&path
= *it
;
1367 const string
&cap
= *(it
+1);
1368 if (cap
!= "r" && cap
!= "rw" && cap
!= "rwp") {
1369 ss
<< "Only 'r', 'rw', and 'rwp' permissions are allowed for filesystems.";
1373 if (cap
.find('w') != string::npos
) {
1374 osd_cap_wanted
= "rw";
1377 mds_cap_string
+= mds_cap_string
.empty() ? "" : ", ";
1378 mds_cap_string
+= "allow " + cap
;
1380 mds_cap_string
+= " path=" + path
;
1384 auto fs
= mon
->mdsmon()->get_fsmap().get_filesystem(filesystem
);
1386 ss
<< "filesystem " << filesystem
<< " does not exist.";
1391 auto data_pools
= fs
->mds_map
.get_data_pools();
1392 for (auto p
: data_pools
) {
1393 const string
&pool_name
= mon
->osdmon()->osdmap
.get_pool_name(p
);
1394 osd_cap_string
+= osd_cap_string
.empty() ? "" : ", ";
1395 osd_cap_string
+= "allow " + osd_cap_wanted
+ " pool=" + pool_name
;
1398 std::map
<string
, bufferlist
> wanted_caps
= {
1399 { "mon", _encode_cap("allow r") },
1400 { "osd", _encode_cap(osd_cap_string
) },
1401 { "mds", _encode_cap(mds_cap_string
) }
1404 EntityAuth entity_auth
;
1405 if (mon
->key_server
.get_auth(entity
, entity_auth
)) {
1406 for (const auto &sys_cap
: wanted_caps
) {
1407 if (entity_auth
.caps
.count(sys_cap
.first
) == 0 ||
1408 !entity_auth
.caps
[sys_cap
.first
].contents_equal(sys_cap
.second
)) {
1409 ss
<< entity
<< " already has fs capabilities that differ from those supplied. To generate a new auth key for "
1410 << entity
<< ", first remove " << entity
<< " from configuration files, execute 'ceph auth rm " << entity
<< "', then execute this command again.";
1417 kr
.add(entity
, entity_auth
.key
);
1419 kr
.set_caps(entity
, entity_auth
.caps
);
1420 kr
.encode_formatted("auth", f
.get(), rdata
);
1422 kr
.encode_plaintext(rdata
);
1428 KeyServerData::Incremental auth_inc
;
1429 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1430 auth_inc
.name
= entity
;
1431 auth_inc
.auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1432 auth_inc
.auth
.caps
= wanted_caps
;
1434 push_cephx_inc(auth_inc
);
1436 kr
.add(entity
, auth_inc
.auth
.key
);
1438 kr
.set_caps(entity
, wanted_caps
);
1439 kr
.encode_formatted("auth", f
.get(), rdata
);
1441 kr
.encode_plaintext(rdata
);
1446 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
, rdata
,
1447 get_last_committed() + 1));
1449 } else if (prefix
== "auth caps" && !entity_name
.empty()) {
1450 KeyServerData::Incremental auth_inc
;
1451 auth_inc
.name
= entity
;
1452 if (!mon
->key_server
.get_auth(auth_inc
.name
, auth_inc
.auth
)) {
1453 ss
<< "couldn't find entry " << auth_inc
.name
;
1458 if (!valid_caps(caps_vec
, &ss
)) {
1463 map
<string
,bufferlist
> newcaps
;
1464 for (vector
<string
>::iterator it
= caps_vec
.begin();
1465 it
!= caps_vec
.end(); it
+= 2)
1466 ::encode(*(it
+1), newcaps
[*it
]);
1468 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1469 auth_inc
.auth
.caps
= newcaps
;
1470 push_cephx_inc(auth_inc
);
1472 ss
<< "updated caps for " << auth_inc
.name
;
1474 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1475 get_last_committed() + 1));
1477 } else if ((prefix
== "auth del" || prefix
== "auth rm") &&
1478 !entity_name
.empty()) {
1479 KeyServerData::Incremental auth_inc
;
1480 auth_inc
.name
= entity
;
1481 if (!mon
->key_server
.contains(auth_inc
.name
)) {
1482 ss
<< "entity " << entity
<< " does not exist";
1486 auth_inc
.op
= KeyServerData::AUTH_INC_DEL
;
1487 push_cephx_inc(auth_inc
);
1491 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1492 get_last_committed() + 1));
1497 getline(ss
, rs
, '\0');
1498 mon
->reply_command(op
, err
, rs
, rdata
, get_last_committed());
1502 bool AuthMonitor::prepare_global_id(MonOpRequestRef op
)
1504 dout(10) << "AuthMonitor::prepare_global_id" << dendl
;
1505 increase_max_global_id();
1510 void AuthMonitor::upgrade_format()
1512 unsigned int current
= 2;
1513 if (!mon
->get_quorum_mon_features().contains_all(
1514 ceph::features::mon::FEATURE_LUMINOUS
)) {
1517 if (format_version
>= current
) {
1518 dout(20) << __func__
<< " format " << format_version
<< " is current" << dendl
;
1522 bool changed
= false;
1523 if (format_version
== 0) {
1524 dout(1) << __func__
<< " upgrading from format 0 to 1" << dendl
;
1525 map
<EntityName
, EntityAuth
>::iterator p
;
1526 for (p
= mon
->key_server
.secrets_begin();
1527 p
!= mon
->key_server
.secrets_end();
1529 // grab mon caps, if any
1531 if (p
->second
.caps
.count("mon") == 0)
1534 bufferlist::iterator it
= p
->second
.caps
["mon"].begin();
1535 ::decode(mon_caps
, it
);
1537 catch (buffer::error
) {
1538 dout(10) << __func__
<< " unable to parse mon cap for "
1539 << p
->first
<< dendl
;
1543 string n
= p
->first
.to_str();
1546 // set daemon profiles
1547 if ((p
->first
.is_osd() || p
->first
.is_mds()) &&
1548 mon_caps
== "allow rwx") {
1549 new_caps
= string("allow profile ") + string(p
->first
.get_type_name());
1552 // update bootstrap keys
1553 if (n
== "client.bootstrap-osd") {
1554 new_caps
= "allow profile bootstrap-osd";
1556 if (n
== "client.bootstrap-mds") {
1557 new_caps
= "allow profile bootstrap-mds";
1560 if (new_caps
.length() > 0) {
1561 dout(5) << __func__
<< " updating " << p
->first
<< " mon cap from "
1562 << mon_caps
<< " to " << new_caps
<< dendl
;
1565 ::encode(new_caps
, bl
);
1567 KeyServerData::Incremental auth_inc
;
1568 auth_inc
.name
= p
->first
;
1569 auth_inc
.auth
= p
->second
;
1570 auth_inc
.auth
.caps
["mon"] = bl
;
1571 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1572 push_cephx_inc(auth_inc
);
1578 if (format_version
== 1) {
1579 dout(1) << __func__
<< " upgrading from format 1 to 2" << dendl
;
1580 map
<EntityName
, EntityAuth
>::iterator p
;
1581 for (p
= mon
->key_server
.secrets_begin();
1582 p
!= mon
->key_server
.secrets_end();
1584 string n
= p
->first
.to_str();
1587 if (n
== "client.admin") {
1588 // admin gets it all
1590 } else if (n
.find("osd.") == 0 ||
1591 n
.find("mds.") == 0 ||
1592 n
.find("mon.") == 0) {
1593 // daemons follow their profile
1594 string type
= n
.substr(0, 3);
1595 newcap
= "allow profile " + type
;
1596 } else if (p
->second
.caps
.count("mon")) {
1597 // if there are any mon caps, give them 'r' mgr caps
1601 if (newcap
.length() > 0) {
1602 dout(5) << " giving " << n
<< " mgr '" << newcap
<< "'" << dendl
;
1604 ::encode(newcap
, bl
);
1606 KeyServerData::Incremental auth_inc
;
1607 auth_inc
.name
= p
->first
;
1608 auth_inc
.auth
= p
->second
;
1609 auth_inc
.auth
.caps
["mgr"] = bl
;
1610 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1611 push_cephx_inc(auth_inc
);
1614 if (n
.find("mgr.") == 0 &&
1615 p
->second
.caps
.count("mon")) {
1616 // the kraken ceph-mgr@.service set the mon cap to 'allow *'.
1617 auto blp
= p
->second
.caps
["mon"].begin();
1619 ::decode(oldcaps
, blp
);
1620 if (oldcaps
== "allow *") {
1621 dout(5) << " fixing " << n
<< " mon cap to 'allow profile mgr'"
1624 ::encode("allow profile mgr", bl
);
1625 KeyServerData::Incremental auth_inc
;
1626 auth_inc
.name
= p
->first
;
1627 auth_inc
.auth
= p
->second
;
1628 auth_inc
.auth
.caps
["mon"] = bl
;
1629 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1630 push_cephx_inc(auth_inc
);
1635 // add bootstrap key if it does not already exist
1636 // (might have already been get-or-create'd by
1637 // ceph-create-keys)
1638 EntityName bootstrap_mgr_name
;
1639 int r
= bootstrap_mgr_name
.from_str("client.bootstrap-mgr");
1641 if (!mon
->key_server
.contains(bootstrap_mgr_name
)) {
1642 KeyServerData::Incremental auth_inc
;
1643 auth_inc
.name
= bootstrap_mgr_name
;
1644 ::encode("allow profile bootstrap-mgr", auth_inc
.auth
.caps
["mon"]);
1645 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1647 auth_inc
.auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1648 push_cephx_inc(auth_inc
);
1655 dout(10) << __func__
<< " proposing update from format " << format_version
1656 << " -> " << current
<< dendl
;
1657 format_version
= current
;
1662 void AuthMonitor::dump_info(Formatter
*f
)
1664 /*** WARNING: do not include any privileged information here! ***/
1665 f
->open_object_section("auth");
1666 f
->dump_unsigned("first_committed", get_first_committed());
1667 f
->dump_unsigned("last_committed", get_last_committed());
1668 f
->dump_unsigned("num_secrets", mon
->key_server
.get_num_secrets());