This commit is contained in:
Jake Kasper
2025-12-09 09:33:48 -06:00
parent 228174e541
commit 4f1e8d3add
55 changed files with 4345 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
---
# ============================================================================
# Sophos Network Role - Default Variables
# ============================================================================
# Default MTU for interfaces
sophos_default_mtu: 1500
# Default interface state
sophos_default_interface_enabled: true
# Default DHCP lease time (seconds)
sophos_default_dhcp_lease_time: 86400 # 24 hours

View File

@@ -0,0 +1,52 @@
---
# ============================================================================
# Configure DHCP Servers
# ============================================================================
- name: Get current DHCP server configuration from firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><DHCPServer/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: current_dhcp_servers
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['dhcp']
- name: Parse current DHCP server names
ansible.builtin.set_fact:
existing_dhcp_servers: "{{ current_dhcp_servers.content | regex_findall('<Name>(.*?)</Name>') }}"
tags: ['dhcp']
- name: Display existing DHCP servers
ansible.builtin.debug:
msg: "Found {{ existing_dhcp_servers | length }} existing DHCP servers: {{ existing_dhcp_servers | join(', ') }}"
tags: ['dhcp']
# Loop through each DHCP server and configure it
- name: Configure DHCP server {{ item.name }}
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
body: "reqxml={{ lookup('template', 'dhcp_server.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_dhcp_servers }}"
loop_control:
label: "{{ item.name }} ({{ item.interface }})"
register: dhcp_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in dhcp_result.content | lower or '200' in dhcp_result.content"
failed_when: "'error' in dhcp_result.content | lower"
tags: ['dhcp']
- name: Display DHCP server configuration results
ansible.builtin.debug:
msg: "Configured {{ sophos_dhcp_servers | length }} DHCP servers successfully"
tags: ['dhcp']

View File

@@ -0,0 +1,43 @@
---
# ============================================================================
# Configure DNS Settings
# ============================================================================
- name: Get current DNS configuration from firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><DNS/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: current_dns_config
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['dns']
- name: Display current DNS forwarders
ansible.builtin.debug:
msg: "Current DNS configuration retrieved"
tags: ['dns']
- name: Configure DNS settings
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
body: "reqxml={{ lookup('template', 'dns_config.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
register: dns_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in dns_result.content | lower or '200' in dns_result.content"
failed_when: "'error' in dns_result.content | lower"
tags: ['dns']
- name: Display DNS configuration result
ansible.builtin.debug:
msg: "DNS configuration applied successfully"
tags: ['dns']

View File

@@ -0,0 +1,52 @@
---
# ============================================================================
# Configure Physical Interfaces
# ============================================================================
- name: Get current interface configuration from firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><Interface/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: current_interfaces
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['interfaces']
- name: Parse current interface names
ansible.builtin.set_fact:
existing_interfaces: "{{ current_interfaces.content | regex_findall('<Name>(.*?)</Name>') }}"
tags: ['interfaces']
- name: Display existing interfaces
ansible.builtin.debug:
msg: "Found {{ existing_interfaces | length }} existing interfaces: {{ existing_interfaces | join(', ') }}"
tags: ['interfaces']
# Loop through each interface and configure it
- name: Configure physical interface {{ item.name }}
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
body: "reqxml={{ lookup('template', 'interface.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_interfaces }}"
loop_control:
label: "{{ item.name }} ({{ item.zone }})"
register: interface_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in interface_result.content | lower or '200' in interface_result.content"
failed_when: "'error' in interface_result.content | lower"
tags: ['interfaces']
- name: Display interface configuration results
ansible.builtin.debug:
msg: "Configured {{ sophos_interfaces | length }} interfaces successfully"
tags: ['interfaces']

View File

@@ -0,0 +1,83 @@
---
# ============================================================================
# Sophos Network Role - Main Tasks
# ============================================================================
# This role configures all network-related settings on Sophos XGS firewalls:
# - Physical interfaces
# - VLAN interfaces
# - DHCP servers
# - DNS configuration
# - Static routes
# ============================================================================
- name: Display network configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Network Settings"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Interfaces: {{ sophos_interfaces | default([]) | length }}"
- "VLANs: {{ sophos_vlans | default([]) | length }}"
- "DHCP Servers: {{ sophos_dhcp_servers | default([]) | length }}"
- "Static Routes: {{ sophos_static_routes | default([]) | length }}"
tags: ['always']
# ============================================================================
# Configure Physical Interfaces
# ============================================================================
- name: Configure physical interfaces
ansible.builtin.include_tasks: interfaces.yml
when: sophos_interfaces is defined and sophos_interfaces | length > 0
tags: ['interfaces']
# ============================================================================
# Configure VLAN Interfaces
# ============================================================================
- name: Configure VLAN interfaces
ansible.builtin.include_tasks: vlans.yml
when: sophos_vlans is defined and sophos_vlans | length > 0
tags: ['vlans']
# ============================================================================
# Configure DHCP Servers
# ============================================================================
- name: Configure DHCP servers
ansible.builtin.include_tasks: dhcp.yml
when: sophos_dhcp_servers is defined and sophos_dhcp_servers | length > 0
tags: ['dhcp']
# ============================================================================
# Configure DNS Settings
# ============================================================================
- name: Configure DNS settings
ansible.builtin.include_tasks: dns.yml
when: sophos_dns is defined
tags: ['dns']
# ============================================================================
# Configure Static Routes
# ============================================================================
- name: Configure static routes
ansible.builtin.include_tasks: routes.yml
when: sophos_static_routes is defined and sophos_static_routes | length > 0
tags: ['routes']
# ============================================================================
# Summary
# ============================================================================
- name: Network configuration completed
ansible.builtin.debug:
msg:
- "======================================"
- "Network Configuration Complete"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "All network settings have been applied."
tags: ['always']

View File

@@ -0,0 +1,52 @@
---
# ============================================================================
# Configure Static Routes
# ============================================================================
- name: Get current static route configuration from firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><StaticRoute/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: current_routes
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['routes']
- name: Parse current route names
ansible.builtin.set_fact:
existing_routes: "{{ current_routes.content | regex_findall('<Name>(.*?)</Name>') }}"
tags: ['routes']
- name: Display existing static routes
ansible.builtin.debug:
msg: "Found {{ existing_routes | length }} existing static routes: {{ existing_routes | join(', ') }}"
tags: ['routes']
# Loop through each static route and configure it
- name: Configure static route {{ item.name }}
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
body: "reqxml={{ lookup('template', 'static_route.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_static_routes }}"
loop_control:
label: "{{ item.name }} ({{ item.destination }}/{{ item.netmask }} via {{ item.gateway }})"
register: route_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in route_result.content | lower or '200' in route_result.content"
failed_when: "'error' in route_result.content | lower"
tags: ['routes']
- name: Display static route configuration results
ansible.builtin.debug:
msg: "Configured {{ sophos_static_routes | length }} static routes successfully"
tags: ['routes']

View File

@@ -0,0 +1,52 @@
---
# ============================================================================
# Configure VLAN Interfaces
# ============================================================================
- name: Get current VLAN configuration from firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><VLANInterface/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: current_vlans
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['vlans']
- name: Parse current VLAN names
ansible.builtin.set_fact:
existing_vlans: "{{ current_vlans.content | regex_findall('<Name>(.*?)</Name>') }}"
tags: ['vlans']
- name: Display existing VLANs
ansible.builtin.debug:
msg: "Found {{ existing_vlans | length }} existing VLANs: {{ existing_vlans | join(', ') }}"
tags: ['vlans']
# Loop through each VLAN and configure it
- name: Configure VLAN interface {{ item.name }}
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
body: "reqxml={{ lookup('template', 'vlan.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_vlans }}"
loop_control:
label: "{{ item.name }} (VLAN {{ item.vlan_id }})"
register: vlan_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in vlan_result.content | lower or '200' in vlan_result.content"
failed_when: "'error' in vlan_result.content | lower"
tags: ['vlans']
- name: Display VLAN configuration results
ansible.builtin.debug:
msg: "Configured {{ sophos_vlans | length }} VLANs successfully"
tags: ['vlans']

View File

@@ -0,0 +1,47 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_dhcp_servers %}update{% else %}add{% endif %}">
<DHCPServer>
<Name>{{ item.name }}</Name>
<Interface>{{ item.interface }}</Interface>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
<StartIPAddress>{{ item.start_ip }}</StartIPAddress>
<EndIPAddress>{{ item.end_ip }}</EndIPAddress>
<Netmask>{{ item.netmask }}</Netmask>
<Gateway>{{ item.gateway }}</Gateway>
<DNSServers>
{% for dns in item.dns_servers %}
<Server>{{ dns }}</Server>
{% endfor %}
</DNSServers>
{% if item.domain is defined %}
<DomainName>{{ item.domain }}</DomainName>
{% endif %}
<LeaseTime>{{ item.lease_time | default(86400) }}</LeaseTime>
{% if item.reservations is defined and item.reservations | length > 0 %}
<Reservations>
{% for reservation in item.reservations %}
<Reservation>
<MACAddress>{{ reservation.mac_address }}</MACAddress>
<IPAddress>{{ reservation.ip_address }}</IPAddress>
<Hostname>{{ reservation.hostname | default('') }}</Hostname>
</Reservation>
{% endfor %}
</Reservations>
{% endif %}
{% if item.dhcp_options is defined and item.dhcp_options | length > 0 %}
<DHCPOptions>
{% for option in item.dhcp_options %}
<Option>
<Code>{{ option.option }}</Code>
<Value>{{ option.value }}</Value>
</Option>
{% endfor %}
</DHCPOptions>
{% endif %}
</DHCPServer>
</Set>
</Request>

View File

@@ -0,0 +1,19 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="update">
<DNS>
<Forwarders>
{% for forwarder in sophos_dns.forwarders %}
<Server>{{ forwarder }}</Server>
{% endfor %}
</Forwarders>
{% if sophos_dns.domain is defined %}
<DomainName>{{ sophos_dns.domain }}</DomainName>
{% endif %}
<DNSForwarder>{{ 'Enable' if sophos_dns.enable_dns_forwarder | default(true) else 'Disable' }}</DNSForwarder>
</DNS>
</Set>
</Request>

View File

@@ -0,0 +1,25 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_interfaces %}update{% else %}add{% endif %}">
<Interface>
<Name>{{ item.name }}</Name>
<Description>{{ item.description | default('') }}</Description>
<Zone>{{ item.zone }}</Zone>
<Type>{{ item.type | default('physical') }}</Type>
{% if item.mode == 'static' %}
<IPAddress>{{ item.ip_address }}</IPAddress>
<Netmask>{{ item.netmask }}</Netmask>
{% if item.gateway is defined %}
<Gateway>{{ item.gateway }}</Gateway>
{% endif %}
{% elif item.mode == 'dhcp' %}
<DHCPMode>Enable</DHCPMode>
{% endif %}
<MTU>{{ item.mtu | default(sophos_default_mtu) }}</MTU>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
</Interface>
</Set>
</Request>

View File

@@ -0,0 +1,19 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_routes %}update{% else %}add{% endif %}">
<StaticRoute>
<Name>{{ item.name }}</Name>
<Destination>{{ item.destination }}</Destination>
<Netmask>{{ item.netmask }}</Netmask>
<Gateway>{{ item.gateway }}</Gateway>
{% if item.interface is defined %}
<Interface>{{ item.interface }}</Interface>
{% endif %}
<Metric>{{ item.metric | default(10) }}</Metric>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
</StaticRoute>
</Set>
</Request>

View File

@@ -0,0 +1,18 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_vlans %}update{% else %}add{% endif %}">
<VLANInterface>
<Name>{{ item.name }}</Name>
<Description>{{ item.description | default('') }}</Description>
<VLANID>{{ item.vlan_id }}</VLANID>
<ParentInterface>{{ item.parent_interface }}</ParentInterface>
<Zone>{{ item.zone }}</Zone>
<IPAddress>{{ item.ip_address }}</IPAddress>
<Netmask>{{ item.netmask }}</Netmask>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
</VLANInterface>
</Set>
</Request>