Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Palo Alto Firewalls support #113

Merged
merged 19 commits into from
Feb 9, 2017
Merged

Add Palo Alto Firewalls support #113

merged 19 commits into from
Feb 9, 2017

Conversation

XioNoX
Copy link
Contributor

@XioNoX XioNoX commented Jan 18, 2017

This PR includes the content of the PR #52
Plus the following modifications:

  • Generic address book and address sets
  • PAN application (> layer 4) with pan-application:: xxx yyy
  • Raises errors if policies/services names are too long
  • uses service_name and protocol in service name instead of port list
  • Used autopep8 (atom beautify) on paloaltofw.py

If this gets accepted, we also need to make sure the original author of PR #52 gets the credits as he did the largest part of the work.

Plus the following modifications:
* Generic applications (known as services in PAN) and applications sets (layer 4)
* PAN application (> layer 4)
* Raises errors if policies/services names are too long
* uses service_name and protocol in service name instead of port list
* Used autopep8 (atom beautify) on paloaltofw.py
@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.


  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data and verify that your email is set on your git commits.
  • If you signed the CLA as a corporation, please let us know the company's name.

aclgen.py Outdated
@@ -54,6 +54,7 @@
from lib import speedway
from lib import srxlo
from lib import windows_advfirewall
from lib import paloaltofw
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this to be in alphabetical order.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -225,6 +225,7 @@ class ACLGenerator(object):
'owner',
'qos',
'routing_instance',
'pan-application'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot a comma?
Also is this strictly necessary? I don't believe it is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I wasn't sure of its purpose when I originally added it.

lib/policy.py Outdated
@@ -1600,6 +1617,7 @@ def __ne__(self, other):
'protocol': 'PROTOCOL',
'protocol-except': 'PROTOCOL_EXCEPT',
'qos': 'QOS',
'pan-application':'PAN_APPLICATION',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put a space after the :?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

lib/policy.py Outdated
@@ -1612,7 +1630,7 @@ def __ne__(self, other):
'timeout': 'TIMEOUT',
'traffic-type': 'TRAFFIC_TYPE',
'verbatim': 'VERBATIM',
'vpn': 'VPN',
# 'vpn': 'VPN',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this meant to be commented out? I don't see why this should be.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed no. This is a workaround specific to our setup, as vpn is a zone name and not a special keyword.
Cf. #62
I removed the comment sign.

lib/policy.py Outdated
@@ -2080,6 +2099,11 @@ def p_qos_spec(p):
""" qos_spec : QOS ':' ':' STRING """
p[0] = VarType(VarType.QOS, p[4])

def p_pan_application_spec(p):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two spaces should be separating this def, same thing for under it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -249,6 +249,8 @@ class ProtocolExcept(Field):
class Qos(Field):
"""A rate-limit-icmp field."""

class PANApplication(Field):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please use two spaces between these classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

import aclgenerator
import nacaddr

import re
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks to be unused.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, removed.

@XioNoX
Copy link
Contributor Author

XioNoX commented Jan 18, 2017

I signed it! Corporation Mozilla.



class PaloAltoFW(aclgenerator.ACLGenerator):
"""PaloAltoFW rendering class.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring should only be one line. Arguments should not be documented here and the description below is kind of redundant. It inherits from the aclgenerator class so it should be obvious it renders a syntax output.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, I think it has been copied from the JuniperSRX docstring, which is very similar.

@@ -0,0 +1,48 @@
################
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we see an example of pan_application being used inside of here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, as well as the expected output in the test folder.
Palo alto comes with a wide array of existing "Applications", that's why I made it a simple variable that the user can define.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can someone make custom applications or is there a set list of things? If it is a set list should this have checking to make sure someone is not applying incorrect services?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's also possible to make custom applications.

term_dup_check = set()
new_terms = []
for term in terms:
term.name = self.FixTermLength(term.name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big deal but is there a max term length? If so we should probably override it because it is likely different from 62 limit in aclgenerator.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand.
The final rule length is limited to 31 chars. I added an exception for that on line 208 (PaloAltoFWTooLongName)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a variable named _TERM_MAX_LENGTH. If there is a max length FixTermLength should be called and _TERM_MAX_LENGTH should be set. This will raise an error if the term name is to long. If there is no limit then FixTermLength is irrelevant. Make sense?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the final name (limited at 31 chars) also contains the source and destination zone name (eg. internal_2_external-term-name. So only checking the term length is not possible (and ends up being quite short).
In order to save rule length, I'm considering the idea of requiring the terms to be unique (similar to the srx lib for example), and then either:
1/ Trimming the sources zone names to 3 char (eg. int_2_ext-term-name), then the prefix is always a fixed length.
or
2/ Not applying any prefix, and letting the user manually set a prefix (eg, src/dst zones) in the term if the user wants it.
I think I like 2/ better as it lets the user have more freedom.
What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 gives more freedom but there should be checks to make sure a invalid ACL is not rendered. Please make sure that is not possible via raising an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a check to raise "PaloAltoFWDuplicateTermError" in case a term is duplicated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As well as use _TERM_MAX_LENGTH instead of custom check.

self.modify_options(terms)

def modify_options(self, PAFWterm):
# for PAFWterm in terms:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be commented out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe the loop has been moved to line 346 (for term in new_terms:)
I removed the line mentioned here.

self.service_map[(ports, protocol)] = {'name': final_service_name}


class Rule():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am confused why this exists, it seems to replace the function of Term. Why was Term not able to be used instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why the original Author went that way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we explore why this was chosen and if this could be rolled up into a term? I don't understand why this is being used this way and I don't like having code integrated that no one understands. I will expect a docstring for Rule explaining what it is and why it is used instead of the term object.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to need help to figure that one out.

rules.append(self.INDENT * 9 + "<action>" + Term.ACTIONS.get(
str(options["action"])) + "</action>")

if fz == tz == "any":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems weird. There are loops above over the from zone and to zone which is a list. From my bit of testing I don't see that this would ever have more than one from-zone or to-zone per rule in rules. So why are these added as a list? The way the logic is setup fz could theoretically be set to an empty list if someone fed in a modified policy object that had the options set to ['from-zone', '', 'to-zone', ''] this would cause a problem.

Copy link
Contributor Author

@XioNoX XioNoX Jan 23, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ankenyr
Not sure why it's originally set up that way, but it can be related to the fact that PAN allows rules to have several source/destination zones.
Right now line 149

self.options["from_zone"] = [from_zone]

sets it to an array containing only 1 element.
But we could for example imagine it (in the future) being a list from the .pol file header, line 292

self.from_zone = filter_options[1].split(',')

(or something similar).

About the possibility of fz or tz being empty, I believe we can add a check after line 150:

    if not from_zone or not to_zone:
        raise PaloAltoFWOptionError("Source or destination zone is empty.")

2nd option would be to default both to "any" if they are not set instead of raising an error.
But I think it makes more sens to have the user explicitly define "any" if he wants "any".

@XioNoX
Copy link
Contributor Author

XioNoX commented Jan 23, 2017

CLA signed with my personal email as well.

@googlebot
Copy link

CLAs look good, thanks!

… duplicated + update .pol and filter expected
@XioNoX
Copy link
Contributor Author

XioNoX commented Jan 28, 2017

Commit 48a5f71 default the "service" field to "application-default" if "service" is not set, but "application" is.
If neither "service" nor "application" is set, the default "any" is used.

This is to follow PaloAlto recommendations and improve security. If "any" is used, the "application" filter can in some cases not be respected.

Here is PaloAlto suport take on it:

When the first packet is coming into firewall, the firewall rules are evaluated with 6 tuples (Source/Destination IP address, Source/Destination Ports, Protocol, and Zone). The application is not necessarily known in this first packets, it can take several packets to determine what the underlying application is. During this evaluation period, packets may be allowed through if there is a rule which has "any" instead of "application-default" for service or an application using dynamic tcp/udp ports. In this case you have a rule with "any" service it means that all ports will be allowed till application is identified.
After the session established with 6 tuples the application will be identified and it will be ultimately blocked by rule set accordingly.

If you change it to "application-default", firewall will only allow standard ports for applications you configured in a rule when the session is set up. So in security aspect we recommend to use "application-default" for service.

Please refer to KB below for more detail.
https://live.paloaltonetworks.com/t5/Management-Articles/Why-are-Rules-Denying-Applications-Allowing-Some-Packets/ta-p/58098
https://live.paloaltonetworks.com/t5/Management-Articles/URL-Block-Page-Response-Page-Appears-When-Custom-URL-is-Used/ta-p/56107

@ankenyr
Copy link
Contributor

ankenyr commented Feb 1, 2017

This is looking good enough that I think you should start making tests for the PR.

@XioNoX
Copy link
Contributor Author

XioNoX commented Feb 2, 2017

Great! Tests added!

lib/policy.py Outdated
@@ -1026,6 +1040,7 @@ def AddObject(self, obj):
# qos?
elif obj.var_type is VarType.QOS:
self.qos = obj.value

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra space added, please remove.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed!

lib/policy.py Outdated
@@ -1334,6 +1349,7 @@ class VarType(object):
HOP_LIMIT = 47
LOG_NAME = 48
FLEXIBLE_MATCH_RANGE = 49
PAN_APPLICATION = 50
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we change this to 54? I have some internal stuff I will be pushing out soon and it will conflict.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed!

@ankenyr ankenyr merged commit d5ff1d5 into google:master Feb 9, 2017
morrowc pushed a commit that referenced this pull request Mar 15, 2017
#113

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=147091309
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants