Environment
- Python version: 3.10.6
- Nautobot version: 1.5.7
- nautobot-plugin-firewall-model version: 1.1.3
Expected Behavior
I created iptables platform and rules in firewall plugin for tah platform. then i started job "Generate FW Config via Capirca."
Job should generate caprica config for iptables
Observed Behavior
First i created iptables platform and assigned it to device.
Then i created Address objects, service objects, zones then policy rules and policy
After that i started job and got error:
Traceback (most recent call last):
File "/opt/nautobot/lib/python3.10/site-packages/nautobot/extras/jobs.py", line 1179, in _run_job
output = job.run(data=data, commit=commit)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/jobs.py", line 51, in run
CapircaPolicy.objects.update_or_create(device=device_obj)
File "/opt/nautobot/lib/python3.10/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/opt/nautobot/lib/python3.10/site-packages/django/db/models/query.py", line 613, in update_or_create
obj.save(using=self.db)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/models/capirca_models.py", line 57, in save
cap_obj.get_all_capirca_cfg()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/utils/capirca.py", line 590, in get_all_capirca_cfg
self.get_capirca_cfg()
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/utils/capirca.py", line 553, in get_capirca_cfg
self.cfg_file = generate_capirca_config(servicecfg, networkcfg, self.pol_file, self.platform)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/utils/capirca.py", line 74, in generate_capirca_config
return str(import_string(CAPIRCA_MAPPER[platform]["lib"])(pol, 0))
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 644, in __init__
super().__init__(pol, exp_info)
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/aclgenerator.py", line 322, in __init__
self._TranslatePolicy(pol, exp_info)
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 782, in _TranslatePolicy
new_terms.append(self._TERM(term, filter_name, all_protocols_stateful,
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 107, in __init__
self.term_name = '%s_%s' % (self.filter[:1], self.term.name)
TypeError: 'NoneType' object is not subscriptable
Steps to Reproduce
- Create iptables platform
- assign it to device
- create policy for that device
- run "Generate FW Config via Capirca."
###Reason of that error
I tried run this objects of this job separately from nautobot shell and i got this error when i tried to start PolicyToCapirca class from capirca.py
First i issued this in shell
from nautobot_firewall_models.models.core_models import Policy,AddressObject, AddressObjectGroup
from nautobot.dcim.models import Platform
from nautobot_firewall_models.utils.capirca import PolicyToCapirca
from nautobot_firewall_models.constants import (
ALLOW_STATUS,
CAPIRCA_OS_MAPPER,
ACTION_MAP,
LOGGING_MAP,
CAPIRCA_MAPPER,
PLUGIN_CFG,
)
pve_policy = Policy.objects.get(name="PVE")
pve_platform = Platform.objects.get(name="iptables")
capirca_policy = PolicyToCapirca(pve_platform.slug, pve_policy)
capirca_policy.get_capirca_cfg()
Then i got this error
WARNING:absl:Term PVE_Cluster has service UDP-5404-5405 which is not defined with protocol tcp, but will be permitted. Unless intended, you should consider splitting the protocols into separate terms!
WARNING:absl:Term PVE_Cluster has service SSH which is not defined with protocol udp, but will be permitted. Unless intended, you should consider splitting the protocols into separate terms!
WARNING:absl:Term PVE_Cluster has service TCP-3128 which is not defined with protocol udp, but will be permitted. Unless intended, you should consider splitting the protocols into separate terms!
WARNING:absl:Term PVE_Cluster has service TCP-5900-5999 which is not defined with protocol udp, but will be permitted. Unless intended, you should consider splitting the protocols into separate terms!
WARNING:absl:Term PVE_Cluster has service TCP-8006 which is not defined with protocol udp, but will be permitted. Unless intended, you should consider splitting the protocols into separate terms!
WARNING:absl:Filter is generating a non-standard chain that will not apply to traffic unless linked from INPUT, OUTPUT or FORWARD filters. New chain name is: None
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/utils/capirca.py", line 553, in get_capirca_cfg
self.cfg_file = generate_capirca_config(servicecfg, networkcfg, self.pol_file, self.platform)
File "/opt/nautobot/lib/python3.10/site-packages/nautobot_firewall_models/utils/capirca.py", line 74, in generate_capirca_config
return str(import_string(CAPIRCA_MAPPER[platform]["lib"])(pol, 0))
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 644, in __init__
super().__init__(pol, exp_info)
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/aclgenerator.py", line 322, in __init__
self._TranslatePolicy(pol, exp_info)
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 782, in _TranslatePolicy
new_terms.append(self._TERM(term, filter_name, all_protocols_stateful,
File "/opt/nautobot/lib/python3.10/site-packages/capirca/lib/iptables.py", line 107, in __init__
self.term_name = '%s_%s' % (self.filter[:1], self.term.name)
TypeError: 'NoneType' object is not subscriptable
As i understad capirca cant find direction for rule (INPUT, OUTPUT or FORWARD) Then i checked
>>> cap_policy
[{'rule-name': 'SSH-to-PVE', 'headers': ['iptables'], 'terms': {'source-address': ['pci-mgmt-z501', 'test'], 'source-port': [], 'destination-address': ['PVE-z501'], 'destination-port': ['SSH'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'ICMP', 'headers': ['iptables'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': [], 'protocol': ['icmp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'Httpftp', 'headers': ['iptables'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': ['FTP', 'Http-Https'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'test-to-http', 'headers': ['iptables'], 'terms': {'source-address': ['pci-mgmt-z501', 'test'], 'source-port': [], 'destination-address': ['PVE-z501', 'test'], 'destination-port': ['HTTP', 'HTTPS'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'https', 'headers': ['iptables'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': ['Http-Https'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'PVE_Cluster', 'headers': ['iptables'], 'terms': {'source-address': ['PVE-z501'], 'source-port': [], 'destination-address': ['PVE-z501'], 'destination-port': ['SSH', 'TCP-3128', 'TCP-5900-5999', 'TCP-8006', 'UDP-5404-5405'], 'protocol': ['tcp', 'udp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}]
>>> pol
['header {', ' target:: iptables', '}', '', 'term SSH-to-PVE {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-port:: SSH', ' logging:: true', ' protocol:: tcp', ' source-address:: pci-mgmt-z501', ' source-address:: test', '}', '', 'header {', ' target:: iptables', '}', '', 'term ICMP {', ' action:: accept', ' comment:: ""', ' logging:: true', ' protocol:: icmp', '}', '', 'header {', ' target:: iptables', '}', '', 'term Httpftp {', ' action:: accept', ' comment:: ""', ' destination-port:: FTP', ' destination-port:: Http-Https', ' logging:: true', ' protocol:: tcp', '}', '', 'header {', ' target:: iptables', '}', '', 'term test-to-http {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-address:: test', ' destination-port:: HTTP', ' destination-port:: HTTPS', ' logging:: true', ' protocol:: tcp', ' source-address:: pci-mgmt-z501', ' source-address:: test', '}', '', 'header {', ' target:: iptables', '}', '', 'term https {', ' action:: accept', ' comment:: ""', ' destination-port:: Http-Https', ' logging:: true', ' protocol:: tcp', '}', '', 'header {', ' target:: iptables', '}', '', 'term PVE_Cluster {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-port:: SSH', ' destination-port:: TCP-3128', ' destination-port:: TCP-5900-5999', ' destination-port:: TCP-8006', ' destination-port:: UDP-5404-5405', ' logging:: true', ' protocol:: tcp', ' protocol:: udp', ' source-address:: PVE-z501', '}', '']
There is no direction header.
I checked capirca manual and this is example from it:
target:: iptables [INPUT|OUTPUT|FORWARD|custom] {ACCEPT|DROP} {truncatenames} {nostate} {inet|inet6}
Then i found PolicyToCapirca class and cheched get_capirca_cfg function.
I found on line 482 this block of code:
if CAPIRCA_MAPPER[self.platform]["type"] == "zone":
from_zone = _slugify(pol["from-zone"])
to_zone = _slugify(pol["to-zone"])
rule_details["headers"].extend(["from-zone", from_zone, "to-zone", to_zone])
LOGGER.debug("Zone Logic hit, from-zone: `%s` to-zone: `%s`", from_zone, to_zone)
if CAPIRCA_MAPPER[self.platform]["type"] == "filter-name":
rule_details["headers"].append(rule_details["rule-name"])
LOGGER.debug("Filter Name Logic hit for: `%s`", str(rule_details["rule-name"]))
i checked platform type of iptables and it was direction:
>>> CAPIRCA_MAPPER[capirca_policy.platform]["type"]
'direction'
this is reason why i got error. This function didn't add right header.
I changed this code for this:
if CAPIRCA_MAPPER[self.platform]["type"] == "zone":
from_zone = _slugify(pol["from-zone"])
to_zone = _slugify(pol["to-zone"])
rule_details["headers"].extend(["from-zone", from_zone, "to-zone", to_zone])
LOGGER.debug("Zone Logic hit, from-zone: `%s` to-zone: `%s`", from_zone, to_zone)
elif CAPIRCA_MAPPER[self.platform]["type"] == "direction":
from_zone = _slugify(pol["from-zone"])
rule_details["headers"].extend([from_zone])
LOGGER.debug("Zone Logic hit, from-zone: `%s` to-zone: `%s`", from_zone)
if CAPIRCA_MAPPER[self.platform]["type"] == "filter-name":
rule_details["headers"].append(rule_details["rule-name"])
LOGGER.debug("Filter Name Logic hit for: `%s`", str(rule_details["rule-name"]))
and everything works
>>> cap_policy
[{'rule-name': 'SSH-to-PVE', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': ['pci-mgmt-z501', 'test'], 'source-port': [], 'destination-address': ['PVE-z501'], 'destination-port': ['SSH'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'ICMP', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': [], 'protocol': ['icmp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'Httpftp', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': ['FTP', 'Http-Https'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'test-to-http', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': ['pci-mgmt-z501', 'test'], 'source-port': [], 'destination-address': ['PVE-z501', 'test'], 'destination-port': ['HTTP', 'HTTPS'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'https', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': [], 'source-port': [], 'destination-address': [], 'destination-port': ['Http-Https'], 'protocol': ['tcp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}, {'rule-name': 'PVE_Cluster', 'headers': ['iptables', 'INPUT'], 'terms': {'source-address': ['PVE-z501'], 'source-port': [], 'destination-address': ['PVE-z501'], 'destination-port': ['SSH', 'TCP-3128', 'TCP-5900-5999', 'TCP-8006', 'UDP-5404-5405'], 'protocol': ['tcp', 'udp'], 'action': 'accept', 'logging': 'true', 'comment': '""'}}]
>>> pol
['header {', ' target:: iptables INPUT', '}', '', 'term SSH-to-PVE {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-port:: SSH', ' logging:: true', ' protocol:: tcp', ' source-address:: pci-mgmt-z501', ' source-address:: test', '}', '', 'header {', ' target:: iptables INPUT', '}', '', 'term ICMP {', ' action:: accept', ' comment:: ""', ' logging:: true', ' protocol:: icmp', '}', '', 'header {', ' target:: iptables INPUT', '}', '', 'term Httpftp {', ' action:: accept', ' comment:: ""', ' destination-port:: FTP', ' destination-port:: Http-Https', ' logging:: true', ' protocol:: tcp', '}', '', 'header {', ' target:: iptables INPUT', '}', '', 'term test-to-http {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-address:: test', ' destination-port:: HTTP', ' destination-port:: HTTPS', ' logging:: true', ' protocol:: tcp', ' source-address:: pci-mgmt-z501', ' source-address:: test', '}', '', 'header {', ' target:: iptables INPUT', '}', '', 'term https {', ' action:: accept', ' comment:: ""', ' destination-port:: Http-Https', ' logging:: true', ' protocol:: tcp', '}', '', 'header {', ' target:: iptables INPUT', '}', '', 'term PVE_Cluster {', ' action:: accept', ' comment:: ""', ' destination-address:: PVE-z501', ' destination-port:: SSH', ' destination-port:: TCP-3128', ' destination-port:: TCP-5900-5999', ' destination-port:: TCP-8006', ' destination-port:: UDP-5404-5405', ' logging:: true', ' protocol:: tcp', ' protocol:: udp', ' source-address:: PVE-z501', '}', '']