]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
auth: rotate rotating keys every time interval
authorYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 17 Sep 2009 17:18:59 +0000 (10:18 -0700)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Thu, 17 Sep 2009 17:18:59 +0000 (10:18 -0700)
src/Makefile.am
src/auth/Auth.h
src/auth/AuthServiceManager.cc
src/auth/KeyRing.cc [new file with mode: 0644]
src/auth/KeysServer.cc [new file with mode: 0644]

index 8c25f8429d7d0b331ca232825f579b5536731d57..3e44523093532fc1d369c16198ce1c1dedd52a0c 100644 (file)
@@ -171,6 +171,10 @@ endif
 testcrypto_SOURCES = testcrypto.cc
 testcrypto_LDADD = libcommon.a -lcrypto
 bin_PROGRAMS += testcrypto
+
+testkeys_SOURCES = testkeys.cc
+testkeys_LDADD = libcommon.a -lcrypto
+bin_PROGRAMS += testkeys
 ## object classes
 
 # libtestclass.so: testclass.cc
@@ -284,6 +288,8 @@ libcommon_files = \
        auth/AuthServiceManager.cc \
        auth/Crypto.cc \
        auth/ExportControl.cc \
+       auth/KeyRing.cc \
+       auth/KeysServer.cc \
        common/LogClient.cc \
        msg/Message.cc \
        common/Logger.cc \
index 8bc6f69143f277591c3d53d6074b6deb85b3ef42..8ae579304f1deb91ec678ddf22fbeb5fb23af10e 100644 (file)
@@ -42,6 +42,9 @@ struct EntityName {
 };
 WRITE_CLASS_ENCODER(EntityName);
 
+inline bool operator<(const EntityName& a, const EntityName& b) {
+  return a.entity_type < b.entity_type || (a.entity_type == b.entity_type && a.name < b.name);
+}
 /*
  * The ticket (if properly validated) authorizes the principal use
  * services as described by 'caps' during the specified validity
index a6c3ecf40c17314bbd47d0d9e5812c904d23cea9..8ca0064604f65689885ca3fdbd9ad0aa369a06ec 100644 (file)
@@ -92,7 +92,6 @@ public:
   }
 };
 
-
 static CephAuthServer auth_server;
 
 /*
diff --git a/src/auth/KeyRing.cc b/src/auth/KeyRing.cc
new file mode 100644 (file)
index 0000000..47bc5f3
--- /dev/null
@@ -0,0 +1,105 @@
+// -*- 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.
+ * 
+ */
+
+#include <errno.h>
+#include <map>
+
+#include "config.h"
+
+#include "Crypto.h"
+
+using namespace std;
+
+#define NUM_CONCURRENT_KEYS 3
+
+/*
+  KeyRing is being used at the service side, for holding the temporary rotating
+  key of that service
+*/
+
+class KeyRing {
+  CryptoKey master;
+  map<uint32_t, CryptoKey> keys;
+  deque<uint32_t> keys_fifo;
+  Mutex lock;
+public:
+  KeyRing() : lock("KeyRing") {}
+
+  bool load_master(const char *filename);
+  bool set_next_key(uint64_t id, CryptoKey& key);
+
+  void get_master(CryptoKey& dest);
+};
+
+
+bool KeyRing::load_master(const char *filename)
+{
+  int fd = open(filename, O_RDONLY);
+  if (fd < 0) {
+    dout(0) << "can't open key ring file " << filename << dendl;
+    return false;
+  }
+
+  // get size
+  struct stat st;
+  int rc = fstat(fd, &st);
+  if (rc != 0) {
+    dout(0) << "error stating key ring file " << filename << dendl;
+    return false;
+  }
+  __int32_t len = st.st_size;
+  bufferlist bl;
+
+  bufferptr bp(len);
+  int off = 0;
+  while (off < len) {
+    int r = read(fd, bp.c_str()+off, len-off);
+    if (r < 0) {
+      derr(0) << "errno on read " << strerror(errno) << dendl;
+      return false;
+    }
+    off += r;
+  }
+  bl.append(bp);
+  close(fd);
+  
+  return true;
+}
+
+bool KeyRing::set_next_key(uint64_t id, CryptoKey& key)
+{
+  Mutex::Locker l(lock);
+
+  keys[id] = key;
+  keys_fifo.push_back(id);
+
+  while (keys_fifo.size() > NUM_CONCURRENT_KEYS) {
+    uint32_t old_id = keys_fifo[0];
+    keys_fifo.pop_front();
+    map<uint32_t, CryptoKey>::iterator iter = keys.find(old_id);
+    assert(iter != keys.end());
+    keys.erase(iter);
+  }
+
+  return true;
+}
+
+void KeyRing::get_master(CryptoKey& dest)
+{
+  Mutex::Locker l(lock);
+
+  dest = master;
+}
+
diff --git a/src/auth/KeysServer.cc b/src/auth/KeysServer.cc
new file mode 100644 (file)
index 0000000..1da8855
--- /dev/null
@@ -0,0 +1,140 @@
+// -*- 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.
+ * 
+ */
+
+#include "config.h"
+
+#include "KeysServer.h"
+
+#include "Crypto.h"
+#include "common/Timer.h"
+#include "Auth.h"
+#include "AuthProtocol.h"
+
+static void hexdump(string msg, const char *s, int len)
+{
+  int buf_len = len*4;
+  char buf[buf_len];
+  int pos = 0;
+  for (int i=0; i<len && pos<buf_len - 8; i++) {
+    if (i && !(i%8))
+      pos += snprintf(&buf[pos], buf_len-pos, " ");
+    if (i && !(i%16))
+      pos += snprintf(&buf[pos], buf_len-pos, "\n");
+    pos += snprintf(&buf[pos], buf_len-pos, "%.2x ", (int)(unsigned char)s[i]);
+  }
+  dout(0) << msg << ":\n" << buf << dendl;
+}
+
+
+
+KeysServer::KeysServer() : rotating_lock("KeysServer::rotating_lock"),
+                 secrets_lock("KeysServer::secrets_lock"), timer(rotating_lock)
+{
+  Mutex::Locker l(rotating_lock);
+
+  generate_all_rotating_secrets();
+
+  rotate_event = new C_RotateTimeout(this, KEY_ROTATE_TIME);
+  timer.add_event_after(KEY_ROTATE_TIME, rotate_event);
+}
+
+void KeysServer::generate_all_rotating_secrets()
+{
+  dout(0) << "generate_all_rotating_secrets()" << dendl;
+  _rotate_secret(CEPHX_PRINCIPAL_MON);
+  _rotate_secret(CEPHX_PRINCIPAL_OSD);
+  _rotate_secret(CEPHX_PRINCIPAL_MDS);
+
+  dout(0) << "generated: " << dendl;
+  
+  map<uint32_t, RotatingSecret>::iterator iter = rotating_secrets.begin();
+
+  for (; iter != rotating_secrets.end(); ++iter) {
+    dout(0) << "service id: " << iter->first << dendl;
+    RotatingSecret& key = iter->second;
+    bufferptr bp = key.secret.get_secret();
+    hexdump("key", bp.c_str(), bp.length());
+    dout(0) << "expiration: " << key.expiration << dendl;
+  }
+}
+
+void KeysServer::_rotate_secret(uint32_t service_id)
+{
+  RotatingSecret secret;
+  generate_secret(secret.secret);
+  secret.expiration = g_clock.now();
+  secret.expiration += (KEY_ROTATE_TIME * 3);
+
+  rotating_secrets[service_id] = secret;
+}
+
+void KeysServer::rotate_timeout(double timeout)
+{
+  generate_all_rotating_secrets();
+
+  rotate_event = new C_RotateTimeout(this, timeout);
+  timer.add_event_after(timeout, rotate_event);
+}
+
+bool KeysServer::get_secret(EntityName& name, CryptoKey& secret)
+{
+  Mutex::Locker l(secrets_lock);
+
+  map<EntityName, CryptoKey>::iterator iter = secrets.find(name);
+  if (iter == secrets.end())
+    return false;
+
+  secret = iter->second;
+  return true;
+}
+
+bool KeysServer::get_service_secret(uint32_t service_id, RotatingSecret& secret)
+{
+  Mutex::Locker l(rotating_lock);
+
+  map<uint32_t, RotatingSecret>::iterator iter = rotating_secrets.find(service_id);
+  if (iter == rotating_secrets.end())
+    return false;
+
+  secret = iter->second;
+  return true;
+}
+
+bool KeysServer::generate_secret(CryptoKey& secret)
+{
+  bufferptr bp;
+  CryptoHandler *crypto = ceph_crypto_mgr.get_crypto(CEPH_SECRET_AES);
+  if (!crypto)
+    return false;
+
+  if (crypto->create(bp) < 0)
+    return false;
+
+  secret.set_secret(CEPH_SECRET_AES, bp);
+
+  return true;
+}
+
+bool KeysServer::generate_secret(EntityName& name, CryptoKey& secret)
+{
+  if (!generate_secret(secret))
+    return false;
+
+  Mutex::Locker l(secrets_lock);
+
+  secrets[name] = secret;
+
+  return true;
+}
+