|
| 1 | +module sonic-user { |
| 2 | + yang-version 1.1; |
| 3 | + namespace "http://github.com/sonic-net/sonic-user"; |
| 4 | + prefix "sonic-user"; |
| 5 | + |
| 6 | + description "SONIC User Management YANG Module"; |
| 7 | + |
| 8 | + revision 2025-06-19 { |
| 9 | + description "Initial revision for declarative user management"; |
| 10 | + } |
| 11 | + |
| 12 | + // Common typedef for user roles |
| 13 | + typedef user-role { |
| 14 | + type enumeration { |
| 15 | + enum "administrator" { |
| 16 | + description "Grants administrative privileges (e.g., member of sudo, docker groups)."; |
| 17 | + } |
| 18 | + enum "operator" { |
| 19 | + description "Grants operator-level (read-only or limited) privileges."; |
| 20 | + } |
| 21 | + } |
| 22 | + description "User role that determines group memberships, privileges, and applicable security policies."; |
| 23 | + } |
| 24 | + |
| 25 | + // Top-level container for the User feature |
| 26 | + container sonic-user { |
| 27 | + description "Top-level container for local user management configuration"; |
| 28 | + |
| 29 | + container LOCAL_USER { |
| 30 | + description "LOCAL_USER part of config_db.json"; |
| 31 | + |
| 32 | + list LOCAL_USER_LIST { |
| 33 | + key "username"; |
| 34 | + description "List of declaratively managed local users."; |
| 35 | + |
| 36 | + must "count(../LOCAL_USER_LIST[role='administrator' and (not(enabled) or enabled='true')]) >= 1" { |
| 37 | + error-message "At least one administrator user must remain enabled."; |
| 38 | + } |
| 39 | + |
| 40 | + leaf username { |
| 41 | + type string { |
| 42 | + pattern '[a-z_][a-z0-9_-]*[$]?' { |
| 43 | + error-message "Invalid username. Must start with a lowercase letter or underscore, followed by lowercase letters, numbers, underscores, or hyphens."; |
| 44 | + } |
| 45 | + length 1..32; |
| 46 | + } |
| 47 | + must ". != 'root'" { |
| 48 | + error-message "Username cannot be 'root'."; |
| 49 | + } |
| 50 | + description "The username for the local account."; |
| 51 | + } |
| 52 | + |
| 53 | + leaf role { |
| 54 | + type user-role; |
| 55 | + mandatory true; |
| 56 | + description "The role assigned to the user, which determines their group memberships and privileges."; |
| 57 | + } |
| 58 | + |
| 59 | + leaf password_hash { |
| 60 | + type string; |
| 61 | + mandatory true; |
| 62 | + must "not(starts-with(., '!'))" { |
| 63 | + error-message "Password hash cannot start with '!'. Use the 'enabled' attribute to disable user accounts."; |
| 64 | + } |
| 65 | + description "The hashed password string for the user, as found in /etc/shadow. Password hashes can be generated using 'mkpasswd' utility or programmatically using libraries like 'passlib'. To disable an account, use the 'enabled' attribute instead of prepending '!' to the password hash."; |
| 66 | + } |
| 67 | + |
| 68 | + leaf-list ssh_keys { |
| 69 | + type string; |
| 70 | + description "A list of full public SSH key strings."; |
| 71 | + } |
| 72 | + |
| 73 | + leaf enabled { |
| 74 | + type boolean; |
| 75 | + default true; |
| 76 | + description "Whether the user account is enabled. When false, the password is disabled by prepending '!' to prevent password-based login while preserving SSH key access."; |
| 77 | + } |
| 78 | + } |
| 79 | + } |
| 80 | + |
| 81 | + container LOCAL_ROLE_SECURITY_POLICY { |
| 82 | + description "LOCAL_ROLE_SECURITY_POLICY part of config_db.json"; |
| 83 | + |
| 84 | + list LOCAL_ROLE_SECURITY_POLICY_LIST { |
| 85 | + key "role"; |
| 86 | + description "Global security policies applied to users based on their role."; |
| 87 | + |
| 88 | + leaf role { |
| 89 | + type user-role; |
| 90 | + description "The role for which this security policy applies."; |
| 91 | + } |
| 92 | + |
| 93 | + leaf max_login_attempts { |
| 94 | + type uint32 { |
| 95 | + range "1..1000"; |
| 96 | + } |
| 97 | + description "Maximum number of failed login attempts before accounts with this role are locked. If not set, system defaults apply."; |
| 98 | + } |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | +} |
0 commit comments