store sliver ssh keys in the root /home and rely on the mounting vsys script to expose it
[nodemanager.git] / plugins / sliverauth.py
1 #!/usr/bin/python -tt
2 # vim:set ts=4 sw=4 expandtab:
3 #
4 # $Id$
5 # $URL$
6 #
7 # NodeManager plugin for creating credentials in slivers
8 # (*) empower slivers to make API calls throught hmac
9 # (*) also create a ssh key - used by the OMF resource controller 
10 #     for authenticating itself with its Experiment Controller
11 # xxx todo : a config option for turning these 2 things on or off ?
12
13 """
14 Sliver authentication support for NodeManager.
15
16 """
17
18 import os
19 import random
20 import string
21 import tempfile
22 import socket
23
24 import logger
25 import tools
26
27 def start():
28     logger.log("sliverauth: (dummy) plugin starting up...")
29
30 def GetSlivers(data, config, plc):
31     if 'OVERRIDES' in dir(config):
32         if config.OVERRIDES.get('sliverauth') == '-1':
33             logger.log("sliverauth:  Disabled", 2)
34             return
35
36     if 'slivers' not in data:
37         logger.log_missing_data("sliverauth.GetSlivers", 'slivers')
38         return
39
40     for sliver in data['slivers']:
41         path = '/vservers/%s' % sliver['name']
42         if not os.path.exists(path):
43             # ignore all non-plc-instantiated slivers
44             instantiation = sliver.get('instantiation','')
45             if instantiation == 'plc-instantiated':
46                 logger.log("sliverauth: plc-instantiated slice %s does not yet exist. IGNORING!" % sliver['name'])
47             continue
48
49         manage_hmac (plc, sliver)
50         manage_sshkey (plc, sliver)
51
52
53 def SetSliverTag(plc, slice, tagname, value):
54     node_id = tools.node_id()
55     slivertags=plc.GetSliceTags({"name":slice,"node_id":node_id,"tagname":tagname})
56     if len(slivertags)==0:
57         # looks like GetSlivers reports about delegated/nm-controller slices that do *not* belong to this node
58         # and this is something that AddSliceTag does not like
59         try:
60             slivertag_id=plc.AddSliceTag(slice,tagname,value,node_id)
61         except:
62             logger.log_exc ("sliverauth.SetSliverTag (probably delegated) slice=%(slice)s tag=%(tagname)s node_id=%(node_id)d"%locals())
63             pass
64     else:
65         slivertag_id=slivertags[0]['slice_tag_id']
66         plc.UpdateSliceTag(slivertag_id,value)
67
68 def find_tag (sliver, tagname):
69     for attribute in sliver['attributes']:
70         # for legacy, try the old-fashioned 'name' as well
71         name = attribute.get('tagname',attribute.get('name',''))
72         if name == tagname:
73             return attribute['value']
74     return None
75
76 def manage_hmac (plc, sliver):
77     hmac = find_tag (sliver, 'hmac')
78
79     if not hmac:
80         # let python do its thing 
81         random.seed()
82         d = [random.choice(string.letters) for x in xrange(32)]
83         hmac = "".join(d)
84         SetSliverTag(plc,sliver['name'],'hmac',hmac)
85         logger.log("sliverauth: %s: setting hmac" % sliver['name'])
86
87     path = '/vservers/%s/etc/planetlab' % sliver['name']
88     if os.path.exists(path):
89         keyfile = '%s/key' % path
90         if (tools.replace_file_with_string(keyfile,hmac,chmod=0400)):
91             logger.log ("sliverauth: (over)wrote hmac into %s " % keyfile)
92
93 # create the key if needed and returns the key contents
94 def generate_sshkey (sliver): 
95 # initial version was storing stuff in the sliver directly
96 #    keyfile="/vservers/%s/home/%s/.ssh/id_rsa"%(sliver['name'],sliver['name'])
97 # we're now storing this in the same place as the authorized_keys, which in turn
98 # gets mounted to the user's home directory in the sliver
99     keyfile="/home/%s/.ssh/id_rsa"%(sliver['name'],sliver['name'])
100     pubfile="%s.pub"%keyfile
101     dotssh=os.path.dirname(keyfile)
102     # create dir if needed
103     if not os.path.isdir (dotssh):
104         os.mkdir (dotssh, 0700)
105         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), dotssh ] )
106     if not os.path.isfile (pubfile):
107         comment="%s@%s"%(sliver['name'],socket.gethostname())
108         logger.log_call( [ 'ssh-keygen', '-t', 'rsa', '-N', '', '-f', keyfile , '-C', comment] )
109         os.chmod (keyfile, 0400)
110         logger.log_call ( [ 'chown', "%s:slices"%(sliver['name']), keyfile, pubfile ] )
111     return file(pubfile).read()
112
113 # a sliver can get created, deleted and re-created
114 # the slice having the tag is not sufficient to skip key geneneration
115 def manage_sshkey (plc, sliver):
116     # regardless of whether the tag is there or not, we need to grab the file
117     # if it's lost b/c e.g. the sliver was destroyed we cannot save the tags content
118     ssh_key = generate_sshkey(sliver)
119     old_tag = find_tag (sliver, 'ssh_key')
120     if ssh_key <> old_tag:
121         SetSliverTag(plc, sliver['name'], 'ssh_key', ssh_key)
122         logger.log ("sliverauth: %s: setting ssh_key" % sliver['name'])