From ed41d93de54e7a214e43c209b6d4256cb59316db Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 20 Oct 2020 15:51:46 -0400 Subject: [PATCH] Add remote authentication configuration While our security guidelines preclude allowing host to know the password, it is considered acceptable to do the out-of-band authentication configuration. Have configbmc request a unicast remote configuration. This should handle authentication as well as ensuring ongoing consistency between out of band and in-band configuration methods. --- .../profiles/default/scripts/configbmc | 19 +++++++++++++++++- .../confluent/discovery/handlers/tsm.py | 13 ++++++++++++ .../confluent/discovery/handlers/xcc.py | 13 ++++++++++++ .../confluent/discovery/protocols/slp.py | 3 +++ confluent_server/confluent/selfservice.py | 20 +++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/confluent_osdeploy/genesis/profiles/default/scripts/configbmc b/confluent_osdeploy/genesis/profiles/default/scripts/configbmc index 7176c12c..604b39b2 100644 --- a/confluent_osdeploy/genesis/profiles/default/scripts/configbmc +++ b/confluent_osdeploy/genesis/profiles/default/scripts/configbmc @@ -165,6 +165,14 @@ def set_port(s, port, vendor, model): return 1 +def get_remote_config_mod(vendor, model): + if vendor in ('IBM', 'Lenovo'): + if _is_tsm(model): + return 'tsm' + else: + return 'xcc' + return None + def set_port_tsm(s, port, model): oport = port sys.stdout.write('Setting TSM port to "{}"...'.format(oport)) @@ -407,7 +415,16 @@ def main(): dotwait() sys.stdout.write('done\n') sys.stdout.flush() - #await_config(s, bmccfg, channel) + cfgmod = get_remote_config_mod(vendor, model) + if cfgmod: + with open('configbmc.configmod', 'w+') as cm: + cm.write('configmod: {0}\n'.format(cfgmod)) + sys.stdout.write('Requesting remote configuration of authentication...') + sys.stdout.flush() + bmccfgsrc = subprocess.check_output( + [sys.executable, apiclient, '/confluent-api/self/remoteconfigbmc', 'configbmc.configmod']) + sys.stdout.write('done\n') + sys.stdout.flush() if __name__ == '__main__': diff --git a/confluent_server/confluent/discovery/handlers/tsm.py b/confluent_server/confluent/discovery/handlers/tsm.py index 7f9f80e7..310d1915 100644 --- a/confluent_server/confluent/discovery/handlers/tsm.py +++ b/confluent_server/confluent/discovery/handlers/tsm.py @@ -229,6 +229,19 @@ class NodeHandler(generic.NodeHandler): rsp, status = wc.grab_json_response_with_status('/api/session', method='DELETE') +def remote_nodecfg(nodename, cfm): + cfg = cfm.get_node_attributes( + nodename, 'hardwaremanagement.manager') + ipaddr = cfg.get(nodename, {}).get('hardwaremanagement.manager', {}).get( + 'value', None) + ipaddr = getaddrinfo(ipaddr, 0)[0][-1] + if not ipaddr: + raise Excecption('Cannot remote configure a system without known ' + 'address') + info = {'addresses': [ipaddr]} + nh = NodeHandler(info, cfm) + nh.config(nodename) + if __name__ == '__main__': import confluent.config.configmanager as cfm c = cfm.ConfigManager(None) diff --git a/confluent_server/confluent/discovery/handlers/xcc.py b/confluent_server/confluent/discovery/handlers/xcc.py index f388d652..51b63219 100644 --- a/confluent_server/confluent/discovery/handlers/xcc.py +++ b/confluent_server/confluent/discovery/handlers/xcc.py @@ -431,3 +431,16 @@ class NodeHandler(immhandler.NodeHandler): if em: self.configmanager.set_node_attributes( {em: {'id.uuid': enclosureuuid}}) + +def remote_nodecfg(nodename, cfm): + cfg = cfm.get_node_attributes( + nodename, 'hardwaremanagement.manager') + ipaddr = cfg.get(nodename, {}).get('hardwaremanagement.manager', {}).get( + 'value', None) + ipaddr = getaddrinfo(ipaddr, 0)[0][-1] + if not ipaddr: + raise Excecption('Cannot remote configure a system without known ' + 'address') + info = {'addresses': [ipaddr]} + nh = NodeHandler(info, cfm) + nh.config(nodename) diff --git a/confluent_server/confluent/discovery/protocols/slp.py b/confluent_server/confluent/discovery/protocols/slp.py index be21f1f8..588a4bc4 100644 --- a/confluent_server/confluent/discovery/protocols/slp.py +++ b/confluent_server/confluent/discovery/protocols/slp.py @@ -360,6 +360,9 @@ def _add_attributes(parsed): return +def unicast_scan(address): + pass + def query_srvtypes(target): """Query the srvtypes advertised by the target diff --git a/confluent_server/confluent/selfservice.py b/confluent_server/confluent/selfservice.py index ac7501c7..7e286a41 100644 --- a/confluent_server/confluent/selfservice.py +++ b/confluent_server/confluent/selfservice.py @@ -5,6 +5,8 @@ import confluent.sshutil as sshutil import confluent.util as util import eventlet.green.socket as socket import eventlet.green.subprocess as subprocess +import confluent.discovery.handlers.xcc as xcc +import confluent.discovery.handlers.tsm as tsm import crypt import json import time @@ -207,6 +209,24 @@ def handle_request(env, start_response): else: start_response('200 OK', (('Content-Type', retype),)) yield dumper(sorted(nodes)) + elif env['PATH_INFO'] == '/self/remoteconfigbmc': + if reqbody: + try: + reqbody = yaml.safe_load(reqbody) + except Exception: + reqbody = None + if not reqbody: + start_response('400 bad request', ()) + cfgmod = reqbody.get('configmod', 'unspecified') + if cfgmod == 'xcc': + xcc.remote_nodecfg(nodename, cfg) + elif cfgmod == 'tsm': + tsm.remote_nodecfg(nodename, cfg) + else: + start_response('500 unsupported configmod', ()) + yield 'Unsupported configmod "{}"'.format(cfgmod) + start_response('200 Ok', ()) + yield 'complete' elif env['PATH_INFO'] == '/self/updatestatus': update = yaml.safe_load(reqbody) if update['status'] == 'staged':