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"
23 #include "mon/ConfigMonitor.h"
25 #include "messages/MMonCommand.h"
26 #include "messages/MAuth.h"
27 #include "messages/MAuthReply.h"
28 #include "messages/MMonGlobalID.h"
29 #include "msg/Messenger.h"
31 #include "auth/AuthServiceHandler.h"
32 #include "auth/KeyRing.h"
33 #include "include/stringify.h"
34 #include "include/ceph_assert.h"
36 #include "mds/MDSAuthCaps.h"
37 #include "osd/OSDCap.h"
39 #define dout_subsys ceph_subsys_mon
41 #define dout_prefix _prefix(_dout, mon, get_last_committed())
42 static ostream
& _prefix(std::ostream
*_dout
, Monitor
*mon
, version_t v
) {
43 return *_dout
<< "mon." << mon
->name
<< "@" << mon
->rank
44 << "(" << mon
->get_state_name()
45 << ").auth v" << v
<< " ";
48 ostream
& operator<<(ostream
&out
, const AuthMonitor
&pm
)
53 bool AuthMonitor::check_rotate()
55 KeyServerData::Incremental rot_inc
;
56 rot_inc
.op
= KeyServerData::AUTH_INC_SET_ROTATING
;
57 if (!mon
->key_server
.updated_rotating(rot_inc
.rotating_bl
, last_rotating_ver
))
59 dout(10) << __func__
<< " updated rotating" << dendl
;
60 push_cephx_inc(rot_inc
);
65 Tick function to update the map based on performance every N seconds
68 void AuthMonitor::tick()
70 if (!is_active()) return;
72 dout(10) << *this << dendl
;
74 // increase global_id?
78 std::lock_guard
l(mon
->auth_lock
);
79 increase
= _should_increase_max_global_id();
82 if (mon
->is_leader()) {
83 increase_max_global_id();
86 dout(10) << __func__
<< "requesting more ids from leader" << dendl
;
87 int leader
= mon
->get_leader();
88 MMonGlobalID
*req
= new MMonGlobalID();
89 req
->old_max_id
= max_global_id
;
90 mon
->send_mon_message(req
, leader
);
94 if (!mon
->is_leader()) {
107 void AuthMonitor::on_active()
109 dout(10) << "AuthMonitor::on_active()" << dendl
;
111 if (!mon
->is_leader())
113 mon
->key_server
.start_server();
117 std::lock_guard
l(mon
->auth_lock
);
118 increase
= _should_increase_max_global_id();
120 if (is_writeable() && increase
) {
121 increase_max_global_id();
126 bufferlist
_encode_cap(const string
& cap
)
133 void AuthMonitor::get_initial_keyring(KeyRing
*keyring
)
135 dout(10) << __func__
<< dendl
;
136 ceph_assert(keyring
!= nullptr);
139 int ret
= mon
->store
->get("mkfs", "keyring", bl
);
140 if (ret
== -ENOENT
) {
143 // fail hard only if there's an error we're not expecting to see
144 ceph_assert(ret
== 0);
146 auto p
= bl
.cbegin();
150 void _generate_bootstrap_keys(
151 list
<pair
<EntityName
,EntityAuth
> >* auth_lst
)
153 ceph_assert(auth_lst
!= nullptr);
155 map
<string
,map
<string
,bufferlist
> > bootstrap
= {
157 { "mon", _encode_cap("allow *") },
158 { "osd", _encode_cap("allow *") },
159 { "mds", _encode_cap("allow *") },
160 { "mgr", _encode_cap("allow *") }
163 { "mon", _encode_cap("allow profile bootstrap-osd") }
166 { "mon", _encode_cap("allow profile bootstrap-rgw") }
169 { "mon", _encode_cap("allow profile bootstrap-mds") }
172 { "mon", _encode_cap("allow profile bootstrap-mgr") }
175 { "mon", _encode_cap("allow profile bootstrap-rbd") }
177 { "bootstrap-rbd-mirror", {
178 { "mon", _encode_cap("allow profile bootstrap-rbd-mirror") }
182 for (auto &p
: bootstrap
) {
184 name
.from_str("client." + p
.first
);
186 auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
187 auth
.caps
= p
.second
;
189 auth_lst
->push_back(make_pair(name
, auth
));
193 void AuthMonitor::create_initial_keys(KeyRing
*keyring
)
195 dout(10) << __func__
<< " with keyring" << dendl
;
196 ceph_assert(keyring
!= nullptr);
198 list
<pair
<EntityName
,EntityAuth
> > auth_lst
;
199 _generate_bootstrap_keys(&auth_lst
);
201 for (auto &p
: auth_lst
) {
202 if (keyring
->exists(p
.first
)) {
205 keyring
->add(p
.first
, p
.second
);
209 void AuthMonitor::create_initial()
211 dout(10) << "create_initial -- creating initial map" << dendl
;
213 // initialize rotating keys
214 mon
->key_server
.clear_secrets();
215 last_rotating_ver
= 0;
217 ceph_assert(pending_auth
.size() == 1);
219 if (mon
->is_keyring_required()) {
221 // attempt to obtain an existing mkfs-time keyring
222 get_initial_keyring(&keyring
);
223 // create missing keys in the keyring
224 create_initial_keys(&keyring
);
225 // import the resulting keyring
226 import_keyring(keyring
);
229 max_global_id
= MIN_GLOBAL_ID
;
232 inc
.inc_type
= GLOBAL_ID
;
233 inc
.max_global_id
= max_global_id
;
234 pending_auth
.push_back(inc
);
239 void AuthMonitor::update_from_paxos(bool *need_bootstrap
)
241 dout(10) << __func__
<< dendl
;
244 version_t version
= get_last_committed();
245 version_t keys_ver
= mon
->key_server
.get_ver();
246 if (version
== keys_ver
)
248 ceph_assert(version
> keys_ver
);
250 version_t latest_full
= get_version_latest_full();
252 dout(10) << __func__
<< " version " << version
<< " keys ver " << keys_ver
253 << " latest " << latest_full
<< dendl
;
255 if ((latest_full
> 0) && (latest_full
> keys_ver
)) {
256 bufferlist latest_bl
;
257 int err
= get_version_full(latest_full
, latest_bl
);
258 ceph_assert(err
== 0);
259 ceph_assert(latest_bl
.length() != 0);
260 dout(7) << __func__
<< " loading summary e " << latest_full
<< dendl
;
261 dout(7) << __func__
<< " latest length " << latest_bl
.length() << dendl
;
262 auto p
= latest_bl
.cbegin();
265 decode(max_global_id
, p
);
266 decode(mon
->key_server
, p
);
267 mon
->key_server
.set_ver(latest_full
);
268 keys_ver
= latest_full
;
271 dout(10) << __func__
<< " key server version " << mon
->key_server
.get_ver() << dendl
;
273 // walk through incrementals
274 while (version
> keys_ver
) {
276 int ret
= get_version(keys_ver
+1, bl
);
277 ceph_assert(ret
== 0);
278 ceph_assert(bl
.length());
280 // reset if we are moving to initial state. we will normally have
281 // keys in here temporarily for bootstrapping that we need to
284 mon
->key_server
.clear_secrets();
286 dout(20) << __func__
<< " walking through version " << (keys_ver
+1)
287 << " len " << bl
.length() << dendl
;
289 auto p
= bl
.cbegin();
295 switch (inc
.inc_type
) {
297 max_global_id
= inc
.max_global_id
;
302 KeyServerData::Incremental auth_inc
;
303 auto iter
= inc
.auth_data
.cbegin();
304 decode(auth_inc
, iter
);
305 mon
->key_server
.apply_data_incremental(auth_inc
);
312 mon
->key_server
.set_ver(keys_ver
);
314 if (keys_ver
== 1 && mon
->is_keyring_required()) {
315 auto t(std::make_shared
<MonitorDBStore::Transaction
>());
316 t
->erase("mkfs", "keyring");
317 mon
->store
->apply_transaction(t
);
322 std::lock_guard
l(mon
->auth_lock
);
323 if (last_allocated_id
== 0) {
324 last_allocated_id
= max_global_id
;
325 dout(10) << __func__
<< " last_allocated_id initialized to "
326 << max_global_id
<< dendl
;
330 dout(10) << __func__
<< " max_global_id=" << max_global_id
331 << " format_version " << format_version
335 bool AuthMonitor::_should_increase_max_global_id()
337 ceph_assert(ceph_mutex_is_locked(mon
->auth_lock
));
338 auto num_prealloc
= g_conf()->mon_globalid_prealloc
;
339 if (max_global_id
< num_prealloc
||
340 (last_allocated_id
+ 1) >= max_global_id
- num_prealloc
/ 2) {
346 void AuthMonitor::increase_max_global_id()
348 ceph_assert(mon
->is_leader());
351 inc
.inc_type
= GLOBAL_ID
;
352 inc
.max_global_id
= max_global_id
+ g_conf()->mon_globalid_prealloc
;
353 dout(10) << "increasing max_global_id to " << inc
.max_global_id
<< dendl
;
354 pending_auth
.push_back(inc
);
357 bool AuthMonitor::should_propose(double& delay
)
359 return (!pending_auth
.empty());
362 void AuthMonitor::create_pending()
364 pending_auth
.clear();
365 dout(10) << "create_pending v " << (get_last_committed() + 1) << dendl
;
368 void AuthMonitor::encode_pending(MonitorDBStore::TransactionRef t
)
370 dout(10) << __func__
<< " v " << (get_last_committed() + 1) << dendl
;
376 vector
<Incremental
>::iterator p
;
377 for (p
= pending_auth
.begin(); p
!= pending_auth
.end(); ++p
)
378 p
->encode(bl
, mon
->get_quorum_con_features());
380 version_t version
= get_last_committed() + 1;
381 put_version(t
, version
, bl
);
382 put_last_committed(t
, version
);
385 health_check_map_t next
;
386 map
<string
,list
<string
>> bad_detail
; // entity -> details
387 for (auto i
= mon
->key_server
.secrets_begin();
388 i
!= mon
->key_server
.secrets_end();
390 for (auto& p
: i
->second
.caps
) {
392 if (!valid_caps(p
.first
, p
.second
, &ss
)) {
394 ss2
<< i
->first
<< " " << ss
.str();
395 bad_detail
[i
->first
.to_str()].push_back(ss2
.str());
399 for (auto& inc
: pending_auth
) {
400 if (inc
.inc_type
== AUTH_DATA
) {
401 KeyServerData::Incremental auth_inc
;
402 auto iter
= inc
.auth_data
.cbegin();
403 decode(auth_inc
, iter
);
404 if (auth_inc
.op
== KeyServerData::AUTH_INC_DEL
) {
405 bad_detail
.erase(auth_inc
.name
.to_str());
406 } else if (auth_inc
.op
== KeyServerData::AUTH_INC_ADD
) {
407 for (auto& p
: auth_inc
.auth
.caps
) {
409 if (!valid_caps(p
.first
, p
.second
, &ss
)) {
411 ss2
<< auth_inc
.name
<< " " << ss
.str();
412 bad_detail
[auth_inc
.name
.to_str()].push_back(ss2
.str());
418 if (bad_detail
.size()) {
420 ss
<< bad_detail
.size() << " auth entities have invalid capabilities";
421 health_check_t
*check
= &next
.add("AUTH_BAD_CAPS", HEALTH_ERR
, ss
.str());
422 for (auto& i
: bad_detail
) {
423 for (auto& j
: i
.second
) {
424 check
->detail
.push_back(j
);
428 encode_health(next
, t
);
431 void AuthMonitor::encode_full(MonitorDBStore::TransactionRef t
)
433 version_t version
= mon
->key_server
.get_ver();
434 // do not stash full version 0 as it will never be removed nor read
438 dout(10) << __func__
<< " auth v " << version
<< dendl
;
439 ceph_assert(get_last_committed() == version
);
442 std::scoped_lock l
{mon
->key_server
.get_lock()};
443 dout(20) << __func__
<< " key server has "
444 << (mon
->key_server
.has_secrets() ? "" : "no ")
445 << "secrets!" << dendl
;
448 encode(max_global_id
, full_bl
);
449 encode(mon
->key_server
, full_bl
);
451 put_version_full(t
, version
, full_bl
);
452 put_version_latest_full(t
, version
);
455 version_t
AuthMonitor::get_trim_to() const
457 unsigned max
= g_conf()->paxos_max_join_drift
* 2;
458 version_t version
= get_last_committed();
459 if (mon
->is_leader() && (version
> max
))
460 return version
- max
;
464 bool AuthMonitor::preprocess_query(MonOpRequestRef op
)
466 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
467 dout(10) << "preprocess_query " << *m
<< " from " << m
->get_orig_source_inst() << dendl
;
468 switch (m
->get_type()) {
469 case MSG_MON_COMMAND
:
471 return preprocess_command(op
);
472 } catch (const bad_cmd_get
& e
) {
474 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
479 return prep_auth(op
, false);
481 case MSG_MON_GLOBAL_ID
:
490 bool AuthMonitor::prepare_update(MonOpRequestRef op
)
492 PaxosServiceMessage
*m
= static_cast<PaxosServiceMessage
*>(op
->get_req());
493 dout(10) << "prepare_update " << *m
<< " from " << m
->get_orig_source_inst() << dendl
;
494 switch (m
->get_type()) {
495 case MSG_MON_COMMAND
:
497 return prepare_command(op
);
498 } catch (const bad_cmd_get
& e
) {
500 mon
->reply_command(op
, -EINVAL
, e
.what(), bl
, get_last_committed());
503 case MSG_MON_GLOBAL_ID
:
504 return prepare_global_id(op
);
506 return prep_auth(op
, true);
513 void AuthMonitor::_set_mon_num_rank(int num
, int rank
)
515 dout(10) << __func__
<< " num " << num
<< " rank " << rank
<< dendl
;
516 ceph_assert(ceph_mutex_is_locked(mon
->auth_lock
));
521 uint64_t AuthMonitor::_assign_global_id()
523 ceph_assert(ceph_mutex_is_locked(mon
->auth_lock
));
524 if (mon_num
< 1 || mon_rank
< 0) {
525 dout(10) << __func__
<< " inactive (num_mon " << mon_num
526 << " rank " << mon_rank
<< ")" << dendl
;
529 if (!last_allocated_id
) {
530 dout(10) << __func__
<< " last_allocated_id == 0" << dendl
;
534 uint64_t id
= last_allocated_id
+ 1;
535 int remainder
= id
% mon_num
;
537 remainder
= mon_num
- remainder
;
539 id
+= remainder
+ mon_rank
;
541 if (id
>= max_global_id
) {
542 dout(10) << __func__
<< " failed (max " << max_global_id
<< ")" << dendl
;
546 last_allocated_id
= id
;
547 dout(10) << __func__
<< " " << id
<< " (max " << max_global_id
<< ")"
552 uint64_t AuthMonitor::assign_global_id(bool should_increase_max
)
556 std::lock_guard
l(mon
->auth_lock
);
557 id
=_assign_global_id();
558 if (should_increase_max
) {
559 should_increase_max
= _should_increase_max_global_id();
562 if (mon
->is_leader() &&
563 should_increase_max
) {
564 increase_max_global_id();
569 bool AuthMonitor::prep_auth(MonOpRequestRef op
, bool paxos_writable
)
571 MAuth
*m
= static_cast<MAuth
*>(op
->get_req());
572 dout(10) << "prep_auth() blob_size=" << m
->get_auth_payload().length() << dendl
;
574 MonSession
*s
= op
->get_session();
576 dout(10) << "no session, dropping" << dendl
;
582 bufferlist response_bl
;
583 auto indata
= m
->auth_payload
.cbegin();
584 __u32 proto
= m
->protocol
;
586 bool finished
= false;
587 EntityName entity_name
;
590 if (m
->protocol
== 0 && !s
->auth_handler
) {
591 set
<__u32
> supported
;
595 decode(struct_v
, indata
);
596 decode(supported
, indata
);
597 decode(entity_name
, indata
);
598 decode(s
->con
->peer_global_id
, indata
);
599 } catch (const buffer::error
&e
) {
600 dout(10) << "failed to decode initial auth message" << dendl
;
605 // do we require cephx signatures?
607 if (!m
->get_connection()->has_feature(CEPH_FEATURE_MSG_AUTH
)) {
608 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
609 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
610 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
611 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
) {
612 if (g_conf()->cephx_cluster_require_signatures
||
613 g_conf()->cephx_require_signatures
) {
614 dout(1) << m
->get_source_inst()
615 << " supports cephx but not signatures and"
616 << " 'cephx [cluster] require signatures = true';"
617 << " disallowing cephx" << dendl
;
618 supported
.erase(CEPH_AUTH_CEPHX
);
621 if (g_conf()->cephx_service_require_signatures
||
622 g_conf()->cephx_require_signatures
) {
623 dout(1) << m
->get_source_inst()
624 << " supports cephx but not signatures and"
625 << " 'cephx [service] require signatures = true';"
626 << " disallowing cephx" << dendl
;
627 supported
.erase(CEPH_AUTH_CEPHX
);
630 } else if (!m
->get_connection()->has_feature(CEPH_FEATURE_CEPHX_V2
)) {
631 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
632 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
633 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
634 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
) {
635 if (g_conf()->cephx_cluster_require_version
>= 2 ||
636 g_conf()->cephx_require_version
>= 2) {
637 dout(1) << m
->get_source_inst()
638 << " supports cephx but not v2 and"
639 << " 'cephx [cluster] require version >= 2';"
640 << " disallowing cephx" << dendl
;
641 supported
.erase(CEPH_AUTH_CEPHX
);
644 if (g_conf()->cephx_service_require_version
>= 2 ||
645 g_conf()->cephx_require_version
>= 2) {
646 dout(1) << m
->get_source_inst()
647 << " supports cephx but not v2 and"
648 << " 'cephx [service] require version >= 2';"
649 << " disallowing cephx" << dendl
;
650 supported
.erase(CEPH_AUTH_CEPHX
);
656 if (entity_name
.get_type() == CEPH_ENTITY_TYPE_MON
||
657 entity_name
.get_type() == CEPH_ENTITY_TYPE_OSD
||
658 entity_name
.get_type() == CEPH_ENTITY_TYPE_MDS
||
659 entity_name
.get_type() == CEPH_ENTITY_TYPE_MGR
)
660 type
= mon
->auth_cluster_required
.pick(supported
);
662 type
= mon
->auth_service_required
.pick(supported
);
664 s
->auth_handler
= get_auth_service_handler(type
, g_ceph_context
, &mon
->key_server
);
665 if (!s
->auth_handler
) {
666 dout(1) << "client did not provide supported auth type" << dendl
;
672 } else if (!s
->auth_handler
) {
673 dout(10) << "protocol specified but no s->auth_handler" << dendl
;
678 /* assign a new global_id? we assume this should only happen on the first
679 request. If a client tries to send it later, it'll screw up its auth
681 if (!s
->con
->peer_global_id
) {
682 s
->con
->peer_global_id
= assign_global_id(paxos_writable
);
683 if (!s
->con
->peer_global_id
) {
685 delete s
->auth_handler
;
686 s
->auth_handler
= NULL
;
688 if (mon
->is_leader() && paxos_writable
) {
689 dout(10) << "increasing global id, waitlisting message" << dendl
;
690 wait_for_active(op
, new C_RetryMessage(this, op
));
694 if (!mon
->is_leader()) {
695 dout(10) << "not the leader, requesting more ids from leader" << dendl
;
696 int leader
= mon
->get_leader();
697 MMonGlobalID
*req
= new MMonGlobalID();
698 req
->old_max_id
= max_global_id
;
699 mon
->send_mon_message(req
, leader
);
700 wait_for_finished_proposal(op
, new C_RetryMessage(this, op
));
704 ceph_assert(!paxos_writable
);
712 ret
= s
->auth_handler
->start_session(entity_name
,
713 0, // no connection_secret needed
715 &s
->con
->peer_caps_info
,
719 ret
= s
->auth_handler
->handle_request(
721 0, // no connection_secret needed
723 &s
->con
->peer_global_id
,
724 &s
->con
->peer_caps_info
,
728 wait_for_active(op
, new C_RetryMessage(this,op
));
732 if (!s
->authenticated
&&
733 mon
->ms_handle_authentication(s
->con
.get()) > 0) {
738 } catch (const buffer::error
&err
) {
740 dout(0) << "caught error when trying to handle auth request, probably malformed request" << dendl
;
744 reply
= new MAuthReply(proto
, &response_bl
, ret
, s
->con
->peer_global_id
);
745 mon
->send_reply(op
, reply
);
747 // always send the latest monmap.
748 if (m
->monmap_epoch
< mon
->monmap
->get_epoch())
749 mon
->send_latest_monmap(m
->get_connection().get());
751 mon
->configmon()->check_sub(s
);
757 bool AuthMonitor::preprocess_command(MonOpRequestRef op
)
759 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
765 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
766 // ss has reason for failure
767 string rs
= ss
.str();
768 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
773 cmd_getval(g_ceph_context
, cmdmap
, "prefix", prefix
);
774 if (prefix
== "auth add" ||
775 prefix
== "auth del" ||
776 prefix
== "auth rm" ||
777 prefix
== "auth get-or-create" ||
778 prefix
== "auth get-or-create-key" ||
779 prefix
== "fs authorize" ||
780 prefix
== "auth import" ||
781 prefix
== "auth caps") {
785 MonSession
*session
= op
->get_session();
787 mon
->reply_command(op
, -EACCES
, "access denied", rdata
, get_last_committed());
791 // entity might not be supplied, but if it is, it should be valid
793 cmd_getval(g_ceph_context
, cmdmap
, "entity", entity_name
);
795 if (!entity_name
.empty() && !entity
.from_str(entity_name
)) {
796 ss
<< "invalid entity_auth " << entity_name
;
797 mon
->reply_command(op
, -EINVAL
, ss
.str(), get_last_committed());
802 cmd_getval(g_ceph_context
, cmdmap
, "format", format
, string("plain"));
803 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
805 if (prefix
== "auth export") {
807 export_keyring(keyring
);
808 if (!entity_name
.empty()) {
810 if (keyring
.get_auth(entity
, eauth
)) {
812 kr
.add(entity
, eauth
);
814 kr
.encode_formatted("auth", f
.get(), rdata
);
816 kr
.encode_plaintext(rdata
);
817 ss
<< "export " << eauth
;
820 ss
<< "no key for " << eauth
;
825 keyring
.encode_formatted("auth", f
.get(), rdata
);
827 keyring
.encode_plaintext(rdata
);
829 ss
<< "exported master keyring";
832 } else if (prefix
== "auth get" && !entity_name
.empty()) {
834 EntityAuth entity_auth
;
835 if(!mon
->key_server
.get_auth(entity
, entity_auth
)) {
836 ss
<< "failed to find " << entity_name
<< " in keyring";
839 keyring
.add(entity
, entity_auth
);
841 keyring
.encode_formatted("auth", f
.get(), rdata
);
843 keyring
.encode_plaintext(rdata
);
844 ss
<< "exported keyring for " << entity_name
;
847 } else if (prefix
== "auth print-key" ||
848 prefix
== "auth print_key" ||
849 prefix
== "auth get-key") {
851 if (!mon
->key_server
.get_auth(entity
, auth
)) {
852 ss
<< "don't have " << entity
;
857 auth
.key
.encode_formatted("auth", f
.get(), rdata
);
859 auth
.key
.encode_plaintext(rdata
);
862 } else if (prefix
== "auth list" ||
863 prefix
== "auth ls") {
865 mon
->key_server
.encode_formatted("auth", f
.get(), rdata
);
867 mon
->key_server
.encode_plaintext(rdata
);
868 if (rdata
.length() > 0)
869 ss
<< "installed auth entries:" << std::endl
;
871 ss
<< "no installed auth entries!" << std::endl
;
876 ss
<< "invalid command";
883 getline(ss
, rs
, '\0');
884 mon
->reply_command(op
, r
, rs
, rdata
, get_last_committed());
888 void AuthMonitor::export_keyring(KeyRing
& keyring
)
890 mon
->key_server
.export_keyring(keyring
);
893 int AuthMonitor::import_keyring(KeyRing
& keyring
)
895 dout(10) << __func__
<< " " << keyring
.size() << " keys" << dendl
;
897 for (map
<EntityName
, EntityAuth
>::iterator p
= keyring
.get_keys().begin();
898 p
!= keyring
.get_keys().end();
900 if (p
->second
.caps
.empty()) {
901 dout(0) << "import: no caps supplied" << dendl
;
904 int err
= add_entity(p
->first
, p
->second
);
905 ceph_assert(err
== 0);
910 int AuthMonitor::remove_entity(const EntityName
&entity
)
912 dout(10) << __func__
<< " " << entity
<< dendl
;
913 if (!mon
->key_server
.contains(entity
))
916 KeyServerData::Incremental auth_inc
;
917 auth_inc
.name
= entity
;
918 auth_inc
.op
= KeyServerData::AUTH_INC_DEL
;
919 push_cephx_inc(auth_inc
);
924 bool AuthMonitor::entity_is_pending(EntityName
& entity
)
926 // are we about to have it?
927 for (auto& p
: pending_auth
) {
928 if (p
.inc_type
== AUTH_DATA
) {
929 KeyServerData::Incremental inc
;
930 auto q
= p
.auth_data
.cbegin();
932 if (inc
.op
== KeyServerData::AUTH_INC_ADD
&&
933 inc
.name
== entity
) {
941 int AuthMonitor::exists_and_matches_entity(
942 const auth_entity_t
& entity
,
946 return exists_and_matches_entity(entity
.name
, entity
.auth
,
947 entity
.auth
.caps
, has_secret
, ss
);
950 int AuthMonitor::exists_and_matches_entity(
951 const EntityName
& name
,
952 const EntityAuth
& auth
,
953 const map
<string
,bufferlist
>& caps
,
958 dout(20) << __func__
<< " entity " << name
<< " auth " << auth
959 << " caps " << caps
<< " has_secret " << has_secret
<< dendl
;
961 EntityAuth existing_auth
;
962 // does entry already exist?
963 if (mon
->key_server
.get_auth(name
, existing_auth
)) {
966 if (existing_auth
.key
.get_secret().cmp(auth
.key
.get_secret())) {
967 ss
<< "entity " << name
<< " exists but key does not match";
973 if (caps
.size() != existing_auth
.caps
.size()) {
974 ss
<< "entity " << name
<< " exists but caps do not match";
977 for (auto& it
: caps
) {
978 if (existing_auth
.caps
.count(it
.first
) == 0 ||
979 !existing_auth
.caps
[it
.first
].contents_equal(it
.second
)) {
980 ss
<< "entity " << name
<< " exists but cap "
981 << it
.first
<< " does not match";
992 int AuthMonitor::add_entity(
993 const EntityName
& name
,
994 const EntityAuth
& auth
)
998 KeyServerData::Incremental auth_inc
;
999 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1000 auth_inc
.name
= name
;
1001 auth_inc
.auth
= auth
;
1003 dout(10) << " add auth entity " << auth_inc
.name
<< dendl
;
1004 dout(30) << " " << auth_inc
.auth
<< dendl
;
1005 push_cephx_inc(auth_inc
);
1009 int AuthMonitor::validate_osd_destroy(
1012 EntityName
& cephx_entity
,
1013 EntityName
& lockbox_entity
,
1016 ceph_assert(paxos
->is_plugged());
1018 dout(10) << __func__
<< " id " << id
<< " uuid " << uuid
<< dendl
;
1020 string cephx_str
= "osd." + stringify(id
);
1021 string lockbox_str
= "client.osd-lockbox." + stringify(uuid
);
1023 if (!cephx_entity
.from_str(cephx_str
)) {
1024 dout(10) << __func__
<< " invalid cephx entity '"
1025 << cephx_str
<< "'" << dendl
;
1026 ss
<< "invalid cephx key entity '" << cephx_str
<< "'";
1030 if (!lockbox_entity
.from_str(lockbox_str
)) {
1031 dout(10) << __func__
<< " invalid lockbox entity '"
1032 << lockbox_str
<< "'" << dendl
;
1033 ss
<< "invalid lockbox key entity '" << lockbox_str
<< "'";
1037 if (!mon
->key_server
.contains(cephx_entity
) &&
1038 !mon
->key_server
.contains(lockbox_entity
)) {
1045 int AuthMonitor::do_osd_destroy(
1046 const EntityName
& cephx_entity
,
1047 const EntityName
& lockbox_entity
)
1049 ceph_assert(paxos
->is_plugged());
1051 dout(10) << __func__
<< " cephx " << cephx_entity
1052 << " lockbox " << lockbox_entity
<< dendl
;
1054 bool removed
= false;
1056 int err
= remove_entity(cephx_entity
);
1057 if (err
== -ENOENT
) {
1058 dout(10) << __func__
<< " " << cephx_entity
<< " does not exist" << dendl
;
1063 err
= remove_entity(lockbox_entity
);
1064 if (err
== -ENOENT
) {
1065 dout(10) << __func__
<< " " << lockbox_entity
<< " does not exist" << dendl
;
1071 dout(10) << __func__
<< " entities do not exist -- no-op." << dendl
;
1075 // given we have paxos plugged, this will not result in a proposal
1076 // being triggered, but it will still be needed so that we get our
1077 // pending state encoded into the paxos' pending transaction.
1085 const map
<string
,bufferlist
>& caps
)
1090 auth
.key
.decode_base64(key
);
1091 } catch (buffer::error
& e
) {
1098 int AuthMonitor::validate_osd_new(
1101 const string
& cephx_secret
,
1102 const string
& lockbox_secret
,
1103 auth_entity_t
& cephx_entity
,
1104 auth_entity_t
& lockbox_entity
,
1108 dout(10) << __func__
<< " osd." << id
<< " uuid " << uuid
<< dendl
;
1110 map
<string
,bufferlist
> cephx_caps
= {
1111 { "osd", _encode_cap("allow *") },
1112 { "mon", _encode_cap("allow profile osd") },
1113 { "mgr", _encode_cap("allow profile osd") }
1115 map
<string
,bufferlist
> lockbox_caps
= {
1116 { "mon", _encode_cap("allow command \"config-key get\" "
1117 "with key=\"dm-crypt/osd/" +
1122 bool has_lockbox
= !lockbox_secret
.empty();
1124 string cephx_name
= "osd." + stringify(id
);
1125 string lockbox_name
= "client.osd-lockbox." + stringify(uuid
);
1127 if (!cephx_entity
.name
.from_str(cephx_name
)) {
1128 dout(10) << __func__
<< " invalid cephx entity '"
1129 << cephx_name
<< "'" << dendl
;
1130 ss
<< "invalid cephx key entity '" << cephx_name
<< "'";
1135 if (!lockbox_entity
.name
.from_str(lockbox_name
)) {
1136 dout(10) << __func__
<< " invalid cephx lockbox entity '"
1137 << lockbox_name
<< "'" << dendl
;
1138 ss
<< "invalid cephx lockbox entity '" << lockbox_name
<< "'";
1143 if (entity_is_pending(cephx_entity
.name
) ||
1144 (has_lockbox
&& entity_is_pending(lockbox_entity
.name
))) {
1145 // If we have pending entities for either the cephx secret or the
1146 // lockbox secret, then our safest bet is to retry the command at
1147 // a later time. These entities may be pending because an `osd new`
1148 // command has been run (which is unlikely, due to the nature of
1149 // the operation, which will force a paxos proposal), or (more likely)
1150 // because a competing client created those entities before we handled
1151 // the `osd new` command. Regardless, let's wait and see.
1155 if (!is_valid_cephx_key(cephx_secret
)) {
1156 ss
<< "invalid cephx secret.";
1160 if (has_lockbox
&& !is_valid_cephx_key(lockbox_secret
)) {
1161 ss
<< "invalid cephx lockbox secret.";
1165 int err
= _create_auth(cephx_entity
.auth
, cephx_secret
, cephx_caps
);
1166 ceph_assert(0 == err
);
1168 bool cephx_is_idempotent
= false, lockbox_is_idempotent
= false;
1169 err
= exists_and_matches_entity(cephx_entity
, true, ss
);
1171 if (err
!= -ENOENT
) {
1175 ceph_assert(0 == err
);
1176 cephx_is_idempotent
= true;
1180 err
= _create_auth(lockbox_entity
.auth
, lockbox_secret
, lockbox_caps
);
1181 ceph_assert(err
== 0);
1182 err
= exists_and_matches_entity(lockbox_entity
, true, ss
);
1183 if (err
!= -ENOENT
) {
1187 ceph_assert(0 == err
);
1188 lockbox_is_idempotent
= true;
1192 if (cephx_is_idempotent
&& (!has_lockbox
|| lockbox_is_idempotent
)) {
1199 int AuthMonitor::do_osd_new(
1200 const auth_entity_t
& cephx_entity
,
1201 const auth_entity_t
& lockbox_entity
,
1204 ceph_assert(paxos
->is_plugged());
1206 dout(10) << __func__
<< " cephx " << cephx_entity
.name
1209 *_dout
<< lockbox_entity
.name
;
1215 // we must have validated before reaching this point.
1216 // if keys exist, then this means they also match; otherwise we would
1217 // have failed before calling this function.
1218 bool cephx_exists
= mon
->key_server
.contains(cephx_entity
.name
);
1220 if (!cephx_exists
) {
1221 int err
= add_entity(cephx_entity
.name
, cephx_entity
.auth
);
1222 ceph_assert(0 == err
);
1226 !mon
->key_server
.contains(lockbox_entity
.name
)) {
1227 int err
= add_entity(lockbox_entity
.name
, lockbox_entity
.auth
);
1228 ceph_assert(0 == err
);
1231 // given we have paxos plugged, this will not result in a proposal
1232 // being triggered, but it will still be needed so that we get our
1233 // pending state encoded into the paxos' pending transaction.
1238 bool AuthMonitor::valid_caps(
1243 if (type
== "mon" || type
== "mgr") {
1245 if (!tmp
.parse(caps
, out
)) {
1248 } else if (type
== "osd") {
1250 if (!ocap
.parse(caps
, out
)) {
1253 } else if (type
== "mds") {
1255 if (!mdscap
.parse(g_ceph_context
, caps
, out
)) {
1260 *out
<< "unknown cap type '" << type
<< "'";
1267 bool AuthMonitor::valid_caps(const vector
<string
>& caps
, ostream
*out
)
1269 for (vector
<string
>::const_iterator p
= caps
.begin();
1270 p
!= caps
.end(); p
+= 2) {
1271 if ((p
+1) == caps
.end()) {
1272 *out
<< "cap '" << *p
<< "' has no value";
1275 if (!valid_caps(*p
, *(p
+1), out
)) {
1282 bool AuthMonitor::prepare_command(MonOpRequestRef op
)
1284 MMonCommand
*m
= static_cast<MMonCommand
*>(op
->get_req());
1285 stringstream ss
, ds
;
1291 if (!cmdmap_from_json(m
->cmd
, &cmdmap
, ss
)) {
1292 // ss has reason for failure
1293 string rs
= ss
.str();
1294 mon
->reply_command(op
, -EINVAL
, rs
, rdata
, get_last_committed());
1299 vector
<string
>caps_vec
;
1303 cmd_getval(g_ceph_context
, cmdmap
, "prefix", prefix
);
1306 cmd_getval(g_ceph_context
, cmdmap
, "format", format
, string("plain"));
1307 boost::scoped_ptr
<Formatter
> f(Formatter::create(format
));
1309 MonSession
*session
= op
->get_session();
1311 mon
->reply_command(op
, -EACCES
, "access denied", rdata
, get_last_committed());
1315 cmd_getval(g_ceph_context
, cmdmap
, "caps", caps_vec
);
1316 if ((caps_vec
.size() % 2) != 0) {
1317 ss
<< "bad capabilities request; odd number of arguments";
1322 cmd_getval(g_ceph_context
, cmdmap
, "entity", entity_name
);
1323 if (!entity_name
.empty() && !entity
.from_str(entity_name
)) {
1324 ss
<< "bad entity name";
1329 if (prefix
== "auth import") {
1330 bufferlist bl
= m
->get_data();
1331 if (bl
.length() == 0) {
1332 ss
<< "auth import: no data supplied";
1334 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
1337 auto iter
= bl
.cbegin();
1340 decode(keyring
, iter
);
1341 } catch (const buffer::error
&ex
) {
1342 ss
<< "error decoding keyring" << " " << ex
.what();
1346 err
= import_keyring(keyring
);
1348 ss
<< "auth import: no caps supplied";
1350 mon
->reply_command(op
, -EINVAL
, rs
, get_last_committed());
1353 ss
<< "imported keyring";
1356 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1357 get_last_committed() + 1));
1359 } else if (prefix
== "auth add" && !entity_name
.empty()) {
1360 /* expected behavior:
1361 * - if command reproduces current state, return 0.
1362 * - if command adds brand new entity, handle it.
1363 * - if command adds new state to existing entity, return error.
1365 KeyServerData::Incremental auth_inc
;
1366 auth_inc
.name
= entity
;
1367 bufferlist bl
= m
->get_data();
1368 bool has_keyring
= (bl
.length() > 0);
1369 map
<string
,bufferlist
> new_caps
;
1371 KeyRing new_keyring
;
1373 auto iter
= bl
.cbegin();
1375 decode(new_keyring
, iter
);
1376 } catch (const buffer::error
&ex
) {
1377 ss
<< "error decoding keyring";
1383 if (!valid_caps(caps_vec
, &ss
)) {
1388 // are we about to have it?
1389 if (entity_is_pending(entity
)) {
1390 wait_for_finished_proposal(op
,
1391 new Monitor::C_Command(mon
, op
, 0, rs
, get_last_committed() + 1));
1395 // build new caps from provided arguments (if available)
1396 for (vector
<string
>::iterator it
= caps_vec
.begin();
1397 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1401 encode(*(it
+1), cap
);
1402 new_caps
[sys
] = cap
;
1405 // pull info out of provided keyring
1408 if (!new_keyring
.get_auth(auth_inc
.name
, new_inc
)) {
1409 ss
<< "key for " << auth_inc
.name
1410 << " not found in provided keyring";
1414 if (!new_caps
.empty() && !new_inc
.caps
.empty()) {
1415 ss
<< "caps cannot be specified both in keyring and in command";
1419 if (new_caps
.empty()) {
1420 new_caps
= new_inc
.caps
;
1424 err
= exists_and_matches_entity(auth_inc
.name
, new_inc
,
1425 new_caps
, has_keyring
, ss
);
1426 // if entity/key/caps do not exist in the keyring, just fall through
1427 // and add the entity; otherwise, make sure everything matches (in
1428 // which case it's a no-op), because if not we must fail.
1429 if (err
!= -ENOENT
) {
1434 ceph_assert(err
== 0);
1441 dout(10) << "AuthMonitor::prepare_command generating random key for "
1442 << auth_inc
.name
<< dendl
;
1443 new_inc
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1445 new_inc
.caps
= new_caps
;
1447 err
= add_entity(auth_inc
.name
, new_inc
);
1448 ceph_assert(err
== 0);
1450 ss
<< "added key for " << auth_inc
.name
;
1452 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1453 get_last_committed() + 1));
1455 } else if ((prefix
== "auth get-or-create-key" ||
1456 prefix
== "auth get-or-create") &&
1457 !entity_name
.empty()) {
1458 // auth get-or-create <name> [mon osdcapa osd osdcapb ...]
1460 if (!valid_caps(caps_vec
, &ss
)) {
1465 // Parse the list of caps into a map
1466 std::map
<std::string
, bufferlist
> wanted_caps
;
1467 for (vector
<string
>::const_iterator it
= caps_vec
.begin();
1468 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1470 const std::string
&sys
= *it
;
1472 encode(*(it
+1), cap
);
1473 wanted_caps
[sys
] = cap
;
1477 EntityAuth entity_auth
;
1478 if (mon
->key_server
.get_auth(entity
, entity_auth
)) {
1479 for (const auto &sys_cap
: wanted_caps
) {
1480 if (entity_auth
.caps
.count(sys_cap
.first
) == 0 ||
1481 !entity_auth
.caps
[sys_cap
.first
].contents_equal(sys_cap
.second
)) {
1482 ss
<< "key for " << entity
<< " exists but cap " << sys_cap
.first
1483 << " does not match";
1489 if (prefix
== "auth get-or-create-key") {
1491 entity_auth
.key
.encode_formatted("auth", f
.get(), rdata
);
1493 ds
<< entity_auth
.key
;
1497 kr
.add(entity
, entity_auth
.key
);
1499 kr
.set_caps(entity
, entity_auth
.caps
);
1500 kr
.encode_formatted("auth", f
.get(), rdata
);
1502 kr
.encode_plaintext(rdata
);
1509 // ...or are we about to?
1510 for (vector
<Incremental
>::iterator p
= pending_auth
.begin();
1511 p
!= pending_auth
.end();
1513 if (p
->inc_type
== AUTH_DATA
) {
1514 KeyServerData::Incremental auth_inc
;
1515 auto q
= p
->auth_data
.cbegin();
1516 decode(auth_inc
, q
);
1517 if (auth_inc
.op
== KeyServerData::AUTH_INC_ADD
&&
1518 auth_inc
.name
== entity
) {
1519 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1520 get_last_committed() + 1));
1527 KeyServerData::Incremental auth_inc
;
1528 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1529 auth_inc
.name
= entity
;
1530 auth_inc
.auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1531 auth_inc
.auth
.caps
= wanted_caps
;
1533 push_cephx_inc(auth_inc
);
1535 if (prefix
== "auth get-or-create-key") {
1537 auth_inc
.auth
.key
.encode_formatted("auth", f
.get(), rdata
);
1539 ds
<< auth_inc
.auth
.key
;
1543 kr
.add(entity
, auth_inc
.auth
.key
);
1545 kr
.set_caps(entity
, wanted_caps
);
1546 kr
.encode_formatted("auth", f
.get(), rdata
);
1548 kr
.encode_plaintext(rdata
);
1554 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
, rdata
,
1555 get_last_committed() + 1));
1557 } else if (prefix
== "fs authorize") {
1559 cmd_getval(g_ceph_context
, cmdmap
, "filesystem", filesystem
);
1560 string mds_cap_string
, osd_cap_string
;
1561 string osd_cap_wanted
= "r";
1563 for (auto it
= caps_vec
.begin();
1564 it
!= caps_vec
.end() && (it
+ 1) != caps_vec
.end();
1566 const string
&path
= *it
;
1567 const string
&cap
= *(it
+1);
1569 if (cap
!= "r" && cap
.compare(0, 2, "rw")) {
1570 ss
<< "Permission flags must start with 'r' or 'rw'.";
1574 if (cap
.compare(0, 2, "rw") == 0)
1575 osd_cap_wanted
= "rw";
1578 for (size_t i
= 2; i
< cap
.size(); ++i
) {
1581 ss
<< "Permission flags (except 'rw') must be specified in alphabetical order.";
1591 ss
<< "Unknown permission flag '" << c
<< "'.";
1597 mds_cap_string
+= mds_cap_string
.empty() ? "" : ", ";
1598 mds_cap_string
+= "allow " + cap
;
1600 mds_cap_string
+= " path=" + path
;
1604 if (filesystem
!= "*" && filesystem
!= "all") {
1605 auto fs
= mon
->mdsmon()->get_fsmap().get_filesystem(filesystem
);
1607 ss
<< "filesystem " << filesystem
<< " does not exist.";
1613 osd_cap_string
+= osd_cap_string
.empty()? "" : ", ";
1614 osd_cap_string
+= "allow " + osd_cap_wanted
1615 + " tag " + pg_pool_t::APPLICATION_NAME_CEPHFS
1616 + " data=" + filesystem
;
1618 std::map
<string
, bufferlist
> wanted_caps
= {
1619 { "mon", _encode_cap("allow r") },
1620 { "osd", _encode_cap(osd_cap_string
) },
1621 { "mds", _encode_cap(mds_cap_string
) }
1624 if (!valid_caps("osd", osd_cap_string
, &ss
) ||
1625 !valid_caps("mds", mds_cap_string
, &ss
)) {
1630 EntityAuth entity_auth
;
1631 if (mon
->key_server
.get_auth(entity
, entity_auth
)) {
1632 for (const auto &sys_cap
: wanted_caps
) {
1633 if (entity_auth
.caps
.count(sys_cap
.first
) == 0 ||
1634 !entity_auth
.caps
[sys_cap
.first
].contents_equal(sys_cap
.second
)) {
1635 ss
<< entity
<< " already has fs capabilities that differ from "
1636 << "those supplied. To generate a new auth key for " << entity
1637 << ", first remove " << entity
<< " from configuration files, "
1638 << "execute 'ceph auth rm " << entity
<< "', then execute this "
1639 << "command again.";
1646 kr
.add(entity
, entity_auth
.key
);
1648 kr
.set_caps(entity
, entity_auth
.caps
);
1649 kr
.encode_formatted("auth", f
.get(), rdata
);
1651 kr
.encode_plaintext(rdata
);
1657 KeyServerData::Incremental auth_inc
;
1658 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1659 auth_inc
.name
= entity
;
1660 auth_inc
.auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1661 auth_inc
.auth
.caps
= wanted_caps
;
1663 push_cephx_inc(auth_inc
);
1665 kr
.add(entity
, auth_inc
.auth
.key
);
1667 kr
.set_caps(entity
, wanted_caps
);
1668 kr
.encode_formatted("auth", f
.get(), rdata
);
1670 kr
.encode_plaintext(rdata
);
1675 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
, rdata
,
1676 get_last_committed() + 1));
1678 } else if (prefix
== "auth caps" && !entity_name
.empty()) {
1679 KeyServerData::Incremental auth_inc
;
1680 auth_inc
.name
= entity
;
1681 if (!mon
->key_server
.get_auth(auth_inc
.name
, auth_inc
.auth
)) {
1682 ss
<< "couldn't find entry " << auth_inc
.name
;
1687 if (!valid_caps(caps_vec
, &ss
)) {
1692 map
<string
,bufferlist
> newcaps
;
1693 for (vector
<string
>::iterator it
= caps_vec
.begin();
1694 it
!= caps_vec
.end(); it
+= 2)
1695 encode(*(it
+1), newcaps
[*it
]);
1697 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1698 auth_inc
.auth
.caps
= newcaps
;
1699 push_cephx_inc(auth_inc
);
1701 ss
<< "updated caps for " << auth_inc
.name
;
1703 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1704 get_last_committed() + 1));
1706 } else if ((prefix
== "auth del" || prefix
== "auth rm") &&
1707 !entity_name
.empty()) {
1708 KeyServerData::Incremental auth_inc
;
1709 auth_inc
.name
= entity
;
1710 if (!mon
->key_server
.contains(auth_inc
.name
)) {
1711 ss
<< "entity " << entity
<< " does not exist";
1715 auth_inc
.op
= KeyServerData::AUTH_INC_DEL
;
1716 push_cephx_inc(auth_inc
);
1720 wait_for_finished_proposal(op
, new Monitor::C_Command(mon
, op
, 0, rs
,
1721 get_last_committed() + 1));
1726 getline(ss
, rs
, '\0');
1727 mon
->reply_command(op
, err
, rs
, rdata
, get_last_committed());
1731 bool AuthMonitor::prepare_global_id(MonOpRequestRef op
)
1733 dout(10) << "AuthMonitor::prepare_global_id" << dendl
;
1734 increase_max_global_id();
1739 bool AuthMonitor::_upgrade_format_to_dumpling()
1741 dout(1) << __func__
<< " upgrading from format 0 to 1" << dendl
;
1742 ceph_assert(format_version
== 0);
1744 bool changed
= false;
1745 map
<EntityName
, EntityAuth
>::iterator p
;
1746 for (p
= mon
->key_server
.secrets_begin();
1747 p
!= mon
->key_server
.secrets_end();
1749 // grab mon caps, if any
1751 if (p
->second
.caps
.count("mon") == 0)
1754 auto it
= p
->second
.caps
["mon"].cbegin();
1755 decode(mon_caps
, it
);
1757 catch (const buffer::error
&) {
1758 dout(10) << __func__
<< " unable to parse mon cap for "
1759 << p
->first
<< dendl
;
1763 string n
= p
->first
.to_str();
1766 // set daemon profiles
1767 if ((p
->first
.is_osd() || p
->first
.is_mds()) &&
1768 mon_caps
== "allow rwx") {
1769 new_caps
= string("allow profile ") + p
->first
.get_type_name();
1772 // update bootstrap keys
1773 if (n
== "client.bootstrap-osd") {
1774 new_caps
= "allow profile bootstrap-osd";
1776 if (n
== "client.bootstrap-mds") {
1777 new_caps
= "allow profile bootstrap-mds";
1780 if (new_caps
.length() > 0) {
1781 dout(5) << __func__
<< " updating " << p
->first
<< " mon cap from "
1782 << mon_caps
<< " to " << new_caps
<< dendl
;
1785 encode(new_caps
, bl
);
1787 KeyServerData::Incremental auth_inc
;
1788 auth_inc
.name
= p
->first
;
1789 auth_inc
.auth
= p
->second
;
1790 auth_inc
.auth
.caps
["mon"] = bl
;
1791 auth_inc
.op
= KeyServerData::AUTH_INC_ADD
;
1792 push_cephx_inc(auth_inc
);
1799 bool AuthMonitor::_upgrade_format_to_luminous()
1801 dout(1) << __func__
<< " upgrading from format 1 to 2" << dendl
;
1802 ceph_assert(format_version
== 1);
1804 bool changed
= false;
1805 map
<EntityName
, EntityAuth
>::iterator p
;
1806 for (p
= mon
->key_server
.secrets_begin();
1807 p
!= mon
->key_server
.secrets_end();
1809 string n
= p
->first
.to_str();
1812 if (n
== "client.admin") {
1813 // admin gets it all
1815 } else if (n
.find("osd.") == 0 ||
1816 n
.find("mds.") == 0 ||
1817 n
.find("mon.") == 0) {
1818 // daemons follow their profile
1819 string type
= n
.substr(0, 3);
1820 newcap
= "allow profile " + type
;
1821 } else if (p
->second
.caps
.count("mon")) {
1822 // if there are any mon caps, give them 'r' mgr caps
1826 if (newcap
.length() > 0) {
1827 dout(5) << " giving " << n
<< " mgr '" << newcap
<< "'" << dendl
;
1831 EntityAuth auth
= p
->second
;
1832 auth
.caps
["mgr"] = bl
;
1834 add_entity(p
->first
, auth
);
1838 if (n
.find("mgr.") == 0 &&
1839 p
->second
.caps
.count("mon")) {
1840 // the kraken ceph-mgr@.service set the mon cap to 'allow *'.
1841 auto blp
= p
->second
.caps
["mon"].cbegin();
1843 decode(oldcaps
, blp
);
1844 if (oldcaps
== "allow *") {
1845 dout(5) << " fixing " << n
<< " mon cap to 'allow profile mgr'"
1848 encode("allow profile mgr", bl
);
1850 EntityAuth auth
= p
->second
;
1851 auth
.caps
["mon"] = bl
;
1852 add_entity(p
->first
, p
->second
);
1858 // add bootstrap key if it does not already exist
1859 // (might have already been get-or-create'd by
1860 // ceph-create-keys)
1861 EntityName bootstrap_mgr_name
;
1862 int r
= bootstrap_mgr_name
.from_str("client.bootstrap-mgr");
1864 if (!mon
->key_server
.contains(bootstrap_mgr_name
)) {
1866 EntityName name
= bootstrap_mgr_name
;
1868 encode("allow profile bootstrap-mgr", auth
.caps
["mon"]);
1869 auth
.key
.create(g_ceph_context
, CEPH_CRYPTO_AES
);
1870 add_entity(name
, auth
);
1876 bool AuthMonitor::_upgrade_format_to_mimic()
1878 dout(1) << __func__
<< " upgrading from format 2 to 3" << dendl
;
1879 ceph_assert(format_version
== 2);
1881 list
<pair
<EntityName
,EntityAuth
> > auth_lst
;
1882 _generate_bootstrap_keys(&auth_lst
);
1884 bool changed
= false;
1885 for (auto &p
: auth_lst
) {
1886 if (mon
->key_server
.contains(p
.first
)) {
1889 int err
= add_entity(p
.first
, p
.second
);
1890 ceph_assert(err
== 0);
1897 void AuthMonitor::upgrade_format()
1899 constexpr unsigned int FORMAT_NONE
= 0;
1900 constexpr unsigned int FORMAT_DUMPLING
= 1;
1901 constexpr unsigned int FORMAT_LUMINOUS
= 2;
1902 constexpr unsigned int FORMAT_MIMIC
= 3;
1904 // when upgrading from the current format to a new format, ensure that
1905 // the new format doesn't break the older format. I.e., if a given format N
1906 // changes or adds something, ensure that when upgrading from N-1 to N+1, we
1907 // still observe the changes for format N if those have not been superseded
1910 unsigned int current
= FORMAT_MIMIC
;
1911 if (!mon
->get_quorum_mon_features().contains_all(
1912 ceph::features::mon::FEATURE_LUMINOUS
)) {
1913 // pre-luminous quorum
1914 current
= FORMAT_DUMPLING
;
1915 } else if (!mon
->get_quorum_mon_features().contains_all(
1916 ceph::features::mon::FEATURE_MIMIC
)) {
1918 current
= FORMAT_LUMINOUS
;
1920 if (format_version
>= current
) {
1921 dout(20) << __func__
<< " format " << format_version
1922 << " is current" << dendl
;
1926 // perform a rolling upgrade of the new format, if necessary.
1927 // i.e., if we are moving from format NONE to MIMIC, we will first upgrade
1928 // to DUMPLING, then to LUMINOUS, and finally to MIMIC, in several different
1931 bool changed
= false;
1932 if (format_version
== FORMAT_NONE
) {
1933 changed
= _upgrade_format_to_dumpling();
1935 } else if (format_version
== FORMAT_DUMPLING
) {
1936 changed
= _upgrade_format_to_luminous();
1937 } else if (format_version
== FORMAT_LUMINOUS
) {
1938 changed
= _upgrade_format_to_mimic();
1943 dout(10) << __func__
<< " proposing update from format " << format_version
1944 << " -> " << current
<< dendl
;
1945 format_version
= current
;
1950 void AuthMonitor::dump_info(Formatter
*f
)
1952 /*** WARNING: do not include any privileged information here! ***/
1953 f
->open_object_section("auth");
1954 f
->dump_unsigned("first_committed", get_first_committed());
1955 f
->dump_unsigned("last_committed", get_last_committed());
1956 f
->dump_unsigned("num_secrets", mon
->key_server
.get_num_secrets());