Firewall rules as code

Started by Otanx, July 19, 2019, 11:55:21 AM

Previous topic - Next topic

Otanx

Anyone built automation for deploying ACLs to firewalls using Ansible? If so how did you define the rules to be pushed? I looked around on Google, and didn't see any standard templates people were using to define the object-groups, and ACL rules. In my head this is the first step. Create templates that can be used to define the aspects of a rule. Then create entries using the templates that are then used to push a rule. So right now I have a template for nework objects, service objects, and ACL rule. All of this is based on ASA so it may be missing items that are needed if I deploy to some other type of firewall.


network-object:
  name: Name of the network-object
    description: Description of the object
    network: List of networks with mask
    group: Name of a nested group
service-object:
  name: Name of the network-object
    description: Description of the object
    group: Name of a nested group
    protocols: List of protocols in the object.
      udp: List of UDP ports
      tcp: List of TCP ports
      ip: Empty list if object is ip.
      icmp: List of icmp message types
      XXX: list of options for the protocol. Must be an empty list if no options


I could then use those templates to build network or service objects on an ASA. Then I can use those as optional components to define rules.


rules:
  name: Name of the rule. Used to create object-groups.
    permit: bool. Yes or no to determine if permit or deny line.
    description: Description of rules
    source: dict of source types. Same fields as a network-object.name
        description:
network:
group:
    destination: dict of destination types. Same fields as a network-object.name
        description:
network:
group:
    services: dict of service types. Same fields as a service-object.name
        description:
group:
        protocols:
          udp:
          tcp:
          ip:
          icmp:
          XXX:


Then I can use a ACL template that I have not fleshed out yet to build the specific ACL.


acl:
  description: Description of the ACL
  host: hostname of firewall to apply ACL to
  interface: Interface to apply ACL to
  direction: Direction to apply ACL (in/out)
  include_before: List of other ACLs to include in this ACL at the top. Must be a list.
  rules: List of rules to use in ACL. Note: must be a list not a dict. List must be in order the ACL should be in.
  include_after: List of other ACLs to include in this ACL after the "rules" list. Must be a list.
  final_deny: bool. Include a deny any any log as the last rule.


Anyone have any thoughts, comments, or criticisms of this? I am trying to spend time on this planning so that it can cover as close to 99% of the use cases as it can without being too complex. This came up because we keep having issues with objects and ACLs being defined differently on different firewalls depending on who did it. I am trying to standardize this so we can get rid of the problem of a new DNS server only got added to 75% of the firewalls. I am already working with our Ansible guru as he has some stuff defined in a global vars file that I can use. Stuff like DNS, and NTP servers are defined globally so I can use those to fill in a object-group of DNS servers. Then when they change the global var because a DNS server changed it will get pushed out the next time we run an object-group playbook.

-Otanx

deanwebb

My first thought was "which vendor firewall is this for?" because syntax differences...

My question is: does this work properly for firewalls deployed in HA pairs?
Take a baseball bat and trash all the routers, shout out "IT'S A NETWORK PROBLEM NOW, SUCKERS!" and then peel out of the parking lot in your Ferrari.
"The world could perish if people only worked on things that were easy to handle." -- Vladimir Savchenko
Вопросы есть? Вопросов нет! | BCEB: Belkin Certified Expert Baffler | "Plan B is Plan A with an element of panic." -- John Clarke
Accounting is architecture, remember that!
Air gaps are high-latency Internet connections.

Otanx

The idea is this should be usable for any vendor. Think of this as more of a way to define the rules I want, and then I can write code to deploy this to whatever firewall I am using. Right now most of this is based on ASA because that is what I am testing against right now, but in theory I should be able to build rules for a PA, or Juniper box as well. So in a PA I could do something like;

The variable would be defined using the network-object template above as;


network-object:
  name: TEST
    group:
      - TEST-ADDRESS1
      - TEST-ADDRESS2


Assuming TEST-ADDRESS1 and TEST-ADDRESS2 are already defined on the PA.

I then run the following;

{% for name in network-object %}
set address-group {{ name }}
{% for group in network-object.name.group %}
set address-group {{ name }} static {{ group }}
{% endfor %}
{% endfor %}


This should give me;


set address-group TEST
set address-group TEST static TEST-ADDRESS1
set address-group TEST sttatic TEST-ADDRESS2


If I was to deploy to an ASA the code would be slightly different


{% for name in network-object %}
network-object {{ name }}
{% for group in name.group %}
group-object group
{% endfor %}
{% endfor %}


Which should give me


network-object TEST
group-object TEST-ADDRESS1
group-object TEST-ADDRESS2


Then the rules and ACL variables follow the same idea. As long as I have the information defined in a standard format I can deploy these to anything just by writing some code to parse the variables correctly. I was kind of surprised I didn't find anything like this already when I searched Google. This may be an impossible task unless you restrict use cases, and maybe that is why there isn't a commonly accepted way of doing this.

-Otanx