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