Guide

Authorization

Ze uses profile-based command authorization (RBAC) to control which commands each user can execute. Profiles are defined in the daemon configuration alongside user accounts. Each user is assigned one or more profiles; each profile contains ordered rules that allow or deny commands.

Authorization is separate from authentication. Authentication (covered in authentication.md) decides who the user is. Authorization decides what they can do.

Concepts

Profiles

A profile is a named set of authorization rules. Each profile has two sections:

Section Governs ReadOnly flag
run Operational (read-only) commands: show, monitor, resolve, validate, help, event, subscribe true
edit Configuration (write) commands: clear, set, request, commit, configure, and everything else false

The dispatcher classifies commands automatically by their leading verb. You do not choose which section a command falls into.

Entries

Each section contains an ordered list of numbered entries. Each entry has:

Field Type Description
number uint32 Sequence number controlling evaluation order (lowest first)
action allow or deny What to do when this entry matches
match string The pattern to match against the command
regex boolean If true, match is a Go regular expression. If absent or false, match is a prefix.

Default action

Each section has a default-action (allow or deny). When no entry matches the command, the default action applies.

Evaluation order

  1. The dispatcher resolves the command and determines which section applies (run or edit).
  2. Entries are evaluated in ascending number order.
  3. The first matching entry wins. Its action is the verdict.
  4. If no entry matches, default-action applies.

When a user has multiple profiles, the profiles are evaluated in assignment order. The first profile with a matching entry wins. If no profile has a matching entry, the first profile's default-action applies.

Matching rules

Prefix matching (default)

When regex is absent or false, the match string is compared as a case-insensitive prefix with word-boundary enforcement.

A match string of "show bgp peer" matches:

It does not match:

The key insight: prefix matching authorizes the command stem, not the arguments. When you allow "show bgp peer", all arguments that follow (peer names, IP addresses, keywords like detail or routes) are implicitly permitted. This is the standard network OS approach: authorize the command, not every parameter.

Regex matching

When regex is true, the match string is a Go regular expression (the regexp package syntax). The regex is tested with MatchString, meaning it matches anywhere in the command unless you anchor it with ^ and $.

Examples:

Pattern Matches Does not match
"^show bgp peer (list\|summary)( \|$)" show bgp peer list, show bgp peer summary, show bgp peer list 10.0.0.1 show bgp peer detail, show bgp peer routes
"peer .* show" peer 10.0.0.1 show, peer myrouter show peer 10.0.0.1 list
"^restart$" restart restart now
"^clear (bgp\|counters)" clear bgp peer1, clear counters all clear l2tp session

Regex entries are compiled and validated at config load. An invalid regex causes a config validation error.

Use prefix matching when you can. It is simpler, faster, and covers most real-world policies. Use regex only when you need to restrict which sub-commands are allowed under a common prefix, or when the command structure requires non-prefix patterns.

What string gets matched

The authorization check receives the full command as typed by the user, including all arguments, before the dispatcher strips selectors or validates argument types.

For peer-scoped commands dispatched through the typed command system, the canonical authorization string prepends "peer" to the command tokens (but not the peer selector value itself). For example, if a plugin dispatches command "show routes" scoped to peer "10.0.0.1", the authorization string is "peer show routes", not "peer 10.0.0.1 show routes".

For CLI-entered commands (the common case), the authorization string is simply what the user typed: show bgp peer list, clear counters, configure, etc.

Configuration

Defining profiles

Profiles are defined under system > authorization:

system {
    authorization {
        profile admin {
            run {
                default-action allow
            }
            edit {
                default-action allow
            }
        }
        profile noc {
            run {
                default-action allow
                entry 10 {
                    action deny
                    match "restart"
                }
                entry 20 {
                    action deny
                    match "kill"
                }
                entry 30 {
                    action deny
                    match "clear"
                }
            }
            edit {
                default-action deny
            }
        }
        profile monitoring {
            run {
                default-action deny
                entry 10 {
                    action allow
                    match "show bgp peer list"
                }
                entry 20 {
                    action allow
                    match "show bgp summary"
                }
                entry 30 {
                    action allow
                    match "show bgp peer"
                    regex true
                }
            }
            edit {
                default-action deny
            }
        }
    }
}

Assigning profiles to users

Profiles are assigned in the system > authentication > user block. Each user has a profile leaf that takes a list of profile names:

system {
    authentication {
        user alice {
            password "$2a$10$..."
            profile [ admin ]
        }
        user bob {
            password "$2a$10$..."
            profile [ noc ]
        }
        user grafana {
            password "$2a$10$..."
            profile [ monitoring ]
        }
    }
}

TACACS+ profile mapping

For TACACS+ authenticated users, profiles are assigned by privilege level using tacacs-profile:

system {
    authentication {
        tacacs-profile 15 { profile [ admin ]; }
        tacacs-profile 1  { profile [ read-only ]; }
    }
}

See tacacs.md for full TACACS+ configuration.

Built-in profiles

Ze provides two built-in profiles that can be referenced without defining them in the configuration. If you define a profile with the same name, your definition overrides the built-in.

admin

Allows everything. Both run and edit default to allow with no entries.

read-only

Allows all operational commands except dangerous ones. Denies all configuration commands.

Section Default Entries
run allow 10: deny restart, 20: deny kill, 30: deny clear
edit deny (none)

Common patterns

Allow specific commands only (allowlist)

Set default-action deny and add allow entries for each permitted command:

profile monitoring {
    run {
        default-action deny
        entry 10 {
            action allow
            match "show bgp peer list"
        }
        entry 20 {
            action allow
            match "show bgp summary"
        }
    }
    edit {
        default-action deny
    }
}

This user can run show bgp peer list (with or without arguments after it, such as an IP address) and show bgp summary, but nothing else.

Deny dangerous commands (denylist)

Set default-action allow and add deny entries for commands to block:

profile noc {
    run {
        default-action allow
        entry 10 {
            action deny
            match "restart"
        }
        entry 20 {
            action deny
            match "kill"
        }
    }
    edit {
        default-action deny
    }
}

Allow a command family but deny a specific sub-command

Use entry ordering. Lower-numbered entries are evaluated first:

run {
    default-action deny
    entry 10 {
        action deny
        match "show bgp peer secret"
    }
    entry 20 {
        action allow
        match "show bgp peer"
    }
}

Entry 10 blocks show bgp peer secret (and anything starting with that prefix). Entry 20 allows all other show bgp peer commands. Order matters: if entry 20 came first, it would match show bgp peer secret before entry 10 could deny it.

Restrict sub-commands with regex

When prefix matching is too broad, use regex to allow only specific sub-commands:

run {
    default-action deny
    entry 10 {
        action allow
        match "^show bgp peer (list|summary)( |$)"
        regex true
    }
}

This allows show bgp peer list and show bgp peer summary (with or without trailing arguments) but denies show bgp peer detail or show bgp peer routes.

Multiple profiles

A user can be assigned multiple profiles. They are evaluated in list order; the first profile with a matching entry wins:

system {
    authentication {
        user ops {
            password "$2a$10$..."
            profile [ restricted ops-extra ]
        }
    }
    authorization {
        profile restricted {
            run {
                default-action deny
                entry 10 {
                    action allow
                    match "show bgp peer"
                }
            }
            edit { default-action deny; }
        }
        profile ops-extra {
            run {
                default-action deny
                entry 10 {
                    action deny
                    match "kill"
                }
            }
            edit { default-action deny; }
        }
    }
}

For user ops, the command show bgp peer list matches entry 10 in restricted (allow). The command kill matches entry 10 in ops-extra (deny). An unmatched command like summary falls to the first profile's default (deny).

Fail-closed behavior

When user assignments are configured (at least one user has a profile list), unassigned users are denied all commands. This prevents unassigned users from silently becoming admin-equivalent.

When no user assignments exist at all (no profiles configured), all access is allowed. This preserves backward compatibility for deployments that do not use authorization.

State Empty username Known user, no profile Known user, profile assigned
βœ• Allow all Allow all N/A
Assignments configured Deny Deny Evaluate profiles

Validation

ze config validate checks that:

$ ze config validate myconfig.conf
configuration valid

An invalid regex pattern causes a validation error:

$ ze config validate bad.conf
profile "test" run: entry 10: invalid regex "[broken": error parsing regexp: missing closing ]: `[broken`

Things that do NOT work

Attempt Why it fails Use this instead
Matching on IP addresses with prefix mode Prefix matches the command stem, not individual tokens in the middle Use regex true with a pattern like "^show bgp peer list 10\\.0\\.0\\.1$"
Using match "show" to allow all show commands and denying specific ones with higher entry numbers The first match wins; entry 10 allow "show" matches before entry 20 deny "show bgp secret" Put the more specific deny entry at a lower number than the broader allow
Expecting regex to be anchored by default Go regex MatchString matches anywhere in the string; "restart" matches "show restart status" Anchor explicitly: "^restart( \|$)"
Referencing a profile name that does not exist The profile is skipped silently; if all assigned profiles are missing, the user gets admin defaults Define the profile, or use one of the built-in names (admin, read-only)

Reference

Symbol Location
YANG schema internal/component/authz/yang/ze-authz-conf.yang
Profile evaluation internal/component/authz/authz.go
Store (thread-safe registry) internal/component/authz/authz.go
StoreAuthorizer adapter internal/component/authz/register.go
Canonical command builder internal/component/aaa/command_args.go
Read-only verb classification (IsReadOnlyPath). internal/component/plugin/server/command.go
Dispatcher authorization check (isAuthorized, isAuthorizedCommandArgs). internal/component/plugin/server/command.go
Built-in admin profile (BuiltinAdminProfile). internal/component/authz/authz.go
Built-in read-only profile (BuiltinReadOnlyProfile). internal/component/authz/authz.go