2
0
mirror of https://github.com/xcat2/confluent.git synced 2026-01-11 10:32:31 +00:00

Implement method to sign BMC certificates

This commit is contained in:
Jarrod Johnson
2025-10-31 10:46:42 -04:00
parent cf8c01ef13
commit f755ba9f91
5 changed files with 62 additions and 4 deletions

View File

@@ -296,7 +296,7 @@ def create_certificate(keyout=None, certout=None, csrfile=None, subj=None, san=N
certout = tlsmateriallocation.get('certs', [None])[0]
if not certout:
certout = tlsmateriallocation.get('bundles', [None])[0]
if not keyout or not certout:
if (not keyout and not csrfile) or not certout:
raise Exception('Unable to locate TLS certificate path automatically')
assure_tls_ca()
if not subj:

View File

@@ -300,6 +300,20 @@ def _init_core():
'default': 'ipmi',
}),
},
'certificate': {
'sign': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
'generate_csr': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
'install': PluginRoute({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',
}),
},
'certificate_authorities': PluginCollection({
'pluginattrs': ['hardwaremanagement.method'],
'default': 'ipmi',

View File

@@ -519,6 +519,8 @@ def get_input_message(path, operation, inputdata, nodes=None, multinode=False,
return InputAlertDestination(path, nodes, inputdata, multinode)
elif len(path) == 3 and path[:3] == ['configuration', 'management_controller', 'certificate_authorities'] and operation not in ('retrieve', 'delete'):
return InputCertificateAuthority(path, nodes, inputdata)
elif len(path) == 4 and path[:4] == ['configuration', 'management_controller', 'certificate', 'sign'] and operation not in ('retrieve', 'delete'):
return InputSigningParameters(path, inputdata, nodes, configmanager)
elif path == ['identify'] and operation != 'retrieve':
return InputIdentifyMessage(path, nodes, inputdata)
elif path == ['events', 'hardware', 'decode']:
@@ -956,6 +958,20 @@ class ConfluentInputMessage(ConfluentMessage):
def is_valid_key(self, key):
return key in self.valid_values
class InputSigningParameters(InputConfigChangeSet):
def get_days(self, node):
attribs = self.get_attributes(node)
return int(attribs['days'])
def get_added_san(self, node):
attribs = self.get_attributes(node)
addsans = []
for subj in attribs.get('added_san', '').split(','):
if subj:
addsans.append(subj.strip())
return addsans
class InputCertificateAuthority(ConfluentInputMessage):
keyname = 'pem'

View File

@@ -20,6 +20,7 @@ import confluent.messages as msg
import confluent.util as util
import copy
import errno
from confluent import certutil
import eventlet
import eventlet.event
import eventlet.green.threading as threading
@@ -37,6 +38,7 @@ ipmicommand = eventlet.import_patched('pyghmi.redfish.command')
import socket
import ssl
import traceback
import tempfile
if not hasattr(ssl, 'SSLEOFError'):
ssl.SSLEOFError = None
@@ -532,6 +534,8 @@ class IpmiHandler(object):
return self.handle_alerts()
elif self.element[1:3] == ['management_controller', 'certificate_authorities']:
return self.handle_cert_authorities()
elif self.element[1:3] == ['management_controller', 'certificate']:
return self.handle_certificate()
elif self.element[1:3] == ['management_controller', 'users']:
return self.handle_users()
elif self.element[1:3] == ['management_controller', 'net_interfaces']:
@@ -582,6 +586,26 @@ class IpmiHandler(object):
self.pyghmi_event_to_confluent(event)
self.output.put(msg.EventCollection((event,), name=self.node))
def handle_certificate(self):
self.element = self.element[3:]
if len(self.element) != 1:
raise Exception('Not implemented')
if self.element[0] == 'sign' and self.op == 'update':
csr = self.ipmicmd.get_bmc_csr()
subj, san = util.get_bmc_subject_san(self.cfm, self.node, self.inputdata.get_added_san(self.node))
with tempfile.NamedTemporaryFile() as tmpfile:
tmpfile.write(csr.encode())
tmpfile.flush()
certfile = tempfile.NamedTemporaryFile(delete=False)
certname = certfile.name
certfile.close()
certutil.create_certificate(None, certname, tmpfile.name, subj, san, backdate=False,
days=self.inputdata.get_days(self.node))
with open(certname, 'rb') as certf:
cert = certf.read()
os.unlink(certname)
self.ipmicmd.install_bmc_certificate(cert)
def handle_cert_authorities(self):
if len(self.element) == 3:
if self.op == 'read':

View File

@@ -94,13 +94,17 @@ def list_interface_indexes():
return
def get_bmc_subject_san(configmanager, nodename, addip=None):
def get_bmc_subject_san(configmanager, nodename, addnames=()):
bmc_san = []
subject = ''
ipas = set([])
if addip:
ipas.add(addip)
dnsnames = set([])
for addname in addnames:
try:
addr = ipaddress.ip_address(addname)
ipas.add(addname)
except Exception:
dnsnames.add(addname)
nodecfg = configmanager.get_node_attributes(nodename,
('dns.domain', 'hardwaremanagement.manager', 'hardwaremanagement.manager_tls_name'))
bmcaddr = nodecfg.get(nodename, {}).get('hardwaremanagement.manager', {}).get('value', '')