KeyRing stores keys (on disk).
RotatingKeyRing mediates access to the in-memory pool of rotating secrets
for a single service.
auth/Crypto.cc \
auth/ExportControl.cc \
auth/KeyRing.cc \
+ auth/RotatingKeyRing.cc \
common/LogClient.cc \
msg/Message.cc \
common/BackTrace.cc \
auth/AuthServiceHandler.h\
auth/AuthAuthorizeHandler.h\
auth/KeyRing.h\
+ auth/RotatingKeyRing.h\
auth/Crypto.h\
auth/ExportControl.h\
ceph_ver.h \
};
WRITE_CLASS_ENCODER(ExpiringCryptoKey);
+static inline ostream& operator<<(ostream& out, const ExpiringCryptoKey& c)
+{
+ return out << c.key << " expires " << c.expiration;
+}
+
struct RotatingSecrets {
map<uint64_t, ExpiringCryptoKey> secrets;
version_t max_ver;
-
+
RotatingSecrets() : max_ver(0) {}
-
+
void encode(bufferlist& bl) const {
__u8 struct_v = 1;
::encode(struct_v, bl);
::decode(secrets, bl);
::decode(max_ver, bl);
}
+
+ void add(ExpiringCryptoKey& key) {
+ secrets[++max_ver] = key;
+ while (secrets.size() > KEY_ROTATE_NUM)
+ secrets.erase(secrets.begin());
+ }
+
+ bool need_new_secrets() {
+ return secrets.size() < KEY_ROTATE_NUM;
+ }
- void add(ExpiringCryptoKey& key);
+ void dump();
};
WRITE_CLASS_ENCODER(RotatingSecrets);
-
class KeyStore {
public:
virtual ~KeyStore() {}
virtual bool get_secret(EntityName& name, CryptoKey& secret) = 0;
- virtual bool get_service_secret(uint32_t service_id, uint64_t secret_id, CryptoKey& secret) = 0;
+ //virtual bool get_service_secret(uint32_t service_id, uint64_t secret_id, CryptoKey& secret) = 0;
};
static inline bool auth_principal_needs_rotating_keys(EntityName& name)
#include "config.h"
#include "Auth.h"
+class KeyRing;
+class RotatingKeyRing;
+
struct AuthAuthorizeHandler {
virtual ~AuthAuthorizeHandler() {}
- virtual bool verify_authorizer(bufferlist& authorizer_data, bufferlist& authorizer_reply,
+ virtual bool verify_authorizer(KeyRing *keys, RotatingKeyRing *rkeys,
+ bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info) = 0;
};
#include "cephx/CephxClientHandler.h"
#include "none/AuthNoneClientHandler.h"
-AuthClientHandler *get_auth_client_handler(int proto)
+AuthClientHandler *get_auth_client_handler(int proto, RotatingKeyRing *rkeys)
{
switch (proto) {
case CEPH_AUTH_CEPHX:
- return new CephxClientHandler();
+ return new CephxClientHandler(rkeys);
case CEPH_AUTH_NONE:
- return new AuthNoneClientHandler();
+ return new AuthNoneClientHandler(rkeys);
default:
return NULL;
}
class MAuthReply;
class AuthClientHandler;
+class RotatingKeyRing;
class AuthClientHandler {
protected:
};
-extern AuthClientHandler *get_auth_client_handler(int proto);
+extern AuthClientHandler *get_auth_client_handler(int proto, RotatingKeyRing *rkeys);
#endif
}
}
-// ----------------
-// rotating crap
-
-void KeyRing::set_rotating(RotatingSecrets& secrets)
-{
- Mutex::Locker l(lock);
-
- rotating_secrets = secrets;
-
- dout(0) << "KeyRing::set_rotating max_ver=" << secrets.max_ver << dendl;
-
- map<uint64_t, ExpiringCryptoKey>::iterator iter = secrets.secrets.begin();
-
- for (; iter != secrets.secrets.end(); ++iter) {
- ExpiringCryptoKey& key = iter->second;
-
- dout(0) << "id: " << iter->first << dendl;
- dout(0) << "key.expiration: " << key.expiration << dendl;
- bufferptr& bp = key.key.get_secret();
- bufferlist bl;
- bl.append(bp);
- hexdump(" key", bl.c_str(), bl.length());
- }
-}
-
-bool KeyRing::need_rotating_secrets()
-{
- Mutex::Locker l(lock);
-
- if (rotating_secrets.secrets.size() < KEY_ROTATE_NUM)
- return true;
-
- map<uint64_t, ExpiringCryptoKey>::iterator iter = rotating_secrets.secrets.lower_bound(0);
- ExpiringCryptoKey& key = iter->second;
- if (key.expiration < g_clock.now()) {
- dout(0) << "key.expiration=" << key.expiration << " now=" << g_clock.now() << dendl;
- return true;
- }
-
- return false;
-}
-
-
-void KeyRing::dump_rotating()
-{
- dout(0) << "dump_rotating:" << dendl;
- for (map<uint64_t, ExpiringCryptoKey>::iterator iter = rotating_secrets.secrets.begin();
- iter != rotating_secrets.secrets.end();
- ++iter)
- dout(0) << " id " << iter->first << " " << iter->second.key
- << " expires " << iter->second.expiration << dendl;
-}
-
-bool KeyRing::get_service_secret(uint32_t service_id, uint64_t secret_id, CryptoKey& secret)
-{
- Mutex::Locker l(lock);
-
- /* we ignore the service id, there's only one service id that we're handling */
- map<uint64_t, ExpiringCryptoKey>::iterator iter = rotating_secrets.secrets.find(secret_id);
- if (iter == rotating_secrets.secrets.end()) {
- dout(0) << "could not find secret_id=" << secret_id << dendl;
- dump_rotating();
- return false;
- }
-
- ExpiringCryptoKey& key = iter->second;
- if (key.expiration > g_clock.now()) {
- secret = key.key;
- return true;
- }
- dout(0) << "secret expired!" << dendl;
- return false;
-}
-
#include "auth/Crypto.h"
#include "auth/Auth.h"
-/*
- KeyRing is being used at the service side, for holding the temporary rotating
- key of that service
-*/
-
class KeyRing : public KeyStore {
map<string, EntityAuth> keys;
- RotatingSecrets rotating_secrets;
- Mutex lock;
-public:
- KeyRing() : lock("KeyRing") {}
+public:
map<string, EntityAuth>& get_keys() { return keys; } // yuck
bool load(const char *filename);
void print(ostream& out);
+ // accessors
bool get_auth(EntityName& name, EntityAuth &a) {
string n = name.to_str();
if (keys.count(n)) {
get_secret(*g_conf.entity_name, dest);
}
- //
+ // modifiers
void add(EntityName& name, EntityAuth &a) {
string s = name.to_str();
keys[s] = a;
}
void import(KeyRing& other);
- // weirdness
- void dump_rotating();
- void set_rotating(RotatingSecrets& secrets);
- bool need_rotating_secrets();
- bool get_service_secret(uint32_t service_id, uint64_t secret_id, CryptoKey& secret);
-
+ // encoders
void encode(bufferlist& bl) const {
__u8 struct_v = 1;
::encode(struct_v, bl);
extern KeyRing g_keyring;
-
-
#endif
--- /dev/null
+#include <errno.h>
+#include <map>
+
+#include "config.h"
+#include "include/str_list.h"
+
+#include "Crypto.h"
+#include "auth/RotatingKeyRing.h"
+
+#define DOUT_SUBSYS auth
+#undef dout_prefix
+#define dout_prefix *_dout << dbeginl << "auth: "
+
+
+bool RotatingKeyRing::need_new_secrets()
+{
+ Mutex::Locker l(lock);
+ return secrets.need_new_secrets();
+}
+
+void RotatingKeyRing::set_secrets(RotatingSecrets& s)
+{
+ Mutex::Locker l(lock);
+ secrets = s;
+}
+
+void RotatingKeyRing::dump_rotating()
+{
+ dout(0) << "dump_rotating:" << dendl;
+ for (map<uint64_t, ExpiringCryptoKey>::iterator iter = secrets.secrets.begin();
+ iter != secrets.secrets.end();
+ ++iter)
+ dout(0) << " id " << iter->first << " " << iter->second << dendl;
+}
+
+bool RotatingKeyRing::get_service_secret(uint64_t secret_id, CryptoKey& secret)
+{
+ Mutex::Locker l(lock);
+
+ map<uint64_t, ExpiringCryptoKey>::iterator iter = secrets.secrets.find(secret_id);
+ if (iter == secrets.secrets.end()) {
+ dout(0) << "could not find secret_id=" << secret_id << dendl;
+ dump_rotating();
+ return false;
+ }
+
+ ExpiringCryptoKey& key = iter->second;
+ if (key.expiration > g_clock.now()) {
+ secret = key.key;
+ return true;
+ }
+ dout(0) << "secret " << key << " expired!" << dendl;
+ return false;
+}
--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2009 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef __ROTATINGKEYRING_H
+#define __ROTATINGKEYRING_H
+
+#include "config.h"
+
+#include "auth/Crypto.h"
+#include "auth/Auth.h"
+
+/*
+ * mediate access to a service's rotating secrets
+ */
+
+class RotatingKeyRing {
+ RotatingSecrets secrets;
+ Mutex lock;
+
+public:
+ RotatingKeyRing() : lock("RotatingKeyRing::lock") {}
+
+ bool need_new_secrets();
+ void set_secrets(RotatingSecrets& s);
+ void dump_rotating();
+ bool get_service_secret(uint64_t secret_id, CryptoKey& secret);
+};
+
+#endif
#include "CephxAuthorizeHandler.h"
-bool CephxAuthorizeHandler::verify_authorizer(bufferlist& authorizer_data, bufferlist& authorizer_reply,
+bool CephxAuthorizeHandler::verify_authorizer(KeyRing *keys, RotatingKeyRing *rkeys,
+ bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info)
{
bufferlist::iterator iter = authorizer_data.begin();
CephXServiceTicketInfo auth_ticket_info;
- bool isvalid = cephx_verify_authorizer(g_keyring, iter, auth_ticket_info, authorizer_reply);
+ bool isvalid = cephx_verify_authorizer(keys, rkeys, iter, auth_ticket_info, authorizer_reply);
dout(0) << "CephxAuthorizeHandler::verify_authorizer isvalid=" << isvalid << dendl;
if (isvalid) {
#include "../AuthAuthorizeHandler.h"
struct CephxAuthorizeHandler : public AuthAuthorizeHandler {
- bool verify_authorizer(bufferlist& authorizer_data, bufferlist& authorizer_reply,
+ bool verify_authorizer(KeyRing *keys, RotatingKeyRing *rkeys,
+ bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info);
};
case CEPHX_GET_ROTATING_KEY:
{
dout(10) << " get_rotating_key" << dendl;
- RotatingSecrets secrets;
- CryptoKey secret_key;
- g_keyring.get_master(secret_key);
- if (decode_decrypt(secrets, secret_key, indata) == 0) {
- g_keyring.set_rotating(secrets);
- } else {
- derr(0) << "could not set rotating key: decode_decrypt failed" << dendl;
+ if (rotating_secrets) {
+ RotatingSecrets secrets;
+ CryptoKey secret_key;
+ g_keyring.get_master(secret_key);
+ if (decode_decrypt(secrets, secret_key, indata) == 0) {
+ rotating_secrets->set_secrets(secrets);
+ } else {
+ derr(0) << "could not set rotating key: decode_decrypt failed" << dendl;
+ }
}
}
break;
CephXAuthorizer *authorizer;
CephXTicketManager tickets;
+
+ RotatingKeyRing *rotating_secrets;
public:
- CephxClientHandler() : authorizer(0) {
+ CephxClientHandler(RotatingKeyRing *rsecrets) :
+ authorizer(0),
+ rotating_secrets(rsecrets) {
reset();
}
#include <sstream>
-void RotatingSecrets::add(ExpiringCryptoKey& key)
-{
- secrets[++max_ver] = key;
-
- while (secrets.size() > KEY_ROTATE_NUM) {
- map<uint64_t, ExpiringCryptoKey>::iterator iter = secrets.lower_bound(0);
- secrets.erase(iter);
- }
-}
-
bool KeyServerData::get_service_secret(uint32_t service_id, ExpiringCryptoKey& secret, uint64_t& secret_id)
{
map<uint32_t, RotatingSecrets>::iterator iter = rotating_secrets.find(service_id);
}
}
-bool cephx_decode_ticket(KeyStore& keys, uint32_t service_id, CephXTicketBlob& ticket_blob, CephXServiceTicketInfo& ticket_info)
+bool cephx_decode_ticket(KeyStore *keys, RotatingKeyRing *rkeys, uint32_t service_id, CephXTicketBlob& ticket_blob, CephXServiceTicketInfo& ticket_info)
{
uint64_t secret_id = ticket_blob.secret_id;
CryptoKey service_secret;
return false;
}
- if (secret_id == (uint64_t)-1) {
- if (!keys.get_secret(*g_conf.entity_name, service_secret)) {
- dout(0) << "ceph_decode_ticket could not get general service secret for service_id=" << service_id << " secret_id=" << secret_id << dendl;
+ if (secret_id == (uint64_t)-1 || rkeys == NULL) {
+ if (!keys->get_secret(*g_conf.entity_name, service_secret)) {
+ dout(0) << "ceph_decode_ticket could not get general service secret for service_id="
+ << service_id << " secret_id=" << secret_id << dendl;
return false;
}
} else {
- if (!keys.get_service_secret(service_id, secret_id, service_secret)) {
- dout(0) << "ceph_decode_ticket could not get service secret for service_id=" << service_id << " secret_id=" << secret_id << dendl;
+ if (!rkeys->get_service_secret(secret_id, service_secret)) {
+ dout(0) << "ceph_decode_ticket could not get service secret for service_id="
+ << service_id << " secret_id=" << secret_id << dendl;
return false;
}
}
*
* {timestamp + 1}^session_key
*/
-bool cephx_verify_authorizer(KeyStore& keys, bufferlist::iterator& indata,
- CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl)
+bool cephx_verify_authorizer(KeyStore *keys, RotatingKeyRing *rkeys,
+ bufferlist::iterator& indata,
+ CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl)
{
__u8 authorizer_v;
::decode(authorizer_v, indata);
dout(10) << "verify_authorizer decrypted service_id=" << service_id
<< " secret_id=" << ticket.secret_id << dendl;
- if (ticket.secret_id == (uint64_t)-1) {
+ if (ticket.secret_id == (uint64_t)-1 || rkeys == NULL) {
EntityName name;
name.entity_type = service_id;
- if (!keys.get_secret(name, service_secret)) {
+ if (!keys->get_secret(name, service_secret)) {
dout(0) << "verify_authorizer could not get general service secret for service_id=" << service_id
<< " secret_id=" << ticket.secret_id << dendl;
return false;
}
} else {
- if (!keys.get_service_secret(service_id, ticket.secret_id, service_secret)) {
+ if (!rkeys->get_service_secret(ticket.secret_id, service_secret)) {
dout(0) << "verify_authorizer could not get service secret for service_id=" << service_id
<< " secret_id=" << ticket.secret_id << dendl;
return false;
#define CEPHX_REQUEST_TYPE_MASK 0x0F00
#include "../Auth.h"
-
+#include "../RotatingKeyRing.h"
/*
* Authentication
/*
* Decode an extract ticket
*/
-bool cephx_decode_ticket(KeyStore& keys, uint32_t service_id, CephXTicketBlob& ticket_blob, CephXServiceTicketInfo& ticket_info);
+bool cephx_decode_ticket(KeyStore *keys, RotatingKeyRing *rkeys,
+ uint32_t service_id, CephXTicketBlob& ticket_blob, CephXServiceTicketInfo& ticket_info);
/*
* Verify authorizer and generate reply authorizer
*/
-extern bool cephx_verify_authorizer(KeyStore& keys, bufferlist::iterator& indata,
+extern bool cephx_verify_authorizer(KeyStore *keys, RotatingKeyRing *rkeys,
+ bufferlist::iterator& indata,
CephXServiceTicketInfo& ticket_info, bufferlist& reply_bl);
}
CephXServiceTicketInfo old_ticket_info;
- if (cephx_decode_ticket(*key_server, CEPH_ENTITY_TYPE_AUTH, req.old_ticket, old_ticket_info)) {
+ if (cephx_decode_ticket(key_server, NULL, CEPH_ENTITY_TYPE_AUTH, req.old_ticket, old_ticket_info)) {
global_id = old_ticket_info.ticket.global_id;
dout(10) << "decoded old_ticket with global_id=" << global_id << dendl;
should_enc_ticket = true;
bufferlist tmp_bl;
CephXServiceTicketInfo auth_ticket_info;
- if (!cephx_verify_authorizer(*key_server, indata, auth_ticket_info, tmp_bl)) {
+ if (!cephx_verify_authorizer(key_server, NULL, indata, auth_ticket_info, tmp_bl)) {
ret = -EPERM;
break;
}
#include "AuthNoneAuthorizeHandler.h"
-bool AuthNoneAuthorizeHandler::verify_authorizer(bufferlist& authorizer_data, bufferlist& authorizer_reply,
- EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info)
+bool AuthNoneAuthorizeHandler::verify_authorizer(KeyRing *keys, RotatingKeyRing *rkeys,
+ bufferlist& authorizer_data, bufferlist& authorizer_reply,
+ EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info)
{
bufferlist::iterator iter = authorizer_data.begin();
#include "../AuthAuthorizeHandler.h"
struct AuthNoneAuthorizeHandler : public AuthAuthorizeHandler {
- bool verify_authorizer(bufferlist& authorizer_data, bufferlist& authorizer_reply,
+ bool verify_authorizer(KeyRing *keys, RotatingKeyRing *rkeys,
+ bufferlist& authorizer_data, bufferlist& authorizer_reply,
EntityName& entity_name, uint64_t& global_id, AuthCapsInfo& caps_info);
};
class AuthNoneClientHandler : public AuthClientHandler {
public:
- AuthNoneClientHandler() {}
+ AuthNoneClientHandler(RotatingKeyRing *rkeys) {}
void reset() { }
if (g_conf.clock_tare) g_clock.tare();
// get monmap
- MonClient mc;
+ RotatingKeyRing rkeys;
+ MonClient mc(&rkeys);
if (mc.build_initial_monmap() < 0)
return -1;
_dout_create_courtesy_output_symlink("osd", whoami);
// get monmap
- MonClient mc;
+ RotatingKeyRing rkeys;
+ MonClient mc(&rkeys);
if (mc.build_initial_monmap() < 0)
return -1;
if (mc.get_monmap_privately() < 0)
#include "messages/MMonCommand.h"
#include "auth/AuthAuthorizeHandler.h"
+#include "auth/KeyRing.h"
#include "config.h"
EntityName name;
uint64_t global_id;
- is_valid = authorize_handler->verify_authorizer(authorizer_data, authorizer_reply, name, global_id, caps_info);
+ is_valid = authorize_handler->verify_authorizer(&g_keyring, monc->rotating_secrets,
+ authorizer_data, authorizer_reply, name, global_id, caps_info);
if (is_valid) {
entity_name_t n(con->get_peer_type(), global_id);
if (state == MC_STATE_NEGOTIATING) {
if (!auth || (int)m->protocol != auth->get_protocol()) {
delete auth;
- auth = get_auth_client_handler(m->protocol);
+ auth = get_auth_client_handler(m->protocol, rotating_secrets);
if (!auth) {
delete m;
return;
_send_mon_message(m);
}
- if (!g_keyring.need_rotating_secrets())
+ if (!rotating_secrets)
+ return 0;
+
+ if (!rotating_secrets->need_new_secrets())
return 0;
if (!auth_principal_needs_rotating_keys(entity_name)) {
return 0;
}
+ if (!rotating_secrets)
+ return 0;
+
while (auth_principal_needs_rotating_keys(entity_name) &&
- g_keyring.need_rotating_secrets())
+ rotating_secrets->need_new_secrets())
auth_cond.WaitInterval(monc_lock, interval);
return 0;
}
#include "common/Timer.h"
#include "auth/AuthClientHandler.h"
+#include "auth/RotatingKeyRing.h"
#include "messages/MMonSubscribe.h"
_sub_got(what, have);
}
+ RotatingKeyRing *rotating_secrets;
+
public:
- MonClient() : state(MC_STATE_NONE),
- messenger(NULL), cur_mon(-1),
- monc_lock("MonClient::monc_lock"),
- timer(monc_lock),
- hunting(false),
- want_monmap(false),
- want_keys(0), global_id(0),
- authenticate_err(0),
- auth(NULL) { }
+ MonClient(RotatingKeyRing *rkeys=0) :
+ state(MC_STATE_NONE),
+ messenger(NULL), cur_mon(-1),
+ monc_lock("MonClient::monc_lock"),
+ timer(monc_lock),
+ hunting(false),
+ want_monmap(false),
+ want_keys(0), global_id(0),
+ authenticate_err(0),
+ auth(NULL),
+ rotating_secrets(rkeys) { }
~MonClient() {
timer.cancel_all_events();
}
if (!authorizer_data.length())
return true; /* we're not picky */
- int ret = cephx_verify_authorizer(key_server, iter, auth_ticket_info, authorizer_reply);
+ int ret = cephx_verify_authorizer(&key_server, NULL, iter, auth_ticket_info, authorizer_reply);
dout(0) << "Monitor::verify_authorizer returns " << ret << dendl;
isvalid = (ret >= 0);
EntityName name;
uint64_t global_id;
- isvalid = authorize_handler->verify_authorizer(authorizer_data, authorizer_reply, name, global_id, caps_info);
+ isvalid = authorize_handler->verify_authorizer(&g_keyring, monc->rotating_secrets,
+ authorizer_data, authorizer_reply, name, global_id, caps_info);
dout(10) << "OSD::ms_verify_authorizer name=" << name << dendl;