Generate random CommonName
[slapos.git] / slapos / recipe / kvm / certificate_authority.py
1 import os
2 import subprocess
3 import time
4 import ConfigParser
5 import uuid
6
7
8 def popenCommunicate(command_list, input=None):
9 subprocess_kw = dict(stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
10 if input is not None:
11 subprocess_kw.update(stdin=subprocess.PIPE)
12 popen = subprocess.Popen(command_list, **subprocess_kw)
13 result = popen.communicate(input)[0]
14 if popen.returncode is None:
15 popen.kill()
16 if popen.returncode != 0:
17 raise ValueError('Issue during calling %r, result was:\n%s' % (
18 command_list, result))
19 return result
20
21
22 class CertificateAuthority:
23 def __init__(self, key, certificate, openssl_binary,
24 openssl_configuration, request_dir):
25 self.key = key
26 self.certificate = certificate
27 self.openssl_binary = openssl_binary
28 self.openssl_configuration = openssl_configuration
29 self.request_dir = request_dir
30
31 def checkAuthority(self):
32 file_list = [ self.key, self.certificate ]
33 ca_ready = True
34 for f in file_list:
35 if not os.path.exists(f):
36 ca_ready = False
37 break
38 if ca_ready:
39 return
40 for f in file_list:
41 if os.path.exists(f):
42 os.unlink(f)
43 try:
44 # no CA, let us create new one
45 popenCommunicate([self.openssl_binary, 'req', '-nodes', '-config',
46 self.openssl_configuration, '-new', '-x509', '-extensions', 'v3_ca',
47 '-keyout', self.key, '-out', self.certificate, '-days', '10950'],
48 'Automatic Certificate Authority %s\n' % uuid.uuid1())
49 except:
50 try:
51 for f in file_list:
52 if os.path.exists(f):
53 os.unlink(f)
54 except:
55 # do not raise during cleanup
56 pass
57 raise
58
59 def _checkCertificate(self, common_name, key, certificate):
60 file_list = [key, certificate]
61 ready = True
62 for f in file_list:
63 if not os.path.exists(f):
64 ready = False
65 break
66 if ready:
67 return False
68 for f in file_list:
69 if os.path.exists(f):
70 os.unlink(f)
71 csr = certificate + '.csr'
72 try:
73 popenCommunicate([self.openssl_binary, 'req', '-config',
74 self.openssl_configuration, '-nodes', '-new', '-keyout',
75 key, '-out', csr, '-days', '3650'],
76 common_name + '\n')
77 try:
78 popenCommunicate([self.openssl_binary, 'ca', '-batch', '-config',
79 self.openssl_configuration, '-out', certificate,
80 '-infiles', csr])
81 finally:
82 if os.path.exists(csr):
83 os.unlink(csr)
84 except:
85 try:
86 for f in file_list:
87 if os.path.exists(f):
88 os.unlink(f)
89 except:
90 # do not raise during cleanup
91 pass
92 raise
93 else:
94 return True
95
96 def checkRequestDir(self):
97 for request_file in os.listdir(self.request_dir):
98 parser = ConfigParser.RawConfigParser()
99 parser.readfp(open(os.path.join(self.request_dir, request_file), 'r'))
100 if self._checkCertificate(parser.get('certificate', 'name'),
101 parser.get('certificate', 'key_file'), parser.get('certificate',
102 'certificate_file')):
103 print 'Created certificate %r' % parser.get('certificate', 'name')
104
105 def runCertificateAuthority(args):
106 ca_conf = args[0]
107 ca = CertificateAuthority(ca_conf['key'], ca_conf['certificate'],
108 ca_conf['openssl_binary'], ca_conf['openssl_configuration'],
109 ca_conf['request_dir'])
110 while True:
111 ca.checkAuthority()
112 ca.checkRequestDir()
113 time.sleep(60)