Skip to content

Commit

Permalink
feat(anta.tests): Added testcase to verify IPv4 ACL sequence entries (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
MaheshGSLAB committed Feb 23, 2024
1 parent 447ee19 commit 7d2a3c7
Show file tree
Hide file tree
Showing 3 changed files with 315 additions and 7 deletions.
81 changes: 77 additions & 4 deletions anta/tests/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@
from datetime import datetime
from typing import List, Union

from pydantic import BaseModel, conint, model_validator
from pydantic import BaseModel, Field, conint, model_validator

from anta.custom_types import EcdsaKeySize, EncryptionAlgorithm, RsaKeySize
from anta.models import AntaCommand, AntaTest
from anta.models import AntaCommand, AntaTemplate, AntaTest
from anta.tools.get_item import get_item
from anta.tools.get_value import get_value
from anta.tools.utils import get_failed_logs

Expand Down Expand Up @@ -381,7 +382,8 @@ def test(self) -> None:

class VerifyBannerLogin(AntaTest):
"""
This class verifies the login banner of a device.
Verifies the login banner of a device.
Expected results:
* success: The test will pass if the login banner matches the provided input.
* failure: The test will fail if the login banner does not match the provided input.
Expand Down Expand Up @@ -412,7 +414,8 @@ def test(self) -> None:

class VerifyBannerMotd(AntaTest):
"""
This class verifies the motd banner of a device.
Verifies the motd banner of a device.
Expected results:
* success: The test will pass if the motd banner matches the provided input.
* failure: The test will fail if the motd banner does not match the provided input.
Expand All @@ -439,3 +442,73 @@ def test(self) -> None:
self.result.is_failure(f"Expected `{cleaned_banner}` as the motd banner, but found `{motd_banner}` instead.")
else:
self.result.is_success()


class VerifyIPv4ACL(AntaTest):
"""
Verifies the configuration of IPv4 ACLs.
Expected results:
* success: The test will pass if an IPv4 ACL is configured with the correct sequence entries.
* failure: The test will fail if an IPv4 ACL is not configured or entries are not in sequence.
"""

name = "VerifyIPv4ACL"
description = "Verifies the configuration of IPv4 ACLs."
categories = ["security"]
commands = [AntaTemplate(template="show ip access-lists {acl}")]

class Input(AntaTest.Input):
"""Inputs for the VerifyIPv4ACL test."""

ipv4_access_lists: List[IPv4ACL]
"""List of IPv4 ACLs to verify"""

class IPv4ACL(BaseModel):
"""Detail of IPv4 ACL"""

name: str
"""Name of IPv4 ACL"""

entries: List[IPv4ACLEntries]
"""List of IPv4 ACL entries"""

class IPv4ACLEntries(BaseModel):
"""IPv4 ACL entries details"""

sequence: int = Field(ge=1, le=4294967295)
"""Sequence number of an ACL entry"""
action: str
"""Action of an ACL entry"""

def render(self, template: AntaTemplate) -> list[AntaCommand]:
return [template.render(acl=acl.name, entries=acl.entries) for acl in self.inputs.ipv4_access_lists]

@AntaTest.anta_test
def test(self) -> None:
self.result.is_success()
for command_output in self.instance_commands:
# Collecting input ACL details
acl_name = command_output.params["acl"]
acl_entries = command_output.params["entries"]

# Check if ACL is configured
ipv4_acl_list = command_output.json_output["aclList"]
if not ipv4_acl_list:
self.result.is_failure(f"{acl_name}: Not found")
continue

# Check if the sequence number is configured and has the correct action applied
failed_log = f"{acl_name}:\n"
for acl_entry in acl_entries:
acl_seq = acl_entry.sequence
acl_action = acl_entry.action
if (actual_entry := get_item(ipv4_acl_list[0]["sequence"], "sequenceNumber", acl_seq)) is None:
failed_log += f"Sequence number `{acl_seq}` is not found.\n"
continue

if actual_entry["text"] != acl_action:
failed_log += f"Expected `{acl_action}` as sequence number {acl_seq} action but found `{actual_entry['text']}` instead.\n"

if failed_log != f"{acl_name}:\n":
self.result.is_failure(f"{failed_log}")
21 changes: 18 additions & 3 deletions examples/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,6 @@ anta.tests.security:
common_name: Arista Networks Internal IT Root Cert Authority
encryption_algorithm: RSA
key_size: 4096

anta.tests.services:
- VerifyBannerLogin:
login_banner: |
# Copyright (c) 2023-2024 Arista Networks, Inc.
Expand All @@ -241,6 +239,24 @@ anta.tests.services:
# Copyright (c) 2023-2024 Arista Networks, Inc.
# Use of this source code is governed by the Apache License 2.0
# that can be found in the LICENSE file.
- VerifyIPv4ACL:
ipv4_access_lists:
- name: default-control-plane-acl
entries:
- sequence: 10
action: permit icmp any any
- sequence: 20
action: permit ip any any tracked
- sequence: 30
action: permit udp any any eq bfd ttl eq 255
- name: LabTest
entries:
- sequence: 10
action: permit icmp any any
- sequence: 20
action: permit tcp any any range 5900 5910

anta.tests.services:
- VerifyHostname:
hostname: s1-spine1
- VerifyDNSLookup:
Expand Down Expand Up @@ -345,7 +361,6 @@ anta.tests.routing:
- VerifyRoutingTableSize:
minimum: 2
maximum: 20
- VerifyBFD:
- VerifyRoutingTableEntry:
vrf: default
routes:
Expand Down
220 changes: 220 additions & 0 deletions tests/units/anta_tests/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
VerifyAPISSLCertificate,
VerifyBannerLogin,
VerifyBannerMotd,
VerifyIPv4ACL,
VerifySSHIPv4Acl,
VerifySSHIPv6Acl,
VerifySSHStatus,
Expand Down Expand Up @@ -677,4 +678,223 @@
],
},
},
{
"name": "success",
"test": VerifyIPv4ACL,
"eos_data": [
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit ip any any tracked", "sequenceNumber": 20},
{"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30},
],
}
]
},
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit tcp any any range 5900 5910", "sequenceNumber": 20},
],
}
]
},
],
"inputs": {
"ipv4_access_lists": [
{
"name": "default-control-plane-acl",
"entries": [
{"sequence": 10, "action": "permit icmp any any"},
{"sequence": 20, "action": "permit ip any any tracked"},
{"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
],
},
{
"name": "LabTest",
"entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
},
]
},
"expected": {"result": "success"},
},
{
"name": "failure-acl-not-found",
"test": VerifyIPv4ACL,
"eos_data": [
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit ip any any tracked", "sequenceNumber": 20},
{"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 30},
],
}
]
},
{"aclList": []},
],
"inputs": {
"ipv4_access_lists": [
{
"name": "default-control-plane-acl",
"entries": [
{"sequence": 10, "action": "permit icmp any any"},
{"sequence": 20, "action": "permit ip any any tracked"},
{"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
],
},
{
"name": "LabTest",
"entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
},
]
},
"expected": {"result": "failure", "messages": ["LabTest: Not found"]},
},
{
"name": "failure-sequence-not-found",
"test": VerifyIPv4ACL,
"eos_data": [
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit ip any any tracked", "sequenceNumber": 20},
{"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 40},
],
}
]
},
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
],
}
]
},
],
"inputs": {
"ipv4_access_lists": [
{
"name": "default-control-plane-acl",
"entries": [
{"sequence": 10, "action": "permit icmp any any"},
{"sequence": 20, "action": "permit ip any any tracked"},
{"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
],
},
{
"name": "LabTest",
"entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
},
]
},
"expected": {
"result": "failure",
"messages": ["default-control-plane-acl:\nSequence number `30` is not found.\n", "LabTest:\nSequence number `20` is not found.\n"],
},
},
{
"name": "failure-action-not-match",
"test": VerifyIPv4ACL,
"eos_data": [
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit ip any any tracked", "sequenceNumber": 20},
{"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
],
}
]
},
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit udp any any eq bfd ttl eq 255", "sequenceNumber": 20},
],
}
]
},
],
"inputs": {
"ipv4_access_lists": [
{
"name": "default-control-plane-acl",
"entries": [
{"sequence": 10, "action": "permit icmp any any"},
{"sequence": 20, "action": "permit ip any any tracked"},
{"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
],
},
{
"name": "LabTest",
"entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
},
]
},
"expected": {
"result": "failure",
"messages": [
"default-control-plane-acl:\n"
"Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n",
"LabTest:\nExpected `permit tcp any any range 5900 5910` as sequence number 20 action but found `permit udp any any eq bfd ttl eq 255` instead.\n",
],
},
},
{
"name": "failure-all-type",
"test": VerifyIPv4ACL,
"eos_data": [
{
"aclList": [
{
"sequence": [
{"text": "permit icmp any any", "sequenceNumber": 10},
{"text": "permit ip any any tracked", "sequenceNumber": 40},
{"text": "permit tcp any any range 5900 5910", "sequenceNumber": 30},
],
}
]
},
{"aclList": []},
],
"inputs": {
"ipv4_access_lists": [
{
"name": "default-control-plane-acl",
"entries": [
{"sequence": 10, "action": "permit icmp any any"},
{"sequence": 20, "action": "permit ip any any tracked"},
{"sequence": 30, "action": "permit udp any any eq bfd ttl eq 255"},
],
},
{
"name": "LabTest",
"entries": [{"sequence": 10, "action": "permit icmp any any"}, {"sequence": 20, "action": "permit tcp any any range 5900 5910"}],
},
]
},
"expected": {
"result": "failure",
"messages": [
"default-control-plane-acl:\nSequence number `20` is not found.\n"
"Expected `permit udp any any eq bfd ttl eq 255` as sequence number 30 action but found `permit tcp any any range 5900 5910` instead.\n",
"LabTest: Not found",
],
},
},
]

0 comments on commit 7d2a3c7

Please sign in to comment.