hostcfgd: Handle missed tacacs updates between load & listen (#8223)
Why I did it The time gap between last config load & db-listen seem to have increased. Any config updates that occurred in this gap gets missed by db-listen. This could miss updating /etc/pam.d/common-auth-sonic How I did it Add a one shot timer, just before db-listen. The timer will fire after the subscribe is done When the timer fires, reload tacacs & aaa
This commit is contained in:
parent
d573cd141d
commit
8cd6714ef4
@ -4,6 +4,7 @@
|
||||
import ast
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
import sys
|
||||
import subprocess
|
||||
import syslog
|
||||
@ -25,6 +26,20 @@ TACPLUS_SERVER_PASSKEY_DEFAULT = ""
|
||||
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
|
||||
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
|
||||
|
||||
global_lock = None
|
||||
|
||||
class lock_mgr:
|
||||
def __init__(self):
|
||||
self.lock = global_lock
|
||||
|
||||
def __enter__( self ):
|
||||
if self.lock:
|
||||
self.lock.acquire()
|
||||
|
||||
def __exit__( self, exc_type, exc_value, traceback ):
|
||||
if self.lock:
|
||||
self.lock.release()
|
||||
|
||||
|
||||
def is_true(val):
|
||||
if val == 'True' or val == 'true':
|
||||
@ -123,7 +138,7 @@ class Iptables(object):
|
||||
.format(err.cmd, err.returncode, err.output))
|
||||
|
||||
class AaaCfg(object):
|
||||
def __init__(self):
|
||||
def __init__(self, config_db):
|
||||
self.auth_default = {
|
||||
'login': 'local',
|
||||
}
|
||||
@ -136,49 +151,42 @@ class AaaCfg(object):
|
||||
self.tacplus_global = {}
|
||||
self.tacplus_servers = {}
|
||||
self.debug = False
|
||||
self.config_db = config_db
|
||||
|
||||
# Load conf from ConfigDb
|
||||
def load(self, aaa_conf, tac_global_conf, tacplus_conf):
|
||||
for row in aaa_conf:
|
||||
self.aaa_update(row, aaa_conf[row], modify_conf=False)
|
||||
for row in tac_global_conf:
|
||||
self.tacacs_global_update(row, tac_global_conf[row], modify_conf=False)
|
||||
for row in tacplus_conf:
|
||||
self.tacacs_server_update(row, tacplus_conf[row], modify_conf=False)
|
||||
def load(self):
|
||||
self.modify_conf_file()
|
||||
|
||||
def aaa_update(self, key, data, modify_conf=True):
|
||||
def aaa_update(self, key):
|
||||
if key == 'authentication':
|
||||
self.auth = data
|
||||
if 'failthrough' in data:
|
||||
self.auth['failthrough'] = is_true(data['failthrough'])
|
||||
if 'debug' in data:
|
||||
self.debug = is_true(data['debug'])
|
||||
if modify_conf:
|
||||
self.modify_conf_file()
|
||||
|
||||
def tacacs_global_update(self, key, data, modify_conf=True):
|
||||
def tacacs_global_update(self, key):
|
||||
if key == 'global':
|
||||
self.tacplus_global = data
|
||||
if modify_conf:
|
||||
self.modify_conf_file()
|
||||
|
||||
def tacacs_server_update(self, key, data, modify_conf=True):
|
||||
if data == {}:
|
||||
if key in self.tacplus_servers:
|
||||
del self.tacplus_servers[key]
|
||||
else:
|
||||
self.tacplus_servers[key] = data
|
||||
|
||||
if modify_conf:
|
||||
self.modify_conf_file()
|
||||
|
||||
def tacacs_server_update(self, key):
|
||||
self.modify_conf_file()
|
||||
|
||||
def modify_single_file(self, filename, operations=None):
|
||||
if operations:
|
||||
cmd = "sed -e {0} {1} > {1}.new; mv -f {1} {1}.old; mv -f {1}.new {1}".format(' -e '.join(operations), filename)
|
||||
os.system(cmd)
|
||||
|
||||
def modify_conf_file(self):
|
||||
with lock_mgr():
|
||||
self.auth = self.config_db.get_table('AAA').get("authentication", {})
|
||||
if 'failthrough' in self.auth:
|
||||
self.auth['failthrough'] = is_true(self.auth['failthrough'])
|
||||
if 'debug' in self.auth:
|
||||
self.debug = is_true(self.auth['debug'])
|
||||
|
||||
self.tacplus_global = self.config_db.get_table('TACPLUS').get(
|
||||
"global", {})
|
||||
self.tacplus_servers = self.config_db.get_table('TACPLUS_SERVER')
|
||||
self._modify_conf_file()
|
||||
|
||||
def _modify_conf_file(self):
|
||||
auth = self.auth_default.copy()
|
||||
auth.update(self.auth)
|
||||
tacplus_global = self.tacplus_global_default.copy()
|
||||
@ -224,6 +232,11 @@ class AaaCfg(object):
|
||||
with open(NSS_TACPLUS_CONF, 'w') as f:
|
||||
f.write(nss_tacplus_conf)
|
||||
|
||||
if 'passkey' in tacplus_global:
|
||||
tacplus_global['passkey'] = obfuscate(tacplus_global['passkey'])
|
||||
syslog.syslog(syslog.LOG_INFO, 'pam.d files updated auth={} global={}'.
|
||||
format(auth, tacplus_global))
|
||||
|
||||
class MultiAsicBgpMonCfg(object):
|
||||
def __init__(self):
|
||||
self.ns_for_bgp_mon = 'asic4'
|
||||
@ -343,7 +356,7 @@ class HostConfigDaemon:
|
||||
self.config_db.connect(wait_for_init=True, retry_on=True)
|
||||
syslog.syslog(syslog.LOG_INFO, 'ConfigDB connect success')
|
||||
|
||||
self.aaacfg = AaaCfg()
|
||||
self.aaacfg = AaaCfg(self.config_db)
|
||||
self.iptables = Iptables()
|
||||
# Cache the values of 'state' field in 'FEATURE' table of each container
|
||||
self.cached_feature_states = {}
|
||||
@ -355,11 +368,19 @@ class HostConfigDaemon:
|
||||
if self.is_multi_npu:
|
||||
self.masicBgpMonCfg = MultiAsicBgpMonCfg()
|
||||
|
||||
|
||||
def timer_load(self):
|
||||
global global_lock
|
||||
|
||||
syslog.syslog(syslog.LOG_INFO, 'reloading tacacs from timer thread')
|
||||
self.aaacfg.load()
|
||||
|
||||
# Remove lock as timer is one shot
|
||||
global_lock = None
|
||||
|
||||
|
||||
def load(self):
|
||||
aaa = self.config_db.get_table('AAA')
|
||||
tacacs_global = self.config_db.get_table('TACPLUS')
|
||||
tacacs_server = self.config_db.get_table('TACPLUS_SERVER')
|
||||
self.aaacfg.load(aaa, tacacs_global, tacacs_server)
|
||||
self.aaacfg.load()
|
||||
|
||||
lpbk_table = self.config_db.get_table('LOOPBACK_INTERFACE')
|
||||
self.iptables.load(lpbk_table)
|
||||
@ -468,17 +489,18 @@ class HostConfigDaemon:
|
||||
self.update_feature_state(feature_name, state, feature_table)
|
||||
|
||||
def aaa_handler(self, key, data):
|
||||
self.aaacfg.aaa_update(key, data)
|
||||
self.aaacfg.aaa_update(key)
|
||||
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, data))
|
||||
|
||||
def tacacs_server_handler(self, key, data):
|
||||
self.aaacfg.tacacs_server_update(key, data)
|
||||
self.aaacfg.tacacs_server_update(key)
|
||||
log_data = copy.deepcopy(data)
|
||||
if 'passkey' in log_data:
|
||||
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||
syslog.syslog(syslog.LOG_INFO, 'value of {} changed to {}'.format(key, log_data))
|
||||
|
||||
def tacacs_global_handler(self, key, data):
|
||||
self.aaacfg.tacacs_global_update(key, data)
|
||||
self.aaacfg.tacacs_global_update(key)
|
||||
log_data = copy.deepcopy(data)
|
||||
if 'passkey' in log_data:
|
||||
log_data['passkey'] = obfuscate(log_data['passkey'])
|
||||
@ -515,6 +537,7 @@ class HostConfigDaemon:
|
||||
self.update_feature_state(feature_name, state, feature_table)
|
||||
|
||||
def start(self):
|
||||
global global_lock
|
||||
|
||||
self.config_db.subscribe('AAA', lambda table, key, data: self.aaa_handler(key, data))
|
||||
self.config_db.subscribe('TACPLUS_SERVER', lambda table, key, data: self.tacacs_server_handler(key, data))
|
||||
@ -537,6 +560,10 @@ class HostConfigDaemon:
|
||||
# Defer load until subscribe
|
||||
self.load()
|
||||
|
||||
global_lock = threading.Lock()
|
||||
self.tmr_thread = threading.Timer(30, self.timer_load)
|
||||
self.tmr_thread.start()
|
||||
|
||||
self.config_db.listen()
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user