Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TACACSPLUS_PASSKEY_ENCRYPTION support Part - II #81

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions scripts/hostcfgd
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ LIMITS_CONF = "/etc/security/limits.conf"
TACPLUS_SERVER_PASSKEY_DEFAULT = ""
TACPLUS_SERVER_TIMEOUT_DEFAULT = "5"
TACPLUS_SERVER_AUTH_TYPE_DEFAULT = "pap"
TACACS_SECRET_SALT = "2e6593364d369fba925092e0c1c51466c276faa127f20d18cc5ed8ae52bedbcd"

# RADIUS
RADIUS_SERVER_AUTH_PORT_DEFAULT = "1812"
Expand All @@ -76,6 +77,38 @@ CFG_DB = "CONFIG_DB"
STATE_DB = "STATE_DB"


def get_salt():
file_path = "/etc/shadow"
target_username = "admin"
nmoray marked this conversation as resolved.
Show resolved Hide resolved
salt = TACACS_SECRET_SALT

# Read the file and search for the "admin" username
try:
with open(file_path, 'r') as file:
for line in file:
if "admin:" in line:
# Format: username:$id$salt$hashed
parts = line.split('$')
if len(parts) == 4:
salt = parts[2]
break

except FileNotFoundError:
syslog.syslog(syslog.LOG_ERR, "File not found: {}".format(file_path))
except Exception as e:
syslog.syslog(syslog.LOG_ERR, "output: {}".format(str(e)))
return salt

def decrypt_passkey(secret):
salt = get_salt()
cmd = "echo " + format(secret) + " | openssl enc -aes-128-cbc -a -d -salt -pbkdf2 -pass pass:" + salt
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
output, errs = proc.communicate()

if not errs:
output = output.decode('utf-8')
return output, errs

def signal_handler(sig, frame):
if sig == signal.SIGHUP:
syslog.syslog(syslog.LOG_INFO, "HostCfgd: signal 'SIGHUP' is caught and ignoring..")
Expand Down Expand Up @@ -500,6 +533,14 @@ class AaaCfg(object):
server = tacplus_global.copy()
server['ip'] = addr
server.update(self.tacplus_servers[addr])
if server['passkey'] is not None:
config_db = ConfigDBConnector()
config_db.connect()
output, errs = decrypt_passkey(server['passkey'])
Copy link
Contributor

@liuh-80 liuh-80 Nov 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will happen when OS upgrade from old version which not support this feature? the passkey not encrypt in old version, decrypt will failed here, code here need identify this.
#closed

another solution is add code to DB migrator, but that script is very complex.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you are right. Decrypt will fail if someone has either manually added the passkey in config_db or the device has old config where encrypted passkey was absent. So is it fine to add a check if the given server['passkey'] is the same as the one present in common-auth-sonic file (in plaintext). If so, skip decrypt_passkey() API and directly write the passkey in the same file in plaintext format only. Is it okay?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed in the HLD: A DB migration script will be added for users to migrate existing config_db to convert tacacs passkey plaintext to encrypted.

So please also create the DB migration script PR.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@liuh-80 As I mentioned in the HLD PR, we can achieve the backward compatibility without DB migration by simply following the logic stated above. Please share your thoughts on the same.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's OK, please update code and HLD according to this design change.

if not errs:
server['passkey'] = output
else:
syslog.syslog(syslog.LOG_ERR, "{}: decrypt_passkey failed.".format(addr))
servers_conf.append(server)
servers_conf = sorted(servers_conf, key=lambda t: int(t['priority']), reverse=True)

Expand Down
24 changes: 12 additions & 12 deletions tests/hostcfgd/test_tacacs_vectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"global": {
"auth_type": "chap",
"timeout": 5,
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"src_intf": "Ethernet0"
}
},
Expand All @@ -56,15 +56,15 @@
"tcp_port": 50,
"timeout": 10,
"auth_type": "chap",
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"vrf": "default"
},
"192.168.1.2" : {
"priority": 2,
"tcp_port": 51,
"timeout": 15,
"auth_type": "pap",
"passkey": "dellsonic1",
"passkey": "U2FsdGVkX1/JWY/fktTzRyZbuUg79+BnvEn1jPupNCM=",
"vrf": "mgmt"
}
},
Expand Down Expand Up @@ -108,7 +108,7 @@
"global": {
"auth_type": "chap",
"timeout": 5,
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"src_intf": "Ethernet0"
}
},
Expand All @@ -118,15 +118,15 @@
"tcp_port": 50,
"timeout": 10,
"auth_type": "chap",
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"vrf": "default"
},
"192.168.1.2" : {
"priority": 2,
"tcp_port": 51,
"timeout": 15,
"auth_type": "pap",
"passkey": "dellsonic1",
"passkey": "U2FsdGVkX1/JWY/fktTzRyZbuUg79+BnvEn1jPupNCM=",
"vrf": "mgmt"
}
},
Expand Down Expand Up @@ -170,7 +170,7 @@
"global": {
"auth_type": "chap",
"timeout": 5,
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"src_intf": "Ethernet0"
}
},
Expand All @@ -180,15 +180,15 @@
"tcp_port": 50,
"timeout": 10,
"auth_type": "chap",
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"vrf": "default"
},
"192.168.1.2" : {
"priority": 2,
"tcp_port": 51,
"timeout": 15,
"auth_type": "pap",
"passkey": "dellsonic1",
"passkey": "U2FsdGVkX1/JWY/fktTzRyZbuUg79+BnvEn1jPupNCM=",
"vrf": "mgmt"
}
},
Expand Down Expand Up @@ -232,7 +232,7 @@
"global": {
"auth_type": "chap",
"timeout": 5,
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"src_intf": "Ethernet0"
}
},
Expand All @@ -242,15 +242,15 @@
"tcp_port": 50,
"timeout": 10,
"auth_type": "chap",
"passkey": "dellsonic",
"passkey": "U2FsdGVkX1+hVtCDFDHckKVtuZsap88euNyLxGToWCw=",
"vrf": "default"
},
"192.168.1.2" : {
"priority": 2,
"tcp_port": 51,
"timeout": 15,
"auth_type": "pap",
"passkey": "dellsonic1",
"passkey": "U2FsdGVkX1/JWY/fktTzRyZbuUg79+BnvEn1jPupNCM=",
"vrf": "mgmt"
}
},
Expand Down
Loading