NAME

Net::Firewall::BlockerHelper::backends::azure - Azure NSG backend via the az CLI.

VERSION

Version 0.2.0

SYNOPSIS

use Net::Firewall::BlockerHelper;

my $fw_helper = Net::Firewall::BlockerHelper->new(
    backend => 'azure',
    name    => 'ssh',
    options => {
        resource_group => 'my-rg',
        nsg            => 'my-nsg',
        rule           => 'blocklist',
    },
);

$fw_helper->init_backend;
$fw_helper->ban( ban => '1.2.3.4' );
$fw_helper->unban( ban => '1.2.3.4' );

DESCRIPTION

Blocks IPs on Azure by maintaining the --source-address-prefixes of a single deny rule in a Network Security Group, using the az CLI. The full set of currently banned IPs is rendered into the rule on every change, so ban/unban are idempotent. Both IPv4 and IPv6 share the one rule.

This backend manages only the rule's source prefixes. The NSG, the inbound deny security rule, and the NSG's association with the subnets or NICs to be protected must already exist.

Requires the az CLI in the PATH, logged in with rights to update the rule.

NOTES

This backend was written going off the az CLI docs and actual testing is needed to double check a few things as the exact behavior is not clear.

When the ban list goes empty, as at teardown or flush, the rule update ends up passing --source-address-prefixes with no value, and whether the az CLI accepts that or errors needs checking.

METHODS

new

Initiates the backend object. Nothing is contacted at this point; that is done by "init".

- options :: Backend specific options. See below.
- name :: Required by Net::Firewall::BlockerHelper, otherwise unused.

The options hash accepts the following.

- az_cmd :: Path to the az binary.
    - Default :: az

- resource_group :: Resource group of the NSG. Required.
    - Default :: undef

- nsg :: Network Security Group name. Required.
    - Default :: undef

- rule :: Security rule whose source prefixes are managed. Required.
    - Default :: undef

- subscription :: Optional subscription; appended as --subscription when set.
    - Default :: undef

All errors are considered fatal, meaning if new fails it will die.

init

Initiates the backend, verifying the configured security rule exists via az network nsg rule show. Nothing is created; the NSG and rule must already exist.

ban

Bans an IP. The value of ban is validated as being a IPv4 or IPv6 address and lowercased, then added to the ban list. The full set of banned IPs (rendered as /32 or /128 prefixes) and CIDR ranges is then pushed to the rule via az network nsg rule update --source-address-prefixes. Banning an already banned IP is a noop.

$fw_helper->ban( ban => $ip );

unban

Unbans an IP. The value of ban is validated as being a IPv4 or IPv6 address and lowercased, then removed from the ban list. The rule's source prefixes are re-rendered without it via az network nsg rule update. Unbanning an IP that is not banned is a noop.

$fw_helper->unban( ban => $ip );

ban_cidr

Bans a CIDR range. The value of ban is validated as being a IPv4 or IPv6 CIDR and lowercased, then added verbatim to the rule's source prefixes via az network nsg rule update. Banning an already banned range is a noop.

$fw_helper->ban_cidr( ban => '1.2.3.0/24' );

unban_cidr

Unbans a CIDR range. The value of ban is validated as being a IPv4 or IPv6 CIDR and lowercased, then the rule's source prefixes are re-rendered without it via az network nsg rule update. Unbanning a range that is not banned is a noop.

$fw_helper->unban_cidr( ban => '1.2.3.0/24' );

list_cidr

List banned CIDR ranges.

my @banned_cidrs = $fw_helper->list_cidr;

list

List banned IPs. Returns an array of the currently banned single IPs from the in-memory ban list; the rule is not queried. CIDR ranges are not included; for those see "list_cidr".

my @banned = $fw_helper->list;

re_init

Tears down (errors ignored) and re-initiates the backend, then re-applies the full retained set of banned IPs and CIDR ranges to the rule via az network nsg rule update.

teardown

Empties the rule's source prefixes. The internal ban list is kept so a following re_init restores them.

stop

Alias for "teardown".

check

Verifies the rule still exists by running az network nsg rule show. Returns 1 if the command exits zero and 0 otherwise.

flush

Removes all bans at once by clearing both the single IP and CIDR ban lists and re-rendering the rule's now empty source prefixes via az network nsg rule update.

ERROR CODES / FLAGS

Error handling is provided by Error::Helper. All errors are considered fatal.

1, notInited

The backend has not been inited yet.

8, optionsNotHash

The item passed to new for options is not a hash.

9, noBanItem

No IP or CIDR range specified to ban or unban.

10, banItemNotIP

The item to ban is not an IP. Either wrong ref type or regexp test using Regexp::IPv4 and Regexp::IPv6 failed.

12, backendInitError

Failed to init the backend.

13, banFailed

Failed to ban the item.

14, unbanFailed

Failed to unban the item.

15, listFailed

Failed to get a list of bans.

16, reInitFailed

Failed to re_init the backend.

17, teardownFailed

Failed to teardown the backend.

18, alreadyInited

init called, but the backend has already been inited.

24, checkFailed

The backend check raised an error.

25, flushFailed

Failed to flush the bans.

30, resourceGroupNotDefined

The option resource_group is undef or blank.

31, nsgNotDefined

The option nsg is undef or blank.

32, ruleNotDefined

The option rule is undef or blank.

33, banCidrFailed

Failed to ban the CIDR range.

34, unbanCidrFailed

Failed to unban the CIDR range.

35, cidrItemNotCidr

The item to ban is not a CIDR range. Either wrong ref type or it is not an IPv4 or IPv6 address followed by a prefix length valid for its family.

36, cidrNotSupported

The backend does not support CIDR bans.

37, listCidrFailed

Failed to get a list of CIDR bans.

AUTHOR

Zane C. Bowers-Hadley, <vvelox at vvelox.ent>

LICENSE AND COPYRIGHT

This software is Copyright (c) 2026 by Zane C. Bowers-Hadley.

This is free software, licensed under:

The GNU Lesser General Public License, Version 2.1, February 1999