Variables
Variables allow you to parameterize snippet content so the same snippet can produce different configurations for different devices or OUs. Inside a snippet’s JSON content, you can use ${variable_name} placeholders that are resolved at sync time.
Variable Scopes
Section titled “Variable Scopes”Variables are defined at multiple levels, and more specific scopes override broader ones:
| Priority | Scope | Meaning |
|---|---|---|
| 1 (lowest) | Organization | The default value for all devices in the organization. |
| 2 | OU | Overrides the organization value for all devices in a specific OU. |
| 3 | Template | Overrides the value for all snippets within a specific template. |
| 4 (highest) | Device | Overrides all other values for a specific device. |
For example, if you define ${listen_port} at the organization level as 51820, you could override it to 52830 for a specific OU’s devices, or to 53840 for one particular device — all while using the same snippet definition.
Parameterizing a Snippet
Section titled “Parameterizing a Snippet”Consider a snippet that allows DNS queries. Instead of hardcoding the DNS server addresses, you can use a variable:
{ "enabled": true, "action": "pass", "interface": "lan", "direction": "in", "ipprotocol": "inet", "protocol": "TCP/UDP", "source_net": "any", "destination_net": "${dns_server}", "destination_port": "53", "description": "Allow DNS to ${dns_server}"}Then define the variable at different scopes:
ndcli variable org create dns_server 8.8.8.8This sets the default DNS server for all devices in the organization. Now override it for the production OU to use an internal resolver:
ndcli variable ou create production dns_server 10.0.1.53And for a specific branch device that needs a local DNS:
ndcli variable device create fw-branch-austin dns_server 10.50.1.53At sync time, the variable is substituted before the configuration reaches the device:
fw-hq-primary(production OU) resolves${dns_server}to10.0.1.53fw-branch-austin(branch-offices OU, device override) resolves to10.50.1.53fw-guest-lobby(guest-networks OU, no override) resolves to8.8.8.8(org default)
Values are inserted exactly as written
Section titled “Values are inserted exactly as written”A value reaches the device exactly as you entered it. NetDefense escapes it to fit the snippet’s JSON, so quotes, backslashes, and line breaks are safe: a password containing " or \ works, and a multi-line value such as a certificate or an SSH key arrives with its line breaks. A value always stays a single string — it can’t add keys or list entries to the snippet.
Escape sequences are not interpreted: a value typed as \n or \" reaches the device as those two characters, not as a line break or a quote. If a value relied on that, enter the real character instead — for a line break, store the value from a file with --value-stdin.
Secret Variables
Section titled “Secret Variables”Secret variables are the right place for passwords, API keys, and pre-shared keys that snippets need — reference them as ${name}, the same as any other variable; NetDefense does not scan snippet content for secrets, so anything sensitive has to go through a variable instead of sitting in a snippet’s JSON body. See Content Format for the snippet-side half of this.
Some variables carry sensitive content — API tokens, shared secrets, anything you want substituted into snippets but never read back. Add --secret when creating the variable at the organization scope, and keep the value off the command line with --value-stdin rather than passing it as an argument — a literal argument lands in shell history and is visible to other users on the host via ps (--value-stdin and the no-echo prompt need ndcli 1.35.0 or later):
ndcli variable org create syslog_token --secret --value-stdin < ./syslog-token.txtExactly one trailing newline is trimmed. Leave off both the value argument and --value-stdin to be prompted interactively instead — the input isn’t echoed to the terminal.
At sync time a secret behaves exactly like a regular variable: its value is substituted into every snippet that references it, and the rendered configuration reaches the device unchanged. The difference is on the read path — the web UI, ndcli variable org describe, and every API response return a redacted placeholder instead of the cleartext. Once written, the value cannot be retrieved.
To rotate a secret, set a new value at the same name the same way:
ndcli variable org set syslog_token --value-stdin < ./new-syslog-token.txtThe --secret flag itself is only available at the organization scope, but an override at a narrower scope (OU, template, or device) of an already-secret organization variable inherits the secret handling automatically, and --value-stdin works at every scope — see the variable command reference.
Variables that need a Superuser
Section titled “Variables that need a Superuser”Every variable value records whether a Superuser saved it, separately at each scope. That decides whether a snippet that grants administrator rights can use it:
- A
USERorGROUPsnippet with elevated content reaches a device only if a Superuser saved the snippet and the value of every variable it uses. The value that counts is the one that wins for that device — an OU, template, or device override, not just the organization default. - A
ZABBIX_USERPARAMETERorZABBIX_SETTINGSsnippet needs a Superuser-saved value for each variable that can decide its command fields. - A value can’t add elevated content its snippet doesn’t already carry, whoever saved it: a
USERsnippet with"scope": "${account_scope}"builds whileaccount_scopeholdsuser, and fails withVARIABLE_ELEVATES_SNIPPETonce it’s set tosystem. - Once a Superuser saves a secret variable, every snippet that uses it, whatever its type, needs Superuser clearance too — otherwise the device’s build fails with
SECRET_VARIABLE_CLEARANCE. A secret last saved by a Read-Write member, or before NetDefense recorded whether a Superuser saved it, doesn’t trigger this.
To record a Superuser’s save on an existing value, a Superuser signed in interactively sets it again. The same value is fine:
ndcli variable org set backup_role --value operatorsndcli variable device set fw-branch-01 backup_role --value operatorsndcli variable org set svc_backup_password --value-stdin < ./svc-backup-password.txtA secret’s value can’t be read back, so it has to be entered again. Changing only the description doesn’t count, and neither does a save through a personal access token, which never carries Superuser clearance. In the web app, open the variable or the override with Edit and save it — retyping the value of a secret.
Conflict Detection
Section titled “Conflict Detection”If a device belongs to multiple OUs that define the same variable with different values, NetDefense detects the conflict and prevents the sync.
Managing Variables
Section titled “Managing Variables”# List all variables across scopesndcli variable overview
# Create variables at each scopendcli variable org create <name> <value>ndcli variable ou create <ou-name> <name> <value>ndcli variable template create <template-name> <name> <value>ndcli variable device create <device-name> <name> <value>