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 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
25 ExpiringCryptoKey
& secret
, uint64_t& secret_id
) const
27 map
<uint32_t, RotatingSecrets
>::const_iterator iter
=
28 rotating_secrets
.find(service_id
);
29 if (iter
== rotating_secrets
.end()) {
30 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
) << " not found " << dendl
;
34 const RotatingSecrets
& secrets
= iter
->second
;
36 // second to oldest, unless it's expired
37 map
<uint64_t, ExpiringCryptoKey
>::const_iterator riter
=
38 secrets
.secrets
.begin();
39 if (secrets
.secrets
.size() > 1)
42 if (riter
->second
.expiration
< ceph_clock_now())
43 ++riter
; // "current" key has expired, use "next" key instead
45 secret_id
= riter
->first
;
46 secret
= riter
->second
;
47 ldout(cct
, 30) << "get_service_secret service " << ceph_entity_type_name(service_id
)
48 << " id " << secret_id
<< " " << secret
<< dendl
;
52 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
53 CryptoKey
& secret
, uint64_t& secret_id
) const
57 if (!get_service_secret(cct
, service_id
, e
, secret_id
))
64 bool KeyServerData::get_service_secret(CephContext
*cct
, uint32_t service_id
,
65 uint64_t secret_id
, CryptoKey
& secret
) const
67 map
<uint32_t, RotatingSecrets
>::const_iterator iter
=
68 rotating_secrets
.find(service_id
);
69 if (iter
== rotating_secrets
.end())
72 const RotatingSecrets
& secrets
= iter
->second
;
73 map
<uint64_t, ExpiringCryptoKey
>::const_iterator riter
=
74 secrets
.secrets
.find(secret_id
);
76 if (riter
== secrets
.secrets
.end()) {
77 ldout(cct
, 10) << "get_service_secret service " << ceph_entity_type_name(service_id
)
78 << " secret " << secret_id
<< " not found" << dendl
;
79 ldout(cct
, 30) << " I have:" << dendl
;
80 for (map
<uint64_t, ExpiringCryptoKey
>::const_iterator iter
=
81 secrets
.secrets
.begin();
82 iter
!= secrets
.secrets
.end();
84 ldout(cct
, 30) << " id " << iter
->first
<< " " << iter
->second
<< dendl
;
88 secret
= riter
->second
.key
;
92 bool KeyServerData::get_auth(const EntityName
& name
, EntityAuth
& auth
) const {
93 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
94 if (iter
!= secrets
.end()) {
98 return extra_secrets
->get_auth(name
, auth
);
101 bool KeyServerData::get_secret(const EntityName
& name
, CryptoKey
& secret
) const {
102 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
103 if (iter
!= secrets
.end()) {
104 secret
= iter
->second
.key
;
107 return extra_secrets
->get_secret(name
, secret
);
110 bool KeyServerData::get_caps(CephContext
*cct
, const EntityName
& name
,
111 const string
& type
, AuthCapsInfo
& caps_info
) const
113 caps_info
.allow_all
= false;
115 ldout(cct
, 10) << "get_caps: name=" << name
.to_str() << dendl
;
116 map
<EntityName
, EntityAuth
>::const_iterator iter
= secrets
.find(name
);
117 if (iter
!= secrets
.end()) {
118 ldout(cct
, 10) << "get_secret: num of caps=" << iter
->second
.caps
.size() << dendl
;
119 map
<string
, bufferlist
>::const_iterator capsiter
= iter
->second
.caps
.find(type
);
120 if (capsiter
!= iter
->second
.caps
.end()) {
121 caps_info
.caps
= capsiter
->second
;
126 return extra_secrets
->get_caps(name
, type
, caps_info
);
131 #define dout_prefix *_dout << "cephx keyserver: "
134 KeyServer::KeyServer(CephContext
*cct_
, KeyRing
*extra_secrets
)
137 lock
{ceph::make_mutex("KeyServer::lock")}
141 int KeyServer::start_server()
143 std::scoped_lock l
{lock
};
145 _check_rotating_secrets();
146 _dump_rotating_secrets();
150 bool KeyServer::_check_rotating_secrets()
152 ldout(cct
, 10) << "_check_rotating_secrets" << dendl
;
155 added
+= _rotate_secret(CEPH_ENTITY_TYPE_AUTH
);
156 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MON
);
157 added
+= _rotate_secret(CEPH_ENTITY_TYPE_OSD
);
158 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MDS
);
159 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MGR
);
162 ldout(cct
, 10) << __func__
<< " added " << added
<< dendl
;
164 //data.next_rotating_time = ceph_clock_now(cct);
165 //data.next_rotating_time += std::min(cct->_conf->auth_mon_ticket_ttl, cct->_conf->auth_service_ticket_ttl);
166 _dump_rotating_secrets();
172 void KeyServer::_dump_rotating_secrets()
174 ldout(cct
, 30) << "_dump_rotating_secrets" << dendl
;
175 for (map
<uint32_t, RotatingSecrets
>::iterator iter
= data
.rotating_secrets
.begin();
176 iter
!= data
.rotating_secrets
.end();
178 RotatingSecrets
& key
= iter
->second
;
179 for (map
<uint64_t, ExpiringCryptoKey
>::iterator mapiter
= key
.secrets
.begin();
180 mapiter
!= key
.secrets
.end();
182 ldout(cct
, 30) << "service " << ceph_entity_type_name(iter
->first
)
183 << " id " << mapiter
->first
184 << " key " << mapiter
->second
<< dendl
;
188 int KeyServer::_rotate_secret(uint32_t service_id
)
190 RotatingSecrets
& r
= data
.rotating_secrets
[service_id
];
192 utime_t now
= ceph_clock_now();
193 double ttl
= service_id
== CEPH_ENTITY_TYPE_AUTH
? cct
->_conf
->auth_mon_ticket_ttl
: cct
->_conf
->auth_service_ticket_ttl
;
195 while (r
.need_new_secrets(now
)) {
196 ExpiringCryptoKey ek
;
197 generate_secret(ek
.key
);
201 utime_t next_ttl
= now
;
203 ek
.expiration
= std::max(next_ttl
, r
.next().expiration
);
205 ek
.expiration
+= ttl
;
206 uint64_t secret_id
= r
.add(ek
);
207 ldout(cct
, 10) << "_rotate_secret adding " << ceph_entity_type_name(service_id
) << dendl
;
208 ldout(cct
, 30) << "_rotate_secret adding " << ceph_entity_type_name(service_id
)
209 << " id " << secret_id
<< " " << ek
216 bool KeyServer::get_secret(const EntityName
& name
, CryptoKey
& secret
) const
218 std::scoped_lock l
{lock
};
219 return data
.get_secret(name
, secret
);
222 bool KeyServer::get_auth(const EntityName
& name
, EntityAuth
& auth
) const
224 std::scoped_lock l
{lock
};
225 return data
.get_auth(name
, auth
);
228 bool KeyServer::get_caps(const EntityName
& name
, const string
& type
,
229 AuthCapsInfo
& caps_info
) const
231 std::scoped_lock l
{lock
};
233 return data
.get_caps(cct
, name
, type
, caps_info
);
236 bool KeyServer::get_service_secret(uint32_t service_id
,
237 CryptoKey
& secret
, uint64_t& secret_id
) const
239 std::scoped_lock l
{lock
};
241 return data
.get_service_secret(cct
, service_id
, secret
, secret_id
);
244 bool KeyServer::get_service_secret(uint32_t service_id
,
245 uint64_t secret_id
, CryptoKey
& secret
) const
247 std::scoped_lock l
{lock
};
249 return data
.get_service_secret(cct
, service_id
, secret_id
, secret
);
252 bool KeyServer::generate_secret(CryptoKey
& secret
)
255 CryptoHandler
*crypto
= cct
->get_crypto_handler(CEPH_CRYPTO_AES
);
259 if (crypto
->create(cct
->random(), bp
) < 0)
262 secret
.set_secret(CEPH_CRYPTO_AES
, bp
, ceph_clock_now());
267 bool KeyServer::generate_secret(EntityName
& name
, CryptoKey
& secret
)
269 if (!generate_secret(secret
))
272 std::scoped_lock l
{lock
};
277 data
.add_auth(name
, auth
);
282 bool KeyServer::contains(const EntityName
& name
) const
284 std::scoped_lock l
{lock
};
286 return data
.contains(name
);
289 int KeyServer::encode_secrets(Formatter
*f
, stringstream
*ds
) const
291 std::scoped_lock l
{lock
};
292 map
<EntityName
, EntityAuth
>::const_iterator mapiter
= data
.secrets_begin();
294 if (mapiter
== data
.secrets_end())
298 f
->open_array_section("auth_dump");
300 while (mapiter
!= data
.secrets_end()) {
301 const EntityName
& name
= mapiter
->first
;
303 *ds
<< name
.to_str() << std::endl
;
304 *ds
<< "\tkey: " << mapiter
->second
.key
<< std::endl
;
307 f
->open_object_section("auth_entities");
308 f
->dump_string("entity", name
.to_str());
309 f
->dump_stream("key") << mapiter
->second
.key
;
310 f
->open_object_section("caps");
313 map
<string
, bufferlist
>::const_iterator capsiter
=
314 mapiter
->second
.caps
.begin();
315 for (; capsiter
!= mapiter
->second
.caps
.end(); ++capsiter
) {
316 // FIXME: need a const_iterator for bufferlist, but it doesn't exist yet.
317 bufferlist
*bl
= const_cast<bufferlist
*>(&capsiter
->second
);
318 auto dataiter
= bl
->cbegin();
321 decode(caps
, dataiter
);
323 *ds
<< "\tcaps: [" << capsiter
->first
<< "] " << caps
<< std::endl
;
325 f
->dump_string(capsiter
->first
.c_str(), caps
);
328 f
->close_section(); // caps
329 f
->close_section(); // auth_entities
336 f
->close_section(); // auth_dump
340 void KeyServer::encode_formatted(string label
, Formatter
*f
, bufferlist
&bl
)
342 ceph_assert(f
!= NULL
);
343 f
->open_object_section(label
.c_str());
344 encode_secrets(f
, NULL
);
349 void KeyServer::encode_plaintext(bufferlist
&bl
)
352 encode_secrets(NULL
, &os
);
356 bool KeyServer::updated_rotating(bufferlist
& rotating_bl
, version_t
& rotating_ver
)
358 std::scoped_lock l
{lock
};
360 _check_rotating_secrets();
362 if (data
.rotating_ver
<= rotating_ver
)
365 data
.encode_rotating(rotating_bl
);
367 rotating_ver
= data
.rotating_ver
;
372 bool KeyServer::get_rotating_encrypted(const EntityName
& name
,
373 bufferlist
& enc_bl
) const
375 std::scoped_lock l
{lock
};
377 map
<EntityName
, EntityAuth
>::const_iterator mapiter
= data
.find_name(name
);
378 if (mapiter
== data
.secrets_end())
381 const CryptoKey
& specific_key
= mapiter
->second
.key
;
383 map
<uint32_t, RotatingSecrets
>::const_iterator rotate_iter
=
384 data
.rotating_secrets
.find(name
.get_type());
385 if (rotate_iter
== data
.rotating_secrets
.end())
388 RotatingSecrets secrets
= rotate_iter
->second
;
391 if (encode_encrypt(cct
, secrets
, specific_key
, enc_bl
, error
))
397 bool KeyServer::_get_service_caps(const EntityName
& name
, uint32_t service_id
,
398 AuthCapsInfo
& caps_info
) const
400 string s
= ceph_entity_type_name(service_id
);
402 return data
.get_caps(cct
, name
, s
, caps_info
);
405 bool KeyServer::get_service_caps(const EntityName
& name
, uint32_t service_id
,
406 AuthCapsInfo
& caps_info
) const
408 std::scoped_lock l
{lock
};
409 return _get_service_caps(name
, service_id
, caps_info
);
413 int KeyServer::_build_session_auth_info(uint32_t service_id
,
414 const AuthTicket
& parent_ticket
,
415 CephXSessionAuthInfo
& info
)
417 info
.service_id
= service_id
;
418 info
.ticket
= parent_ticket
;
419 info
.ticket
.init_timestamps(ceph_clock_now(),
420 cct
->_conf
->auth_service_ticket_ttl
);
422 generate_secret(info
.session_key
);
424 // mon keys are stored externally. and the caps are blank anyway.
425 if (service_id
!= CEPH_ENTITY_TYPE_MON
) {
426 string s
= ceph_entity_type_name(service_id
);
427 if (!data
.get_caps(cct
, info
.ticket
.name
, s
, info
.ticket
.caps
)) {
434 int KeyServer::build_session_auth_info(uint32_t service_id
,
435 const AuthTicket
& parent_ticket
,
436 CephXSessionAuthInfo
& info
)
438 if (!get_service_secret(service_id
, info
.service_secret
, info
.secret_id
)) {
442 std::scoped_lock l
{lock
};
444 return _build_session_auth_info(service_id
, parent_ticket
, info
);
447 int KeyServer::build_session_auth_info(uint32_t service_id
,
448 const AuthTicket
& parent_ticket
,
449 CephXSessionAuthInfo
& info
,
450 CryptoKey
& service_secret
,
453 info
.service_secret
= service_secret
;
454 info
.secret_id
= secret_id
;
456 std::scoped_lock l
{lock
};
457 return _build_session_auth_info(service_id
, parent_ticket
, info
);