Merged PR 290: #2356: optional dmz port + optional external acl rules
## Summary Bug fix to allow firewall dmz port to be optional as well as external acl rules to be optional ## Test process See https://dev.azure.com/ma-dev-uk/PrimAITE/_git/PrimAITE/pullrequest/290?_a=files&path=/tests/integration_tests/configuration_file_parsing/nodes/network/test_firewall_config.py ## Checklist - [X] PR is linked to a **work item** - [X] **acceptance criteria** of linked ticket are met - [X] performed **self-review** of the code - [X] written **tests** for any new functionality added with this PR - [ ] updated the **documentation** if this PR changes or adds functionality - [ ] written/updated **design docs** if this PR implements new functionality - [ ] updated the **change log** - [X] ran **pre-commit** checks for code style - [ ] attended to any **TO-DOs** left in the code #2356: optional dmz port + optional external acl rules Related work items: #2356
This commit is contained in:
@@ -500,7 +500,7 @@ class Firewall(Router):
|
|||||||
if "ports" in cfg:
|
if "ports" in cfg:
|
||||||
internal_port = cfg["ports"]["internal_port"]
|
internal_port = cfg["ports"]["internal_port"]
|
||||||
external_port = cfg["ports"]["external_port"]
|
external_port = cfg["ports"]["external_port"]
|
||||||
dmz_port = cfg["ports"]["dmz_port"]
|
dmz_port = cfg["ports"].get("dmz_port")
|
||||||
|
|
||||||
# configure internal port
|
# configure internal port
|
||||||
firewall.configure_internal_port(
|
firewall.configure_internal_port(
|
||||||
@@ -514,11 +514,12 @@ class Firewall(Router):
|
|||||||
subnet_mask=IPV4Address(external_port.get("subnet_mask", "255.255.255.0")),
|
subnet_mask=IPV4Address(external_port.get("subnet_mask", "255.255.255.0")),
|
||||||
)
|
)
|
||||||
|
|
||||||
# configure dmz port
|
# configure dmz port if not none
|
||||||
firewall.configure_dmz_port(
|
if dmz_port is not None:
|
||||||
ip_address=IPV4Address(dmz_port.get("ip_address")),
|
firewall.configure_dmz_port(
|
||||||
subnet_mask=IPV4Address(dmz_port.get("subnet_mask", "255.255.255.0")),
|
ip_address=IPV4Address(dmz_port.get("ip_address")),
|
||||||
)
|
subnet_mask=IPV4Address(dmz_port.get("subnet_mask", "255.255.255.0")),
|
||||||
|
)
|
||||||
if "acl" in cfg:
|
if "acl" in cfg:
|
||||||
# acl rules for internal_inbound_acl
|
# acl rules for internal_inbound_acl
|
||||||
if cfg["acl"]["internal_inbound_acl"]:
|
if cfg["acl"]["internal_inbound_acl"]:
|
||||||
@@ -573,7 +574,7 @@ class Firewall(Router):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# acl rules for external_inbound_acl
|
# acl rules for external_inbound_acl
|
||||||
if cfg["acl"]["external_inbound_acl"]:
|
if cfg["acl"].get("external_inbound_acl"):
|
||||||
for r_num, r_cfg in cfg["acl"]["external_inbound_acl"].items():
|
for r_num, r_cfg in cfg["acl"]["external_inbound_acl"].items():
|
||||||
firewall.external_inbound_acl.add_rule(
|
firewall.external_inbound_acl.add_rule(
|
||||||
action=ACLAction[r_cfg["action"]],
|
action=ACLAction[r_cfg["action"]],
|
||||||
@@ -586,7 +587,7 @@ class Firewall(Router):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# acl rules for external_outbound_acl
|
# acl rules for external_outbound_acl
|
||||||
if cfg["acl"]["external_outbound_acl"]:
|
if cfg["acl"].get("external_outbound_acl"):
|
||||||
for r_num, r_cfg in cfg["acl"]["external_outbound_acl"].items():
|
for r_num, r_cfg in cfg["acl"]["external_outbound_acl"].items():
|
||||||
firewall.external_outbound_acl.add_rule(
|
firewall.external_outbound_acl.add_rule(
|
||||||
action=ACLAction[r_cfg["action"]],
|
action=ACLAction[r_cfg["action"]],
|
||||||
|
|||||||
174
tests/assets/configs/basic_firewall.yaml
Normal file
174
tests/assets/configs/basic_firewall.yaml
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# Basic Switched network
|
||||||
|
#
|
||||||
|
# -------------- -------------- --------------
|
||||||
|
# | client_1 |------| switch_1 |------| client_2 |
|
||||||
|
# -------------- -------------- --------------
|
||||||
|
#
|
||||||
|
|
||||||
|
training_config:
|
||||||
|
rl_framework: SB3
|
||||||
|
rl_algorithm: PPO
|
||||||
|
seed: 333
|
||||||
|
n_learn_episodes: 1
|
||||||
|
n_eval_episodes: 5
|
||||||
|
max_steps_per_episode: 128
|
||||||
|
deterministic_eval: false
|
||||||
|
n_agents: 1
|
||||||
|
agent_references:
|
||||||
|
- defender
|
||||||
|
|
||||||
|
io_settings:
|
||||||
|
save_checkpoints: true
|
||||||
|
checkpoint_interval: 5
|
||||||
|
save_step_metadata: false
|
||||||
|
save_pcap_logs: true
|
||||||
|
save_sys_logs: true
|
||||||
|
|
||||||
|
|
||||||
|
game:
|
||||||
|
max_episode_length: 256
|
||||||
|
ports:
|
||||||
|
- ARP
|
||||||
|
- DNS
|
||||||
|
- HTTP
|
||||||
|
- POSTGRES_SERVER
|
||||||
|
protocols:
|
||||||
|
- ICMP
|
||||||
|
- TCP
|
||||||
|
- UDP
|
||||||
|
|
||||||
|
agents:
|
||||||
|
- ref: client_2_green_user
|
||||||
|
team: GREEN
|
||||||
|
type: GreenWebBrowsingAgent
|
||||||
|
observation_space:
|
||||||
|
type: UC2GreenObservation
|
||||||
|
action_space:
|
||||||
|
action_list:
|
||||||
|
- type: DONOTHING
|
||||||
|
- type: NODE_APPLICATION_EXECUTE
|
||||||
|
options:
|
||||||
|
nodes:
|
||||||
|
- node_name: client_2
|
||||||
|
applications:
|
||||||
|
- application_name: WebBrowser
|
||||||
|
max_folders_per_node: 1
|
||||||
|
max_files_per_folder: 1
|
||||||
|
max_services_per_node: 1
|
||||||
|
max_applications_per_node: 1
|
||||||
|
|
||||||
|
reward_function:
|
||||||
|
reward_components:
|
||||||
|
- type: DUMMY
|
||||||
|
|
||||||
|
agent_settings:
|
||||||
|
start_settings:
|
||||||
|
start_step: 5
|
||||||
|
frequency: 4
|
||||||
|
variance: 3
|
||||||
|
|
||||||
|
simulation:
|
||||||
|
network:
|
||||||
|
nodes:
|
||||||
|
|
||||||
|
- ref: firewall
|
||||||
|
type: firewall
|
||||||
|
hostname: firewall
|
||||||
|
start_up_duration: 0
|
||||||
|
shut_down_duration: 0
|
||||||
|
ports:
|
||||||
|
external_port: # port 1
|
||||||
|
ip_address: 192.168.20.1
|
||||||
|
subnet_mask: 255.255.255.0
|
||||||
|
internal_port: # port 2
|
||||||
|
ip_address: 192.168.1.2
|
||||||
|
subnet_mask: 255.255.255.0
|
||||||
|
acl:
|
||||||
|
internal_inbound_acl:
|
||||||
|
21:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: TCP
|
||||||
|
22:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: UDP
|
||||||
|
23:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: ICMP
|
||||||
|
internal_outbound_acl:
|
||||||
|
21:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: TCP
|
||||||
|
22:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: UDP
|
||||||
|
23:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: ICMP
|
||||||
|
dmz_inbound_acl:
|
||||||
|
21:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: TCP
|
||||||
|
22:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: UDP
|
||||||
|
23:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: ICMP
|
||||||
|
dmz_outbound_acl:
|
||||||
|
21:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: TCP
|
||||||
|
22:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: UDP
|
||||||
|
23:
|
||||||
|
action: PERMIT
|
||||||
|
protocol: ICMP
|
||||||
|
|
||||||
|
- ref: switch_1
|
||||||
|
type: switch
|
||||||
|
hostname: switch_1
|
||||||
|
num_ports: 8
|
||||||
|
- ref: switch_2
|
||||||
|
type: switch
|
||||||
|
hostname: switch_2
|
||||||
|
num_ports: 8
|
||||||
|
|
||||||
|
- ref: client_1
|
||||||
|
type: computer
|
||||||
|
hostname: client_1
|
||||||
|
ip_address: 192.168.10.21
|
||||||
|
subnet_mask: 255.255.255.0
|
||||||
|
default_gateway: 192.168.10.1
|
||||||
|
dns_server: 192.168.1.10
|
||||||
|
# pre installed services and applications
|
||||||
|
- ref: client_2
|
||||||
|
type: computer
|
||||||
|
hostname: client_2
|
||||||
|
ip_address: 192.168.10.22
|
||||||
|
subnet_mask: 255.255.255.0
|
||||||
|
default_gateway: 192.168.10.1
|
||||||
|
dns_server: 192.168.1.10
|
||||||
|
# pre installed services and applications
|
||||||
|
|
||||||
|
links:
|
||||||
|
- ref: switch_1___client_1
|
||||||
|
endpoint_a_ref: switch_1
|
||||||
|
endpoint_a_port: 1
|
||||||
|
endpoint_b_ref: client_1
|
||||||
|
endpoint_b_port: 1
|
||||||
|
- ref: switch_2___client_2
|
||||||
|
endpoint_a_ref: switch_2
|
||||||
|
endpoint_a_port: 1
|
||||||
|
endpoint_b_ref: client_2
|
||||||
|
endpoint_b_port: 1
|
||||||
|
- ref: switch_1___firewall
|
||||||
|
endpoint_a_ref: switch_1
|
||||||
|
endpoint_a_port: 2
|
||||||
|
endpoint_b_ref: firewall
|
||||||
|
endpoint_b_port: 1
|
||||||
|
- ref: switch_2___firewall
|
||||||
|
endpoint_a_ref: switch_2
|
||||||
|
endpoint_a_port: 2
|
||||||
|
endpoint_b_ref: firewall
|
||||||
|
endpoint_b_port: 2
|
||||||
@@ -10,6 +10,8 @@ BASIC_CONFIG = TEST_ASSETS_ROOT / "configs/basic_switched_network.yaml"
|
|||||||
|
|
||||||
DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml"
|
DMZ_NETWORK = TEST_ASSETS_ROOT / "configs/dmz_network.yaml"
|
||||||
|
|
||||||
|
BASIC_FIREWALL = TEST_ASSETS_ROOT / "configs/basic_firewall.yaml"
|
||||||
|
|
||||||
|
|
||||||
def load_config(config_path: Union[str, Path]) -> PrimaiteGame:
|
def load_config(config_path: Union[str, Path]) -> PrimaiteGame:
|
||||||
"""Returns a PrimaiteGame object which loads the contents of a given yaml path."""
|
"""Returns a PrimaiteGame object which loads the contents of a given yaml path."""
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from ipaddress import IPv4Address
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from primaite.simulator.network.container import Network
|
from primaite.simulator.network.container import Network
|
||||||
@@ -8,7 +10,7 @@ from primaite.simulator.network.hardware.nodes.network.firewall import Firewall
|
|||||||
from primaite.simulator.network.hardware.nodes.network.router import ACLAction
|
from primaite.simulator.network.hardware.nodes.network.router import ACLAction
|
||||||
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
from primaite.simulator.network.transmission.network_layer import IPProtocol
|
||||||
from primaite.simulator.network.transmission.transport_layer import Port
|
from primaite.simulator.network.transmission.transport_layer import Port
|
||||||
from tests.integration_tests.configuration_file_parsing import DMZ_NETWORK, load_config
|
from tests.integration_tests.configuration_file_parsing import BASIC_FIREWALL, DMZ_NETWORK, load_config
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="function")
|
@pytest.fixture(scope="function")
|
||||||
@@ -17,6 +19,12 @@ def dmz_config() -> Network:
|
|||||||
return game.simulation.network
|
return game.simulation.network
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def basic_firewall_config() -> Network:
|
||||||
|
game = load_config(BASIC_FIREWALL)
|
||||||
|
return game.simulation.network
|
||||||
|
|
||||||
|
|
||||||
def test_firewall_is_in_configuration(dmz_config):
|
def test_firewall_is_in_configuration(dmz_config):
|
||||||
"""Test that the firewall exists in the configuration file."""
|
"""Test that the firewall exists in the configuration file."""
|
||||||
network: Network = dmz_config
|
network: Network = dmz_config
|
||||||
@@ -109,3 +117,19 @@ def test_firewall_acl_rules_correctly_added(dmz_config):
|
|||||||
# external_outbound should have implicit action PERMIT
|
# external_outbound should have implicit action PERMIT
|
||||||
# ICMP does not have a provided ACL Rule but implicit action should allow anything
|
# ICMP does not have a provided ACL Rule but implicit action should allow anything
|
||||||
assert firewall.external_outbound_acl.implicit_action == ACLAction.PERMIT
|
assert firewall.external_outbound_acl.implicit_action == ACLAction.PERMIT
|
||||||
|
|
||||||
|
|
||||||
|
def test_firewall_with_no_dmz_port(basic_firewall_config):
|
||||||
|
"""
|
||||||
|
Test to check that:
|
||||||
|
- the DMZ port can be ignored i.e. is optional.
|
||||||
|
- the external_outbound_acl and external_inbound_acl are optional
|
||||||
|
"""
|
||||||
|
network: Network = basic_firewall_config
|
||||||
|
|
||||||
|
firewall: Firewall = network.get_node_by_hostname("firewall")
|
||||||
|
|
||||||
|
assert firewall.dmz_port.ip_address == IPv4Address("127.0.0.1")
|
||||||
|
|
||||||
|
assert firewall.external_outbound_acl.num_rules == 0
|
||||||
|
assert firewall.external_inbound_acl.num_rules == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user