Open consentfactory opened 3 years ago
Hi,
Try this template:
<vars>
SVC_PORTS = "tcp-udp|tcp|udp"
</vars>
<group name="object-{{ object_type }}-groups**.{{ object_name }}**">
object-group {{ object_type }} {{ object_name | _start_ }}
object-group {{ object_type }} {{ object_name | _start_ }} {{ protocol | re("SVC_PORTS")}}
description {{ description | re(".*") }}
<group name="network-objects" itemize="obj_name" method="table">
network-object object {{ obj_name | }}
network-object host {{ obj_name | IP }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
group-object {{ obj_name }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
service-object object {{ obj_name }}
service-object {{ obj_name }}
</group>
<group name="service-object-ports*">
service-object {{ protocol | re("SVC_PORTS") }} destination eq {{port}}
</group>
<group name="service-object-port-ranges*">
service-object {{ protocol | re("SVC_PORTS") }} destination range {{port_begin}} {{port_end}}
</group>
<group name="service-port-objects" itemize="port_obj">
port-object eq {{ port_obj }}
</group>
</group>
it gives these results:
[[{'object-network-groups': {'Space-Users': {'network-objects': ['ab',
'ac',
'ad',
'ae',
'af',
'ag',
'ah',
'ai',
'aj']},
'dalmatians': {'group-objects': ['trunks',
'Space-Users'],
'network-objects': ['dog-01',
'vlan_950',
'Darts-Summary']},
'gohan': {'network-objects': ['gohan-01',
'gohan-02',
'vlan_944',
'gohan-03',
'gohan-05',
'gohan-06']},
'vegeta': {'group-objects': ['trunks'],
'network-objects': ['vegeta-01']}},
'object-service-groups': {'gokuhead': {'service-object-ports': [{'port': 'gokurpc',
'protocol': 'tcp-udp'},
{'port': '902',
'protocol': 'tcp'},
{'port': 'https',
'protocol': 'tcp'},
{'port': 'nfs',
'protocol': 'tcp'},
{'port': '10025',
'protocol': 'tcp'}]},
'sql': {'protocol': 'tcp',
'service-port-objects': ['1433']}}}]]
Key difference is using dynamic path to encode object type as well:
<group name="object-{{ object_type }}-groups**.{{ object_name }}**">
In you original template lines
group-object trunks
group-object Space-Users
matched under object-service-groups
because both object-service-groups
and object-network-groups
having this pattern defined:
group-object {{ net_obj_name }}
group-object {{ svc_group_objs }}
which translates to same regular expression.
TTP processes top object-service-groups
and object-network-groups
groups independently collecting all matches for them, combining these groups in a single group using dynamic path allows to obtain better results.
That makes sense, and I can actually see where I could use more dynamic pathing for some other templates.
Thank you for taking the time to create that and explain it!
Quick follow-up: is possible to combine matched items into a new object?
For example, objects in ASA configs can also appear as IPs and subnets:
object-group network Test-Group
network-object 192.168.168.1 255.255.255.0
So I create a template item under the group like this:
network-object {{ obj_ip | IP }} {{ obj_subnet | to_cidr }}
But what would be really nice for my purposes is to concatenate obj_ip
and obj_subnet
into a new item called obj_name
so they can appear in the list of network-objects.
Ideally, I would be able to add a backslash to have an IP in full CIDR notation like this: 192.168.168.1/24.
Is that possible? I haven't yet found documentation on something like this yet.
Have a look at to_ip function
network-object {{ ip | PHRASE | to_ip | with_prefixlen }}
That's perfect. Thank you.
That said, in general is it possible to concatenate matches?
There is joinmatches
function available that can help in certain cases, also group function sformat
can concatenate matches in a string, but in your case you not only need to concatenate but also translate mask to prefix length value, so only to_ip
will do the trick.
I'll check that out. Thanks again.
I might have closed this early.
I can't seem to make this work.
network-object {{ ip | PHRASE | to_ip | with_prefixlen }}
Using this input:
object-group network gohan
network-object 192.168.168.1 255.255.255.255
network-object 192.168.168.2 255.255.255.255
network-object host 192.168.168.3
network-object object gohan-01
network-object object gohan-02
network-object object vlan_944
network-object object gohan-03
network-object object gohan-05
network-object object gohan-06
I put the above template into this template:
<group name="object-{{ object_type }}-groups**.{{ object_name }}**">
object-group {{ object_type }} {{ object_name | _start_ }}
object-group {{ object_type }} {{ object_name | _start_ }} {{ protocol | re("SVC_PORTS")}}
description {{ description | re(".*") }}
<group name="network-objects" itemize="obj_name" method="table">
network-object object {{ obj_name | WORD }}
network-object host {{ obj_name | IP }}
network-object {{ obj_name | PHRASE | to_ip | with_prefixlen }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
group-object {{ obj_name }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
service-object object {{ obj_name }}
service-object {{ obj_name }}
</group>
<group name="service-object-ports*">
service-object {{ protocol | re("SVC_PORTS") }} destination eq {{port}}
</group>
<group name="service-object-port-ranges*">
service-object {{ protocol | re("SVC_PORTS") }} destination range {{port_begin}} {{port_end}}
</group>
<group name="service-port-objects" itemize="port_obj">
port-object eq {{ port_obj }}
</group>
</group>
I get an error from the Python ipaddress module:
ValueError: 'object/gohan-01' does not appear to be an IPv4 or IPv6 interface
# Also:
ValueError: 'host/192.168.168.3' does not appear to be an IPv4 or IPv6 interface
What I don't understand is why network-object object {{ obj_name | WORD }}
or network-object host {{ obj_name | IP }}
isn't processing this. Those are more specific matches than the third template line network-object {{ obj_name | PHRASE | to_ip | with_prefixlen }}
.
Once again, appreciate your help with this. Definitely learning a lot about ttp
than what I knew before.
Was able to get the IP prefix to work by adding a variable with a regex pattern of words to exclude, then using that in the template to exclude. Is this the right approach?
<vars>
OBJECT_EXCLUDE = "host|object"
</vars>
<group name="object-groups">
<group name="object-{{ object_type }}-groups**.{{ object_name }}**">
object-group {{ object_type }} {{ object_name | _start_ }}
object-group {{ object_type }} {{ object_name | _start_ }} {{ protocol | re("SVC_PORTS")}}
description {{ description | re(".*") }}
<group name="network-objects" itemize="obj_name" method="table">
network-object object {{ obj_name | WORD }}
network-object host {{ obj_name | IP }}
network-object {{ obj_name | PHRASE | exclude_re('OBJECT_EXCLUDE') | to_ip | with_prefixlen }}
</group>
</group>
Yes, that one of the options. You need to apply match filtering here, either using regexes or pattern check, for instance this should do the trick as well
network-object {{ obj_name | PHRASE | contains(".") | to_ip | with_prefixlen }}
I echo what @consentfactory is saying.. i have learnt a lot from this thread.. @consentfactory : are you able to share the final template that you are using?
@SudarshanVK would you mind sharing more info on these:
I echo what @consentfactory is saying.. i have learnt a lot from this thread.. @consentfactory : are you able to share the final template that you are using?
Yes, I have a template for the ASA, but I can't share it yet due to a project I'm working on. I'll update this thread with it when I upload the template*.
@dmulyalin : i am not able to share the configuration file unfortunately. But, here is the template i am using so far. I am yet to work out a template for ACL, user groups, OSPF configuration. I am hoping for a structure that would be easy to output to a spreadsheet for further analysis.
PS: I started looking into TTP only 4 days ago.
<vars>
SVC_PORTS = "tcp-udp|tcp|udp"
OBJECT_EXCLUDE = "host|object"
</vars>
<group name="global">
hostname {{hostname}}
</group>
<group name="interface.PortChannel">
interface Port-channel{{ number | DIGIT }}.{{ subinterface | DIGIT }}
nameif {{ name }}
security-level {{ security_level }}
ip address {{ ip | PHRASE | to_ip | with_prefixlen }}
ospf network {{ ospf_type }}
</group>
<group name="object-{{ object_type }}-groups**.{{ object_name }}**">
object-group {{ object_type }} {{ object_name | _start_ }}
object-group {{ object_type }} {{ object_name | _start_ }} {{ protocol | re("SVC_PORTS")}}
description {{ description | re(".*") }}
<group name="network-objects" itemize="obj_name" method="table">
network-object object {{ obj_name | WORD}}
network-object host {{ obj_name | IP }}
network-object {{ obj_name | PHRASE | exclude_re('OBJECT_EXCLUDE') | to_ip | with_prefixlen }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
group-object {{ obj_name }}
</group>
<group name="group-objects" itemize="obj_name" method="table">
service-object object {{ obj_name }}
service-object {{ obj_name }}
</group>
<group name="service-object-ports*">
service-object {{ protocol | re("SVC_PORTS") }} destination eq {{port}}
</group>
<group name="service-object-port-ranges*">
service-object {{ protocol | re("SVC_PORTS") }} destination range {{port_begin}} {{port_end}}
</group>
<group name="service-port-objects" itemize="port_obj">
port-object eq {{ port_obj }}
</group>
</group>
<output
format="excel"
returner="file"
filename="ASA_report.xslx"
url="./"
load="yaml"
>
table:
- path: interface.PortChannel
tab_name: PortChannel
</output>
@SudarshanVK That template of yours is quiet sophisticated, looks like you picked up quiet a bit of TTP so far.
What is the problem with above template, what exactly does not work in it for you? Also, would strongly advise against sharing any actual devices configs here, good idea is to anonymize them before doing so.
Will need sample data with template and desired results structure to help with building the template, without it cannot do much apart from general advice.
If you Guys finish doing the template for ASA, mind to think about contributing them to TTP Templates repo, if you think that it would be good for other people to benefit from your work.
structure that would be easy to output to a spreadsheet - that structure should be a list of dictionaries in that case, make sure to align your templates toward that format.
@dmulyalin i have a 80 context firewall to migrate.. I am still developing the template and absolutely i am keen to share it with everyone once i have everything working.. I might reach-out over here in case i run into issues with the rest of the configuration that I am trying to Parse... Thank you thus far...
If you Guys finish doing the template for ASA, mind to think about contributing them to TTP Templates repo, if you think that it would be good for other people to benefit from your work.
I would be more than happy to help contribute to the templates.
That said, the most difficult problem I face with ASA configs is the access-list configurations. I'm not sure if there are issues with the way my template is written (possible), or if the configs are just that complicated because there are lots, and I mean lots, of variations in how the configuration can be written, and I'm not sure I've captured all of them ( I think I have ~100 lines of variations, not including another set of lines that append these lines with 'log debugging').
Would be great to open-source that for someone else to take a look and improve them.
Here is the ASA template I've put together: https://gist.github.com/consentfactory/85872fc83453d1735b15aed3e47a9763
@consentfactory I'm having some errors trying to load your template. This is even before I pass it any configs to parse.
from ttp import ttp
ttp_template = """
[insert contents of your linked gist from above]
"""
parser = ttp()
parser.add_template(ttp_template)
The resulting error:
Traceback (most recent call last):
File "C:\Users\my_username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\ttp\ttp.py", line 1324, in construct_etree
template_ET = ET.XML(template_text)
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.2800.0_x64__qbz5n2kfra8p0\lib\xml\etree\ElementTree.py", line 1320, in XML
parser.feed(text)
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 2, column 1
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "c:/Users/my_username/Desktop/Python/New Stuff/ttp_test.py", line 368, in <module>
parser.add_template(ttp_template)
File "C:\Users\my_username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\ttp\ttp.py", line 347, in add_template
template_obj = _template_class(
File "C:\Users\my_username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\ttp\ttp.py", line 906, in __init__
self.template = self.handle_extend(template_text)
File "C:\Users\my_username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\ttp\ttp.py", line 1278, in handle_extend
template_ET = self.construct_etree(template_text)
File "C:\Users\my_username\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.8_qbz5n2kfra8p0\LocalCache\local-packages\Python38\site-packages\ttp\ttp.py", line 1331, in construct_etree
template_ET = ET.XML("<template>\n{}\n</template>".format(template_text))
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.8_3.8.2800.0_x64__qbz5n2kfra8p0\lib\xml\etree\ElementTree.py", line 1320, in XML
parser.feed(text)
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 26, column 9
Any ideas?
^Ignore.
I closed my laptop up for the day and went home.
Once home, I re-did everything and it is all now working. 🤷 Operator error? possibly.
Have a strange issue with an ASA template that I suspect is likely related to my template, but I'm unsure.
The gist is that I'm trying to get service and network object-groups into json, and generally they work, but I seem to have this issue where network group-objects end up in the service group objects.
Any tips on what I'm doing wrong (and how to improve it) would be great. Thanks in advance.
The code: