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,18 @@
---
# ============================================================================
# Sophos Common Role - Default Variables
# ============================================================================
# These are default values that can be overridden in group_vars or host_vars.
# ============================================================================
# API connection defaults
sophos_mgmt_port: 4444
sophos_validate_certs: false
sophos_api_timeout: 30
# Retry settings
sophos_api_retries: 3
sophos_api_retry_delay: 5
# Security settings
sophos_no_log_sensitive: true

View File

@@ -0,0 +1,130 @@
---
# ============================================================================
# Sophos Common Role - Main Tasks
# ============================================================================
# This role performs common setup tasks for all Sophos XGS firewalls:
# - Validates required variables
# - Tests API connectivity
# - Authenticates to the firewall
# - Gathers basic system facts
#
# This role should always run first before other configuration roles.
# ============================================================================
- name: Validate required variables are defined
ansible.builtin.assert:
that:
- sophos_mgmt_host is defined
- sophos_mgmt_host | length > 0
- sophos_mgmt_port is defined
- (sophos_api_key is defined) or (sophos_api_username is defined and sophos_api_password is defined)
fail_msg: |
Required variables are missing for {{ inventory_hostname }}.
Please ensure the following are defined in host_vars:
- sophos_mgmt_host (management IP or hostname)
- sophos_mgmt_port (API port, default 4444)
- Authentication: either sophos_api_key OR (sophos_api_username AND sophos_api_password)
success_msg: "All required variables are defined for {{ inventory_hostname }}"
tags: ['validation']
- name: Display firewall connection information
ansible.builtin.debug:
msg:
- "Connecting to Sophos XGS Firewall:"
- " Hostname: {{ inventory_hostname }}"
- " Management IP: {{ sophos_mgmt_host }}"
- " API Port: {{ sophos_mgmt_port }}"
- " Auth Method: {{ 'API Key' if sophos_api_key is defined else 'Username/Password' }}"
- " Validate Certs: {{ sophos_validate_certs }}"
tags: ['always']
# ============================================================================
# Test API connectivity
# ============================================================================
- name: Test HTTPS connectivity to Sophos XGS API
ansible.builtin.wait_for:
host: "{{ sophos_mgmt_host }}"
port: "{{ sophos_mgmt_port }}"
timeout: 10
state: started
delegate_to: localhost
tags: ['validation', 'connectivity']
- name: Display connectivity success
ansible.builtin.debug:
msg: "Successfully connected to {{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}"
tags: ['validation', 'connectivity']
# ============================================================================
# Authenticate and gather system information
# ============================================================================
- name: Authenticate to Sophos XGS firewall and retrieve system status
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><System/></Get></Request>"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
register: sophos_system_info
no_log: "{{ sophos_no_log_sensitive }}"
retries: "{{ sophos_api_retries }}"
delay: "{{ sophos_api_retry_delay }}"
tags: ['authentication', 'facts']
- name: Parse system information from API response
ansible.builtin.set_fact:
sophos_facts:
hostname: "{{ sophos_system_info.content | regex_search('<HostName>(.*?)</HostName>', '\\1') | first | default('unknown') }}"
serial_number: "{{ sophos_system_info.content | regex_search('<SerialNumber>(.*?)</SerialNumber>', '\\1') | first | default('unknown') }}"
firmware_version: "{{ sophos_system_info.content | regex_search('<FirmwareVersion>(.*?)</FirmwareVersion>', '\\1') | first | default('unknown') }}"
device_model: "{{ sophos_system_info.content | regex_search('<ApplianceModel>(.*?)</ApplianceModel>', '\\1') | first | default('unknown') }}"
uptime_days: "{{ sophos_system_info.content | regex_search('<Uptime>(.*?)</Uptime>', '\\1') | first | default('0') }}"
tags: ['facts']
- name: Display Sophos XGS system information
ansible.builtin.debug:
msg:
- "======================================"
- "Sophos XGS System Information"
- "======================================"
- "Hostname: {{ sophos_facts.hostname }}"
- "Model: {{ sophos_facts.device_model }}"
- "Serial Number: {{ sophos_facts.serial_number }}"
- "Firmware Version: {{ sophos_facts.firmware_version }}"
- "Uptime: {{ sophos_facts.uptime_days }} days"
tags: ['facts']
# ============================================================================
# Check firmware version compatibility (optional warning)
# ============================================================================
- name: Check if firmware version is recent
ansible.builtin.debug:
msg: "WARNING: This automation was tested with firmware version 19.x and 20.x. Current version: {{ sophos_facts.firmware_version }}"
when:
- sophos_facts.firmware_version is defined
- not sophos_facts.firmware_version is match('^(19|20)\.')
tags: ['validation']
# ============================================================================
# Store authentication token for subsequent API calls (if using token-based auth)
# ============================================================================
- name: Store API authentication credentials for use in other roles
ansible.builtin.set_fact:
sophos_api_auth_header: "{{ sophos_api_key | default('') }}"
sophos_api_credentials:
username: "{{ sophos_api_username | default('') }}"
password: "{{ sophos_api_password | default('') }}"
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['authentication']
- name: Common role tasks completed successfully
ansible.builtin.debug:
msg: "Sophos common role completed for {{ inventory_hostname }}"
tags: ['always']

View File

@@ -0,0 +1,30 @@
---
# ============================================================================
# Sophos Common Role - Internal Variables
# ============================================================================
# These variables are internal to the role and should not be overridden.
# ============================================================================
# API endpoint paths (Sophos XGS XML API)
sophos_api_base_path: "/webconsole/APIController"
# XML API request wrapper template
sophos_api_request_template: |
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
{{ api_request_body }}
</Request>
# Supported firmware versions (for validation)
sophos_supported_firmware_versions:
- "19.0"
- "19.5"
- "20.0"
# Default HTTP headers for API requests
sophos_api_default_headers:
Content-Type: "application/x-www-form-urlencoded"
Accept: "application/xml"

View File

@@ -0,0 +1,3 @@
---
# Default device access settings
sophos_default_device_access_enabled: true

View File

@@ -0,0 +1,35 @@
---
# ============================================================================
# Sophos Device Access Role - Main Tasks
# ============================================================================
- name: Display device access configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Device Access Policies"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Policies: {{ sophos_common_device_access_policies | default([]) | length }}"
tags: ['always']
- name: Configure device access policies
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', 'device_access_rule.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_common_device_access_policies | default([]) }}"
loop_control:
label: "{{ item.service }}"
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['device-access']
- name: Device access configuration completed
ansible.builtin.debug:
msg: "Device access policies configured successfully"
tags: ['always']

View File

@@ -0,0 +1,24 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="update">
<DeviceAccess>
<Service>{{ item.service | upper }}</Service>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
<AllowedZones>
{% for zone in item.allowed_zones %}
<Zone>{{ zone }}</Zone>
{% endfor %}
</AllowedZones>
{% if item.allowed_networks is defined and item.allowed_networks | length > 0 %}
<AllowedNetworks>
{% for network in item.allowed_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</AllowedNetworks>
{% endif %}
</DeviceAccess>
</Set>
</Request>

View File

@@ -0,0 +1,4 @@
---
# Default firewall rule action
sophos_default_rule_action: "deny"
sophos_default_rule_log: true

View File

@@ -0,0 +1,61 @@
---
# ============================================================================
# Sophos Firewall Rules Role - Main Tasks
# ============================================================================
- name: Display firewall rules configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Firewall Rules"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Common Rules: {{ sophos_common_firewall_rules | default([]) | length }}"
- "Custom Rules: {{ sophos_firewall_rules | default([]) | length }}"
tags: ['always']
- name: Get current firewall rules 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><FirewallRule/></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_firewall_rules
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['rules']
- name: Parse current firewall rule names
ansible.builtin.set_fact:
existing_firewall_rules: "{{ current_firewall_rules.content | regex_findall('<Name>(.*?)</Name>') }}"
tags: ['rules']
- name: Combine common and custom firewall rules
ansible.builtin.set_fact:
all_firewall_rules: "{{ sophos_common_firewall_rules | default([]) + sophos_firewall_rules | default([]) }}"
tags: ['rules']
- name: Configure firewall rule {{ 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', 'firewall_rule.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ all_firewall_rules }}"
loop_control:
label: "{{ item.name }}"
register: fw_rule_result
no_log: "{{ sophos_no_log_sensitive }}"
changed_when: "'successful' in fw_rule_result.content | lower"
tags: ['rules']
- name: Firewall rules configuration completed
ansible.builtin.debug:
msg: "Configured {{ all_firewall_rules | length }} firewall rules successfully"
tags: ['always']

View File

@@ -0,0 +1,43 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_firewall_rules %}update{% else %}add{% endif %}">
<FirewallRule>
<Name>{{ item.name }}</Name>
<Description>{{ item.description | default('') }}</Description>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
<Action>{{ item.action | upper }}</Action>
<LogTraffic>{{ 'Enable' if item.log | default(false) else 'Disable' }}</LogTraffic>
<SourceZones>
{% for zone in item.source_zones %}
<Zone>{{ zone }}</Zone>
{% endfor %}
</SourceZones>
<DestinationZones>
{% for zone in item.dest_zones %}
<Zone>{{ zone }}</Zone>
{% endfor %}
</DestinationZones>
<SourceNetworks>
{% for network in item.source_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</SourceNetworks>
<DestinationNetworks>
{% for network in item.dest_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</DestinationNetworks>
<Services>
{% for service in item.services %}
<Service>{{ service }}</Service>
{% endfor %}
</Services>
{% if item.position is defined %}
<Position>{{ item.position }}</Position>
{% endif %}
</FirewallRule>
</Set>
</Request>

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>

View File

@@ -0,0 +1,4 @@
---
# Default SNMP and logging settings
sophos_default_snmp_enabled: false
sophos_default_logging_enabled: true

View File

@@ -0,0 +1,68 @@
---
# ============================================================================
# Sophos SNMP and Logging Role - Main Tasks
# ============================================================================
- name: Display SNMP and logging configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring SNMP and Logging"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "SNMP Enabled: {{ sophos_snmp.enabled | default(false) }}"
- "Syslog Servers: {{ sophos_logging.syslog_servers | default([]) | length }}"
tags: ['always']
# Configure SNMP
- name: Configure SNMP 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', 'snmp_config.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
when: sophos_snmp is defined
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['snmp']
# Configure Syslog
- name: Configure syslog servers
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', 'syslog_server.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_logging.syslog_servers | default([]) }}"
loop_control:
label: "{{ item.host }}"
when: sophos_logging is defined
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['logging', 'syslog']
# Configure NTP
- name: Configure NTP 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', 'ntp_config.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
when: sophos_ntp is defined
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['ntp']
- name: SNMP and logging configuration completed
ansible.builtin.debug:
msg: "SNMP, logging, and NTP configured successfully"
tags: ['always']

View File

@@ -0,0 +1,16 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="update">
<NTP>
<Servers>
{% for server in sophos_ntp.servers %}
<Server>{{ server }}</Server>
{% endfor %}
</Servers>
<Timezone>{{ sophos_ntp.timezone | default('UTC') }}</Timezone>
</NTP>
</Set>
</Request>

View File

@@ -0,0 +1,35 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="update">
<SNMP>
<Status>{{ 'Enable' if sophos_snmp.enabled | default(false) else 'Disable' }}</Status>
<Version>{{ sophos_snmp.version | default('v2c') }}</Version>
{% if sophos_snmp.version | default('v2c') == 'v2c' %}
<Community>{{ sophos_snmp.community }}</Community>
{% endif %}
<Location>{{ sophos_snmp.location | default('') }}</Location>
<Contact>{{ sophos_snmp.contact | default('') }}</Contact>
{% if sophos_snmp.allowed_networks is defined %}
<AllowedNetworks>
{% for network in sophos_snmp.allowed_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</AllowedNetworks>
{% endif %}
{% if sophos_snmp.trap_destinations is defined %}
<TrapDestinations>
{% for trap in sophos_snmp.trap_destinations %}
<Destination>
<Host>{{ trap.host }}</Host>
<Port>{{ trap.port | default(162) }}</Port>
<Community>{{ trap.community }}</Community>
</Destination>
{% endfor %}
</TrapDestinations>
{% endif %}
</SNMP>
</Set>
</Request>

View File

@@ -0,0 +1,15 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="add">
<SyslogServer>
<Host>{{ item.host }}</Host>
<Port>{{ item.port | default(514) }}</Port>
<Protocol>{{ item.protocol | default('udp') | upper }}</Protocol>
<Facility>{{ item.facility | default('local0') }}</Facility>
<Severity>{{ item.severity | default('informational') }}</Severity>
</SyslogServer>
</Set>
</Request>

View File

@@ -0,0 +1,5 @@
---
# Default remote access VPN settings
sophos_default_remote_vpn_port: 443
sophos_default_remote_vpn_encryption: "aes256"
sophos_default_remote_vpn_hash: "sha256"

View File

@@ -0,0 +1,43 @@
---
# ============================================================================
# Sophos Remote Access VPN Role - Main Tasks
# ============================================================================
- name: Display remote access VPN configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Remote Access VPN"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Type: {{ sophos_remote_access_vpn.type | default('Not configured') }}"
tags: ['always']
when: sophos_remote_access_vpn is defined
- name: Skip remote access VPN configuration (not defined)
ansible.builtin.debug:
msg: "No remote access VPN configuration defined for {{ inventory_hostname }}"
when: sophos_remote_access_vpn is not defined
tags: ['always']
- name: Configure remote access VPN
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', 'remote_access_vpn.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
register: remote_vpn_result
no_log: "{{ sophos_no_log_sensitive }}"
when: sophos_remote_access_vpn is defined
changed_when: "'successful' in remote_vpn_result.content | lower"
tags: ['vpn', 'remote-access']
- name: Remote access VPN configuration completed
ansible.builtin.debug:
msg: "Remote access VPN configured successfully"
when: sophos_remote_access_vpn is defined
tags: ['always']

View File

@@ -0,0 +1,63 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="update">
<RemoteAccessVPN>
<Name>{{ sophos_remote_access_vpn.name | default('Remote-Access-VPN') }}</Name>
<Status>{{ 'Enable' if sophos_remote_access_vpn.enabled | default(true) else 'Disable' }}</Status>
<Type>{{ sophos_remote_access_vpn.type | upper }}</Type>
<!-- Connection Settings -->
<ListeningPort>{{ sophos_remote_access_vpn.listening_port | default(443) }}</ListeningPort>
<ListeningInterface>{{ sophos_remote_access_vpn.listening_interface }}</ListeningInterface>
<!-- Authentication -->
<AuthenticationMethod>{{ sophos_remote_access_vpn.authentication_method | default('local') }}</AuthenticationMethod>
<UserGroups>
{% for group in sophos_remote_access_vpn.user_groups %}
<Group>{{ group }}</Group>
{% endfor %}
</UserGroups>
<!-- IP Address Pool -->
<AddressPool>
<Network>{{ sophos_remote_access_vpn.address_pool.network }}</Network>
<Netmask>{{ sophos_remote_access_vpn.address_pool.netmask }}</Netmask>
<StartIP>{{ sophos_remote_access_vpn.address_pool.start_ip }}</StartIP>
<EndIP>{{ sophos_remote_access_vpn.address_pool.end_ip }}</EndIP>
</AddressPool>
<!-- DNS Settings -->
<DNSServers>
{% for dns in sophos_remote_access_vpn.dns_servers %}
<Server>{{ dns }}</Server>
{% endfor %}
</DNSServers>
<!-- Tunnel Mode -->
<TunnelMode>{{ sophos_remote_access_vpn.tunnel_mode | default('split') }}</TunnelMode>
{% if sophos_remote_access_vpn.tunnel_mode | default('split') == 'split' %}
<TunnelNetworks>
{% for network in sophos_remote_access_vpn.tunnel_networks | default([]) %}
<Network>{{ network }}</Network>
{% endfor %}
</TunnelNetworks>
{% endif %}
<!-- Encryption -->
<Encryption>{{ sophos_remote_access_vpn.encryption | default('aes256') }}</Encryption>
<Hash>{{ sophos_remote_access_vpn.hash | default('sha256') }}</Hash>
<!-- Timeouts -->
<IdleTimeout>{{ sophos_remote_access_vpn.idle_timeout | default(1800) }}</IdleTimeout>
<SessionTimeout>{{ sophos_remote_access_vpn.session_timeout | default(43200) }}</SessionTimeout>
<!-- Advanced Settings -->
<MaxConnections>{{ sophos_remote_access_vpn.max_concurrent_connections | default(50) }}</MaxConnections>
<Compression>{{ 'Enable' if sophos_remote_access_vpn.enable_compression | default(true) else 'Disable' }}</Compression>
<BlockLANAccess>{{ 'Enable' if sophos_remote_access_vpn.block_lan_access | default(true) else 'Disable' }}</BlockLANAccess>
</RemoteAccessVPN>
</Set>
</Request>

View File

@@ -0,0 +1,11 @@
---
# Default VPN encryption settings
sophos_default_ike_encryption: "aes256"
sophos_default_ike_hash: "sha256"
sophos_default_ike_dh_group: 14
sophos_default_ike_lifetime: 28800
sophos_default_ipsec_encryption: "aes256"
sophos_default_ipsec_hash: "sha256"
sophos_default_ipsec_pfs_group: 14
sophos_default_ipsec_lifetime: 3600

View File

@@ -0,0 +1,66 @@
---
# ============================================================================
# Sophos Site-to-Site VPN Role - Main Tasks
# ============================================================================
- name: Display site-to-site VPN configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Site-to-Site VPN Tunnels"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Tunnels: {{ sophos_site_to_site_vpns | default([]) | length }}"
tags: ['always']
when: sophos_site_to_site_vpns is defined
- name: Skip site-to-site VPN configuration (not defined)
ansible.builtin.debug:
msg: "No site-to-site VPN tunnels defined for {{ inventory_hostname }}"
when: sophos_site_to_site_vpns is not defined or sophos_site_to_site_vpns | length == 0
tags: ['always']
- name: Get current IPsec connections 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><IPSecConnection/></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_ipsec_connections
no_log: "{{ sophos_no_log_sensitive }}"
when: sophos_site_to_site_vpns is defined and sophos_site_to_site_vpns | length > 0
tags: ['vpn', 'site-to-site']
- name: Parse current IPsec connection names
ansible.builtin.set_fact:
existing_ipsec_connections: "{{ current_ipsec_connections.content | regex_findall('<Name>(.*?)</Name>') }}"
when: sophos_site_to_site_vpns is defined and sophos_site_to_site_vpns | length > 0
tags: ['vpn', 'site-to-site']
- name: Configure site-to-site VPN tunnel {{ 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', 'ipsec_connection.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_site_to_site_vpns }}"
loop_control:
label: "{{ item.name }} ({{ item.local_gateway }} <-> {{ item.remote_gateway }})"
register: vpn_result
no_log: "{{ sophos_no_log_sensitive }}"
when: sophos_site_to_site_vpns is defined and sophos_site_to_site_vpns | length > 0
changed_when: "'successful' in vpn_result.content | lower"
tags: ['vpn', 'site-to-site']
- name: Site-to-site VPN configuration completed
ansible.builtin.debug:
msg: "Configured {{ sophos_site_to_site_vpns | length }} site-to-site VPN tunnels successfully"
when: sophos_site_to_site_vpns is defined and sophos_site_to_site_vpns | length > 0
tags: ['always']

View File

@@ -0,0 +1,58 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="{% if item.name in existing_ipsec_connections | default([]) %}update{% else %}add{% endif %}">
<IPSecConnection>
<Name>{{ item.name }}</Name>
<Description>{{ item.description | default('') }}</Description>
<Status>{{ 'Enable' if item.enabled | default(true) else 'Disable' }}</Status>
<ConnectionType>{{ item.connection_type | default('tunnel') }}</ConnectionType>
<!-- Local Settings -->
<LocalGateway>{{ item.local_gateway }}</LocalGateway>
<LocalID>{{ item.local_id | default(item.local_gateway) }}</LocalID>
<LocalNetworks>
{% for network in item.local_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</LocalNetworks>
<!-- Remote Settings -->
<RemoteGateway>{{ item.remote_gateway }}</RemoteGateway>
<RemoteID>{{ item.remote_id | default(item.remote_gateway) }}</RemoteID>
<RemoteNetworks>
{% for network in item.remote_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</RemoteNetworks>
<!-- Phase 1 (IKE) Settings -->
<IKEVersion>{{ item.ike_version | default(2) }}</IKEVersion>
<IKEEncryption>{{ item.ike_encryption | default(sophos_default_ike_encryption) }}</IKEEncryption>
<IKEHash>{{ item.ike_hash | default(sophos_default_ike_hash) }}</IKEHash>
<IKEDHGroup>{{ item.ike_dh_group | default(sophos_default_ike_dh_group) }}</IKEDHGroup>
<IKELifetime>{{ item.ike_lifetime | default(sophos_default_ike_lifetime) }}</IKELifetime>
<!-- Authentication -->
<AuthenticationMethod>{{ item.authentication_method | default('psk') }}</AuthenticationMethod>
{% if item.authentication_method | default('psk') == 'psk' %}
<PreSharedKey>{{ item.psk }}</PreSharedKey>
{% endif %}
<!-- Phase 2 (IPsec) Settings -->
<IPSecMode>{{ item.ipsec_mode | default('tunnel') }}</IPSecMode>
<IPSecEncryption>{{ item.ipsec_encryption | default(sophos_default_ipsec_encryption) }}</IPSecEncryption>
<IPSecHash>{{ item.ipsec_hash | default(sophos_default_ipsec_hash) }}</IPSecHash>
<IPSecPFSGroup>{{ item.ipsec_pfs_group | default(sophos_default_ipsec_pfs_group) }}</IPSecPFSGroup>
<IPSecLifetime>{{ item.ipsec_lifetime | default(sophos_default_ipsec_lifetime) }}</IPSecLifetime>
<!-- Advanced Settings -->
<DPDEnabled>{{ 'Enable' if item.dpd_enabled | default(true) else 'Disable' }}</DPDEnabled>
<DPDInterval>{{ item.dpd_interval | default(30) }}</DPDInterval>
<DPDRetries>{{ item.dpd_retries | default(3) }}</DPDRetries>
<NATTraversal>{{ 'Enable' if item.nat_traversal | default(true) else 'Disable' }}</NATTraversal>
</IPSecConnection>
</Set>
</Request>

View File

@@ -0,0 +1,4 @@
---
# Default WAF settings
sophos_default_waf_mode: "prevention"
sophos_default_waf_session_timeout: 1800

View File

@@ -0,0 +1,90 @@
---
# ============================================================================
# Sophos WAF Role - Main Tasks
# ============================================================================
- name: Display WAF configuration overview
ansible.builtin.debug:
msg:
- "======================================"
- "Configuring Web Application Firewall"
- "======================================"
- "Firewall: {{ inventory_hostname }}"
- "Backends: {{ sophos_waf_backends | default([]) | length }}"
- "Policies: {{ sophos_waf_policies | default([]) | length }}"
- "Virtual Hosts: {{ sophos_waf_virtual_hosts | default([]) | length }}"
- "Exceptions: {{ sophos_waf_exceptions | default([]) | length }}"
tags: ['always']
- name: Configure WAF backend servers
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', 'waf_backend.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_waf_backends | default([]) }}"
loop_control:
label: "{{ item.name }}"
when: sophos_waf_backends is defined and sophos_waf_backends | length > 0
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['waf', 'backends']
- name: Configure WAF protection policies
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', 'waf_policy.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_waf_policies | default([]) }}"
loop_control:
label: "{{ item.name }}"
when: sophos_waf_policies is defined and sophos_waf_policies | length > 0
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['waf', 'policies']
- name: Configure WAF virtual hosts
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', 'waf_policy.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_waf_virtual_hosts | default([]) }}"
loop_control:
label: "{{ item.name }} ({{ item.domain }})"
when: sophos_waf_virtual_hosts is defined and sophos_waf_virtual_hosts | length > 0
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['waf', 'virtual-hosts']
- name: Configure WAF exceptions
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', 'waf_exception.json.j2') | urlencode }}"
status_code: [200, 201]
timeout: "{{ sophos_api_timeout }}"
loop: "{{ sophos_waf_exceptions | default([]) }}"
loop_control:
label: "{{ item.name }}"
when: sophos_waf_exceptions is defined and sophos_waf_exceptions | length > 0
no_log: "{{ sophos_no_log_sensitive }}"
tags: ['waf', 'exceptions']
- name: WAF configuration completed
ansible.builtin.debug:
msg: "Web Application Firewall configured successfully"
tags: ['always']

View File

@@ -0,0 +1,15 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="add">
<WebServer>
<Name>{{ item.name }}</Name>
<Host>{{ item.host }}</Host>
<Port>{{ item.port }}</Port>
<Protocol>{{ item.protocol | upper }}</Protocol>
<HealthCheck>{{ 'Enable' if item.health_check | default(true) else 'Disable' }}</HealthCheck>
</WebServer>
</Set>
</Request>

View File

@@ -0,0 +1,24 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="add">
<WebException>
<Name>{{ item.name }}</Name>
<VirtualHost>{{ item.virtual_host }}</VirtualHost>
<Path>{{ item.path }}</Path>
<SkipRules>
{% for rule in item.skip_rules %}
<Rule>{{ rule }}</Rule>
{% endfor %}
</SkipRules>
<SourceNetworks>
{% for network in item.source_networks %}
<Network>{{ network }}</Network>
{% endfor %}
</SourceNetworks>
<Comment>{{ item.comment | default('') }}</Comment>
</WebException>
</Set>
</Request>

View File

@@ -0,0 +1,31 @@
<Request>
<Login>
<Username>{{ sophos_api_username }}</Username>
<Password>{{ sophos_api_password }}</Password>
</Login>
<Set operation="add">
<WebPolicy>
<Name>{{ item.name }}</Name>
<Domain>{{ item.domain }}</Domain>
<ListeningIP>{{ item.listening_ip }}</ListeningIP>
<ListeningPort>{{ item.listening_port }}</ListeningPort>
<Protocol>{{ item.protocol | upper }}</Protocol>
{% if item.ssl_certificate is defined %}
<SSLCertificate>{{ item.ssl_certificate }}</SSLCertificate>
{% endif %}
<BackendServers>
{% for backend in item.backend_servers %}
<Server>{{ backend }}</Server>
{% endfor %}
</BackendServers>
<LoadBalancing>{{ item.load_balancing | default('round-robin') }}</LoadBalancing>
<ProtectionPolicy>{{ item.protection_policy }}</ProtectionPolicy>
<SessionTimeout>{{ item.session_timeout | default(1800) }}</SessionTimeout>
<HSTS>{{ 'Enable' if item.enable_hsts | default(false) else 'Disable' }}</HSTS>
<Compression>{{ 'Enable' if item.enable_compression | default(false) else 'Disable' }}</Compression>
{% if item.websocket_support is defined %}
<WebSocketSupport>{{ 'Enable' if item.websocket_support else 'Disable' }}</WebSocketSupport>
{% endif %}
</WebPolicy>
</Set>
</Request>