37
from nova import exception
37
gettext.install('nova', unicode=1)
39
from nova import context
38
41
from nova import flags
41
44
FLAGS = flags.FLAGS
42
flags.DEFINE_string('ca_file', 'cacert.pem', 'Filename of root CA')
45
flags.DEFINE_string('ca_file', 'cacert.pem', _('Filename of root CA'))
46
flags.DEFINE_string('key_file',
47
os.path.join('private', 'cakey.pem'),
48
_('Filename of private key'))
49
flags.DEFINE_string('crl_file', 'crl.pem',
50
_('Filename of root Certificate Revokation List'))
43
51
flags.DEFINE_string('keys_path', '$state_path/keys',
44
'Where we keep our keys')
52
_('Where we keep our keys'))
45
53
flags.DEFINE_string('ca_path', '$state_path/CA',
46
'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)
54
_('Where we keep our root CA'))
55
flags.DEFINE_boolean('use_project_ca', False,
56
_('Should we use a CA for each project?'))
57
flags.DEFINE_string('user_cert_subject',
58
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
59
'OU=NovaDev/CN=%s-%s-%s',
60
_('Subject for certificate for users, '
61
'%s for project, user, timestamp'))
62
flags.DEFINE_string('project_cert_subject',
63
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
64
'OU=NovaDev/CN=project-ca-%s-%s',
65
_('Subject for certificate for projects, '
66
'%s for project, timestamp'))
67
flags.DEFINE_string('vpn_cert_subject',
68
'/C=US/ST=California/L=MountainView/O=AnsoLabs/'
69
'OU=NovaDev/CN=project-vpn-%s-%s',
70
_('Subject for certificate for vpns, '
71
'%s for project, timestamp'))
74
def ca_folder(project_id=None):
75
if FLAGS.use_project_ca and project_id:
76
return os.path.join(FLAGS.ca_path, 'projects', project_id)
80
def ca_path(project_id=None):
81
return os.path.join(ca_folder(project_id), FLAGS.ca_file)
84
def key_path(project_id=None):
85
return os.path.join(ca_folder(project_id), FLAGS.key_file)
57
88
def fetch_ca(project_id=None, chain=True):
58
if not FLAGS.use_intermediate_ca:
89
if not FLAGS.use_project_ca:
106
137
return '%s %s %s@%s\n' % (key_type, b64_blob, name, suffix)
109
def generate_x509_cert(subject, bits=1024):
140
def revoke_cert(project_id, file_name):
141
"""Revoke a cert by file name"""
143
os.chdir(ca_folder(project_id))
144
# NOTE(vish): potential race condition here
145
utils.execute("openssl ca -config ./openssl.cnf -revoke '%s'" % file_name)
146
utils.execute("openssl ca -gencrl -config ./openssl.cnf -out '%s'" %
151
def revoke_certs_by_user(user_id):
152
"""Revoke all user certs"""
153
admin = context.get_admin_context()
154
for cert in db.certificate_get_all_by_user(admin, user_id):
155
revoke_cert(cert['project_id'], cert['file_name'])
158
def revoke_certs_by_project(project_id):
159
"""Revoke all project certs"""
160
# NOTE(vish): This is somewhat useless because we can just shut down
162
admin = context.get_admin_context()
163
for cert in db.certificate_get_all_by_project(admin, project_id):
164
revoke_cert(cert['project_id'], cert['file_name'])
167
def revoke_certs_by_user_and_project(user_id, project_id):
168
"""Revoke certs for user in project"""
169
admin = context.get_admin_context()
170
for cert in db.certificate_get_all_by_user(admin, user_id, project_id):
171
revoke_cert(cert['project_id'], cert['file_name'])
174
def _project_cert_subject(project_id):
175
"""Helper to generate user cert subject"""
176
return FLAGS.project_cert_subject % (project_id, utils.isotime())
179
def _vpn_cert_subject(project_id):
180
"""Helper to generate user cert subject"""
181
return FLAGS.vpn_cert_subject % (project_id, utils.isotime())
184
def _user_cert_subject(user_id, project_id):
185
"""Helper to generate user cert subject"""
186
return FLAGS.user_cert_subject % (project_id, user_id, utils.isotime())
189
def generate_x509_cert(user_id, project_id, bits=1024):
190
"""Generate and sign a cert for user in project"""
191
subject = _user_cert_subject(user_id, project_id)
110
192
tmpdir = tempfile.mkdtemp()
111
193
keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
112
194
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" %
195
utils.execute("openssl genrsa -out %s %s" % (keyfile, bits))
196
utils.execute("openssl req -new -key %s -out %s -batch -subj %s" %
118
197
(keyfile, csrfile, subject))
119
198
private_key = open(keyfile).read()
120
199
csr = open(csrfile).read()
121
200
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):
201
(serial, signed_csr) = sign_csr(csr, project_id)
202
fname = os.path.join(ca_folder(project_id), "newcerts/%s.pem" % serial)
203
cert = {'user_id': user_id,
204
'project_id': project_id,
206
db.certificate_create(context.get_admin_context(), cert)
207
return (private_key, signed_csr)
210
def _ensure_project_folder(project_id):
211
if not os.path.exists(ca_path(project_id)):
132
212
start = os.getcwd()
133
os.chdir(FLAGS.ca_path)
134
utils.runthis("Generating intermediate CA: %s",
135
"sh geninter.sh %s" % (intermediate))
213
os.chdir(ca_folder())
214
utils.execute("sh geninter.sh %s %s" %
215
(project_id, _project_cert_subject(project_id)))
137
return _sign_csr(csr_text, user_ca)
219
def generate_vpn_files(project_id):
220
project_folder = ca_folder(project_id)
221
csr_fn = os.path.join(project_folder, "server.csr")
222
crt_fn = os.path.join(project_folder, "server.crt")
224
if os.path.exists(crt_fn):
226
_ensure_project_folder(project_id)
228
os.chdir(ca_folder())
229
# TODO(vish): the shell scripts could all be done in python
230
utils.execute("sh genvpn.sh %s %s" %
231
(project_id, _vpn_cert_subject(project_id)))
232
with open(csr_fn, "r") as csrfile:
233
csr_text = csrfile.read()
234
(serial, signed_csr) = sign_csr(csr_text, project_id)
235
with open(crt_fn, "w") as crtfile:
236
crtfile.write(signed_csr)
240
def sign_csr(csr_text, project_id=None):
241
if not FLAGS.use_project_ca:
244
return _sign_csr(csr_text, ca_folder())
245
_ensure_project_folder(project_id)
246
project_folder = ca_folder(project_id)
247
return _sign_csr(csr_text, ca_folder(project_id))
140
250
def _sign_csr(csr_text, ca_folder):
141
251
tmpfolder = tempfile.mkdtemp()
142
csrfile = open("%s/inbound.csr" % (tmpfolder), "w")
252
inbound = os.path.join(tmpfolder, "inbound.csr")
253
outbound = os.path.join(tmpfolder, "outbound.csr")
254
csrfile = open(inbound, "w")
143
255
csrfile.write(csr_text)
145
logging.debug("Flags path: %s" % ca_folder)
257
logging.debug(_("Flags path: %s") % ca_folder)
146
258
start = os.getcwd()
147
259
# Change working dir to CA
148
260
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))
261
utils.execute("openssl ca -batch -out %s -config "
262
"./openssl.cnf -infiles %s" % (outbound, inbound))
263
out, _err = utils.execute("openssl x509 -in %s -serial -noout" % outbound)
264
serial = out.rpartition("=")[2]
154
with open("%s/outbound.crt" % (tmpfolder), "r") as crtfile:
155
return crtfile.read()
266
with open(outbound, "r") as crtfile:
267
return (serial, crtfile.read())
158
270
def mkreq(bits, subject="foo", ca=0):