Skip to content

Usage

This page covers running nac-validate and the options shared by both validation stages. How to write a schema is described in Schema Validation, how to write rules in Semantic Validation.

nac-validate takes one or more YAML files or directories. Directories are searched recursively for .yaml and .yml files:

Terminal window
nac-validate data/

By default, the schema is read from .schema.yaml and the rules from .rules/ in the current directory. If they don’t exist, the respective validation is skipped. Other locations are passed with -s/--schema and -r/--rules, which can be repeated to use rules from several directories:

Terminal window
nac-validate data/ -s schemas/schema.yaml -r rules/ -r custom_rules/

All options can also be set with environment variables, listed in the Overview.

Every file is first parsed and validated against the schema on its own. For semantic validation, all files are then merged into a single data structure:

  • Maps are merged recursively.
  • List items that are maps are merged if all the fields they have in common have the same values. Otherwise, they are added as separate items.
  • Other list items are concatenated.

For example, these two files:

nodes.yaml
fabric:
nodes:
- id: 101
name: leaf-101
management.yaml
fabric:
nodes:
- id: 101
mgmt_ip: 10.0.0.101/24

result in a single node 101 with name and mgmt_ip. If a list in one of the files contains duplicate items, its items are not merged but concatenated. See Merging YAML for details and more examples.

-o/--output writes the merged data to a file, for example to inspect it or to pass it to other tools:

Terminal window
nac-validate data/ -o merged.yaml

The output is only written if the validation passed. Variables and templates of Network as Code architectures that support them (IOS XE, NX-OS, IOS XR and Meraki) are resolved by the Terraform module, not by nac-validate, so the merged output still contains them.

The !env YAML tag can be used to read values from environment variables.

root:
name: !env VAR_NAME

Values can be encrypted using Ansible Vault and the !vault tag:

password: !vault |
$ANSIBLE_VAULT;1.2;AES256;dev
6535616566336139303566666336633163663431306337356461633439626638...

This requires Ansible (ansible-core) to be installed and the following two environment variables to be defined:

export ANSIBLE_VAULT_ID=dev
export ANSIBLE_VAULT_PASSWORD=Password123

ANSIBLE_VAULT_ID is optional, and if not defined will be omitted. Ansible Vault is not supported on Windows.

nac-validate uses distinct exit codes so CI pipelines can distinguish between failure types:

CodeMeaning
0Validation passed
1Semantic validation failed (rule violations)
2Syntax validation failed (YAML syntax or schema errors)
3Configuration error (e.g. missing schema, invalid schema or rules, a rule raising an exception)

By default, results are printed as text with colors, followed by a summary. --no-color (or the NO_COLOR environment variable) disables colors, and --compact omits the explanations and recommendations of rules.

-f json/--format json prints the results as JSON to stdout, for example for CI/CD integration:

Terminal window
nac-validate data/ -s schema.yaml -r rules/ --format json
{
"syntax_errors": [],
"semantic_errors": [
{
"rule_id": "101",
"description": "Verify interfaces reference existing nodes",
"severity": "HIGH",
"errors": [
{
"message": "Node 103 of interface eth1/3 is not defined",
"path": "fabric.interfaces[node_id=103,name=eth1/3].node_id",
"details": {
"node_id": 103
}
}
],
"title": "Interface references unknown node",
"explanation": "Every interface must belong to a node defined under fabric.nodes.",
"recommendation": "Add the node to fabric.nodes or fix the node_id of the interface."
}
]
}

Syntax errors are listed with their file and message:

{
"syntax_errors": [
{
"file": "data/nodes.yaml",
"message": "fabric.nodes.[name=leaf-102].role: 'border' not in ('leaf', 'spine')"
}
],
"semantic_errors": []
}

Configuration errors are reported in an additional error field.

--list-artifacts shows the schema and the rules that would be used, without validating any data:

$ nac-validate --list-artifacts
Artifact Layers (highest priority first):
schema .schema.yaml, rules .rules [local]
Effective Schema:
.schema.yaml [local]
Available Validation Rules:
────────────────────────────────────────────────────────────────────────────────
[101] Verify interfaces reference existing nodes (HIGH) [local]
────────────────────────────────────────────────────────────────────────────────
Total: 1 rules

Rules are read from their source code without executing them.

The tool can be integrated via a pre-commit hook with the following config (.pre-commit-config.yaml), assuming the default values (.schema.yaml, .rules/) are appropriate:

repos:
- repo: https://github.com/netascode/nac-validate
rev: v2.1.0
hooks:
- id: nac-validate

In case the schema or validation rules are located somewhere else the required CLI arguments can be added like this:

repos:
- repo: https://github.com/netascode/nac-validate
rev: v2.1.0
hooks:
- id: nac-validate
args:
- '-s'
- 'my_schema.yaml'
- '-r'
- 'rules/'

Besides the local --schema and --rules paths, schema and rules can be packaged with the Terraform module of a Network as Code architecture or distributed as bundles. Loading them is enabled with --artifacts (or NAC_VALIDATE_ARTIFACTS=true), and also by passing --bundle or --module-dir:

Terminal window
nac-validate --artifacts data/

Schema and rules are combined from the following layers, highest priority first:

  1. Local: --schema/--rules, or the .schema.yaml and .rules/ defaults
  2. Bundle: every .zip, .tar.gz or .tgz archive and every directory in the project’s nac/bundles/ (or the paths given with --bundle), with manifest.yaml, schema.yaml and rules/ at its root
  3. Module: the nac/ directory (nac/schema.yaml, nac/rules/) of the Terraform module installed by terraform init (or the one given with --module-dir)

The schema of the highest layer providing one is used. A rule replaces rules with the same ID from lower layers. Rules of bundles and modules can be disabled by ID in nac/overrides.yaml:

disable:
rules:
- "101"

The project directory is the current working directory: nac/bundles/, nac/overrides.yaml and the .terraform/ directory (or TF_DATA_DIR) are looked up there, so run nac-validate from the root module directory. --list-artifacts shows the layers in use and the origin of each rule.

Rules are Python code executed by nac-validate, so bundles and modules require the same trust as code in your own repository. Review them with --list-artifacts before enabling --artifacts, and note that a module update (terraform init -upgrade) or a new file in nac/bundles/ changes which code runs.