]>
git.proxmox.com Git - ceph.git/blob - ceph/src/auth/cephx/CephxKeyServer.cc
86ccc1ca2fbb78e8c3da6da5f4597df742326ba4
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_secret: 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
};
152 _dump_rotating_secrets();
156 void KeyServer::dump()
158 _dump_rotating_secrets();
161 void KeyServer::_dump_rotating_secrets()
163 ldout(cct
, 30) << "_dump_rotating_secrets" << dendl
;
164 for (auto iter
= data
.rotating_secrets
.begin();
165 iter
!= data
.rotating_secrets
.end();
167 RotatingSecrets
& key
= iter
->second
;
168 for (auto mapiter
= key
.secrets
.begin();
169 mapiter
!= key
.secrets
.end();
171 ldout(cct
, 30) << "service " << ceph_entity_type_name(iter
->first
)
172 << " id " << mapiter
->first
173 << " key " << mapiter
->second
<< dendl
;
177 int KeyServer::_rotate_secret(uint32_t service_id
, KeyServerData
&pending_data
)
179 RotatingSecrets
& r
= pending_data
.rotating_secrets
[service_id
];
181 utime_t now
= ceph_clock_now();
182 double ttl
= service_id
== CEPH_ENTITY_TYPE_AUTH
? cct
->_conf
->auth_mon_ticket_ttl
: cct
->_conf
->auth_service_ticket_ttl
;
184 while (r
.need_new_secrets(now
)) {
185 ExpiringCryptoKey ek
;
186 generate_secret(ek
.key
);
190 utime_t next_ttl
= now
;
192 ek
.expiration
= std::max(next_ttl
, r
.next().expiration
);
194 ek
.expiration
+= ttl
;
195 uint64_t secret_id
= r
.add(ek
);
196 ldout(cct
, 10) << "_rotate_secret adding " << ceph_entity_type_name(service_id
) << dendl
;
197 ldout(cct
, 30) << "_rotate_secret adding " << ceph_entity_type_name(service_id
)
198 << " id " << secret_id
<< " " << ek
205 bool KeyServer::get_secret(const EntityName
& name
, CryptoKey
& secret
) const
207 std::scoped_lock l
{lock
};
208 return data
.get_secret(name
, secret
);
211 bool KeyServer::get_auth(const EntityName
& name
, EntityAuth
& auth
) const
213 std::scoped_lock l
{lock
};
214 return data
.get_auth(name
, auth
);
217 bool KeyServer::get_caps(const EntityName
& name
, const string
& type
,
218 AuthCapsInfo
& caps_info
) const
220 std::scoped_lock l
{lock
};
222 return data
.get_caps(cct
, name
, type
, caps_info
);
225 bool KeyServer::get_service_secret(uint32_t service_id
, CryptoKey
& secret
,
226 uint64_t& secret_id
, double& ttl
) const
228 std::scoped_lock l
{lock
};
230 return data
.get_service_secret(cct
, service_id
, secret
, secret_id
, ttl
);
233 bool KeyServer::get_service_secret(uint32_t service_id
,
234 uint64_t secret_id
, CryptoKey
& secret
) const
236 std::scoped_lock l
{lock
};
238 return data
.get_service_secret(cct
, service_id
, secret_id
, secret
);
241 bool KeyServer::generate_secret(CryptoKey
& secret
)
244 CryptoHandler
*crypto
= cct
->get_crypto_handler(CEPH_CRYPTO_AES
);
248 if (crypto
->create(cct
->random(), bp
) < 0)
251 secret
.set_secret(CEPH_CRYPTO_AES
, bp
, ceph_clock_now());
256 bool KeyServer::generate_secret(EntityName
& name
, CryptoKey
& secret
)
258 if (!generate_secret(secret
))
261 std::scoped_lock l
{lock
};
266 data
.add_auth(name
, auth
);
271 bool KeyServer::contains(const EntityName
& name
) const
273 std::scoped_lock l
{lock
};
275 return data
.contains(name
);
278 int KeyServer::encode_secrets(Formatter
*f
, stringstream
*ds
) const
280 std::scoped_lock l
{lock
};
281 auto mapiter
= data
.secrets_begin();
283 if (mapiter
== data
.secrets_end())
287 f
->open_array_section("auth_dump");
289 while (mapiter
!= data
.secrets_end()) {
290 const EntityName
& name
= mapiter
->first
;
292 *ds
<< name
.to_str() << std::endl
;
293 *ds
<< "\tkey: " << mapiter
->second
.key
<< std::endl
;
296 f
->open_object_section("auth_entities");
297 f
->dump_string("entity", name
.to_str());
298 f
->dump_stream("key") << mapiter
->second
.key
;
299 f
->open_object_section("caps");
302 auto capsiter
= mapiter
->second
.caps
.begin();
303 for (; capsiter
!= mapiter
->second
.caps
.end(); ++capsiter
) {
304 // FIXME: need a const_iterator for bufferlist, but it doesn't exist yet.
305 bufferlist
*bl
= const_cast<bufferlist
*>(&capsiter
->second
);
306 auto dataiter
= bl
->cbegin();
309 decode(caps
, dataiter
);
311 *ds
<< "\tcaps: [" << capsiter
->first
<< "] " << caps
<< std::endl
;
313 f
->dump_string(capsiter
->first
.c_str(), caps
);
316 f
->close_section(); // caps
317 f
->close_section(); // auth_entities
324 f
->close_section(); // auth_dump
328 void KeyServer::encode_formatted(string label
, Formatter
*f
, bufferlist
&bl
)
330 ceph_assert(f
!= NULL
);
331 f
->open_object_section(label
.c_str());
332 encode_secrets(f
, NULL
);
337 void KeyServer::encode_plaintext(bufferlist
&bl
)
340 encode_secrets(NULL
, &os
);
344 bool KeyServer::prepare_rotating_update(bufferlist
& rotating_bl
)
346 std::scoped_lock l
{lock
};
347 ldout(cct
, 20) << __func__
<< " before: data.rotating_ver=" << data
.rotating_ver
350 KeyServerData
pending_data(nullptr);
351 pending_data
.rotating_ver
= data
.rotating_ver
+ 1;
352 pending_data
.rotating_secrets
= data
.rotating_secrets
;
355 added
+= _rotate_secret(CEPH_ENTITY_TYPE_AUTH
, pending_data
);
356 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MON
, pending_data
);
357 added
+= _rotate_secret(CEPH_ENTITY_TYPE_OSD
, pending_data
);
358 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MDS
, pending_data
);
359 added
+= _rotate_secret(CEPH_ENTITY_TYPE_MGR
, pending_data
);
364 ldout(cct
, 20) << __func__
<< " after: pending_data.rotating_ver="
365 << pending_data
.rotating_ver
367 pending_data
.encode_rotating(rotating_bl
);
371 bool KeyServer::get_rotating_encrypted(const EntityName
& name
,
372 bufferlist
& enc_bl
) const
374 std::scoped_lock l
{lock
};
376 auto mapiter
= data
.find_name(name
);
377 if (mapiter
== data
.secrets_end())
380 const CryptoKey
& specific_key
= mapiter
->second
.key
;
382 auto rotate_iter
= data
.rotating_secrets
.find(name
.get_type());
383 if (rotate_iter
== data
.rotating_secrets
.end())
386 RotatingSecrets secrets
= rotate_iter
->second
;
389 if (encode_encrypt(cct
, secrets
, specific_key
, enc_bl
, error
))
395 bool KeyServer::_get_service_caps(const EntityName
& name
, uint32_t service_id
,
396 AuthCapsInfo
& caps_info
) const
398 string s
= ceph_entity_type_name(service_id
);
400 return data
.get_caps(cct
, name
, s
, caps_info
);
403 bool KeyServer::get_service_caps(const EntityName
& name
, uint32_t service_id
,
404 AuthCapsInfo
& caps_info
) const
406 std::scoped_lock l
{lock
};
407 return _get_service_caps(name
, service_id
, caps_info
);
411 int KeyServer::_build_session_auth_info(uint32_t service_id
,
412 const AuthTicket
& parent_ticket
,
413 CephXSessionAuthInfo
& info
,
416 info
.service_id
= service_id
;
417 info
.ticket
= parent_ticket
;
418 info
.ticket
.init_timestamps(ceph_clock_now(), ttl
);
419 info
.validity
.set_from_double(ttl
);
421 generate_secret(info
.session_key
);
423 // mon keys are stored externally. and the caps are blank anyway.
424 if (service_id
!= CEPH_ENTITY_TYPE_MON
) {
425 string s
= ceph_entity_type_name(service_id
);
426 if (!data
.get_caps(cct
, info
.ticket
.name
, s
, info
.ticket
.caps
)) {
433 int KeyServer::build_session_auth_info(uint32_t service_id
,
434 const AuthTicket
& parent_ticket
,
435 CephXSessionAuthInfo
& info
)
438 if (!get_service_secret(service_id
, info
.service_secret
, info
.secret_id
,
443 std::scoped_lock l
{lock
};
444 return _build_session_auth_info(service_id
, parent_ticket
, info
, ttl
);
447 int KeyServer::build_session_auth_info(uint32_t service_id
,
448 const AuthTicket
& parent_ticket
,
449 const CryptoKey
& service_secret
,
451 CephXSessionAuthInfo
& info
)
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
,
458 cct
->_conf
->auth_service_ticket_ttl
);