37
from nova import exception
36
from nova import context
38
38
from nova import flags
41
41
FLAGS = flags.FLAGS
42
42
flags.DEFINE_string('ca_file', 'cacert.pem', _('Filename of root CA'))
43
flags.DEFINE_string('key_file',
44
os.path.join('private', 'cakey.pem'),
45
_('Filename of private key'))
46
flags.DEFINE_string('crl_file', 'crl.pem',
47
_('Filename of root Certificate Revokation List'))
43
48
flags.DEFINE_string('keys_path', '$state_path/keys',
44
49
_('Where we keep our keys'))
45
50
flags.DEFINE_string('ca_path', '$state_path/CA',
46
51
_('Where we keep our root CA'))
47
flags.DEFINE_boolean('use_intermediate_ca', False,
48
_('Should we use intermediate CAs for each project?'))
51
def ca_path(project_id):
53
return "%s/INTER/%s/cacert.pem" % (FLAGS.ca_path, project_id)
54
return "%s/cacert.pem" % (FLAGS.ca_path)
52
flags.DEFINE_boolean('use_project_ca', False,
53
_('Should we use a CA for each project?'))
54
flags.DEFINE_string('user_cert_subject',
55
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
56
'OU=NovaDev/CN=%s-%s-%s',
57
_('Subject for certificate for users, '
58
'%s for project, user, timestamp'))
59
flags.DEFINE_string('project_cert_subject',
60
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
61
'OU=NovaDev/CN=project-ca-%s-%s',
62
_('Subject for certificate for projects, '
63
'%s for project, timestamp'))
64
flags.DEFINE_string('vpn_cert_subject',
65
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
66
'OU=NovaDev/CN=project-vpn-%s-%s',
67
_('Subject for certificate for vpns, '
68
'%s for project, timestamp'))
71
def ca_folder(project_id=None):
72
if FLAGS.use_project_ca and project_id:
73
return os.path.join(FLAGS.ca_path, 'projects', project_id)
77
def ca_path(project_id=None):
78
return os.path.join(ca_folder(project_id), FLAGS.ca_file)
81
def key_path(project_id=None):
82
return os.path.join(ca_folder(project_id), FLAGS.key_file)
57
85
def fetch_ca(project_id=None, chain=True):
58
if not FLAGS.use_intermediate_ca:
86
if not FLAGS.use_project_ca:
106
134
return '%s %s %s@%s\n' % (key_type, b64_blob, name, suffix)
109
def generate_x509_cert(subject, bits=1024):
137
def revoke_cert(project_id, file_name):
138
"""Revoke a cert by file name"""
140
os.chdir(ca_folder(project_id))
141
# NOTE(vish): potential race condition here
142
utils.execute("openssl ca -config ./openssl.cnf -revoke '%s'" % file_name)
143
utils.execute("openssl ca -gencrl -config ./openssl.cnf -out '%s'" %
148
def revoke_certs_by_user(user_id):
149
"""Revoke all user certs"""
150
admin = context.get_admin_context()
151
for cert in db.certificate_get_all_by_user(admin, user_id):
152
revoke_cert(cert['project_id'], cert['file_name'])
155
def revoke_certs_by_project(project_id):
156
"""Revoke all project certs"""
157
# NOTE(vish): This is somewhat useless because we can just shut down
159
admin = context.get_admin_context()
160
for cert in db.certificate_get_all_by_project(admin, project_id):
161
revoke_cert(cert['project_id'], cert['file_name'])
164
def revoke_certs_by_user_and_project(user_id, project_id):
165
"""Revoke certs for user in project"""
166
admin = context.get_admin_context()
167
for cert in db.certificate_get_all_by_user(admin, user_id, project_id):
168
revoke_cert(cert['project_id'], cert['file_name'])
171
def _project_cert_subject(project_id):
172
"""Helper to generate user cert subject"""
173
return FLAGS.project_cert_subject % (project_id, utils.isotime())
176
def _vpn_cert_subject(project_id):
177
"""Helper to generate user cert subject"""
178
return FLAGS.vpn_cert_subject % (project_id, utils.isotime())
181
def _user_cert_subject(user_id, project_id):
182
"""Helper to generate user cert subject"""
183
return FLAGS.user_cert_subject % (project_id, user_id, utils.isotime())
186
def generate_x509_cert(user_id, project_id, bits=1024):
187
"""Generate and sign a cert for user in project"""
188
subject = _user_cert_subject(user_id, project_id)
110
189
tmpdir = tempfile.mkdtemp()
111
190
keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
112
191
csrfile = os.path.join(tmpdir, 'temp.csr')
113
logging.debug("openssl genrsa -out %s %s" % (keyfile, bits))
114
utils.runthis(_("Generating private key: %s"),
115
"openssl genrsa -out %s %s" % (keyfile, bits))
116
utils.runthis(_("Generating CSR: %s"),
117
"openssl req -new -key %s -out %s -batch -subj %s" %
192
utils.execute("openssl genrsa -out %s %s" % (keyfile, bits))
193
utils.execute("openssl req -new -key %s -out %s -batch -subj %s" %
118
194
(keyfile, csrfile, subject))
119
195
private_key = open(keyfile).read()
120
196
csr = open(csrfile).read()
121
197
shutil.rmtree(tmpdir)
122
return (private_key, csr)
125
def sign_csr(csr_text, intermediate=None):
126
if not FLAGS.use_intermediate_ca:
129
return _sign_csr(csr_text, FLAGS.ca_path)
130
user_ca = "%s/INTER/%s" % (FLAGS.ca_path, intermediate)
131
if not os.path.exists(user_ca):
198
(serial, signed_csr) = sign_csr(csr, project_id)
199
fname = os.path.join(ca_folder(project_id), "newcerts/%s.pem" % serial)
200
cert = {'user_id': user_id,
201
'project_id': project_id,
203
db.certificate_create(context.get_admin_context(), cert)
204
return (private_key, signed_csr)
207
def _ensure_project_folder(project_id):
208
if not os.path.exists(ca_path(project_id)):
132
209
start = os.getcwd()
133
os.chdir(FLAGS.ca_path)
134
utils.runthis(_("Generating intermediate CA: %s"),
135
"sh geninter.sh %s" % (intermediate))
210
os.chdir(ca_folder())
211
utils.execute("sh geninter.sh %s %s" %
212
(project_id, _project_cert_subject(project_id)))
137
return _sign_csr(csr_text, user_ca)
216
def generate_vpn_files(project_id):
217
project_folder = ca_folder(project_id)
218
csr_fn = os.path.join(project_folder, "server.csr")
219
crt_fn = os.path.join(project_folder, "server.crt")
221
if os.path.exists(crt_fn):
223
_ensure_project_folder(project_id)
225
os.chdir(ca_folder())
226
# TODO(vish): the shell scripts could all be done in python
227
utils.execute("sh genvpn.sh %s %s" %
228
(project_id, _vpn_cert_subject(project_id)))
229
with open(csr_fn, "r") as csrfile:
230
csr_text = csrfile.read()
231
(serial, signed_csr) = sign_csr(csr_text, project_id)
232
with open(crt_fn, "w") as crtfile:
233
crtfile.write(signed_csr)
237
def sign_csr(csr_text, project_id=None):
238
if not FLAGS.use_project_ca:
241
return _sign_csr(csr_text, ca_folder())
242
_ensure_project_folder(project_id)
243
project_folder = ca_folder(project_id)
244
return _sign_csr(csr_text, ca_folder(project_id))
140
247
def _sign_csr(csr_text, ca_folder):
141
248
tmpfolder = tempfile.mkdtemp()
142
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")
249
inbound = os.path.join(tmpfolder, "inbound.csr")
250
outbound = os.path.join(tmpfolder, "outbound.csr")
251
csrfile = open(inbound, "w")
143
252
csrfile.write(csr_text)
145
254
logging.debug(_("Flags path: %s") % ca_folder)
146
255
start = os.getcwd()
147
256
# Change working dir to CA
148
257
os.chdir(ca_folder)
149
utils.runthis(_("Signing cert: %s"),
150
"openssl ca -batch -out %s/outbound.crt "
151
"-config ./openssl.cnf -infiles %s/inbound.csr" %
152
(tmpfolder, tmpfolder))
258
utils.execute("openssl ca -batch -out %s -config "
259
"./openssl.cnf -infiles %s" % (outbound, inbound))
260
out, _err = utils.execute("openssl x509 -in %s -serial -noout" % outbound)
261
serial = out.rpartition("=")[2]
154
with open("%s/outbound.crt" % (tmpfolder), "r") as crtfile:
155
return crtfile.read()
263
with open(outbound, "r") as crtfile:
264
return (serial, crtfile.read())
158
267
def mkreq(bits, subject="foo", ca=0):