Firewall Rule¶
Firewall rules in SMC can be created, modified or deleted. Rules can also be fetched in various ways outlined in the documentation below.
Creating, Modifying or Deleting Firewall Rules¶
Firewall policy rules can be created, modified or deleted based on the playbook configuration. See the sections below for details on each operation type.
Creating a rule¶
Creating a rule requires basic information as documented by the Firewall Rule module.
An operation will be considered a ‘create’ if the playbook definition does not provide the ‘tag’ attribute. The ‘tag’ attribute is a unique identifier for an existing rule that uniquely identifies the rule since rule names can be identical. Therefore, if a rule definition in a playbook has the tag attribute, it will be considered a ‘modify’ operation.
Note
The ‘tag’ field of an existing rule is ‘read-only’ and only uniquely identifies the rule. It does not specify the rule position in a rule set.
Setting ‘present’ on the playbook state attribute is required to create or modify a rule. If the state is absent, the operation will be considered a delete operation and will use the rule tag identifier to find the correct rule.
Basic rule creation
The minimalist example of creating a rule is providing only the name field. If sources, destinations or services are not provided, the default value is ‘any’. If action is not provided, the default setting is ‘allow’:
- name:
hosts: localhost
gather_facts: no
tasks:
- name: Task output
firewall_rule:
policy: TestPolicy
rules:
- name: foo
You can create much more detailed rules by using other options within the firewall rule module.
Creating more detailed rules
An example of creating a basic continue rules that allows all logging at the beginning of a ruleset:
- name: Task output
register: result
firewall_rule:
policy: TestPolicy
rules:
- action: continue
comment: logging rule
log_options:
log_accounting_info_mode: true
log_closing_mode: true
log_level: stored
is_disabled: false
name: Log all continue rule
However, there are many more options available to create a rule, including setting connection tracking settings, inspection features, mss settings, and additional log settings. It is also possible to specify elaborate rules based on sources, destinations and services. Rule actions such as use_vpn, forward_vpn and apply_vpn, and jump_rules are supported.
Generally it is easier to retrieve an existing rule using and dumping to yaml, then making modifications to suit your requirements. See Finding Firewall Rules for more information on retrieving existing rules.
Customize all rule fields
Example of creating a rule with specific destinations and service elements. All source, destination and service elements are documented in the firewall_rule module. Elements can also be retrieved or created using the Network Elements module.
Note
Source, destination and service elements are validated before any only operations are performed to modify or create an element. The playbook run will fail on missing elements.
- name:
hosts: localhost
gather_facts: no
tasks:
- name: Task output
register: result
firewall_rule:
smc_logging:
level: 10
path: ansible-smc.log
policy: TestPolicy
rules:
- action: allow
comment: my comment
connection_tracking:
mss_enforced: true
mss_enforced_max: 1555
mss_enforced_min: 0
timeout: 10
state: normal
destinations:
group:
- foogroup
ip_list:
- Amazon S3
host:
- host-1.1.1.1
network:
- foonet
inspection_options:
decrypting: null
deep_inspection: null
file_filtering: null
is_disabled: false
log_options:
application_logging: enforced
eia_executable_logging: 'off'
log_accounting_info_mode: false
log_closing_mode: true
log_compression: 'off'
log_level: none
log_payload_additionnal: true
log_payload_excerpt: false
log_payload_record: false
log_severity: -1
user_logging: enforced
authentication_options:
methods: []
require_auth: false
name: ruletest2
services:
tcp_service:
- AOL
udp_service:
- Biff
ip_service:
- CHAOS
sources:
engine:
- myfw
alias:
- $$ Interface ID 0.ip
country:
- China
Creating rules with authentication
Rules can be created that specify authentication by setting the authentication_options dict on the rule. When enabling authentication, you must provide the authentication method along with at least one reference to a user or group from an internal user domain or an external ldap domain.
When specifying the user or group information, it is required to specify in full DN syntax as this is how users and groups are identified within the SMC.
An simple example YAML for authentication might look like:
authentication_options:
groups:
- dc=lepages,dc=local,domain=myldapdomain
methods:
- LDAP Authentication
- Network Policy Server
- User password
require_auth: true
users:
- cn=test,dc=stonegate,domain=InternalDomain
- cn=test2,dc=stonegate,domain=InternalDomain
This specifies that auth is required and several authentication methods are supported. In addition, two internal users and one external ldap domain is allowed to authenticate (using the LDAP domains base DN).
Creating VPN rules
An example of creating a ‘enforce_vpn’ rule requires the use of the parameter vpn_policy along with one of the valid vpn actions. In addition, the rule specifies a valid authentication service, sets require_auth to true and defines the base DN of the domain to allow authentication:
- name: Task output
register: result
firewall_rule:
smc_logging:
level: 10
path: ansible-smc.log
policy: TestPolicy
rules:
- action: enforce_vpn
comment: my comment
connection_tracking:
mss_enforced: false
mss_enforced_max: -1
mss_enforced_min: -1
timeout: -1
destinations:
any: true
inspection_options:
decrypting: true
deep_inspection: true
file_filtering: null
is_disabled: false
authentication_options:
methods:
- LDAP Authentication
require_auth: true
groups:
- dc=lepages,dc=local,domain=myldapdomain
users:
- cn=myuser,dc=stonegate,domain=InternalDomain
log_options:
application_logging: default
eia_executable_logging: default
log_accounting_info_mode: true
log_closing_mode: false
log_compression: 'off'
log_level: stored
log_payload_additionnal: false
log_payload_excerpt: false
log_payload_record: false
log_severity: -1
name: ruletest2
services:
any: true
sources:
any: true
vpn_policy: MOBILE CLIENT VPN
Creating jump rules
An example of creating a ‘jump’ rule requires the use of the parameter sub_policy along with the action of jump:
- name: Task output
register: result
firewall_rule:
smc_logging:
level: 10
path: ansible-smc.log
policy: TestPolicy
rules:
- action: jump
comment: my comment
connection_tracking:
mss_enforced: false
mss_enforced_max: -1
mss_enforced_min: -1
timeout: -1
destinations:
any: true
inspection_options:
decrypting: null
deep_inspection: null
file_filtering: null
is_disabled: false
authentication_options:
methods: []
require_auth: false
users: []
log_options:
application_logging: enforced
eia_executable_logging: default
log_accounting_info_mode: true
log_closing_mode: false
log_compression: 'off'
log_level: stored
log_payload_additionnal: false
log_payload_excerpt: true
log_payload_record: false
log_severity: -1
user_logging: 'true'
name: ruletest2
services:
any: true
sources:
any: true
sub_policy: mysubpolicy
Inserting rules in a specific position
It is also possible to add a rule after or before another specified rule using the target rules tag field. It is recommended that when you want rules inserted in a specific position, you locate the rule to insert ‘before’ or ‘after’ and specify that in the rule yaml. When rules are added, without a position they will be added in position #1 (top of the rule list).
Using that logic, if you have multiple rules that should all be inserted in a specific order somewhere in the rule list, one strategy is to fetch the existing policy to locate the rule tag which will act as the insert point. Then list your rules in the yaml from lowest in the list to highest, with all using the same add_after rule tag.
This example shows inserting a deny all rule after rule with a specific tag:
Note
By default rules are always inserted at the top of the policy unless specified otherwise
- name: Add a deny rule after specified rule using add_after syntax
register: result
firewall_rule:
smc_logging:
level: 10
path: ansible-smc.log
policy: TestPolicy
rules:
- action: discard
comment: deny rule
is_disabled: false
name: my deny
add_after: '2097193.0'
Note
You can leave fields like log_options, inspection_options and connection_tracking out of the playbook run if there is no need to customize those settings.
More examples can be found in the playbooks directory.
Modifying a rule¶
Modifying a rule consists of first retrieving the rule, making modifications, and re-running the playbook. Retrieving the rule can be done using the techniques describes below in Finding Firewall Rules.
Once you have retrieved the rule, you will notice a ‘tag’ field. This is a unique identifier for each rule. Rule names are not unique and rules can have the same rule name. Hence when a playbook is run on a rule that has a ‘tag’ value, the operation will be considered a modify.
To modify rules, once the rule has been retrieved, the content will look similar to the following:
- name: Task output
register: result
firewall_rule:
smc_logging:
level: 10
path: ansible-smc.log
policy: TestPolicy
rules:
- action: continue
comment: null
connection_tracking:
mss_enforced: false
mss_enforced_max: 0
mss_enforced_min: 0
timeout: -1
destinations:
any: true
inspection_options:
decrypting: null
deep_inspection: null
file_filtering: null
is_disabled: false
log_options:
log_accounting_info_mode: false
log_closing_mode: true
log_level: undefined
log_payload_additionnal: false
log_payload_excerpt: false
log_payload_record: false
log_severity: -1
name: Rule @2097166.2
services:
any: true
sources:
any: true
tag: '2097166.2'
When modifying rules you can also move a rule by using the add_after or add_before fields. For these fields to work, you must provide the ‘tag’ for the rule you want to move the rule ‘before’ or ‘after’. This will result in the rule being duplicated into the correct position and the original rule removed.
Note
This will be a no-op if the rule could not be found based on the rule tag value provided. In addition, this will change the rule tag of the original rule so a refetch will be necessary to operate on the rule again.
An example of modifying a rule and moving it into a new position:
- name:
hosts: localhost
gather_facts: no
tasks:
- name: Task output
register: result
firewall_rule:
policy: TestPolicy
rules:
- action: allow
destinations:
host:
- host-2.2.2.5
network:
- gateway_170.27.126.0/24
is_disabled: false
name: newruleinpos
services:
any: true
sources:
any: true
tag: '2097164.19'
add_after: '2097260.0'
See Exporting a Firewall Rule into YAML for more information on retrieving existing rules.
Deleting a rule¶
Deleting a firewall rule can be done by setting state=absent on the playbook. You must also pre-fetch the rule in order to validate deleting the correct rule. Rules are identified by the ‘tag’ attribute returned after fetching the rule since rule names are not unique.
Example of deleting a rule by rule tag after fetching (and removing other unneeded attributes):
- name: Task output
firewall_rule:
policy: TestPolicy
rules:
- tag: '2097203.0'
state: absent
Generally you might want to search for the particular rule of interest using firewall_rule_facts to narrow the search, return the results in yaml and delete.
Finding Firewall Rules¶
Layer 3 Firewall rule facts can be obtained by providing various filters for retrieving data.
The filter parameter is always required when obtaining rules, with filter specifying the Firewall Policy for which to retrieve the rules from.
There are varying details and options for retrieving rules. These are outlined in the next section.
Retrieving only name and rule position (metadata):
This is done by providing only a filter for to specify the rule policy. All rules are returned with only metadata.
- name: Rule tasks
hosts: localhost
gather_facts: no
tasks:
- name: Show rules for policy 'TestPolicy' (only shows name, type)
firewall_rule_facts:
filter: TestPolicy
This results in the following output:
ok: [localhost] => {
"ansible_facts": {
"firewall_rule": [
{
"comment": null,
"inspection_policy": "High-Security Inspection Template",
"policy": "TestPolicy",
"rules": [
{
"name": "Rule @2097166.2",
"pos": 1,
"type": "fw_ipv4_access_rule"
},
{
"name": "my@rule",
"pos": 2,
"type": "fw_ipv4_access_rule"
},
You can also obtain rules based a specific range of rules using the rule_range field. For example, you might want to grab the first 5 rules, or rules 10-15 to limit the search.
Retrieving rule based on rule range:
- name: Get specific rules based on range order (rules 1-3)
firewall_rule_facts:
filter: TestPolicy
rule_range: 1-3
Resulting in the following output:
ok: [localhost] => {
"ansible_facts": {
"firewall_rule": [
{
"comment": null,
"inspection_policy": "High-Security Inspection Template",
"policy": "TestPolicy",
"rules": [
{
"name": "Rule @2097166.2",
"type": "fw_ipv4_access_rule"
},
{
"name": "ruletest",
"type": "fw_ipv4_access_rule"
},
{
"name": "Rule @2097168.0",
"type": "fw_ipv4_access_rule"
}
],
"template": "Firewall Inspection Template"
}
]
}
Note
rule_range and search are mutually exclusive operations
Many times it is necessary to get more details about the rule configuration itself and you may even know the name of the rule you are looking for. If the rule name is known, you can provide the parameter search with a keyword that will be used as a wildcard to find any rules with this content in the name or comment field of a rule.
Retrieving rule based on search string:
- name: Search for specific rule/s using search value (partial searching supported)
firewall_rule_facts:
filter: TestPolicy
search: rulet
Note
Searching may return multiple results
This results in the following output:
ok: [localhost] => {
"ansible_facts": {
"firewall_rule": [
{
"comment": null,
"inspection_policy": "High-Security Inspection Template",
"policy": "TestPolicy",
"rules": [
{
"name": "ruletest",
"type": "fw_ipv4_access_rule"
}
],
"template": "Firewall Inspection Template"
}
]
}
This still only tells us that the a rule was found but no details about the contents of the rule.
The as_yaml parameter is available that provides the ability to ‘dump’ the contents of the rule into a format that can be re-used in a playbook or alternatively just dumped into a result register.
Retrieving more details about the rule:
Adding the as_yaml parameter to obtain more detail about a rule:
- name: Dump the results in yaml format, showing details of rule
firewall_rule_facts:
filter: TestPolicy
search: rulet
as_yaml: true
The output from the run now contains must more data and the specifics about the rule itself:
ok: [localhost] => {
"ansible_facts": {
"firewall_rule": [
{
"comment": null,
"inspection_policy": "High-Security Inspection Template",
"policy": "TestPolicy",
"rules": [
{
"action": "allow",
"comment": null,
"connection_tracking": {
"mss_enforced": false,
"mss_enforced_max": 0,
"mss_enforced_min": 0,
"state": "no",
"timeout": -1
},
"destinations": [
"https://1.1.1.1:8082/6.4/elements/host/942",
"https://1.1.1.1:8082/6.4/elements/host/944",
"https://1.1.1.1:8082/6.4/elements/host/948",
"https://1.1.1.1:8082/6.4/elements/network/3969"
],
"inspection_options": {
"decryption": false,
"deep_inspection": false,
"file_filtering": false
},
"is_disabled": false,
"logging": {
"application_logging": "enforced",
"eia_executable_logging": "off",
"log_accounting_info_mode": true,
"log_closing_mode": false,
"log_compression": "off",
"log_level": "stored",
"log_payload_additionnal": false,
"log_payload_excerpt": false,
"log_payload_record": false,
"log_severity": -1,
"user_logging": "enforced"
},
"name": "ruletest",
"services": [
"https://1.1.1.1:8082/6.4/elements/ip_service/58",
"https://1.1.1.1:8082/6.4/elements/icmp_service/312",
"https://1.1.1.1:8082/6.4/elements/tcp_service/358",
"https://1.1.1.1:8082/6.4/elements/tcp_service/468",
"https://1.1.1.1:8082/6.4/elements/udp_service/541",
"https://1.1.1.1:8082/6.4/elements/udp_service/551"
],
"sources": {
"any": true
},
"tag": "2097164.14"
}
],
"template": "Firewall Inspection Template"
}
]
}
However, you will notice that certain fields, sources, destinations and services will contain href’s that specify the location of the element but not the actual element itself by type or name. To obtain the resolved information for the elements, you can alternatively provide a parameter expand which is a list of fields to resolve into element and types.
Note
Expanding HREFs will result in a single SMC query per element href and is therefore only recommended in a limited fashion. For example, expanding all rules in a rule list of 100 rules will likely result in hundreds of queries against the SMC. It is recommended to narrow your search before expanding fields.
Expanding href fields in a facts run:
Add the expand field list to the existing playbook to provide resolution for the fields source, destination and services:
- name: Resolve the source, destination and services fields
firewall_rule_facts:
filter: TestPolicy
search: rulet
as_yaml: true
expand:
- sources
- destinations
- services
Running this task results in the following:
ok: [localhost] => {
"ansible_facts": {
"firewall_rule": [
{
"comment": null,
"inspection_policy": "High-Security Inspection Template",
"policy": "TestPolicy",
"rules": [
{
"action": "allow",
"comment": null,
"connection_tracking": {
"mss_enforced": false,
"mss_enforced_max": 0,
"mss_enforced_min": 0,
"state": "no",
"timeout": -1
},
"destinations": {
"host": [
"2.2.2.5",
"2.2.2.6",
"2.2.2.23"
],
"network": [
"gateway_170.27.126.0/24"
]
},
"inspection_options": {
"decryption": false,
"deep_inspection": false,
"file_filtering": false
},
"is_disabled": false,
"logging": {
"application_logging": "enforced",
"eia_executable_logging": "off",
"log_accounting_info_mode": true,
"log_closing_mode": false,
"log_compression": "off",
"log_level": "stored",
"log_payload_additionnal": false,
"log_payload_excerpt": false,
"log_payload_record": false,
"log_severity": -1,
"user_logging": "enforced"
},
"name": "ruletest",
"services": {
"icmp_service": [
"Alternate Host Address (Any Code)"
],
"ip_service": [
"ARIS"
],
"tcp_service": [
"CreativePartnr",
"CreativeServer"
],
"udp_service": [
"CMIP-Manager (UDP)",
"CMIP Agent (UDP)"
]
},
"sources": {
"any": true
},
"tag": "2097164.14"
}
],
"template": "Firewall Inspection Template"
}
]
}
Looking at the output, you may notice that the format of the output matches the input format that can be used to create a firewall rule. This is a useful way to also provide modifications to an existing rule. One technique for modifying an existing rule is to fetch the rule, make modifications and re-run the playbook. To do this, there are helper jinja templates that will write the output to a specified filename and can also be added to the task.
Exporting a firewall rule into YAML using templates:
Below is a full example that builds on the previous where you can optionally export the content into valid YML format, modify as necessary and re-run the playbook.
Templates are provided in the playbooks/templates directory.
- name: Get firewall rule as yaml
register: results
firewall_rule_facts:
smc_logging:
level: 10
path: ansible-smc.log
filter: TestPolicy
search: rulet
as_yaml: true
expand:
- services
- destinations
- sources
- name: Write the yaml using a jinja template
template: src=templates/facts_yaml.j2 dest=./firewall_rules_test.yml
vars:
playbook: firewall_rule
For details on supported options for playbook runs, see the Fact and Module documentation.