@@ -207,85 +207,98 @@ def substitute_cfg(setting, key, val, newval, cfgfile, line):
207207 return False
208208
209209async def create_full_ca (certout ):
210- mkdirp ('/etc/confluent/tls/ca/private' )
211- keyout = '/etc/confluent/tls/ca/private/cakey.pem'
212- csrout = '/etc/confluent/tls/ca/ca.csr'
213- mkdirp ('/etc/confluent/tls/ca/newcerts' )
214- with open ('/etc/confluent/tls/ca/index.txt' , 'w' ) as idx :
215- pass
216- with open ('/etc/confluent/tls/ca/index.txt.attr' , 'w' ) as idx :
217- idx .write ('unique_subject = no' )
218- with open ('/etc/confluent/tls/ca/serial' , 'w' ) as srl :
219- srl .write ('01' )
220- sslcfg = get_openssl_conf_location ()
221- newcfg = '/etc/confluent/tls/ca/openssl.cfg'
222- settings = {
223- 'dir' : '/etc/confluent/tls/ca' ,
224- 'certificate' : '$dir/cacert.pem' ,
225- 'private_key' : '$dir/private/cakey.pem' ,
226- 'countryName' : 'optional' ,
227- 'stateOrProvinceName' : 'optional' ,
228- 'organizationName' : 'optional' ,
229- }
230- subj = '/CN=Confluent TLS Certificate authority ({0})' .format (socket .gethostname ())
231- if len (subj ) > 68 :
232- subj = subj [:68 ]
233- with open (sslcfg , 'r' ) as cfgin :
234- with open (newcfg , 'w' ) as cfgfile :
235- for line in cfgin .readlines ():
236- cfg = line .split ('#' )[0 ]
237- if '=' in cfg :
238- key , val = cfg .split ('=' , 1 )
239- for stg in settings :
240- if substitute_cfg (stg , key , val , settings [stg ], cfgfile , line ):
241- break
242- else :
243- cfgfile .write (line .strip () + '\n ' )
244- continue
245- cfgfile .write (line .strip () + '\n ' )
246- cfgfile .write ('\n [CACert]\n basicConstraints = critical,CA:true\n keyUsage = critical,keyCertSign,cRLSign\n [ca_confluent]\n ' )
247- await util .check_call (
248- 'openssl' , 'ecparam' , '-name' , 'secp384r1' , '-genkey' , '-out' ,
249- keyout )
250- await util .check_call (
251- 'openssl' , 'req' , '-new' , '-key' , keyout , '-out' , csrout , '-subj' , subj )
252- await util .check_call (
253- 'openssl' , 'ca' , '-config' , newcfg , '-batch' , '-selfsign' ,
254- '-extensions' , 'CACert' , '-extfile' , newcfg ,
255- '-notext' , '-md' , 'sha384' , '-startdate' ,
256- '19700101010101Z' , '-enddate' , '21000101010101Z' , '-keyfile' ,
257- keyout , '-out' , '/etc/confluent/tls/ca/cacert.pem' , '-in' , csrout
258- )
259- shutil .copy2 ('/etc/confluent/tls/ca/cacert.pem' , certout )
210+ # The CA is used by the confluent service, which runs as the owner of
211+ # /etc/confluent rather than root; create the CA material as that user
212+ # so the service can use the database for issuing certificates
213+ ouid = normalize_uid ()
214+ try :
215+ mkdirp ('/etc/confluent/tls/ca/private' )
216+ keyout = '/etc/confluent/tls/ca/private/cakey.pem'
217+ csrout = '/etc/confluent/tls/ca/ca.csr'
218+ mkdirp ('/etc/confluent/tls/ca/newcerts' )
219+ with open ('/etc/confluent/tls/ca/index.txt' , 'w' ) as idx :
220+ pass
221+ with open ('/etc/confluent/tls/ca/index.txt.attr' , 'w' ) as idx :
222+ idx .write ('unique_subject = no' )
223+ with open ('/etc/confluent/tls/ca/serial' , 'w' ) as srl :
224+ srl .write ('01' )
225+ sslcfg = get_openssl_conf_location ()
226+ newcfg = '/etc/confluent/tls/ca/openssl.cfg'
227+ settings = {
228+ 'dir' : '/etc/confluent/tls/ca' ,
229+ 'certificate' : '$dir/cacert.pem' ,
230+ 'private_key' : '$dir/private/cakey.pem' ,
231+ 'countryName' : 'optional' ,
232+ 'stateOrProvinceName' : 'optional' ,
233+ 'organizationName' : 'optional' ,
234+ }
235+ subj = '/CN=Confluent TLS Certificate authority ({0})' .format (socket .gethostname ())
236+ if len (subj ) > 68 :
237+ subj = subj [:68 ]
238+ with open (sslcfg , 'r' ) as cfgin :
239+ with open (newcfg , 'w' ) as cfgfile :
240+ for line in cfgin .readlines ():
241+ cfg = line .split ('#' )[0 ]
242+ if '=' in cfg :
243+ key , val = cfg .split ('=' , 1 )
244+ for stg in settings :
245+ if substitute_cfg (stg , key , val , settings [stg ], cfgfile , line ):
246+ break
247+ else :
248+ cfgfile .write (line .strip () + '\n ' )
249+ continue
250+ cfgfile .write (line .strip () + '\n ' )
251+ cfgfile .write ('\n [CACert]\n basicConstraints = critical,CA:true\n keyUsage = critical,keyCertSign,cRLSign\n [ca_confluent]\n ' )
252+ await util .check_call (
253+ 'openssl' , 'ecparam' , '-name' , 'secp384r1' , '-genkey' , '-out' ,
254+ keyout )
255+ await util .check_call (
256+ 'openssl' , 'req' , '-new' , '-key' , keyout , '-out' , csrout , '-subj' , subj )
257+ await util .check_call (
258+ 'openssl' , 'ca' , '-config' , newcfg , '-batch' , '-selfsign' ,
259+ '-extensions' , 'CACert' , '-extfile' , newcfg ,
260+ '-notext' , '-md' , 'sha384' , '-startdate' ,
261+ '19700101010101Z' , '-enddate' , '21000101010101Z' , '-keyfile' ,
262+ keyout , '-out' , '/etc/confluent/tls/ca/cacert.pem' , '-in' , csrout
263+ )
264+ shutil .copy2 ('/etc/confluent/tls/ca/cacert.pem' , certout )
265+ finally :
266+ os .seteuid (ouid )
260267#openssl ca -config openssl.cnf -selfsign -keyfile cakey.pem -startdate 20150214120000Z -enddate 20160214120000Z
261268#20160107071311Z -enddate 20170106071311Z
262269
263270async def create_simple_ca (keyout , certout ):
271+ # As with create_full_ca, the CA material must be owned by the owner
272+ # of /etc/confluent for use by the confluent service
273+ ouid = normalize_uid ()
264274 try :
265- os .makedirs ('/etc/confluent/tls' )
266- except OSError as e :
267- if e .errno != 17 :
268- raise
269- sslcfg = get_openssl_conf_location ()
270- tmphdl , tmpconfig = tempfile .mkstemp ()
271- os .close (tmphdl )
272- shutil .copy2 (sslcfg , tmpconfig )
273- await util .check_call (
274- 'openssl' , 'ecparam' , '-name' , 'secp384r1' , '-genkey' , '-out' ,
275- keyout )
276- try :
277- subj = '/CN=Confluent TLS Certificate authority ({0})' .format (socket .gethostname ())
278- if len (subj ) > 68 :
279- subj = subj [:68 ]
280- with open (tmpconfig , 'a' ) as cfgfile :
281- cfgfile .write ('\n [CACert]\n basicConstraints = critical,CA:true\n ' )
275+ try :
276+ os .makedirs ('/etc/confluent/tls' )
277+ except OSError as e :
278+ if e .errno != 17 :
279+ raise
280+ sslcfg = get_openssl_conf_location ()
281+ tmphdl , tmpconfig = tempfile .mkstemp ()
282+ os .close (tmphdl )
283+ shutil .copy2 (sslcfg , tmpconfig )
282284 await util .check_call (
283- 'openssl' , 'req' , '-new' , '-x509' , '-key' , keyout , '-days' ,
284- '27300' , '-out' , certout , '-subj' , subj ,
285- '-extensions' , 'CACert' , '-config' , tmpconfig
286- )
285+ 'openssl' , 'ecparam' , '-name' , 'secp384r1' , '-genkey' , '-out' ,
286+ keyout )
287+ try :
288+ subj = '/CN=Confluent TLS Certificate authority ({0})' .format (socket .gethostname ())
289+ if len (subj ) > 68 :
290+ subj = subj [:68 ]
291+ with open (tmpconfig , 'a' ) as cfgfile :
292+ cfgfile .write ('\n [CACert]\n basicConstraints = critical,CA:true\n ' )
293+ await util .check_call (
294+ 'openssl' , 'req' , '-new' , '-x509' , '-key' , keyout , '-days' ,
295+ '27300' , '-out' , certout , '-subj' , subj ,
296+ '-extensions' , 'CACert' , '-config' , tmpconfig
297+ )
298+ finally :
299+ os .remove (tmpconfig )
287300 finally :
288- os .remove ( tmpconfig )
301+ os .seteuid ( ouid )
289302
290303async def create_certificate (keyout = None , certout = None , csrfile = None , subj = None , san = None , backdate = True , days = None ):
291304 now_utc = datetime .datetime .now (datetime .timezone .utc )
@@ -413,12 +426,30 @@ async def create_certificate(keyout=None, certout=None, csrfile=None, subj=None,
413426 shutil .copy2 (cacfgfile , tmpcafile )
414427 os .close (tmphdl )
415428 cacfgfile = tmpcafile
416- await util .check_call (
417- 'openssl' , 'ca' , '-config' , cacfgfile , '-rand_serial' ,
418- '-in' , csrfile , '-out' , certout , '-batch' , '-notext' ,
419- '-startdate' , startdate , '-enddate' , enddate , '-md' , 'sha384' ,
420- '-extfile' , extconfig , '-subj' , subj
421- )
429+ os .chmod (cacfgfile , 0o644 )
430+ os .chmod (csrfile , 0o644 )
431+ # openssl ca rewrites the CA database (index, serial) as the
432+ # invoking user; run it as the owner of /etc/confluent so the
433+ # database remains usable by the confluent service. The chmodded
434+ # temporary inputs hold no secrets, and the certificate is
435+ # written to a temporary path first, as certout may only be
436+ # writable by the original user (e.g. a web server certificate
437+ # path during osdeploy initialize -t)
438+ os .chmod (extconfig , 0o644 )
439+ ouid = normalize_uid ()
440+ try :
441+ tmphdl , tmpcertout = tempfile .mkstemp ()
442+ os .close (tmphdl )
443+ await util .check_call (
444+ 'openssl' , 'ca' , '-config' , cacfgfile , '-rand_serial' ,
445+ '-in' , csrfile , '-out' , tmpcertout , '-batch' , '-notext' ,
446+ '-startdate' , startdate , '-enddate' , enddate , '-md' , 'sha384' ,
447+ '-extfile' , extconfig , '-subj' , subj
448+ )
449+ finally :
450+ os .seteuid (ouid )
451+ shutil .copy (tmpcertout , certout )
452+ os .remove (tmpcertout )
422453 for keycopy in tlsmateriallocation .get ('keys' , []):
423454 if keycopy != keyout :
424455 shutil .copy2 (keyout , keycopy )
0 commit comments