Skip to content
80 changes: 80 additions & 0 deletions documentation/rework-2025/rulebase-links.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Rulebase Links

## Concept

- each firewall device defines one directed tree for its rulebases
- rulebases are the tree verticies and rulebase links are tree edges
- rulebases contain a (possibly empty) list of rules and a uid/id
- in context of database we use ids, in importer context uids, here we default to ids
- each rulebase tree is rooted, this is defined with the initial rulebase link
- rulebase links have many fields, each is explained in this document

## Rulebase Link Fields

### From and To Rulebase Id

- **from_rulebase_id** and **to_rulebase_id** constitute the directed tree edges
- both fields are not NULL, with one exception, from_rulebase_id is empty for the initial rulebase link
- sometimes rulebases need to be linked from a specific rule (e.g. inline-layer, domain)
- this is done with **from_rule_id**
- from _rule_id is a rule id that is in the from_rulebase_id

### Boolean Flags

- **is_initial** is true, if to_rulebase_id is the first rulebase for the device
- **is_global** is true, if to_rulebase_id belongs to the super manager
- **is_section** is true, if to_rulebase_id gets a section header in reporting
- sections get a section header in reporting and are collapsible

### Types

Each link has a **type** that explains
- how the rulebase tree is traversed by incoming traffic requests
- how the rules report should look like
- how rule numbers are created

#### Ordered

- high level rulebase concept
- ordered rulebases are a chain
- each ordered rulebase needs one accept rule to allow traffic request
- first ordered rulebase gets number 1 and so on
- rules are numbered in dot notation, 2.13 is the 13th rule in the 2nd ordered rulebase
- if only one (initial) ordered rulebase exists the number 1. is ommited for all rules
- each ordered rulebase gets a header that is collapsible in reporting

#### Domain

- from_rulebase_id is a global rulebase, to_rulebase_id is a local rulebase
- from_rule_id is defined and named placeholder rule
- traffic request traverses from_rulebase_id up to and including placeholder rule
- then domain rules are traversed and after that the remaining global rules
- if traffic is droped in domain rules, it is droped overall
- numbering is in dot notation, each domain rule gets the number of placeholder rule as prefix
- 2.3.38 is the 38th rule in the local rulebase, placeholder rule is the 3rd global rule in the 2nd global ordered rulebase
- in reporting to_rulebase_id is collapsible with a the placeholder rule as banner

#### Concatenated

- from_rulebase_id and to_rulebase_id are the same rulebase in context of a traffic request
- first from_rulebase_id is traversed for an accept rule and if none is found, then to_rulebase_id
- rule numbers are continued, if rulebase 1 ends with rule 16, then rulebase 2 starts with rule 17
- concatenated rulebases are not collapsible in reporting by default, but could be if is_section is true

#### Inline

- from_rulebase_id is interrupted by to_rulebase_id
- from_rule_id is defined and named layer guard
- if layer guard is reached by traffic traversal and allows traffic, then all to_rulebase_id are traversed
- if to_rulebase_id allows traffic it is allowed overall, else from_rulebase_id keeps getting traversed after layer guard
- inline rulebases may be nested
- numbering is in dot notation, each inline rule gets the number of from_rule_id as prefix
- 2.3.18 is the 18th rule in the nested inline rulebase, its layerguard is the 3rd rule in the inline rulebase with layer guard 2 in the ordered layer
- in reporting to_rulebase_id is collapsible with a the layer guard rule as banner

#### NAT

- each ordered from_rulebase_id may have a nat to_rulebase_id
- nat rulebases do not contain access rules but nat rules
- nat rules are not important for numbering or traffic traversal
- nat rules get their own report
1 change: 1 addition & 0 deletions roles/database/files/sql/creation/fworch-fill-stm.sql
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ insert into stm_link_type (id, name) VALUES (2, 'ordered');
insert into stm_link_type (id, name) VALUES (3, 'inline');
insert into stm_link_type (id, name) VALUES (4, 'concatenated');
insert into stm_link_type (id, name) VALUES (5, 'domain');
insert into stm_link_type (id, name) VALUES (6, 'nat');

-- insert into compliance.assessability_issue_type (type_id, type_name) VALUES (1, 'empty group');
-- insert into compliance.assessability_issue_type (type_id, type_name) VALUES (2, 'broadcast address');
Expand Down
1 change: 1 addition & 0 deletions roles/database/files/upgrade/9.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ insert into stm_link_type (id, name) VALUES (2, 'ordered') ON CONFLICT DO NOTHIN
insert into stm_link_type (id, name) VALUES (3, 'inline') ON CONFLICT DO NOTHING;
insert into stm_link_type (id, name) VALUES (4, 'concatenated') ON CONFLICT DO NOTHING;
insert into stm_link_type (id, name) VALUES (5, 'domain') ON CONFLICT DO NOTHING;
insert into stm_link_type (id, name) VALUES (6, 'nat') ON CONFLICT DO NOTHING;
delete from stm_link_type where name in ('initial','global','local','section'); -- initial and global/local are additional flags now

-- TODO delete all rule.parent_rule_id and rule.parent_rule_type, always = None so far
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,9 @@ def get_global_assignments(api_v_url: str, sid: str, show_params_policy_structur

# parse global assignments
for assignment in assignments["objects"]:
global_assignment = parse_global_assignment(assignment)
global_assignments.append(global_assignment)
if "global-access-policy" in assignment:
global_assignment = parse_global_assignment(assignment)
global_assignments.append(global_assignment)

return global_assignments

Expand All @@ -344,7 +345,7 @@ def get_rulebases(
rulebase_uid: str | None = None,
rulebase_name: str | None = None,
) -> list[str]:
# i access_type : access / nat
# access_type is either "access" or "nat"
native_config_rulebase_key = "rulebases"
current_rulebase = {}

Expand Down Expand Up @@ -635,11 +636,14 @@ def assign_placeholder_uids(


def get_nat_rules_from_api_as_dict(
api_v_url: str, sid: str, show_params_rules: dict[str, Any], native_config_domain: dict[str, Any] | None = None
):
if native_config_domain is None:
native_config_domain = {}
nat_rules: dict[str, list[Any]] = {"nat_rule_chunks": []}
policy_dict: dict[str, Any],
api_v_url: str,
sid: str,
show_params_rules: dict[str, Any],
native_config_domain: dict[str, Any],
) -> dict[str, Any]:
"""Gets NAT rulebases, uid and name are augmented with _nat for uniquenes of rulebase_links"""
nat_rules: dict[str, Any] = {"uid": policy_dict["uid"] + "_nat", "name": policy_dict["name"] + "_nat", "chunks": []}
current = 0
total = current + 1
while current < total:
Expand All @@ -661,7 +665,7 @@ def get_nat_rules_from_api_as_dict(
]:
resolve_ref_list_from_object_dictionary(rulebase, rule_field, native_config_domain=native_config_domain)

nat_rules["nat_rule_chunks"].append(rulebase)
nat_rules["chunks"].append(rulebase)
if "total" in rulebase:
total = rulebase["total"]
else:
Expand Down
Loading
Loading