Skip to main content
Question

Network Audit Scripts - AAA NXOS, IOS, EOS

  • June 10, 2026
  • 0 replies
  • 11 views

cariddir
Spotter
Forum|alt.badge.img+5

 

 

As part of a network initiative, I’m sharing all the scripts that I have worked on to create an audit program. These files feed are then fed into PowerBi for better visualization by engineers and mgmt.

PowerBi Presentation


Starting with AAA.
First step is create a utility called, “tag_var_util” to grab tags, of which, will be used as part of the logic to assign a template to different sets of attribtues.
This utility will then be imported on all other NQE Audit Scripts.

// Best practice is to tag all devices with the following:
// Environment && Sub-Environment && Manager && Region && Function && VRF && Mgmt-Interface (source interface for mgmt. traffic)
// Each Script will import the utilities: import "PROD/Standards_Network/NetworkVars/tag_var_util";
let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let subDc = get_SubDc_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp

// Create a new NQE Function called: tag_var_util
// Add the following utility to extract tags given to devices in Forward Networks Sources

// TAGS to identify Environment
export get_env_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"DC",
"CoLo",
"Branch",
"AWS"]);

// TAGS to identify a sub category of location
export get_SubDc_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"Branch",
"DC01",
"DC02" ]);

// TAGS to identify which managers owns the product
export get_mgr_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"Moe",
"Larry",
"Curly"
]);

// TAGS to identify which region a device resides
export get_region_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"EMEA",
"AMRS",
"APAC",
"LATM"
]);

// TAGS to identify what function a device performs
export get_function_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"Firewall",
"LB",
"Proxy",
"WLC",
"Router",
"Switch",
"Controller"
]);

// TAGS to identify if a VRF is associated with Mgmt_interface for a device
export return_vrf_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"vrf_1",
"vrf_NM",
"vrf_None",
"vrf_mgmt"
]);

// TAGS to identify the management interface for a device
export return_mgmt_from_tags(tags: Bag<String>)=
get_list_match_from_tags(tags, [
"mgmt_mgmt0",
"Mgmt_Lo0",
"Mgmt_Ma0",
"Mgmt_Gi0"
]);

Arista  NQE for AAA
 

/***
* @intent AAA Validation (NX-OS)
* @description Validates Cisco NX-OS AAA authentication/authorization/accounting config.
***/

import "PROD/Standards_Network/NetworkVars/tag_var_util";

// =============================================================================
// SECTION 1 — HELPER FUNCTIONS
// =============================================================================

isAciNode(device) =
CommandType.CISCO_ACI_FABRIC_VRFS in
(foreach command in device.outputs.commands
select command.commandType);

getConfigAsString(device) =
max(foreach command in device.outputs.commands
where command.commandType == CommandType.CONFIG
select command.response);

trimLine(line) =
"\n" + max(foreach m in regexMatches(line, re`[^ \t\n][^\n]*[^ \t\n]|[^ \t\n]`)
select m.string);

// =============================================================================
// SECTION 2 — COMPLIANCE PATTERNS (AAA lines only)
// =============================================================================

nxosPatternDefault = ```
Investigate
```;

// --- AMRS ---
nxosPatternAMRS_AAA = ```
aaa group server tacacs+ vty
server 1.1.1.1
server 1.1.1.2
source-interface {string}

aaa authentication login default group vty local
aaa authentication login console group vty local
aaa accounting default group vty
```;

// --- APAC ---
nxosPatternAPAC_AAA = ```
aaa group server tacacs+ vty
server 1.1.1.1
server 1.1.1.2
source-interface {string}

aaa authentication login default group vty local
```;

// --- China ---
nxosPatternChina_AAA = ```
aaa group server tacacs+ GROUP_DC10_TACACS+
server 1.1.1.1
use-vrf management

aaa authentication login default group GROUP_DC10_TACACS+
aaa authentication login console group GROUP_DC10_TACACS+
aaa authorization config-commands default group GROUP_DC10_TACACS+ local
aaa authorization commands default group GROUP_DC10_TACACS+ local
aaa authorization config-commands console group GROUP_DC10_TACACS+ local
aaa authorization commands console group GROUP_DC10_TACACS+ local
aaa accounting default group GROUP_DC10_TACACS+
```;

// --- EMEA ---
nxosPatternEMEA_AAA = ```
aaa group server tacacs+ tac1
server 1.1.1.1
server 1.1.1.2

aaa authentication login default group tac1
aaa authorization config-commands default group tac1 local
aaa authorization commands default group tac1 local
```;

// =============================================================================
// SECTION 3 — REGEX PATTERNS
// =============================================================================

nxosAaaPattern = re`\naaa [^\n]*`;
nxosAaaGroupBlock = re`\naaa group server tacacs\+[^\n]*(?:\n[ \t]+[^\n]+)*`;
nxosAaaGroupMembers = re`\n[ \t]+(?:server|source-interface|use-vrf)[^\n]*`;

// Combined pattern for ordered config extraction (AAA only)
nxosAaaCombinedPattern = re`\n(?:aaa group server tacacs\+[^\n]*(?:\n[ \t]+[^\n]+)*|aaa [^\n]*)`;

// =============================================================================
// SECTION 4 — MAIN LOGIC
// =============================================================================

main =
foreach device in network.devices
where device.platform.os == OS.NXOS
where !isAciNode(device)
where device.name == device.system.physicalName

let configResponse = getConfigAsString(device)
let configAsString = if isPresent(configResponse) then configResponse else ""

let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let subDc = get_SubDc_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp // STEP 1: Select compliance template
// Each branch returns {block: <template>, name: "<templateName>"}
let selected =
// --- AMRS ---
if region == "AMRS" then {block: nxosPatternAMRS_AAA, name: "nxosPatternAMRS_AAA"}
// --- APAC ---
else if region == "APAC" then {block: nxosPatternAPAC_AAA, name: "nxosPatternAPAC_AAA"}
// --- China ---
else if region == "China" then {block: nxosPatternChina_AAA, name: "nxosPatternChina_AAA"}
// --- EMEA ---
else if region == "EMEA" then {block: nxosPatternEMEA_AAA, name: "nxosPatternEMEA_AAA"}
// --- Default / Investigate ---
else {block: nxosPatternDefault, name: "Investigate"}

let nxosPattern = selected.block
let patternName = selected.name

// STEP 2: Build valid lines from template
let patternStr = replace(toString(nxosPattern), "```", "")
let patternGroupStr = join("", foreach grpMatch in regexMatches(patternStr, nxosAaaGroupBlock) select grpMatch.string)

let validLines =
(foreach r in regexMatches(patternStr, nxosAaaPattern) select trimLine(r.string)) +
(foreach r in regexMatches(patternGroupStr, nxosAaaGroupMembers) select trimLine(r.string))

// Normalize {string} placeholders in source-interface lines
let normalizedValid =
(foreach line in validLines
select if length(regexMatches(line, re`\nsource-interface \{string\}`)) > 0
then "\nsource-interface"
else replace(line, " {string}", ""))

// STEP 3: Run blockDiff
let blockDiffResult = blockDiff(device.files.config, nxosPattern)

// STEP 4: Extract actual AAA lines from device config
let deviceGroupStr = join("", foreach devGrpMatch in regexMatches(configAsString, nxosAaaGroupBlock) select devGrpMatch.string)

let configuredLines =
(foreach r in regexMatches(configAsString, nxosAaaPattern) select trimLine(r.string)) +
(foreach r in regexMatches(deviceGroupStr, nxosAaaGroupMembers) select trimLine(r.string))

let normalizedConfigured =
(foreach line in configuredLines
select if length(regexMatches(line, re`\nsource-interface [^\n]+`)) > 0
then "\nsource-interface"
else line)

// STEP 5: Extra = lines on device not in template
let extraLines = normalizedConfigured - normalizedValid

// STEP 6: Ordered config extraction for display
let aaaConfigStr =
join("", foreach r in regexMatches(configAsString, nxosAaaCombinedPattern)
select r.string)

select {
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0 then "Fail" else "Pass",
device: device.name,
ip: ip,
OS: device.platform.osVersion,
model: device.platform.model,
pattern: patternName,
missing: if blockDiffResult.diffCount == 0
then "None"
else toString(blockDiffResult.blocks),
extra: if length(extraLines) == 0
then "None"
else join("\n", foreach line in extraLines
select replace(line, "\n", "")),
AAA_Config: if aaaConfigStr == ""
then "None"
else aaaConfigStr,
region: region,
vrf: vrf,
mgmtSource: mgmtSource,
environment: environment,
SubEnv: subDc,
function: deviceFunc,
manager: manager,
tags: device.tagNames,
};

export nxos_aaa_compliance = main();

main()

 

 

 IOS-XE NQE for AAA

/***
* @intent AAA Validation (IOS-XE)
* @description Validates Cisco IOS-XE AAA authentication/authorization/accounting config.
***/

import "PROD/Standards_Network/NetworkVars/tag_var_util";

// =============================================================================
// SECTION 1 — HELPER FUNCTIONS
// =============================================================================

flatten(outer) =
foreach list in outer
foreach item in list
select item;

getAAATextBlock(parsedConfig) =
flatten(foreach line in parsedConfig
where matches(line.text, "aaa [ag]*")
select [line.text] +
flatten(foreach child in line.children
select [" " + child.text] +
(foreach child2 in child.children
select " " + child2.text)));

// =============================================================================
// SECTION 2 — COMPLIANCE PATTERNS (AAA lines only)
// =============================================================================

IosDiffPatternDummy = ```
Investigate_Device
```;

// --- AMRS ---
IosDiffPatternAMRS_Switch_AAA = ```
aaa group server tacacs+ vty
server name dc02gmcisepn01
server name dc01gmcisepn01
ip tacacs source-interface Loopback0
aaa authentication login vty group standard local
aaa authentication dot1x default group ise
aaa authorization console
aaa authorization config-commands
aaa authorization exec default group standard local
aaa authorization commands 15 default group standard local
aaa authorization network default group ise
aaa authorization network dnac-cts-list group ise
aaa accounting update newinfo periodic 480
aaa accounting identity default start-stop group ise
aaa accounting exec default start-stop group standard
aaa accounting commands 15 default start-stop group standard
aaa accounting system default start-stop group standard
```;

// --- EMEA ---
IosDiffPatternEmeaLan_AAA = ```
aaa group server tacacs+ tac1
server name TIN1
server name BCN1
aaa authentication login default group standard local
aaa authentication login console local
aaa authorization config-commands
aaa authorization exec default group standard local
aaa authorization commands 1 default group standard local
aaa authorization commands 15 default group standard local
aaa accounting exec default start-stop group standard
aaa accounting commands 1 default stop-only group standard
aaa accounting commands 15 default start-stop group standard
aaa accounting system default start-stop group standard
```;

// --- APAC ---
IosDiffPatternApacLan_AAA = ```
aaa group server tacacs+ vty
server name pum1gmcisepn01
server name hyd1gmcisepn01
ip tacacs source-interface Loopback0
aaa authentication login vty group standard local
aaa authorization config-commands
aaa authorization exec default group standard local
aaa authorization commands 15 default group standard local
aaa accounting update newinfo periodic 480
aaa accounting exec default start-stop group standard
aaa accounting commands 15 default start-stop group standard
```;

// =============================================================================
// SECTION 3 — MAIN LOGIC
// =============================================================================

main =
foreach device in network.devices
where device.platform.os == OS.IOS_XE
where device.name == device.system.physicalName

// STEP 1: Collect tag-based metadata
let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let subDc = get_SubDc_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp // STEP 2: Select compliance template
// Each branch returns {block: <template>, name: "<templateName>"}
let selected =
// --- AMRS ---
if region == "AMRS" then {block: IosDiffPatternAMRS_Switch_AAA, name: "IosDiffPatternAMRS_Switch_AAA"}
// --- EMEA ---
else if region == "EMEA" then {block: IosDiffPatternEmeaLan_AAA, name: "IosDiffPatternEmeaLan_AAA"}
// --- APAC ---
else if region == "APAC" then {block: IosDiffPatternApacLan_AAA, name: "IosDiffPatternApacLan_AAA"}
// --- Default / Investigate ---
else {block: IosDiffPatternDummy, name: "Investigate"}

let IosDiffPattern = selected.block
let patternName = selected.name

// STEP 3: Run blockDiff and extract lines
let blockDiffResult = blockDiff(device.files.config, IosDiffPattern)
let patternText = replace(toString(IosDiffPattern), "```", "")
let patternAsConfig = parseConfigBlocks(OS.OTHER, patternText)
let validLines = getAAATextBlock(patternAsConfig)
let configuredLines = getAAATextBlock(device.files.config)
let extraLines = configuredLines - validLines

select {
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0 then "Fail" else "Pass",
device: device.name,
ip: ip,
auth: auth,
OS: device.platform.osVersion,
model: device.platform.model,
pattern: patternName,
missing: if blockDiffResult.diffCount == 0
then "None"
else toString(blockDiffResult.blocks),
extra: if length(extraLines) == 0
then "None"
else join("\n", extraLines),
AAA_Config: if length(configuredLines) == 0
then "None"
else join("\n", configuredLines),
region: region,
vrf: vrf,
mgmtSource: mgmtSource,
environment: environment,
SubEnv: subDc,
function: deviceFunc,
manager: manager,
};

export ios_aaa_compliance = main();

main()

Arista  NQE for AAA

/***
* @intent AAA Validation (EOS)
* @description Validates Arista EOS AAA authentication/authorization/accounting config.
***/

import "PROD/Standards_Network/NetworkVars/tag_var_util";

// =============================================================================
// SECTION 1 — HELPER FUNCTIONS
// =============================================================================

getConfigAsString(device) =
max(foreach command in device.outputs.commands
where command.commandType == CommandType.CONFIG
select command.response);

// =============================================================================
// SECTION 2 — COMPLIANCE PATTERNS (AAA lines only)
// =============================================================================

patternDefault = ```
Investigate
```;

patternAAA_Standard = ```
aaa authentication login default group tacacs+ local
aaa authentication enable default group tacacs+ local
aaa authorization exec default group tacacs+ local
aaa authorization commands all default group tacacs+ local
aaa accounting exec default start-stop group tacacs+
aaa accounting commands all default start-stop group tacacs+
```;

// All AMRS patterns share the same AAA lines — one pattern covers all variants
patternAAA_AMRS = ```
aaa authentication login default group tacacs+ local
aaa authentication enable default group tacacs+ local
aaa authorization exec default group tacacs+ local
aaa authorization commands all default group tacacs+ local
aaa accounting exec default start-stop group tacacs+
aaa accounting commands all default start-stop group tacacs+
```;

// =============================================================================
// SECTION 3 — REGEX PATTERNS
// =============================================================================

eosAaaPattern = re`\naaa a[^\n]*`;

// =============================================================================
// SECTION 4 — MAIN LOGIC
// =============================================================================

main =
foreach device in network.devices
where device.platform.os == OS.ARISTA_EOS
where device.name == device.system.physicalName

// STEP 1: Get config as String
let configResponse = getConfigAsString(device)
let configAsString = if isPresent(configResponse) then configResponse else ""

// STEP 2: Collect tag-based metadata
let region = get_region_from_tags(device.tagNames)
let deviceFunc = get_function_from_tags(device.tagNames)
let environment = get_env_from_tags(device.tagNames)
let vrf = return_vrf_from_tags(device.tagNames)
let manager = get_mgr_from_tags(device.tagNames)
let subDc = get_SubDc_from_tags(device.tagNames)
let mgmtSource = return_mgmt_from_tags(device.tagNames)
let auth = get_auth_from_tags(device.tagNames)
let ip = device.snapshotInfo.collectionIp

// STEP 3: Select compliance template
// All AMRS variants share the same AAA lines so one pattern covers all
// Each branch returns {block: <template>, name: "<templateName>"}
let selected =
if region == "AMRS" then {block: patternAAA_AMRS, name: "patternAAA_AMRS"}
else {block: patternDefault, name: "Investigate"}

let pattern = selected.block
let patternName = selected.name

// STEP 4: Extract valid AAA lines from the selected template
let patternStr = replace(toString(pattern), "```", "")
let validLines =
(foreach r in regexMatches(patternStr, eosAaaPattern) select r.string)

// STEP 5: Run blockDiff against selected pattern
let blockDiffResult = blockDiff(device.files.config, pattern)

// STEP 6: Extract actual AAA lines from device config
let configuredLines =
(foreach r in regexMatches(configAsString, eosAaaPattern) select r.string)

// STEP 7: Extra = lines on device not in the selected template
let extraLines = configuredLines - validLines

// STEP 8: Build display column
let allAaaLines =
(foreach r in regexMatches(configAsString, eosAaaPattern)
select replace(r.string, "\n", ""))

select {
violation: if blockDiffResult.diffCount > 0 || length(extraLines) > 0 then "Fail" else "Pass",
device: device.name,
ip: ip,
auth: auth,
OS: device.platform.osVersion,
model: device.platform.model,
pattern: patternName,
missing: if blockDiffResult.diffCount == 0
then "None"
else toString(blockDiffResult.blocks),
extra: if length(extraLines) == 0
then "None"
else join("\n", order(foreach line in extraLines
select replace(line, "\n", ""))),
AAA_Config: if length(allAaaLines) == 0
then "None"
else join("\n", order(allAaaLines)),
region: region,
vrf: vrf,
mgmtSource: mgmtSource,
environment: environment,
SubEnv: subDc,
function: deviceFunc,
manager: manager,
};

export eos_aaa_compliance = main();

main()