Network Access Control Model (NACM)¶
NETCONF Access Control Model (RFC 8341) provides fine-grained access control for YANG data models. NACM controls who can read, write, and execute operations on specific parts of the configuration and operational state.
This document provides technical details about how NACM works, how rules are evaluated, and best practices for creating custom access control policies.
Tip
For a practical introduction to user management and the built-in user levels (admin, operator, guest), see the Multiple Users section in the System Configuration guide.
TL;DR - The Factory Defaults Work¶
You don't need to understand NACM to use the system securely.
The factory configuration implements a "permit by default, deny sensitive items" policy that provides:
- Immediate usability - Operators can configure the entire system without custom NACM rules
- Automatic security - Passwords, cryptographic keys, and dangerous operations are protected out-of-the-box
- Future-proof design - New features work immediately without NACM updates
The three built-in user levels (admin, operator, guest) cover most use cases. Only read on if you need to create custom access control policies.
Overview¶
NACM provides three types of access control:
- Data node access - Control read/write access to configuration and state
- Operation access - Control execution of RPCs (remote procedure calls)
- Notification access - Control subscription to event notifications (not covered here)
Access is controlled through:
- Global defaults - Default permissions for read/write/exec
- YANG-level annotations - Security markers in YANG modules (see below)
- NACM rules - Explicit permit/deny rules organized in rule-lists
Rule Evaluation¶
NACM rules are evaluated in a specific order:
- Rule-lists are processed sequentially in the order they appear in the configuration
- Within each rule-list, rules are evaluated sequentially
- First matching rule wins - no further rules are evaluated
- If no rule matches, global defaults apply (read-default, write-default, exec-default)
- YANG annotations override everything -
nacm:default-deny-allin a YANG module requires an explicit permit rule regardless of global defaults
Example Rule Evaluation¶
Given this configuration:
{
"read-default": "permit",
"write-default": "permit",
"rule-list": [
{
"name": "operator-acl",
"group": ["operator"],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"access-operations": "exec",
"action": "permit"
}
]
},
{
"name": "default-deny-all",
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
When operator user "jacky" tries to:
- Read password: Matches "deny-passwords" → DENIED
- Write interface config: No match, uses write-default → PERMITTED (write-default=permit)
- Write hostname: No match, uses write-default → PERMITTED (write-default=permit)
- Reboot system: Matches "permit-system-rpcs" → PERMITTED (overrides
nacm:default-deny-all)
Global Defaults¶
NACM has three global defaults that apply when no rule matches:
Factory configuration defaults:
read-default: "permit"- Users can read configuration and state by defaultwrite-default: "permit"- Users can modify configuration by defaultexec-default: "permit"- Users can execute RPCs by default
This permit-by-default approach, combined with targeted denials for sensitive items (passwords, cryptographic keys), provides a balance between usability and security. It also makes the system "future proof" - when new YANG modules are added, operators can immediately configure them without updating NACM rules.
Important
YANG modules with nacm:default-deny-all or nacm:default-deny-write
annotations override these global defaults. You must create explicit
permit rules for those operations.
Module-Name vs Path¶
NACM rules can match operations using either module-name or path.
The following sub-sections provide detailed information and examples of
both.
Module-Name Matching¶
Matches all nodes defined in a specific YANG module:
{
"name": "permit-keystore",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "permit"
}
This permits all operations on data defined in ietf-keystore, but does NOT cover augments from other modules.
Example: The /interfaces/interface/ipv4/address path:
- Interface is defined in
ietf-interfaces - IPv4 config is defined in
ietf-ip(augments ietf-interfaces) - A rule with
module-name: "ietf-interfaces"does NOT cover ipv4/address
Path Matching¶
Matches a specific data tree path and all nodes under it, including augments from other modules:
{
"name": "permit-network-config",
"path": "/ietf-interfaces:interfaces/interface",
"access-operations": "*",
"action": "permit"
}
This permits operations on /interfaces/interface and all child nodes,
including augments like:
/interfaces/interface/ipv4(from ietf-ip)/interfaces/interface/ipv6(from ietf-ip)/interfaces/interface/bridge-port(from infix-interfaces)
Path syntax:
-
When used with module-name: Path is module-relative (no prefix)
-
When used without module-name: Path must include module prefix
Use path-based rules
When you want to permit/deny access to a configuration subtree
including all augments, e.g., all IP settings below
/ietf-interfaces:interfaces/. This is more flexible and requires
less maintenance as new features are added.
YANG-Level Annotations¶
Many YANG modules include NACM annotations that provide baseline security:
nacm:default-deny-all¶
Requires an explicit permit rule, regardless of global defaults:
Even with exec-default: "permit", users need an explicit permit rule to
execute system-restart.
nacm:default-deny-write¶
Write operations require an explicit permit rule:
container authentication {
nacm:default-deny-write;
description "User authentication configuration";
}
Even with write-default: "permit", users need an explicit permit rule to
modify authentication settings.
Protected Operations¶
The following are protected by YANG annotations and require explicit permits:
RPC Operations:
ietf-system:system-restart(ietf-system)ietf-system:system-shutdown(ietf-system)ietf-system:set-current-datetime(ietf-system)infix-factory-default:factory-defaultietf-factory-default:factory-reset(RFC 8808)infix-system-software:install-bundleinfix-system-software:set-boot-order
Data Containers:
/system/authentication(nacm:default-deny-write, ietf-system)/nacm(nacm:default-deny-all, RFC 8341)- Routing protocol key chains (ietf-key-chain)
- RADIUS shared secrets (ietf-system)
- TLS client/server credentials (ietf-tls-client)
This provides defense-in-depth - even if NACM rules are misconfigured, these critical operations remain protected.
Access Operations¶
NACM supports the following access operations:
create- Create new data nodesread- Read existing data nodesupdate- Modify existing data nodesdelete- Delete data nodesexec- Execute RPC operations*- All operations (wildcard)
Common combinations:
"create update delete"- All write operations"*"- Everything (read, write, execute)"read"- Read-only access
Rule-List Groups¶
Each rule-list applies to one or more user groups:
Special group names:
"*"- Matches all users (including those not in any NACM group)
Evaluation: A user can be in multiple NACM groups. All rule-lists matching the user's groups are evaluated in order until a matching rule is found.
Example: Factory Configuration¶
The factory configuration uses a "permit by default, deny sensitive items" approach. This design is "future proof" - when new YANG modules are added, operators can immediately configure them without updating NACM rules.
{
"ietf-netconf-acm:nacm": {
"enable-nacm": true,
"read-default": "permit",
"write-default": "permit",
"exec-default": "permit",
"groups": {
"group": [
{"name": "admin", "user-name": ["admin"]},
{"name": "operator", "user-name": []},
{"name": "guest", "user-name": []}
]
},
"rule-list": [
{
"name": "admin-acl",
"group": ["admin"],
"rule": [
{
"name": "permit-all",
"module-name": "*",
"access-operations": "*",
"action": "permit",
"comment": "Admin has full unrestricted access"
}
]
},
{
"name": "operator-acl",
"group": ["operator"],
"rule": [
{
"name": "permit-system-rpcs",
"module-name": "ietf-system",
"rpc-name": "*",
"access-operations": "exec",
"action": "permit",
"comment": "Operators can reboot, shutdown, and set system time"
}
]
},
{
"name": "guest-acl",
"group": ["guest"],
"rule": [
{
"name": "deny-all-write+exec",
"module-name": "*",
"access-operations": "create update delete exec",
"action": "deny",
"comment": "Guests can only read, not modify or execute"
}
]
},
{
"name": "default-deny-all",
"group": ["*"],
"rule": [
{
"name": "deny-password-access",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access password hashes"
},
{
"name": "deny-keystore-access",
"module-name": "ietf-keystore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access cryptographic keys"
},
{
"name": "deny-truststore-access",
"module-name": "ietf-truststore",
"access-operations": "*",
"action": "deny",
"comment": "No user except admins can access trust store"
}
]
}
]
}
}
Key design decisions:
- Permit by default -
write-default: permitallows operators to configure any module - Minimal operator rules - Only one rule to permit system RPCs (reboot, set time)
- Future proof - New YANG modules automatically configurable by operators
- Targeted denials - Only sensitive items (passwords, keys) are explicitly denied
- Global denials - Password/keystore/truststore denied for everyone via group "*"
- YANG annotations - Sensitive operations (factory-reset, software upgrades) still protected by
nacm:default-deny-allin YANG modules
Effective permissions by group:
| Group | Read | Write | Exec | Exceptions |
|---|---|---|---|---|
| admin | All | All | All | None |
| operator | All | All | All | Cannot access passwords, keystore, truststore |
| guest | All | None | None | Read-only access |
Common Patterns¶
Permit-by-Default¶
The factory default approach - allow everything except sensitive items:
{
"write-default": "permit",
"exec-default": "permit",
"rule-list": [
{
"name": "admin-acl",
"group": ["admin"],
"rule": [
{
"name": "permit-all",
"module-name": "*",
"access-operations": "*",
"action": "permit"
}
]
},
{
"name": "global-denials",
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
This approach is "future proof" - new YANG modules are automatically
accessible without rule updates. Admins bypass the global denials
because their permit-all rule is evaluated first.
Deny-by-Default¶
More restrictive approach - deny everything except what is explicitly allowed:
{
"write-default": "deny",
"exec-default": "deny",
"rule-list": [
{
"group": ["limited-user"],
"rule": [
{
"name": "permit-interface-config",
"path": "/ietf-interfaces:interfaces/interface",
"access-operations": "create update delete",
"action": "permit"
}
]
}
]
}
Note
This requires updating NACM rules whenever new features are added.
Global Restrictions¶
Deny access to sensitive data for all users (except admins with permit-all):
{
"rule-list": [
{
"group": ["*"],
"rule": [
{
"name": "deny-passwords",
"path": "/ietf-system:system/authentication/user/password",
"access-operations": "*",
"action": "deny"
}
]
}
]
}
Debugging NACM¶
Viewing Effective Permissions¶
Check what NACM groups a user belongs to:
admin@example:/> show nacm
enabled : yes
default read access : permit
default write access : permit
default exec access : permit
denied operations : 0
denied data writes : 0
denied notifications : 0
┌──────────┬─────────┬─────────┬─────────┐
│ GROUP │ READ │ WRITE │ EXEC │
├──────────┼─────────┼─────────┼─────────┤
│ admin │ ✓ │ ✓ │ ✓ │
│ operator │ ⚠ │ ⚠ │ ⚠ │
│ guest │ ⚠ │ ✗ │ ✗ │
└──────────┴─────────┴─────────┴─────────┘
✓ Full ⚠ Restricted ✗ Denied
USER SHELL LOGIN
admin bash password+key
jacky bash password
monitor false key
GROUP USERS
admin admin
operator jacky
guest monitor
For details about a group's restrictions, use show nacm group <name>:
admin@example:/> show nacm group operator
members : jacky
read permission : restricted
write permission : restricted
exec permission : restricted
applicable rules : 4
──────────────────────────────────────────────────────────────────────
permit-system-rpcs
action : permit
operations : exec
target : ietf-system (rpc: *)
──────────────────────────────────────────────────────────────────────
deny-password-access (via '*')
action : deny
operations : *
target : /ietf-system:system/authentication/user/password
──────────────────────────────────────────────────────────────────────
deny-keystore-access (via '*')
action : deny
operations : *
target : ietf-keystore
──────────────────────────────────────────────────────────────────────
deny-truststore-access (via '*')
action : deny
operations : *
target : ietf-truststore
Testing Access¶
The easiest way to test NACM permissions is to log in as the user and try the operation:
$ ssh jacky@host
jacky@example:/> configure
jacky@example:/config/> edit system authentication user admin
jacky@example:/config/system/authentication/user/admin/> set authorized-key foo
Error: Access to the data model "ietf-system" is denied because "jacky" NACM authorization failed.
Error: Failed applying changes (2).
NACM Statistics¶
NACM tracks denied operations. If you suspect permission issues, check the statistics:
admin@example:/> show nacm
...
denied operations : 5
denied data writes : 12
...
Increasing counters indicate permission denials are occurring.
Best Practices¶
-
Leverage permit-by-default - The factory configuration uses
write-default: "permit"with targeted denials. This is "future proof" - new features work immediately without NACM updates. -
Protect sensitive items globally - Use
group: ["*"]rule-list to deny access to passwords, cryptographic keys, and similar sensitive data. Admin's permit-all rule (evaluated first) bypasses these denials. -
Leverage YANG annotations - Many sensitive operations are already protected by
nacm:default-deny-allin YANG modules (factory-reset, software upgrades, etc.). Only add explicit permit rules when needed. -
Order matters - Rule-lists are evaluated in order. Place admin's permit-all rule first so it bypasses global denials.
-
Use path-based denials - For protecting specific data (like password hashes), use path rules. For protecting entire modules (like keystore), use module-name rules.
-
Test thoroughly - Always test user permissions after changes. NACM errors can be subtle (nodes may be silently omitted from read operations).
-
Keep it simple - The factory configuration uses only 6 rules for three user levels. Fewer rules are easier to understand and maintain.
-
Document rules - Use the "comment" field to explain why specific permissions are granted or denied.