]>
git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxKeyServer.cc
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-2009 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.
15 #include "common/config.h"
16 #include "CephxKeyServer.h"
17 #include "common/dout.h"
20 #define dout_subsys ceph_subsys_auth
22 #define dout_prefix *_dout << "cephx keyserverdata: "
24 using std::ostringstream
;
26 using std::stringstream
;
28 using ceph::bufferptr
;
29 using ceph::bufferlist
;
30 using ceph::Formatter
;
32 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
33 CryptoKey
& secret
, uint64_t& secret_id
,
36 auto iter
= rotating_secrets
.find(service_id
);
37 if (iter
== rotating_secrets
.end()) {
38 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
) << " not found " << dendl
;
42 const RotatingSecrets
& secrets
= iter
->second
;
44 // second to oldest, unless it's expired
45 auto riter
= secrets
.secrets
.begin();
46 if (secrets
.secrets
.size() > 1)
49 utime_t now
= ceph_clock_now();
50 if (riter
->second
.expiration
< now
)
51 ++riter
; // "current" key has expired, use "next" key instead
53 secret_id
= riter
->first
;
54 secret
= riter
->second
.key
;
56 // ttl may have just been increased by the user
57 // cap it by expiration of "next" key to prevent handing out a ticket
58 // with a bogus, possibly way into the future, validity
59 ttl
= service_id
== CEPH_ENTITY_TYPE_AUTH
?
60 cct
->_conf
->auth_mon_ticket_ttl
: cct
->_conf
->auth_service_ticket_ttl
;
61 ttl
= std::min(ttl
, static_cast<double>(
62 secrets
.secrets
.rbegin()->second
.expiration
- now
));
64 ldout(cct
, 30) << __func__
<< " service "
65 << ceph_entity_type_name(service_id
) << " secret_id "
66 << secret_id
<< " " << riter
->second
<< " ttl " << ttl
71 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
72 uint64_t secret_id
, CryptoKey
& secret
) const
74 auto iter
= rotating_secrets
.find(service_id
);
75 if (iter
== rotating_secrets
.end()) {
76 ldout(cct
, 10) << __func__
<< " no rotating_secrets for service " << service_id
77 << " " << ceph_entity_type_name(service_id
) << dendl
;
81 const RotatingSecrets
& secrets
= iter
->second
;
82 auto riter
= secrets
.secrets
.find(secret_id
);
84 if (riter
== secrets
.secrets
.end()) {
85 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
)
86 << " secret " << secret_id
<< " not found" << dendl
;
87 ldout(cct
, 30) << " I have:" << dendl
;
88 for (auto iter
= secrets
.secrets
.begin();
89 iter
!= secrets
.secrets
.end();
91 ldout(cct
, 30) << " id " << iter
->first
<< " " << iter
->second
<< dendl
;
95 secret
= riter
->second
.key
;
99 bool KeyServerData::get_auth(const EntityName
& name
, EntityAuth
& auth
) const {
100 auto iter
= secrets
.find(name
);
101 if (iter
!= secrets
.end()) {
105 return extra_secrets
->get_auth(name
, auth
);
108 bool KeyServerData::get_secret(const EntityName
& name
, CryptoKey
& secret
) const {
109 auto iter
= secrets
.find(name
);
110 if (iter
!= secrets
.end()) {
111 secret
= iter
->second
.key
;
114 return extra_secrets
->get_secret(name
, secret
);
117 bool KeyServerData::get_caps(CephContext
*cct
, const EntityName
& name
,
118 const string
& type
, AuthCapsInfo
& caps_info
) const
120 caps_info
.allow_all
= false;
122 ldout(cct
, 10) << "get_caps: name=" << name
.to_str() << dendl
;
123 auto iter
= secrets
.find(name
);
124 if (iter
!= secrets
.end()) {
125 ldout(cct
, 10) << "get_caps: num of caps=" << iter
->second
.caps
.size() << dendl
;
126 auto capsiter
= iter
->second
.caps
.find(type
);
127 if (capsiter
!= iter
->second
.caps
.end()) {
128 caps_info
.caps
= capsiter
->second
;
133 return extra_secrets
->get_caps(name
, type
, caps_info
);
138 #define dout_prefix *_dout << "cephx keyserver: "
141 KeyServer::KeyServer(CephContext
*cct_
, KeyRing
*extra_secrets
)
144 lock
{ceph::make_mutex("KeyServer::lock")}
148 int KeyServer::start_server()
150 std::scoped_lock l
{lock
};
151 _dump_rotating_secrets();
155 void KeyServer::dump()
157 _dump_rotating_secrets();
160 void KeyServer::_dump_rotating_secrets()
162 ldout(cct
, 30) << "_dump_rotating_secrets" << dendl
;
163 for (auto iter
= data
.rotating_secrets
.begin();
164 iter
!= data
.rotating_secrets
.end();
166 RotatingSecrets
& key
= iter
->second
;
167 for (auto mapiter
= key
.secrets
.begin();
168 mapiter
!= key
.secrets
.end();
170 ldout(cct
, 30) << "service " << ceph_entity_type_name(iter
->first
)
171 << " id " << mapiter
->first
172 << " key " << mapiter
->second
<< dendl
;
176 int KeyServer::_rotate_secret(uint32_t service_id
, KeyServerData
&pending_data
)
178 RotatingSecrets
& r
= pending_data
.rotating_secrets
[service_id
];
180 utime_t now
= ceph_clock_now();
181 double ttl
= service_id
== CEPH_ENTITY_TYPE_AUTH
? cct
->_conf
->auth_mon_ticket_ttl
: cct
->_conf
->auth_service_ticket_ttl
;
183 while (r
.need_new_secrets(now
)) {
184 ExpiringCryptoKey ek
;
185 generate_secret(ek
.key
);
189 utime_t next_ttl
= now
;
191 ek
.expiration
= std::max(next_ttl
, r
.next().expiration
);
193 ek
.expiration
+= ttl
;
194 uint64_t secret_id
= r
.add(ek
);
195 ldout(cct
, 10) << "_rotate_secret adding " << ceph_entity_type_name(service_id
) << dendl
;
196 ldout(cct
, 30) << "_rotate_secret adding " << ceph_entity_type_name(service_id
)
197 << " id " << secret_id
<< " " << ek
204 bool KeyServer::get_secret(const EntityName
& name
, CryptoKey
& secret
) const
206 std::scoped_lock l
{lock
};
207 return data
.get_secret(name
, secret
);
210 bool KeyServer::get_auth(const EntityName
& name
, EntityAuth
& auth
) const
212 std::scoped_lock l
{lock
};
213 return data
.get_auth(name
, auth
);
216 bool KeyServer::get_caps(const EntityName
& name
, const string
& type
,
217 AuthCapsInfo
& caps_info
) const
219 std::scoped_lock l
{lock
};
221 return data
.get_caps(cct
, name
, type
, caps_info
);
224 bool KeyServer::get_service_secret(uint32_t service_id
, CryptoKey
& secret
,
225 uint64_t& secret_id
, double& ttl
) const
227 std::scoped_lock l
{lock
};
229 return data
.get_service_secret(cct
, service_id
, secret
, secret_id
, ttl
);
232 bool KeyServer::get_service_secret(uint32_t service_id
,
233 uint64_t secret_id
, CryptoKey
& secret
) const
235 std::scoped_lock l
{lock
};
237 return data
.get_service_secret(cct
, service_id
, secret_id
, secret
);
240 void KeyServer::note_used_pending_key(const EntityName
& name
, const CryptoKey
& key
)
242 std::scoped_lock
l(lock
);
243 used_pending_keys
[name
] = key
;
246 void KeyServer::clear_used_pending_keys()
248 std::scoped_lock
l(lock
);
249 used_pending_keys
.clear();
252 std::map
<EntityName
,CryptoKey
> KeyServer::get_used_pending_keys()
254 std::map
<EntityName
,CryptoKey
> ret
;
255 std::scoped_lock
l(lock
);
256 ret
.swap(used_pending_keys
);
260 bool KeyServer::generate_secret(CryptoKey
& secret
)
263 CryptoHandler
*crypto
= cct
->get_crypto_handler(CEPH_CRYPTO_AES
);
267 if (crypto
->create(cct
->random(), bp
) < 0)
270 secret
.set_secret(CEPH_CRYPTO_AES
, bp
, ceph_clock_now());
275 bool KeyServer::generate_secret(EntityName
& name
, CryptoKey
& secret
)
277 if (!generate_secret(secret
))
280 std::scoped_lock l
{lock
};
285 data
.add_auth(name
, auth
);
290 bool KeyServer::contains(const EntityName
& name
) const
292 std::scoped_lock l
{lock
};
294 return data
.contains(name
);
297 int KeyServer::encode_secrets(Formatter
*f
, stringstream
*ds
) const
299 std::scoped_lock l
{lock
};
300 auto mapiter
= data
.secrets_begin();
302 if (mapiter
== data
.secrets_end())
306 f
->open_array_section("auth_dump");
308 while (mapiter
!= data
.secrets_end()) {
309 const EntityName
& name
= mapiter
->first
;
311 *ds
<< name
.to_str() << std::endl
;
312 *ds
<< "\tkey: " << mapiter
->second
.key
<< std::endl
;
315 f
->open_object_section("auth_entities");
316 f
->dump_string("entity", name
.to_str());
317 f
->dump_stream("key") << mapiter
->second
.key
;
318 f
->open_object_section("caps");
321 auto capsiter
= mapiter
->second
.caps
.begin();
322 for (; capsiter
!= mapiter
->second
.caps
.end(); ++capsiter
) {
323 // FIXME: need a const_iterator for bufferlist, but it doesn't exist yet.
324 bufferlist
*bl
= const_cast<bufferlist
*>(&capsiter
->second
);
325 auto dataiter
= bl
->cbegin();
328 decode(caps
, dataiter
);
330 *ds
<< "\tcaps: [" << capsiter
->first
<< "] " << caps
<< std::endl
;
332 f
->dump_string(capsiter
->first
.c_str(), caps
);
335 f
->close_section(); // caps
336 f
->close_section(); // auth_entities
343 f
->close_section(); // auth_dump
347 void KeyServer::encode_formatted(string label
, Formatter
*f
, bufferlist
&bl
)
349 ceph_assert(f
!= NULL
);
350 f
->open_object_section(label
.c_str());
351 encode_secrets(f
, NULL
);
356 void KeyServer::encode_plaintext(bufferlist
&bl
)
359 encode_secrets(NULL
, &os
);
363 bool KeyServer::prepare_rotating_update(bufferlist
& rotating_bl
)
365 std::scoped_lock l
{lock
};
366 ldout(cct
, 20) << __func__
<< " before: data.rotating_ver=" << data
.rotating_ver
369 KeyServerData
pending_data(nullptr);
370 pending_data
.rotating_ver
= data
.rotating_ver
+ 1;
371 pending_data
.rotating_secrets
= data
.rotating_secrets
;
374 added
+= _rotate_secret(CEPH_ENTITY_TYPE_AUTH
, pending_data
);
375 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MON
, pending_data
);
376 added
+= _rotate_secret(CEPH_ENTITY_TYPE_OSD
, pending_data
);
377 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MDS
, pending_data
);
378 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MGR
, pending_data
);
383 ldout(cct
, 20) << __func__
<< " after: pending_data.rotating_ver="
384 << pending_data
.rotating_ver
386 pending_data
.encode_rotating(rotating_bl
);
390 bool KeyServer::get_rotating_encrypted(const EntityName
& name
,
391 bufferlist
& enc_bl
) const
393 std::scoped_lock l
{lock
};
395 auto mapiter
= data
.find_name(name
);
396 if (mapiter
== data
.secrets_end())
399 const CryptoKey
& specific_key
= mapiter
->second
.key
;
401 auto rotate_iter
= data
.rotating_secrets
.find(name
.get_type());
402 if (rotate_iter
== data
.rotating_secrets
.end())
405 RotatingSecrets secrets
= rotate_iter
->second
;
408 if (encode_encrypt(cct
, secrets
, specific_key
, enc_bl
, error
))
414 bool KeyServer::_get_service_caps(const EntityName
& name
, uint32_t service_id
,
415 AuthCapsInfo
& caps_info
) const
417 string s
= ceph_entity_type_name(service_id
);
419 return data
.get_caps(cct
, name
, s
, caps_info
);
422 bool KeyServer::get_service_caps(const EntityName
& name
, uint32_t service_id
,
423 AuthCapsInfo
& caps_info
) const
425 std::scoped_lock l
{lock
};
426 return _get_service_caps(name
, service_id
, caps_info
);
430 int KeyServer::_build_session_auth_info(uint32_t service_id
,
431 const AuthTicket
& parent_ticket
,
432 CephXSessionAuthInfo
& info
,
435 info
.service_id
= service_id
;
436 info
.ticket
= parent_ticket
;
437 info
.ticket
.init_timestamps(ceph_clock_now(), ttl
);
438 info
.validity
.set_from_double(ttl
);
440 generate_secret(info
.session_key
);
442 // mon keys are stored externally. and the caps are blank anyway.
443 if (service_id
!= CEPH_ENTITY_TYPE_MON
) {
444 string s
= ceph_entity_type_name(service_id
);
445 if (!data
.get_caps(cct
, info
.ticket
.name
, s
, info
.ticket
.caps
)) {
452 int KeyServer::build_session_auth_info(uint32_t service_id
,
453 const AuthTicket
& parent_ticket
,
454 CephXSessionAuthInfo
& info
)
457 if (!get_service_secret(service_id
, info
.service_secret
, info
.secret_id
,
462 std::scoped_lock l
{lock
};
463 return _build_session_auth_info(service_id
, parent_ticket
, info
, ttl
);
466 int KeyServer::build_session_auth_info(uint32_t service_id
,
467 const AuthTicket
& parent_ticket
,
468 const CryptoKey
& service_secret
,
470 CephXSessionAuthInfo
& info
)
472 info
.service_secret
= service_secret
;
473 info
.secret_id
= secret_id
;
475 std::scoped_lock l
{lock
};
476 return _build_session_auth_info(service_id
, parent_ticket
, info
,
477 cct
->_conf
->auth_service_ticket_ttl
);