Skip to content

Commit 62d56bc

Browse files
HLD for persistent local user management
1 parent 977fbb0 commit 62d56bc

File tree

1 file changed

+301
-0
lines changed

1 file changed

+301
-0
lines changed
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
# Declarative Local User Management
2+
3+
## Revision
4+
5+
| Rev | Date | Author | Change Description |
6+
|:---:|:--------------:|:-----------:|:----------------------------------------------------------------------------------------------------------------------------------------------------:|
7+
| 1.0 | June 16, 2025 | Manoharan Sundaramoorthy | Initial HLD |
8+
9+
10+
## 1. Scope
11+
This document describes the high-level design for a new feature that provides a declarative and persistent method for managing local user accounts on a SONiC device. This feature allows administrators to define local users, including their roles, password hashes, SSH keys, and **security policies** including **login attempt limits**.
12+
13+
This ensures that local user accounts are consistently applied with robust security postures and persist across reboots and upgrades.
14+
15+
## 2. Definitions/Abbreviations
16+
17+
| Abbreviation | Definition |
18+
|:------------:|:--------------------------------------------------------------------------|
19+
| **`userd`** | The new User Daemon proposed in this design. |
20+
| **PAM** | Pluggable Authentication Modules |
21+
22+
23+
## 3. Overview
24+
This feature introduces a new dedicated daemon, **`userd`**, which manages the full lifecycle of local users based on definitions in `CONFIG_DB`. It simplifies management by providing a user-friendly CLI, mapping abstract roles (`administrator`, `operator`) to specific Linux groups, and enforcing security policies. This provides a solution for managing secure, persistent local user accounts.
25+
26+
## 4. Requirements
27+
### 4.1 Functional Requirements
28+
1. The system must allow an administrator to define a local user account declaratively.
29+
2. The user definition must support:
30+
* Username and a pre-hashed password.
31+
* A role, limited to either **`administrator`** or **`operator`**.
32+
* Authorized SSH keys (statically defined).
33+
3. The system will **auto-generate** a unique UID for each new user.
34+
4. **Special User Management:**
35+
* The **`admin`** user must always exist and be manageable through CONFIG_DB to modify attributes (password, SSH keys, security policies).
36+
* The **`admin`** user cannot be deleted but can be disabled by setting the password to `!`.
37+
* If the **`admin`** user is removed from CONFIG_DB, the system must reset it to the default password `YourPaSsWoRd`.
38+
5. **Security Policy Requirements:**
39+
* **Login Attempts:** The system must support configuring a global maximum number of failed login attempts per role before accounts are temporarily locked.
40+
6. The system must map roles to underlying Linux groups:
41+
* `administrator`: members of `sudo`, `docker`, `redis` and `admin` groups.
42+
* `operator`: members of a standard, non-privileged and would belong to `users` group.
43+
7. User accounts and their configurations must persist across system reboots and upgrades.
44+
8. **System Consistency:** On startup, the system must perform a consistency check to ensure Linux users match CONFIG_DB definitions and automatically remove any users that were added directly to Linux (bypassing CONFIG_DB).
45+
46+
## 5. Architecture Design
47+
The architecture centers on the new `userd` daemon. This daemon will now interact with several core Linux subsystems to enforce the configured security policies.
48+
49+
**`userd`'s Points of Interaction:**
50+
1. **CONFIG_DB:** Single source of truth for user configuration and global security policies.
51+
2. **Core User Files:** `/etc/passwd`, `/etc/shadow`, `/etc/group` for basic user identity.
52+
3. **PAM Configuration (`/etc/security/faillock.conf`):** To manage global failed login attempt policies per role via `pam_faillock`.
53+
54+
## 6. High-Level Design
55+
56+
### 6.1 `userd` Daemon
57+
The `userd` daemon's logic will be expanded to manage security configurations idempotently.
58+
59+
**Startup Consistency Check:**
60+
* **System Reconciliation:** On startup, `userd` will perform a consistency check to ensure that all local users in the Linux system (`/etc/passwd`, `/etc/shadow`, `/etc/group`) match the definitions in CONFIG_DB.
61+
* **Cleanup of Unmanaged Users:** Any users found in the Linux system that are not defined in CONFIG_DB (except for system users like `root`, `admin`, `daemon`, etc.) will be automatically removed to maintain consistency.
62+
* **CONFIG_DB as Source of Truth:** This ensures that CONFIG_DB remains the single source of truth for user management and prevents configuration drift.
63+
64+
**Special Admin User Handling:**
65+
* **Admin User Management:** `userd` will ensure the `admin` user always exists in the system. If not present in CONFIG_DB, it will reset the admin user to the default system password `YourPaSsWoRd`.
66+
* **Admin User Protection:** `userd` will prevent deletion of the `admin` user even if the entry is removed from CONFIG_DB, but will allow modification of its attributes.
67+
* **Admin User Disabling:** When the `admin` user's password is set to `!` in CONFIG_DB, `userd` will update `/etc/shadow` accordingly to disable password-based login while preserving SSH key access.
68+
69+
**New Logic for Security Policies:**
70+
71+
* **To enforce Login Attempts:**
72+
* `userd` will manage the PAM configuration file at `/etc/security/faillock.conf`.
73+
* For global role-based limits (e.g., administrators with limit of 5), it will ensure appropriate configuration in the global section.
74+
* `userd` will configure PAM to apply different limits based on user group membership (administrator vs operator roles).
75+
* `userd` will be responsible for ensuring the PAM stack is configured to use `pam_faillock` with role-based policies.
76+
77+
## 7. SAI API
78+
No SAI API changes are required.
79+
80+
## 8. Configuration and Management
81+
### 8.1 Config DB Enhancements
82+
The `USER` table schema is defined for individual user accounts, and a new `USER_SECURITY_POLICY` table is added for global role-based security policies.
83+
84+
**Schema:**
85+
```json
86+
// Example for CONFIG_DB
87+
{
88+
"USER": {
89+
"admin": {
90+
"role": "administrator",
91+
"password": "hashed_password",
92+
"ssh_keys": ["ssh-rsa AAA..."]
93+
},
94+
"newadmin": {
95+
"role": "administrator",
96+
"password": "hashed_password",
97+
"ssh_keys": ["ssh-rsa BBB..."]
98+
},
99+
"showuser": {
100+
"role": "operator",
101+
"password": "!",
102+
"ssh_keys": ["ssh-rsa CCC..."]
103+
}
104+
},
105+
"USER_SECURITY_POLICY": {
106+
"administrator": {
107+
"max_login_attempts": 5
108+
},
109+
"operator": {
110+
"max_login_attempts": 3
111+
}
112+
}
113+
}
114+
```
115+
116+
**USER Table:**
117+
* `role` (string, required): `administrator` or `operator`.
118+
* `password` (string, required): The hashed password.
119+
* `ssh_keys` (optional): List of SSH public keys for the user.
120+
121+
**USER_SECURITY_POLICY Table:**
122+
* **`max_login_attempts`** (integer, optional): Number of failed login attempts before accounts with this role are locked.
123+
124+
**Notes:**
125+
* Session timeouts are managed by the system's default timeout policy and are not configurable per user.
126+
* Password hashes can be generated using `mkpasswd` command-line utility or programmatically using libraries like `passlib` in Python for NETCONF/RESTCONF implementations.
127+
* The CLI provides both `--password-hash` (for pre-hashed passwords) and `--password-prompt` (for interactive secure password entry) options for improved security and usability.
128+
* **CONFIG_DB as Source of Truth:** On startup, `userd` performs a consistency check and removes any users that were added directly to Linux (bypassing CONFIG_DB) to ensure CONFIG_DB remains the authoritative source for user management.
129+
* The **`admin`** user is a special case: it must always exist and can be managed through CONFIG_DB but cannot be deleted. To disable the admin user, set the password to `!`. If the admin user is removed from CONFIG_DB, it will be reset to the default system password `YourPaSsWoRd`.
130+
131+
### 8.2 Yang Model Enhancements
132+
```
133+
module sonic-user {
134+
yang-version 1.1;
135+
namespace "http://sonicproject.com/sonic-user";
136+
prefix "sonic-user";
137+
138+
import sonic-ext {
139+
prefix "sonic-ext";
140+
}
141+
142+
// Common typedef for user roles
143+
typedef user-role {
144+
type enumeration {
145+
enum "administrator" {
146+
description "Grants administrative privileges (e.g., member of sudo, docker groups).";
147+
}
148+
enum "operator" {
149+
description "Grants operator-level (read-only or limited) privileges.";
150+
}
151+
}
152+
description "User role that determines group memberships, privileges, and applicable security policies.";
153+
}
154+
155+
// Top-level container for the User feature
156+
container sonic-user {
157+
description "Top-level container for local user management configuration";
158+
159+
list USER_LIST {
160+
key "username";
161+
description "List of declaratively managed local users.";
162+
163+
leaf username {
164+
type string {
165+
pattern '[a-z_][a-z0-9_-]*[$]?' {
166+
error-message "Invalid username. Must start with a lowercase letter or underscore, followed by lowercase letters, numbers, underscores, or hyphens.";
167+
}
168+
must ". != 'root'" {
169+
error-message "Username cannot be 'root'.";
170+
};
171+
length 1..32;
172+
}
173+
description "The username for the local account.";
174+
}
175+
176+
leaf role {
177+
type user-role;
178+
mandatory true;
179+
description "The role assigned to the user, which determines their group memberships and privileges.";
180+
}
181+
182+
leaf password {
183+
type string;
184+
mandatory true;
185+
description "The hashed password string for the user, as found in /etc/shadow. To lock an account from password login, use '!'. Password hashes can be generated using 'mkpasswd' utility or programmatically using libraries like 'passlib'.";
186+
}
187+
188+
leaf-list ssh_keys {
189+
type string;
190+
description "A list of full public SSH key strings.";
191+
}
192+
}
193+
194+
list USER_SECURITY_POLICY_LIST {
195+
key "role";
196+
description "Global security policies applied to users based on their role.";
197+
198+
leaf role {
199+
type user-role;
200+
description "The role for which this security policy applies.";
201+
}
202+
203+
leaf max_login_attempts {
204+
type uint32 {
205+
range "1..1000";
206+
}
207+
description "Maximum number of failed login attempts before accounts with this role are locked. If not set, system defaults apply.";
208+
}
209+
}
210+
}
211+
}
212+
```
213+
214+
### 8.3 CLI Enhancements
215+
The CLI is enhanced with user management and global security policy commands.
216+
217+
**User Add Command:**
218+
```
219+
config user add <username> --role <role>
220+
[--password-hash <hash> | --password-prompt]
221+
[--ssh-key <key>]
222+
```
223+
* Multiple `--ssh-key` flags can be provided to build a list.
224+
* Use `--password-hash` to provide a pre-hashed password directly.
225+
* Use `--password-prompt` to enter the password securely through an interactive prompt (password will be hashed automatically).
226+
* If neither password option is provided, the user account will be created with password login disabled (password set to `!`).
227+
228+
**User Delete Command:**
229+
```
230+
config user del <username>
231+
```
232+
* The `admin` user cannot be deleted and will return an error if attempted.
233+
234+
**User Modify Command:**
235+
```
236+
config user modify <username> [--password-hash <hash> | --password-prompt]
237+
[--ssh-key <key>]
238+
```
239+
* The `admin` user can be modified like any other user, including disabling by setting password to `!`.
240+
* Use `--password-hash` to provide a pre-hashed password directly.
241+
* Use `--password-prompt` to enter the password securely through an interactive prompt (password will be hashed automatically).
242+
243+
**Security Policy Commands:**
244+
```
245+
config user security-policy <role> --max-login-attempts <count>
246+
```
247+
* Configure global login attempt limits for a specific role (`administrator` or `operator`).
248+
249+
```
250+
show user security-policy [<role>]
251+
```
252+
* Display current security policies for all roles or a specific role.
253+
254+
**Password Prompt Implementation:**
255+
When `--password-prompt` is used, the CLI will:
256+
1. Display a secure password prompt (e.g., "Enter password for user <username>:")
257+
2. Hide password input (no echo to terminal)
258+
3. Prompt for password confirmation (e.g., "Confirm password:")
259+
4. Validate that both entries match
260+
5. Hash the password using the same algorithm as `mkpasswd` (e.g., SHA-512)
261+
6. Store only the hashed password in CONFIG_DB
262+
7. Clear the plaintext password from memory immediately after hashing
263+
264+
**Other commands (e.g., `show user`) remain as previously defined.**
265+
266+
## 9. Testing Requirements
267+
### New System Test cases
268+
* **Global Login Attempts Policy:**
269+
* Configure `administrator` role with `max_login_attempts` of 5 and `operator` role with 3.
270+
* Create users with both roles and verify that login attempt limits are enforced according to their role.
271+
* Attempt to log in with incorrect passwords and verify accounts are locked based on their role's policy.
272+
* Verify `faillock --user <username>` shows the correct state for users of different roles.
273+
274+
* **Password Management:**
275+
* Test user creation with `--password-hash` option and verify the hash is stored correctly.
276+
* Test user creation with `--password-prompt` option and verify the password is hashed and stored securely.
277+
* Verify that passwords entered via prompt are not logged in command history.
278+
* Test password modification using both hash and prompt methods.
279+
280+
* **Admin User Management:**
281+
* Verify the `admin` user exists by default and can be modified through CONFIG_DB.
282+
* Attempt to delete the `admin` user and verify it fails with an appropriate error.
283+
* Remove the `admin` user from CONFIG_DB and verify it resets to the default password `YourPaSsWoRd`.
284+
* Set the `admin` user password to `!` and verify password login is disabled while SSH key access remains functional.
285+
286+
* **Startup Consistency Check:**
287+
* Create a user directly in Linux using `useradd` (bypassing CONFIG_DB).
288+
* Restart the `userd` daemon and verify the manually created user is automatically removed.
289+
* Verify that users defined in CONFIG_DB are preserved and properly configured.
290+
* Ensure system users (root, daemon, etc.) are not affected by the cleanup process.
291+
292+
* **User Management:** Create users with different roles and verify all security policies are enforced correctly based on role-based policies.
293+
294+
## 10. Future Enhancements
295+
296+
### 10.1 Remote SSH Key Management
297+
Support for dynamically fetching SSH keys from remote URLs could be added in future versions to enable centralized SSH key management.
298+
299+
## 11. Open/Resolved Issues
300+
301+
None

0 commit comments

Comments
 (0)