Skip to main content
Intermediate

Check for Unused Firewall Rules (and Catch New Ones Too)

  • May 30, 2025
  • 0 replies
  • 20 views
  • Translate
Check for Unused Firewall Rules (and Catch New Ones Too)
rob
Employee
  • Employee
  • 2 replies

This NQE script helps you spot firewall rules that haven’t processed traffic lately. It flags rules as unused if they haven’t processed any packets in the last 30 days—but only on active firewalls (not ones in BACKUP or STANDALONE_INACTIVE modes).

If you have rules that are supposed to be quiet (like for failover scenarios), you can list them in expectedUnusedRules so they don’t show up as false positives.

As a bonus, it also highlights newly created rules—anything added in the last 30 days—so you get visibility into what’s changing as well as what’s sitting idle.

All timing is based on the device’s snapshot collection time.

 

You can also find this script in the Forward NQE Library

Forward Library > Security > Firewalls with Unused Security Rules

/**
 * @intent Verifies that active firewalls have no unused security rules
 * @description This query considers a rule to be unused if it last processed 
 * a packet more than 30 days ago. This query only applies this check to 
 * firewalls that are not in BACKUP or STANDALONE_INACTIVE HA operation modes.
 * To avoid flagging rules that are designed to be used infrequently 
 * (for example, because it is provisioned for a failover scenario), add the 
 * name of the rule to the expectedUnusedRules list.
 * 
 * This query also shows recently-added rules, which are rules that were 
 * created within the last 30 days. 
 * 
 * All time durations are measured relative to the snapshot collection
 * time of the device.
 */

activeModes = [HaOperationMode.BACKUP, HaOperationMode.STANDALONE_INACTIVE];

@query
query(expectedUnusedRules: List<String>) =
  foreach device in network.devices
  where device.platform.deviceType == DeviceType.FIREWALL
  where device.ha.clusterHa?.operationMode not in activeModes
  let now = if isPresent(device.snapshotInfo.collectionTime)
            then device.snapshotInfo.collectionTime
            else device.snapshotInfo.backfillTime
  // Note that `distinct` is used because currently a single
  // firewall rule may be modelled as several AclEntry records.
  // However, this query should count number of firewall rules.
  let newRules = (foreach aclEntry in device.aclEntries
                  let createdAt = aclEntry.lifecycleData?.createdAt
                  where isPresent(createdAt)
                  where now - createdAt < days(30)
                  select distinct aclEntry.name)
  // Note that `distinct` is used because currently a single
  // firewall rule may be modelled as several AclEntry records.
  // However, this query should count number of firewall rules.
  let unusedRules = (foreach aclEntry in device.aclEntries
                     where aclEntry.name not in expectedUnusedRules
                     let lastUsed = aclEntry.lifecycleData?.lastUsed
                     where isPresent(lastUsed)
                     where now - lastUsed > days(30)
                     select distinct aclEntry.name)
  select {
    violation: length(unusedRules) > 0,
    Device: device.name,
    "HA Mode": device.ha.clusterHa?.operationMode,
    "Count of ACL Entries": length(device.aclEntries),
    "Count of Unused Rules": length(unusedRules),
    "Unused Rules": unusedRules,
    "Count of New Rules": length(newRules),
    "New Rules": newRules,
    OS: device.platform.os,
    Tags: device.tagNames,
    Location: device.locationName
  };

 

Have questions? Ask below!

Did this topic help you find an answer to your question?

0 replies

Be the first to reply!

Reply


Cookie policy

We use cookies to enhance and personalize your experience. If you accept you agree to our full cookie policy. Learn more about our cookies.

 
Cookie settings