def main(): argument_spec = dict( ip_address=dict(required=True), username=dict(default='admin'), password=dict(no_log=True), api_key=dict(no_log=True), rule_name=dict(required=True), source_zone=dict(type='list', default=['any']), source_ip=dict(type='list', default=["any"]), source_user=dict(type='list', default=['any']), hip_profiles=dict(type='list', default=['any']), destination_zone=dict(type='list', default=['any']), destination_ip=dict(type='list', default=["any"]), application=dict(type='list', default=['any']), service=dict(type='list', default=['application-default']), category=dict(type='list', default=['any']), action=dict(default='allow', choices=[ 'allow', 'deny', 'drop', 'reset-client', 'reset-server', 'reset-both' ]), log_setting=dict(), log_start=dict(type='bool', default=False), log_end=dict(type='bool', default=True), description=dict(default=''), rule_type=dict(default='universal', choices=['universal', 'intrazone', 'interzone']), tag_name=dict(type='list'), negate_source=dict(type='bool', default=False), negate_destination=dict(type='bool', default=False), disabled=dict(type='bool', default=False), schedule=dict(), icmp_unreachable=dict(type='bool'), disable_server_response_inspection=dict(type='bool', default=False), group_profile=dict(), antivirus=dict(), spyware=dict(), vulnerability=dict(), url_filtering=dict(), file_blocking=dict(), wildfire_analysis=dict(), data_filtering=dict(), target=dict(type='list'), negate_target=dict(type='bool', default=False), location=dict(choices=['top', 'bottom', 'before', 'after']), existing_rule=dict(), devicegroup=dict(), rulebase=dict(default='pre-rulebase', choices=['pre-rulebase', 'post-rulebase']), vsys=dict(default='vsys1'), state=dict(choices=['present', 'absent']), operation=dict(default='add', choices=['add', 'update', 'delete', 'find']), commit=dict(type='bool', default=True)) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True, required_one_of=[['api_key', 'password']]) if not HAS_LIB: module.fail_json(msg='Missing required libraries.') elif not hasattr(SecurityRule, 'move'): module.fail_json(msg='Python library pandevice needs to be updated.') # Get the firewall / panorama auth. auth = ( module.params['ip_address'], module.params['username'], module.params['password'], module.params['api_key'], ) # Set the SecurityRule object params rule_spec = { 'name': module.params['rule_name'], 'fromzone': module.params['source_zone'], 'tozone': module.params['destination_zone'], 'source': module.params['source_ip'], 'source_user': module.params['source_user'], 'hip_profiles': module.params['hip_profiles'], 'destination': module.params['destination_ip'], 'application': module.params['application'], 'service': module.params['service'], 'category': module.params['category'], 'action': module.params['action'], 'log_setting': module.params['log_setting'], 'log_start': module.params['log_start'], 'log_end': module.params['log_end'], 'description': module.params['description'], 'type': module.params['rule_type'], 'tag': module.params['tag_name'], 'negate_source': module.params['negate_source'], 'negate_destination': module.params['negate_destination'], 'disabled': module.params['disabled'], 'schedule': module.params['schedule'], 'icmp_unreachable': module.params['icmp_unreachable'], 'disable_server_response_inspection': module.params['disable_server_response_inspection'], 'group': module.params['group_profile'], 'virus': module.params['antivirus'], 'spyware': module.params['spyware'], 'vulnerability': module.params['vulnerability'], 'url_filtering': module.params['url_filtering'], 'file_blocking': module.params['file_blocking'], 'wildfire_analysis': module.params['wildfire_analysis'], 'data_filtering': module.params['data_filtering'], } # Get other info location = module.params['location'] existing_rule = module.params['existing_rule'] devicegroup = module.params['devicegroup'] rulebase = module.params['rulebase'] vsys = module.params['vsys'] state = module.params['state'] operation = module.params['operation'] commit = module.params['commit'] # Sanity check the location / existing_rule params. if location in ('before', 'after') and not existing_rule: module.fail_json( msg= "'existing_rule' must be specified if location is 'before' or 'after'." ) # Open the connection to the PAN-OS device device = None try: device = PanDevice.create_from_device(*auth) except PanDeviceError: e = get_exception() module.fail_json(msg=e.message) # Add some additional rule params if device is Panorama if isinstance(device, Panorama): rule_spec['target'] = module.params['target'] rule_spec['negate_target'] = module.params['negate_target'] # Set the attachment point for the RuleBase object parent = device if isinstance(parent, Firewall): if vsys is not None: vsys_list = Vsys.refreshall(parent) parent = get_vsys(vsys, vsys_list) if parent is None: module.fail_json(msg='VSYS not found: {0}'.format(vsys)) parent = parent.add(Rulebase()) elif isinstance(parent, Panorama): if devicegroup == 'shared': devicegroup = None if devicegroup is not None: parent = parent.add(Rulebase()) else: parent = get_devicegroup(parent, devicegroup) if parent is None: module.fail_json( msg='Device group not found: {0}'.format(devicegroup)) if rulebase == 'pre-rulebase': parent = parent.add(PreRulebase()) elif rulebase == 'post-rulebase': parent = parent.add(PostRulebase()) # Now that we have the rulebase let's grab its security rules rules = SecurityRule.refreshall(parent) # Create new rule object from the params and add to rulebase new_rule = SecurityRule(**rule_spec) parent.add(new_rule) # Which action shall we take on the rule object? changed = False if state == 'present': match = find_rule(rules, new_rule) if match: # Change an existing rule if not match.equal(new_rule): try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json( msg='Failed "present" apply: {0}'.format(e)) else: changed = True else: # Add a new rule try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "present" apply: {0}'.format(e)) else: changed = True # Move the rule if location is defined if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) else: changed = True elif state == 'absent': match = find_rule(rules, new_rule) if match: # Delete an existing rule try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "absent" delete: {0}'.format(e)) else: changed = True elif operation == "find": # Search for the rule match = find_rule(rules, new_rule) # If found, format and return the result if match: module.exit_json(stdout_lines=match.about(), msg='Rule matched') else: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) elif operation == "delete": # Search for the object match = find_rule(rules, new_rule) if match is None: module.fail_json( msg='Rule \'%s\' not found. Is the name correct?' % new_rule.name) try: if not module.check_mode: new_rule.delete() except PanDeviceError as e: module.fail_json(msg='Failed "delete" delete: {0}'.format(e)) else: changed = True elif operation == "add": # Search for the rule. Fail if found. match = find_rule(rules, new_rule) if match: module.fail_json( msg= 'Rule \'%s\' already exists. Use operation: \'update\' to change it.' % new_rule.name) try: if not module.check_mode: new_rule.create() except PanDeviceError as e: module.fail_json(msg='Failed "add" create: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) elif operation == 'update': # Search for the rule. Update if found. match = find_rule(rulebase, new_rule.name) if not match: module.fail_json( msg= 'Rule \'%s\' does not exist. Use operation: \'add\' to add it.' % new_rule.name) try: if not module.check_mode: new_rule.apply() except PanDeviceError as e: module.fail_json(msg='Failed "update" apply: {0}'.format(e)) else: changed = True if location: try: if not module.check_mode: new_rule.move(location, existing_rule) except PanDeviceError as e: if '{0}'.format(e) not in ACCEPTABLE_MOVE_ERRORS: module.fail_json(msg='Failed move: {0}'.format(e)) # Optional commit. # FIXME: Commits should be done using the separate commit module if changed and commit: try: device.commit(sync=True) except PanDeviceError as e: module.fail_json(msg='Failed commit: {0}'.format(e)) module.exit_json(changed=changed, msg='Done')
def configure_policy(device): web_srv = AddressObject(name='web-srv', value='192.168.45.5') db_srv = AddressObject(name='db-srv', value='192.168.35.5') device.add(web_srv) device.add(db_srv) web_srv.create() db_srv.create() service_tcp_221 = ServiceObject(name='service-tcp-221', protocol='tcp', destination_port='221') service_tcp_222 = ServiceObject(name='service-tcp-222', protocol='tcp', destination_port='222') device.add(service_tcp_221) device.add(service_tcp_222) service_tcp_221.create() service_tcp_222.create() rulebase = Rulebase() device.add(rulebase) allow_ping = SecurityRule(name='Allow ping', fromzone=['any'], source=['any'], tozone=['any'], destination=['any'], application=['ping'], service=['application-default'], action='allow') ssh_inbound = SecurityRule(name='SSH inbound', fromzone=['untrust'], source=['any'], tozone=['web', 'db'], destination=['any'], application=['ping', 'ssh'], service=['service-tcp-221', 'service-tcp-222'], action='allow') web_inbound = SecurityRule(name='Web inbound', fromzone=['untrust'], source=['any'], tozone=['web'], destination=['any'], application=['any'], service=['service-http'], action='allow') web_to_db = SecurityRule(name='Web to DB', fromzone=['any'], source=['web-srv'], tozone=['any'], destination=['db-srv'], application=['mysql'], service=['application-default'], action='allow') allow_outbound = SecurityRule(name='Allow outbound', fromzone=['web', 'db'], source=['any'], tozone=['untrust'], destination=['any'], application=['any'], service=['application-default'], action='allow') rulebase.add(allow_ping) rulebase.add(ssh_inbound) rulebase.add(web_inbound) rulebase.add(web_to_db) rulebase.add(allow_outbound) allow_ping.create() ssh_inbound.create() web_inbound.create() web_to_db.create() allow_outbound.create() web_ssh = NatRule(name='Web SSH', fromzone=['untrust'], source=['any'], tozone=['untrust'], destination=['192.168.55.20'], service='service-tcp-221', source_translation_type='dynamic-ip-and-port', source_translation_address_type='interface-address', source_translation_interface='ethernet1/2', destination_translated_address='web-srv', destination_translated_port='22') db_ssh = NatRule(name='DB SSH', fromzone=['untrust'], source=['any'], tozone=['untrust'], destination=['192.168.55.20'], service='service-tcp-222', source_translation_type='dynamic-ip-and-port', source_translation_address_type='interface-address', source_translation_interface='ethernet1/3', destination_translated_address='db-srv', destination_translated_port='22') wordpress_nat = NatRule( name='WordPress NAT', fromzone=['untrust'], source=['any'], tozone=['untrust'], destination=['192.168.55.20'], service='service-http', source_translation_type='dynamic-ip-and-port', source_translation_address_type='interface-address', source_translation_interface='ethernet1/2', destination_translated_address='web-srv') outgoing_traffic = NatRule( name='Outgoing traffic', fromzone=['web', 'db'], source=['any'], tozone=['untrust'], destination=['any'], source_translation_type='dynamic-ip-and-port', source_translation_address_type='interface-address', source_translation_interface='ethernet1/1', ) rulebase.add(web_ssh) rulebase.add(db_ssh) rulebase.add(wordpress_nat) rulebase.add(outgoing_traffic) web_ssh.create() db_ssh.create() wordpress_nat.create() outgoing_traffic.create()