mirror of
https://github.com/xcat2/confluent.git
synced 2024-11-21 17:11:58 +00:00
Provide components for cert management with modern XCC
Refresh getcsr and installcert to handle latest firmware. Also add ability to have pre-existing CSR, and trust the SAN on the way through. If this becomes more properly a feature, then would likely impose a SAN on certs, similar to the SSH principals, rather than deferring to the CSR to get it right.
This commit is contained in:
parent
77bb03e96c
commit
34804b2d5f
@ -206,7 +206,7 @@ def create_simple_ca(keyout, certout):
|
||||
finally:
|
||||
os.remove(tmpconfig)
|
||||
|
||||
def create_certificate(keyout=None, certout=None):
|
||||
def create_certificate(keyout=None, certout=None, csrout=None):
|
||||
if not keyout:
|
||||
keyout, certout = get_certificate_paths()
|
||||
if not keyout:
|
||||
@ -214,9 +214,10 @@ def create_certificate(keyout=None, certout=None):
|
||||
assure_tls_ca()
|
||||
shortname = socket.gethostname().split('.')[0]
|
||||
longname = shortname # socket.getfqdn()
|
||||
subprocess.check_call(
|
||||
['openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
|
||||
keyout])
|
||||
if not csrout:
|
||||
subprocess.check_call(
|
||||
['openssl', 'ecparam', '-name', 'secp384r1', '-genkey', '-out',
|
||||
keyout])
|
||||
san = ['IP:{0}'.format(x) for x in get_ip_addresses()]
|
||||
# It is incorrect to put IP addresses as DNS type. However
|
||||
# there exists non-compliant clients that fail with them as IP
|
||||
@ -229,21 +230,34 @@ def create_certificate(keyout=None, certout=None):
|
||||
os.close(tmphdl)
|
||||
tmphdl, extconfig = tempfile.mkstemp()
|
||||
os.close(tmphdl)
|
||||
tmphdl, csrout = tempfile.mkstemp()
|
||||
os.close(tmphdl)
|
||||
needcsr = False
|
||||
if csrout is None:
|
||||
needcsr = True
|
||||
tmphdl, csrout = tempfile.mkstemp()
|
||||
os.close(tmphdl)
|
||||
shutil.copy2(sslcfg, tmpconfig)
|
||||
serialnum = '0x' + ''.join(['{:02x}'.format(x) for x in bytearray(os.urandom(20))])
|
||||
try:
|
||||
with open(tmpconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\n[SAN]\nsubjectAltName={0}'.format(san))
|
||||
with open(extconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\nbasicConstraints=CA:false\nsubjectAltName={0}'.format(san))
|
||||
subprocess.check_call([
|
||||
'openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj',
|
||||
'/CN={0}'.format(longname),
|
||||
'-extensions', 'SAN', '-config', tmpconfig
|
||||
])
|
||||
if needcsr:
|
||||
with open(tmpconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\n[SAN]\nsubjectAltName={0}'.format(san))
|
||||
with open(extconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\nbasicConstraints=CA:false\nsubjectAltName={0}'.format(san))
|
||||
subprocess.check_call([
|
||||
'openssl', 'req', '-new', '-key', keyout, '-out', csrout, '-subj',
|
||||
'/CN={0}'.format(longname),
|
||||
'-extensions', 'SAN', '-config', tmpconfig
|
||||
])
|
||||
else:
|
||||
# when used manually, allow the csr SAN to stand
|
||||
# may add explicit subj/SAN argument, in which case we would skip copy
|
||||
with open(tmpconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\ncopy_extensions=copy\n')
|
||||
with open(extconfig, 'a') as cfgfile:
|
||||
cfgfile.write('\nbasicConstraints=CA:false\n')
|
||||
if os.path.exists('/etc/confluent/tls/cakey.pem'):
|
||||
# simple style CA in effect, make a random serial number and
|
||||
# hope for the best, and accept inability to backdate the cert
|
||||
serialnum = '0x' + ''.join(['{:02x}'.format(x) for x in bytearray(os.urandom(20))])
|
||||
subprocess.check_call([
|
||||
'openssl', 'x509', '-req', '-in', csrout,
|
||||
'-CA', '/etc/confluent/tls/cacert.pem',
|
||||
@ -252,20 +266,40 @@ def create_certificate(keyout=None, certout=None):
|
||||
'-extfile', extconfig
|
||||
])
|
||||
else:
|
||||
# we moved to a 'proper' CA, mainly for access to backdating
|
||||
# start of certs for finicky system clocks
|
||||
# this also provides a harder guarantee of serial uniqueness, but
|
||||
# not of practical consequence (160 bit random value is as good as
|
||||
# guaranteed unique)
|
||||
# downside is certificate generation is serialized
|
||||
cacfgfile = '/etc/confluent/tls/ca/openssl.cfg'
|
||||
if needcsr:
|
||||
tmphdl, tmpcafile = tempfile.mkstemp()
|
||||
shutil.copy2(cacfgfile, tmpcafile)
|
||||
os.close(tmphdl)
|
||||
cacfgfile = tmpcafile
|
||||
# with realcalock: # if we put it in server, we must lock it
|
||||
subprocess.check_call([
|
||||
'openssl', 'ca', '-config', '/etc/confluent/tls/ca/openssl.cfg',
|
||||
'openssl', 'ca', '-config', cacfgfile,
|
||||
'-in', csrout, '-out', certout, '-batch', '-notext',
|
||||
'-startdate', '19700101010101Z', '-enddate', '21000101010101Z',
|
||||
'-extfile', extconfig
|
||||
])
|
||||
finally:
|
||||
os.remove(tmpconfig)
|
||||
os.remove(csrout)
|
||||
os.remove(extconfig)
|
||||
if needcsr:
|
||||
os.remove(csrout)
|
||||
print(extconfig) # os.remove(extconfig)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
outdir = os.getcwd()
|
||||
keyout = os.path.join(outdir, 'key.pem')
|
||||
certout = os.path.join(outdir, 'cert.pem')
|
||||
create_certificate(keyout, certout)
|
||||
certout = os.path.join(outdir, sys.argv[2] + 'cert.pem')
|
||||
csrout = None
|
||||
try:
|
||||
csrout = sys.argv[1]
|
||||
except IndexError:
|
||||
csrout = None
|
||||
create_certificate(keyout, certout, csrout)
|
||||
|
@ -12,11 +12,40 @@ ap.add_argument('--state', help='State or Province')
|
||||
ap.add_argument('--city', help='City or Locality')
|
||||
ap.add_argument('--org', help='Organization name')
|
||||
ap.add_argument('--name', help='Common/Host Name')
|
||||
ap.add_argument('outcsr', help='CSR filename to save')
|
||||
args = ap.parse_args()
|
||||
|
||||
c = cmd.Command(args.xcc, os.environ['XCCUSER'], os.environ['XCCPASS'],
|
||||
verifycallback=lambda x: True)
|
||||
params = [
|
||||
|
||||
overview = c._do_web_request('/redfish/v1/')
|
||||
cs = overview.get('CertificateService', {}).get('@odata.id', None)
|
||||
if cs:
|
||||
csinfo = c._do_web_request(cs)
|
||||
gcsr = csinfo.get('Actions', {}).get('#CertificateService.GenerateCSR', {}).get('target', None)
|
||||
if gcsr:
|
||||
#https://n241-bmc/redfish/v1/Managers/1/NetworkProtocol HTTPS
|
||||
#/redfish/v1/Managers/1/NetworkProtocol/HTTPS/Certificates
|
||||
#/redfish/v1/CertificateService/CertificateLocations
|
||||
csrargs = {
|
||||
'City': args.city,
|
||||
'State': args.state,
|
||||
'Organization': args.org,
|
||||
'Country': args.country,
|
||||
'CommonName': args.name,
|
||||
'KeyPairAlgorithm': 'TPM_ALG_ECDH',
|
||||
'KeyCurveId': 'TPM_ECC_NIST_P384',
|
||||
'CertificateCollection': { '@odata.id': '/redfish/v1/Managers/1/NetworkProtocol/HTTPS/Certificates'}
|
||||
}
|
||||
|
||||
csrinfo = c._do_web_request(gcsr, csrargs)
|
||||
if 'CSRString' in csrinfo:
|
||||
with open(args.outcsr, 'w') as csrout:
|
||||
csrout.write(csrinfo['CSRString'])
|
||||
sys.exit(0)
|
||||
|
||||
else:
|
||||
params = [
|
||||
'0', # 'serviceType'
|
||||
args.country,
|
||||
args.state,
|
||||
@ -32,15 +61,16 @@ params = [
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
]
|
||||
wc = c.oem.wc
|
||||
rsp, status = wc.grab_json_response_with_status('/api/function', {'Sec_GenKeyAndCSR': ','.join(params)})
|
||||
rsp, status = wc.grab_json_response_with_status('/api/dataset', {'CSR_Format': '1'})
|
||||
rsp, status = wc.grab_json_response_with_status('/api/function', {'Sec_DownloadCSRANDCert': '0,4,0'})
|
||||
wc.request('GET', '/download/{0}'.format(rsp['FileName']))
|
||||
rsp = wc.getresponse()
|
||||
csr = rsp.read()
|
||||
if rsp.getheader('Content-Encoding', None) == 'gzip':
|
||||
csr = gzip.GzipFile(fileobj=io.BytesIO(csr)).read()
|
||||
print(csr)
|
||||
]
|
||||
|
||||
wc = c.oem.wc
|
||||
rsp, status = wc.grab_json_response_with_status('/api/function', {'Sec_GenKeyAndCSR': ','.join(params)})
|
||||
rsp, status = wc.grab_json_response_with_status('/api/dataset', {'CSR_Format': '1'})
|
||||
rsp, status = wc.grab_json_response_with_status('/api/function', {'Sec_DownloadCSRANDCert': '0,4,0'})
|
||||
wc.request('GET', '/download/{0}'.format(rsp['FileName']))
|
||||
rsp = wc.getresponse()
|
||||
csr = rsp.read()
|
||||
if rsp.getheader('Content-Encoding', None) == 'gzip':
|
||||
csr = gzip.GzipFile(fileobj=io.BytesIO(csr)).read()
|
||||
print(csr)
|
||||
|
||||
|
@ -8,8 +8,23 @@ ap.add_argument('xcc', help='XCC address')
|
||||
ap.add_argument('cert', help='Certificate in PEM format')
|
||||
args = ap.parse_args()
|
||||
|
||||
cert = open(args.cert, 'r').read()
|
||||
c = cmd.Command(args.xcc, os.environ['XCCUSER'], os.environ['XCCPASS'],
|
||||
verifycallback=lambda x: True)
|
||||
overview = c._do_web_request('/redfish/v1/')
|
||||
cs = overview.get('CertificateService', {}).get('@odata.id', None)
|
||||
if cs:
|
||||
csinfo = c._do_web_request(cs)
|
||||
gcsr = csinfo.get('Actions', {}).get('#CertificateService.ReplaceCertificate', {}).get('target', None)
|
||||
if gcsr:
|
||||
repcertargs = {
|
||||
'CertificateUri': { '@odata.id': '/redfish/v1/Managers/1/NetworkProtocol/HTTPS/Certificates/1' },
|
||||
'CertificateType': 'PEM',
|
||||
'CertificateString': cert }
|
||||
print(repr(c._do_web_request(gcsr, repcertargs)))
|
||||
sys.exit(0)
|
||||
|
||||
#CertificateService.ReplaceCertificate
|
||||
wc = c.oem.wc
|
||||
cert = open(args.cert, 'rb').read()
|
||||
res = wc.grab_json_response_with_status('/api/function', {'Sec_ImportCert': '0,1,0,0,,{0}'.format(cert)})
|
||||
|
Loading…
Reference in New Issue
Block a user