Skip to content

Adding support of common security cipher module for encryption and decryption of a passkey#17201

Merged
qiluo-msft merged 26 commits intosonic-net:masterfrom
nmoray:security_cipher
May 23, 2025
Merged

Adding support of common security cipher module for encryption and decryption of a passkey#17201
qiluo-msft merged 26 commits intosonic-net:masterfrom
nmoray:security_cipher

Conversation

@nmoray
Copy link
Contributor

@nmoray nmoray commented Nov 16, 2023

Why I did it

This module is created to handle the passkey encryption, decryption and the cipher storage. It's a common module which will be used for feature like TACACS, RADIUS, LDAP etc.
This implementation is aligned with HLD

How I did it

This module will expose following APIs.

  1. Passkey encryption for a given feature
  2. Passkey decryption for a given feature
  3. Check whether encryption feature is enabled for a given feature

How to verify it

Cipher / password used for the encryption:
root@sonic:/tmp# cat /etc/cipher_pass 
#Auto generated file for storing the encryption passwords
TACPLUS : TEST1
RADIUS : TEST2
LDAP : TEST3


Is encryption enabled for TACACS: False
Encrypted passkey for Feature: TACPLUS - U2FsdGVkX1/frdwl4GGD7bTKyzLi+lr2K76v0IECzkQ=
Passkey post decryption:TACPLUS - passkey1
Encrypted passkey for Feature: RADIUS - U2FsdGVkX1/fdiBo3RWWxIIPFJYCy1CF/ZQeLt8N96Q=
Passkey post decryption: RADIUS - passkey2
Encrypted passkey for Feature: LDAP - U2FsdGVkX1/o0UkHtWgOjr46UzLQRhXKAHngctey9TE=
Passkey post decryption: LDAP - passkey3

`

Which release branch to backport (provide reason below if selected)

  • 201811
  • 201911
  • 202006
  • 202012
  • 202106
  • 202111
  • 202205
  • 202211
  • 202305

Tested branch (Please provide the tested image version)

Master

Link to config_db schema for YANG module changes

Schema

Related PRs:

Part I
Part II

Copy link

@madhupalu madhupalu left a comment

Choose a reason for hiding this comment

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

Changes looks good me except few minor comments. please address it.

@nmoray
Copy link
Contributor Author

nmoray commented Nov 24, 2023

@venkatmahalingam I have added the AUT too. Can you please approve the PR now? This is an independent module. It doesn't have any impact on any other functionalities. Thus we can merge this into master. I will work on other PRs parallelly to integrate this module into TACACS feature.

@nmoray
Copy link
Contributor Author

nmoray commented Nov 24, 2023

@venkatmahalingam Once this PR is merged, build will get pass of both the following PRs.

PR: TACACS passkey encryption Part - I
PR: TACACS passkey encryption Part - II

@nmoray nmoray requested a review from qiluo-msft as a code owner November 24, 2023 11:36
Copy link
Collaborator

@venkatmahalingam venkatmahalingam left a comment

Choose a reason for hiding this comment

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

Please address the outstanding comments.

@nmoray
Copy link
Contributor Author

nmoray commented Nov 28, 2023

Please address the outstanding comments.

@venkatmahalingam I have replied to the comments. IMO, Flexible design is a good approach. Why to restrict user to go on a certain path only. He / she should have multiple options.

@avinothcgl
Copy link

Please address the outstanding comments.

@venkatmahalingam I have replied to the comments. IMO, Flexible design is a good approach. Why to restrict user to go on a certain path only. He / she should have multiple options.

@nmoray @venkatmahalingam giving multiple option is good but also customers who migrates from other well known NOS to SONiC will be using one master key. To accommodate those customers , Can you include one master key option as well.

@nmoray
Copy link
Contributor Author

nmoray commented Dec 1, 2023

Please address the outstanding comments.

@venkatmahalingam I have replied to the comments. IMO, Flexible design is a good approach. Why to restrict user to go on a certain path only. He / she should have multiple options.

@nmoray @venkatmahalingam giving multiple option is good but also customers who migrates from other well known NOS to SONiC will be using one master key. To accommodate those customers , Can you include one master key option as well.

@avinothcgl Using one master key for all the feature is still possible with the current implementation. Just keep same master key for all in cipher_pass file.

For instance,
"#Auto generated file for storing the encryption passwords"
TACPLUS : <SAME_MASTER_KEY>
RADIUS : <SAME_MASTER_KEY>
LDAP : <SAME_MASTER_KEY>

One more advantage of this design is, same security_cipher module can be extended to other applications as well which need to make use of encryption / decryption. That application can have it's own master_key which will be different from TACPLUS, RADIUS and LDAP.

@madhupalu
Copy link

madhupalu commented Dec 5, 2023

@venkatmahalingam @avinothcgl
Thanks bringing up migration use case (Migrating NON-SONiC to SONiC).
With the current implementation, using single master key for all the feature is still quite possible. the network admin Just keep same master key for all in cipher_pass file.

@venkatmahalingam shouldn't it be enough to solve the migration use case? please suggest to move forward with this PR?

For instance,
"#Auto generated file for storing the encryption passwords"
TACPLUS : <SAME_MASTER_KEY>
RADIUS : <SAME_MASTER_KEY>
LDAP : <SAME_MASTER_KEY>

One more advantage of this design is, same security_cipher module can be extended to other applications as well which need to make use of encryption / decryption. That application can have it's own master_key which will be different from TACPLUS, RADIUS and LDAP.

@zhangyanzhao
Copy link

Reviewers, if you are ok with this PR, please help to approve it. Thanks.

@nmoray
Copy link
Contributor Author

nmoray commented Apr 12, 2024

@venkatmahalingam As requested, updated the class name as "master_key_mgr".

@brholmes1
Copy link
Contributor

This is a great feature! In addition to the TACPLUS PRs already proposed, I would also recommend that the RADIUS keys (partially implemented per this PR) and SNMPv3 user passwords/privs also have the ability to be encrypted to align with industry security standards. If a new issue needs to be opened for tracking of RADIUS/SNMPv3 components let me know and I can submit them.

@nmoray
Copy link
Contributor Author

nmoray commented May 30, 2024

This is a great feature! In addition to the TACPLUS PRs already proposed, I would also recommend that the RADIUS keys (partially implemented per this PR) and SNMPv3 user passwords/privs also have the ability to be encrypted to align with industry security standards. If a new issue needs to be opened for tracking of RADIUS/SNMPv3 components let me know and I can submit them.

Thanks @brholmes1. IMO, let's first merge the initial infra. Later, we can easily extend the support for other modules. For tracking purpose, please open the new issues in the community.

@nmoray
Copy link
Contributor Author

nmoray commented May 30, 2024

@lguohan Can you please help in approving / merging this PR.

@nmoray
Copy link
Contributor Author

nmoray commented Jan 23, 2025

Folks please help in merging the PR if there are no more comments. It is open from more than 6 months now. Please help in merging the PR.
cc: @zhangyanzhao @qiluo-msft @madhupalu

Copy link
Contributor

Choose a reason for hiding this comment

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

It's probably worth generating this file from the features in _feature_list. that way if we want to add a new feature we just add a list entry instead of having to make changes here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure

Copy link
Contributor

Choose a reason for hiding this comment

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

Looking at how this is used in later commits, I think this is incorrect. We should not be removing the entire file, but instead just changing/deleting the entry. If I have both TACACS and RADIUS configured and i remove the passkey for one of them, I still want the other one to work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Agreed!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will update the method.

@mssonicbld
Copy link
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link

Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

@nmoray
Copy link
Contributor Author

nmoray commented Mar 10, 2025

@qiluo-msft @anders-nexthop I have addressed the comments.

@nmoray
Copy link
Contributor Author

nmoray commented Mar 10, 2025

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@nmoray
Copy link
Contributor Author

nmoray commented May 20, 2025

hat to re-trigger the tests to make sure it's not an

@anders-nexthop you mean just rebase the

@qiluo-msft Will you please help me understand the test failures? Why the kvmtest-* failed? BTW I have fixed the Semgrep errors.

It looks like unrelated failures in test setup code to me, but @qiluo-msft will know more.
From ElasticTest page:

Sanity check failed for vms-kvm-t1-lag on running test_pretest.py|||vms-kvm-t1-lag_399220

I looked through and saw a few failures that were ignored (NTP, a bad key "get_testbed_info\nKeyError: 'vms-kvm-t1-lag'\n", and an ACL one that's seemingly always there). I don't see how any of these would be related to your change.
You could try pulling the latest from master branch and pushing that to re-trigger the tests to make sure it's not an intermittent issue.

I tried to re-trigger the failed tests manually and got this error:

TF400813: The user 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' is not authorized to access this resource.

@anders-nexthop I just rebased my remote branch and re-pushed it. Let's see if it makes any difference.
@qiluo-msft BTW, In case these failures are known ones, will you please help in merging the changes.

@nmoray
Copy link
Contributor Author

nmoray commented May 20, 2025

hat to re-trigger the tests to make sure it's not an

@anders-nexthop you mean just rebase the

@qiluo-msft Will you please help me understand the test failures? Why the kvmtest-* failed? BTW I have fixed the Semgrep errors.

It looks like unrelated failures in test setup code to me, but @qiluo-msft will know more.
From ElasticTest page:

Sanity check failed for vms-kvm-t1-lag on running test_pretest.py|||vms-kvm-t1-lag_399220

I looked through and saw a few failures that were ignored (NTP, a bad key "get_testbed_info\nKeyError: 'vms-kvm-t1-lag'\n", and an ACL one that's seemingly always there). I don't see how any of these would be related to your change.
You could try pulling the latest from master branch and pushing that to re-trigger the tests to make sure it's not an intermittent issue.

I tried to re-trigger the failed tests manually and got this error:
TF400813: The user 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa' is not authorized to access this resource.

@anders-nexthop I just rebased my remote branch and re-pushed it. Let's see if it makes any difference. @qiluo-msft BTW, In case these failures are known ones, will you please help in merging the changes.

@qiluo-msft The checks are still failing. Please let us know what needs to be done to fix these failures.

@mssonicbld
Copy link
Collaborator

/azp run Azure.sonic-buildimage

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@nmoray nmoray requested a review from qiluo-msft May 22, 2025 09:16
@nmoray
Copy link
Contributor Author

nmoray commented May 22, 2025

@qiluo-msft Please re-approve the PR. I pushed one more commit for removing commented code.

@nmoray
Copy link
Contributor Author

nmoray commented May 23, 2025

@qiluo-msft can you please re-approve and merge the PR. All the checks have been passed now.

@qiluo-msft qiluo-msft merged commit bce7621 into sonic-net:master May 23, 2025
19 checks passed
}

leaf key_encrypt {
type boolean;
Copy link
Collaborator

Choose a reason for hiding this comment

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

boolean

Please add a default value (false). This is needed for backward compatible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure. I will raise a new PR to accomodate this change.

default 5;
}

leaf key_encrypt {
Copy link
Collaborator

@qiluo-msft qiluo-msft May 25, 2025

Choose a reason for hiding this comment

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

Mix tabs with spaces, please reformat this "leaf key_encrypt" section.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean, replace the tabs with spaces for the entire leaf section?

Copy link
Contributor Author

@nmoray nmoray May 26, 2025

Choose a reason for hiding this comment

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

@qiluo-msft The link that you shared is not accessible.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I removed the link. Yes, I mean to replace the tabs with spaces for the entire leaf section

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, will do as a part of new PR.


def __init__(self):
if not self._initialized:
self._file_path = "/etc/cipher_pass"
Copy link
Collaborator

Choose a reason for hiding this comment

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

/etc/cipher_pass

When you boot into a new version, the /etc/config_db.json will be carried over, but this file will be lost. Then you have only encrypted passkey and lost cipher_pass. How does the new version survive?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@qiluo-msft As per https://github.com/sonic-net/SONiC/blob/master/doc/ztp/SONiC-config-setup.md#222-config-migration
the backup and restore of cipher_pass file will automatically be taken care, right?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for the link! The file "/etc/cipher_pass" is outside the folder of config migration design, could you check again?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

oh yes. Okay then, I will create another PR to add pre-hook and post-hook scripts to backup and restore the cipher_pass file during the up-gradation. Is that okay? Or just change the location to "/etc/sonic"?

qiluo-msft pushed a commit that referenced this pull request Feb 3, 2026
…kup and Restore support for NOS Upgrades (#22711)

What I did it
Updated the existing design to support password rotate feature in the Security Cipher module.
Additionally, now multiple modules of same feature type can make use of same password for generating their unique encrypted passkey.
Added backup and restore support for cipher_pass.json file stored at /etc dir.
Reference PR: Adding support of common security cipher module for encryption and decryption of a passkey #17201
Reference HLDs:
TACACSPLUS_PASSKEY_ENCRYPTION.md SONiC#1471

Link to config_db schema for YANG module changes
https://github.com/Azure/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md
https://github.com/sonic-net/SONiC/blob/master/doc/ztp/SONiC-config-setup.md#222-config-migration
Now the module / application / feature who wants to use the security cipher module for encryption / decryption, it needs to first register with it by providing a callback function which will be responsible for updating the existing encrypted passkey in the CONFIG_DB table or which ever the storage media used. This way, all the registered parties will be notified and at the same time gets updated with the new password. The security cipher module keeps a list of all the callbacks and at the time of password rotation, it simply notifies and updates everyone one after the other.

How to verify it
Encrypt the passkey for multiple TACPLUS / RADIUS servers using same password
NOS upgrade to verify backup / restore feature
Test Logs:

1. Encrypt passkey:
sonic# config tacacs passkey nikhil --encrypt
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX19YTUcG+0r3+d78A5E0zTXEukS3ZNrfyFk=",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST1"
  }

2. Encrypt passkey and update existing password
sonic# config tacacs passkey nikhil --encrypt --rotate
Password:
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST3"
  }
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX18/8nFrAiCe01pOqgPoUUZFaTpmtawdi8I=",
    "src_intf": "Loopback0"
  }
}

3. Revert back to plaintext passkey
sonic# config tacacs passkey ravi
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "False",
    "passkey": "ravi",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [],
    "password": null
  }
FengPan-Frank pushed a commit to FengPan-Frank/sonic-buildimage that referenced this pull request Mar 6, 2026
…kup and Restore support for NOS Upgrades (sonic-net#22711)

What I did it
Updated the existing design to support password rotate feature in the Security Cipher module.
Additionally, now multiple modules of same feature type can make use of same password for generating their unique encrypted passkey.
Added backup and restore support for cipher_pass.json file stored at /etc dir.
Reference PR: Adding support of common security cipher module for encryption and decryption of a passkey sonic-net#17201
Reference HLDs:
TACACSPLUS_PASSKEY_ENCRYPTION.md SONiC#1471

Link to config_db schema for YANG module changes
https://github.com/Azure/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md
https://github.com/sonic-net/SONiC/blob/master/doc/ztp/SONiC-config-setup.md#222-config-migration
Now the module / application / feature who wants to use the security cipher module for encryption / decryption, it needs to first register with it by providing a callback function which will be responsible for updating the existing encrypted passkey in the CONFIG_DB table or which ever the storage media used. This way, all the registered parties will be notified and at the same time gets updated with the new password. The security cipher module keeps a list of all the callbacks and at the time of password rotation, it simply notifies and updates everyone one after the other.

How to verify it
Encrypt the passkey for multiple TACPLUS / RADIUS servers using same password
NOS upgrade to verify backup / restore feature
Test Logs:

1. Encrypt passkey:
sonic# config tacacs passkey nikhil --encrypt
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX19YTUcG+0r3+d78A5E0zTXEukS3ZNrfyFk=",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST1"
  }

2. Encrypt passkey and update existing password
sonic# config tacacs passkey nikhil --encrypt --rotate
Password:
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST3"
  }
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX18/8nFrAiCe01pOqgPoUUZFaTpmtawdi8I=",
    "src_intf": "Loopback0"
  }
}

3. Revert back to plaintext passkey
sonic# config tacacs passkey ravi
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "False",
    "passkey": "ravi",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [],
    "password": null
  }

Signed-off-by: Feng Pan <fenpan@microsoft.com>
dprital pushed a commit that referenced this pull request Mar 19, 2026
…kup and Restore support for NOS Upgrades (#22711)

What I did it
Updated the existing design to support password rotate feature in the Security Cipher module.
Additionally, now multiple modules of same feature type can make use of same password for generating their unique encrypted passkey.
Added backup and restore support for cipher_pass.json file stored at /etc dir.
Reference PR: Adding support of common security cipher module for encryption and decryption of a passkey #17201
Reference HLDs:
TACACSPLUS_PASSKEY_ENCRYPTION.md SONiC#1471

Link to config_db schema for YANG module changes
https://github.com/Azure/sonic-buildimage/blob/master/src/sonic-yang-models/doc/Configuration.md
https://github.com/sonic-net/SONiC/blob/master/doc/ztp/SONiC-config-setup.md#222-config-migration
Now the module / application / feature who wants to use the security cipher module for encryption / decryption, it needs to first register with it by providing a callback function which will be responsible for updating the existing encrypted passkey in the CONFIG_DB table or which ever the storage media used. This way, all the registered parties will be notified and at the same time gets updated with the new password. The security cipher module keeps a list of all the callbacks and at the time of password rotation, it simply notifies and updates everyone one after the other.

How to verify it
Encrypt the passkey for multiple TACPLUS / RADIUS servers using same password
NOS upgrade to verify backup / restore feature
Test Logs:

1. Encrypt passkey:
sonic# config tacacs passkey nikhil --encrypt
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX19YTUcG+0r3+d78A5E0zTXEukS3ZNrfyFk=",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST1"
  }

2. Encrypt passkey and update existing password
sonic# config tacacs passkey nikhil --encrypt --rotate
Password:
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [
      "TACPLUS|global"
    ],
    "password": "TEST3"
  }
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=nikhil login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "True",
    "passkey": "U2FsdGVkX18/8nFrAiCe01pOqgPoUUZFaTpmtawdi8I=",
    "src_intf": "Loopback0"
  }
}

3. Revert back to plaintext passkey
sonic# config tacacs passkey ravi
sonic# cat /etc/pam.d/common-auth-sonic
#THIS IS AN AUTO-GENERATED FILE
#
# /etc/pam.d/common-auth- authentication settings common to all services
# This file is included from other service-specific PAM config files,
# and should contain a list of the authentication modules that define
# the central authentication scheme for use on the system
# (e.g., /etc/shadow, LDAP, Kerberos, etc.). The default is to use the
# traditional Unix authentication mechanisms.
#
# here are the per-package modules (the "Primary" block)

auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=done new_authtok_reqd=done default=ignore auth_err=die]	pam_tacplus.so server=<> secret=ravi login=login timeout=5   try_first_pass
auth	[success=1 default=ignore]	pam_unix.so nullok try_first_pass

#
# here's the fallback if no module succeeds
auth    requisite                       pam_deny.so
# prime the stack with a positive return value if there isn't one already;
# this avoids us returning an error just because nothing sets a success code
# since the modules above will each just jump around
auth    required                        pam_permit.so
# and here are more per-package modules (the "Additional" block)
sonic# show run al | jq .TACPLUS
{
  "global": {
    "auth_type": "login",
    "key_encrypt": "False",
    "passkey": "ravi",
    "src_intf": "Loopback0"
  }
}
sonic# cat /etc/cipher_pass.json
{
  "TACPLUS": {
    "table_info": [],
    "password": null
  }

Signed-off-by: dprital <drorp@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants