Often you need to verify that the configuration of your network matches certain requirements. These could be standard benchmarks, such as CIS benchmarks, or internal benchmarks specific to your environment.
For example, you may need to:
You can verify these settings, or anything else in the configuration, using NQE.
Verify that all Cisco devices have only SSH version 2 enabled
The following query looks for the exact pattern ssh version 2
in the device configuration file (device.files.config
). If the pattern does not exist (!checkpattern
), then the violation will be True
.
pattern =
```
ssh version 2
```;
checkPattern(config) =
hasBlockMatch(config, pattern);
foreach device in network.devices
where device.platform.vendor == Vendor.CISCO
select {
device: device.name,
os: device.platform.os,
violation: !checkPattern(device.files.config),
}
Note that we only perform the check on devices from Vendor.CISCO
. Since all Cisco devices may not use the same syntax, we could limit this query further to only operate on certain Cisco models or OS versions.
Verify that all Palo Alto devices have a login banner set
This is a common verification that also correlates to a CIS benchmark.
The following query verifies that a login banner is set on all Palo Alto devices:
pattern =
```
config
devices
localhost.localdomain
deviceconfig
system
login-banner {banner:(string*)}
```;
checkPattern(config) =
!hasBlockMatch(config, pattern);
foreach device in network.devices
where device.platform.os == OS.PAN_OS
let loginBanner = blockDiff(device.files.config, pattern)
select {
device: device.name,
os: device.platform.os,
violation: checkPattern(device.files.config),
banner: if isPresent(loginBanner.data.banner)
then join(" ", loginBanner.data.banner)
else null : String
}
We use the where
statement to limit the query to devices running PAN OS, since the pattern only applies to those devices.
We define a pattern to search for. Note that the blockDiff
function looks for the pattern in the config file collected from each device (device.files.config
) by matching the lines of config in the pattern against lines in the config at the same level of the hierarchy based on the indentation.
Since the actual login banner is probably a few sentences long, string*
captures all the words as a list and stores them in banner
.
The query will show a violation if there is no pattern match. If the banner exists, the join command will combine the words in banner
together (separated by spaces) so that the actual login banner is listed in the NQE query output.
Verify the mininum password length for Fortinet devices
The following NQE query requires an extra step because the configuration for the password setting is NOT listed in the configuration file that Forward Networks collects by default.
pattern =
```
config system password-policy
set status {sysStat:string}
set minimum-length {passLength:number}
```;
foreach device in network.devices
where device.platform.vendor == Vendor.FORTINET
foreach command in device.outputs.commands
where command.commandText == "show full-configuration"
let parsedCommand = parseConfigBlocks(OS.FORTINET, command.response)
let configDiff = blockDiff(parsedCommand, pattern)
select {
violation: configDiff.data.sysStat != "enable" || configDiff.data.passLength < 10,
device: device.name,
Diff: configDiff.blocks,
length: configDiff.data.length
}
We must first add a custom command to the collection to capture the entire configuration using show full-configuration
Consult the Forward documentation on how to add a custom command to the collection:
https://fwd.app/docs/enterprise/getting_started/configure_collection/devices/custom_commands/
We access the output of the custom command by iterating through the list of commands and matching on the name of the custom command.
Note the name of the custom command in the where
statement must match the custom command exactly. For example, “show full-configuration” would match no data if the custom command used during collection is “sh full-configuration”.
We convert the command.response
string to a configuration blocks object using parseConfigBlocks
.
This allows us to use configDiff
to extract the status of the password-policy (sysStat
) and the minimum password length (passLength
).
The NQE query result will show a violation if the status is anything other than “enable” OR the minimum password length is less than 10 characters.
Combining multiple checks into a single NQE query
Benchmarks often require many checks - dozens or even hundreds. You can streamline the validation of these checks by running multiple checks from a single query.
For example, we could create a table of all the Cisco devices in our network along with PASS/FAIL results for multiple benchmarks. The following article shows how to combine multiple queries into a single query:
Which benchmarks do you need to validate for your organization? Do you take a different approach to benchmarks? Let me know in the comments!