1 ##############################################################################
3 # Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved.
5 # WARNING: This program as such is intended to be used by professional
6 # programmers who take the whole responsibility of assessing all potential
7 # consequences resulting from its eventual inadequacies and bugs
8 # End users who are looking for a ready-to-use solution with commercial
9 # guarantees and support are strongly adviced to contract a Free Software
12 # This program is Free Software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 3
15 # of the License, or (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 ##############################################################################
32 from slapos
.recipe
.librecipe
import GenericBaseRecipe
33 from slapos
.recipe
.librecipe
.inotify
import subfiles
35 # This authority only works with dropbear sshkey generator
36 def sshkeys_authority(args
):
37 requests_directory
= args
['requests']
38 keygen_binary
= args
['sshkeygen']
40 for request_filename
in subfiles(requests_directory
):
42 with
open(request_filename
) as request_file
:
43 request
= json
.load(request_file
)
45 key_type
= request
.get('type', 'rsa')
46 size
= str(request
.get('size', 2048))
48 private_key
= request
['private_key']
49 public_key
= request
['public_key']
53 if not os
.path
.exists(private_key
):
54 keygen_cmd
= [keygen_binary
, '-t', key_type
, '-f', private_key
,
56 # If the keygeneration return an non-zero status, it means there's a
57 # big problem. Let's exit in this case
58 subprocess
.check_call(keygen_cmd
, env
=os
.environ
.copy())
60 if not os
.path
.exists(public_key
):
61 keygen_cmd
= [keygen_binary
, '-f', private_key
, '-y']
63 keygen
= subprocess
.Popen(keygen_cmd
, stdout
=subprocess
.PIPE
,
64 stdin
=subprocess
.PIPE
,
65 stderr
=subprocess
.STDOUT
,
66 env
=os
.environ
.copy())
70 # If the keygeneration return an non-zero status, it means there's a
71 # big problem. Let's exit in this case
72 if keygen
.wait() != 0:
73 raise subprocess
.CalledProcessError("%r returned a non-zero status" % \
75 # Line : "Public key portion is :"
76 keygen
.stdout
.readline()
77 public_key_value
= keygen
.stdout
.readline().strip()
78 with
open(public_key
, 'w') as public_key_file
:
79 public_key_file
.write(public_key_value
)
83 class Recipe(GenericBaseRecipe
):
87 requests
=self
.options
['request-directory'],
88 sshkeygen
=self
.options
['keygen-binary'],
91 wrapper
= self
.createPythonScript(self
.options
['wrapper'],
92 __name__
+ '.sshkeys_authority', args
)
95 class Request(GenericBaseRecipe
):
97 def _options(self
, options
):
98 if 'name' not in options
:
99 options
['name'] = self
.name
101 keys_directory
= options
['keys-directory']
103 self
.private_key
= os
.path
.join(keys_directory
,
104 hashlib
.sha256(options
['name']).hexdigest())
105 self
.public_key
= self
.private_key
+ '.pub'
107 if os
.path
.exists(self
.public_key
):
108 with
open(self
.public_key
) as key
:
109 options
['public-key-value'] = key
.read()
111 options
['public-key-value'] = ''
114 requests_directory
= self
.options
['request-directory']
115 request_file
= os
.path
.join(requests_directory
, self
.options
['name'])
118 private_key
=self
.private_key
,
119 public_key
=self
.public_key
,
121 if 'size' in self
.options
:
122 request
.update(size
=int(self
.options
['size'], 10))
123 if 'type' in self
.options
:
124 request
.update(type=self
.options
['type'])
126 with
open(request_file
, 'w') as file_
:
127 json
.dump(request
, file_
)
129 public_key_link
, private_key_link
= (self
.options
['public-key'],
130 self
.options
['private-key'],
132 # XXX: Copy and past from certificate_authority/__init__.py:Request
133 # We should factorize that
134 for link
in [public_key_link
, private_key_link
]:
135 if os
.path
.islink(link
):
137 elif os
.path
.exists(link
):
138 raise OSError("%r should be a symbolic link." % link
)
140 os
.symlink(self
.public_key
, public_key_link
)
141 os
.symlink(self
.private_key
, private_key_link
)
144 wrapper
= self
.createPythonScript(
145 self
.options
['wrapper'],
146 'slapos.recipe.librecipe.execute.execute_wait',
147 [ [self
.options
['executable']],
148 [self
.private_key
, self
.public_key
] ])
151 return [request_file
, wrapper
, public_key_link
, private_key_link
]