From 030819db61f9c6316f1d44d7c3e3486348ae49cc Mon Sep 17 00:00:00 2001 From: Thierry Parmentelat Date: Thu, 24 Jun 2010 15:09:58 +0000 Subject: [PATCH] sliverauth generates a sliver ssh keypair and exposes it in the 'ssh_key' tag sliverauth uses replace_file_with_string replace_file_with_string uses sliverauth's atomic code --- plugins/sliverauth.py | 122 ++++++++++++++++++++++++------------------ tools.py | 24 +++++---- 2 files changed, 83 insertions(+), 63 deletions(-) diff --git a/plugins/sliverauth.py b/plugins/sliverauth.py index e840a4d..15f0142 100644 --- a/plugins/sliverauth.py +++ b/plugins/sliverauth.py @@ -4,7 +4,11 @@ # $Id$ # $URL$ # -# NodeManager plugin to empower slivers to make API calls +# NodeManager plugin for creating credentials in slivers +# (*) empower slivers to make API calls throught hmac +# (*) also create a ssh key - used by the OMF resource controller +# for authenticating itself with its Experiment Controller +# xxx todo : a config option for turning these 2 things on or off ? """ Sliver authentication support for NodeManager. @@ -22,22 +26,7 @@ import logger import tools def start(options, conf): - logger.log("sliverauth: plugin starting up...") - -def SetSliverTag(plc, slice, tagname, value): - node_id = tools.node_id() - slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname}) - if len(slivertags)==0: - # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node - # and this is something that AddSliceTag does not like - try: - slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id) - except: - logger.log ("sliverauth: SetSliverTag - CAUGHT exception for (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals()) - pass - else: - slivertag_id=slivertags[0]['slice_tag_id'] - plc.UpdateSliceTag(slivertag_id,value) + logger.log("sliverauth: (dummy) plugin starting up...") def GetSlivers(data, config, plc): if 'OVERRIDES' in dir(config): @@ -58,39 +47,66 @@ def GetSlivers(data, config, plc): logger.log("sliverauth: plc-instantiated slice %s does not yet exist. IGNORING!" % sliver['name']) continue - found_hmac = False - for attribute in sliver['attributes']: - name = attribute.get('tagname',attribute.get('name','')) - if name == 'hmac': - found_hmac = True - hmac = attribute['value'] - break - - if not found_hmac: - # XXX need a better random seed?! - random.seed(time.time()) - d = [random.choice(string.letters) for x in xrange(32)] - hmac = "".join(d) - SetSliverTag(plc,sliver['name'],'hmac',hmac) - logger.log("sliverauth: setting %s hmac" % sliver['name']) - - path = '/vservers/%s/etc/planetlab' % sliver['name'] - if os.path.exists(path): - keyfile = '%s/key' % path - oldhmac = '' - if os.path.exists(keyfile): - f = open(keyfile,'r') - oldhmac = f.read() - f.close() - - if oldhmac <> hmac: - # create a temporary file in the vserver - fd, name = tempfile.mkstemp('','key',path) - os.write(fd,hmac) - os.close(fd) - if os.path.exists(keyfile): - os.unlink(keyfile) - os.rename(name,keyfile) - logger.log("sliverauth: writing hmac to %s " % keyfile) - - os.chmod(keyfile,0400) + manage_hmac (plc, sliver) + manage_sshkey (plc, sliver) + + +def SetSliverTag(plc, slice, tagname, value): + node_id = tools.node_id() + slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname}) + if len(slivertags)==0: + # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node + # and this is something that AddSliceTag does not like + try: + slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id) + except: + logger.log_exc ("sliverauth.SetSliverTag (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals()) + pass + else: + slivertag_id=slivertags[0]['slice_tag_id'] + plc.UpdateSliceTag(slivertag_id,value) + +def find_tag (sliver, tagname): + for attribute in sliver['attributes']: + # for legacy, try the old-fashioned 'name' as well + name = attribute.get('tagname',attribute.get('name','')) + if name == tagname: + return attribute['value'] + return None + +def manage_hmac (plc, sliver): + hmac = find_tag (sliver, 'hmac') + + if not hmac: + # let python do its thing + random.seed() + d = [random.choice(string.letters) for x in xrange(32)] + hmac = "".join(d) + SetSliverTag(plc,sliver['name'],'hmac',hmac) + logger.log("sliverauth: %s: setting hmac" % sliver['name']) + + path = '/vservers/%s/etc/planetlab' % sliver['name'] + if os.path.exists(path): + keyfile = '%s/key' % path + if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)): + logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile) + +def manage_sshkey (plc, sliver): + ssh_key = find_tag (sliver, 'ssh_key') + + # generate if not present + if not ssh_key: + # create dir if needed + dotssh="/vservers/%s/home/%s/.ssh"%(sliver['name'],sliver['name']) + if not os.path.isdir (dotssh): + os.mkdir (dotssh, 0700) + logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), dotssh ] ) + keyfile="%s/id_rsa"%dotssh + pubfile="%s.pub"%keyfile + if not os.path.isfile (pubfile): + logger.log_call( [ 'ssh-keygen', '-t', 'rsa', '-N', '', '-f', keyfile ] ) + os.chmod (keyfile, 0400) + logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), keyfile, pubfile ] ) + ssh_key = file(pubfile).read() + SetSliverTag(plc, sliver['name'], 'ssh_key', ssh_key) + logger.log ("sliverauth: %s: setting ssh_key" % sliver['name']) diff --git a/tools.py b/tools.py index b6a189a..22895c4 100644 --- a/tools.py +++ b/tools.py @@ -3,7 +3,7 @@ """A few things that didn't seem to fit anywhere else.""" -import os +import os, os.path import pwd import tempfile import fcntl @@ -123,8 +123,11 @@ def write_temp_file(do_write, mode=None, uidgid=None): return temporary_filename # replace a target file with a new contents - checks for changes -# return True if a change occurred, in which case -# chown/chmod settings should be taken care of +# can handle chmod if requested +# can also remove resulting file if contents are void, if requested +# performs atomically: +# writes in a tmp file, which is then renamed (from sliverauth originally) +# returns True if a change occurred, or the file is deleted def replace_file_with_string (target, new_contents, chmod=None, remove_if_empty=False): try: current=file(target).read() @@ -138,16 +141,17 @@ def replace_file_with_string (target, new_contents, chmod=None, remove_if_empty= try: os.unlink(target) finally: return True return False - # overwrite target file - f=file(target,'w') - f.write(new_contents) - f.close() + # overwrite target file: create a temp in the same directory + path=os.path.dirname(target) or '.' + fd, name = tempfile.mkstemp('','repl',path) + os.write(fd,new_contents) + os.close(fd) + if os.path.exists(target): + os.unlink(target) + os.rename(name,target) if chmod: os.chmod(target,chmod) return True -# not needed yet - should that unlink the new file ? -#def replace_file_with_file (target, new): -# return replace_file_with_string (target, file(new).read()) #################### # utilities functions to get (cached) information from the node -- 2.43.0