---
# ============================================================================
# Sophos XGS Firewall Baseline Import Playbook
# ============================================================================
# This playbook connects to the designated baseline Sophos XGS firewall
# and exports its current web application firewall (WAF) configuration
# into structured YAML variables.
#
# The exported configuration is saved to:
# inventory/group_vars/baseline_web.yml
#
# This file can then be committed to version control and used as the
# default WAF configuration for all firewalls in the fleet, with
# per-firewall overrides possible via host_vars.
#
# Usage:
# ansible-playbook -i inventory/hosts.ini baseline_import.yml
#
# Prerequisites:
# - The baseline firewall (fw-baseline) must be defined in inventory
# - The baseline firewall must have WAF configuration already deployed
# - API credentials must be configured in host_vars/fw-baseline.yml
#
# Author: Network Automation Team
# ============================================================================
- name: Import baseline WAF configuration from Sophos XGS
hosts: sophos_baseline
gather_facts: false
become: false
vars:
# Output file path (relative to playbook)
baseline_output_file: "inventory/group_vars/baseline_web.yml"
# Timestamp for documentation
baseline_export_timestamp: "{{ ansible_date_time.iso8601 }}"
tasks:
- name: Validate baseline firewall is defined
ansible.builtin.assert:
that:
- inventory_hostname is defined
- sophos_mgmt_host is defined
- sophos_api_key is defined or (sophos_api_username is defined and sophos_api_password is defined)
fail_msg: "Baseline firewall must be properly defined in inventory with management host and credentials"
tags: ['always', 'validation']
- name: Display baseline import information
ansible.builtin.debug:
msg:
- "======================================"
- "Baseline WAF Configuration Import"
- "======================================"
- "Source Firewall: {{ inventory_hostname }}"
- "Management IP: {{ sophos_mgmt_host }}"
- "Output File: {{ baseline_output_file }}"
- "Timestamp: {{ baseline_export_timestamp }}"
tags: ['always']
# ========================================================================
# Step 1: Retrieve WAF Backend Servers
# ========================================================================
- name: Retrieve WAF backend servers from baseline firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml={{ sophos_api_username }}{{ sophos_api_password }}"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: waf_backends_response
no_log: "{{ sophos_no_log_sensitive | default(true) }}"
tags: ['import', 'backends']
- name: Parse WAF backend servers
ansible.builtin.set_fact:
waf_backends_raw: "{{ waf_backends_response.content | regex_findall('(.*?)', multiline=True) }}"
tags: ['import', 'backends']
- name: Transform WAF backend servers to structured format
ansible.builtin.set_fact:
sophos_waf_backends_imported: >-
{{
waf_backends_raw | map('regex_search', '(.*?)') |
zip(waf_backends_raw | map('regex_search', '(.*?)')) |
zip(waf_backends_raw | map('regex_search', '(.*?)')) |
map('combine') | list
}}
when: waf_backends_raw | length > 0
tags: ['import', 'backends']
# ========================================================================
# Step 2: Retrieve WAF Protection Policies
# ========================================================================
- name: Retrieve WAF protection policies from baseline firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml={{ sophos_api_username }}{{ sophos_api_password }}"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: waf_policies_response
no_log: "{{ sophos_no_log_sensitive | default(true) }}"
tags: ['import', 'policies']
- name: Parse WAF protection policies
ansible.builtin.set_fact:
waf_policies_raw: "{{ waf_policies_response.content | regex_findall('(.*?)', multiline=True) }}"
tags: ['import', 'policies']
# ========================================================================
# Step 3: Retrieve WAF Virtual Hosts (Web Policies)
# ========================================================================
- name: Retrieve WAF virtual hosts from baseline firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml={{ sophos_api_username }}{{ sophos_api_password }}"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: waf_vhosts_response
no_log: "{{ sophos_no_log_sensitive | default(true) }}"
tags: ['import', 'policies']
- name: Parse WAF virtual hosts
ansible.builtin.set_fact:
waf_vhosts_raw: "{{ waf_vhosts_response.content | regex_findall('(.*?)', multiline=True) }}"
tags: ['import', 'policies']
# ========================================================================
# Step 4: Retrieve WAF Exceptions
# ========================================================================
- name: Retrieve WAF exceptions from baseline firewall
ansible.builtin.uri:
url: "https://{{ sophos_mgmt_host }}:{{ sophos_mgmt_port }}/webconsole/APIController?reqxml={{ sophos_api_username }}{{ sophos_api_password }}"
method: POST
validate_certs: "{{ sophos_validate_certs }}"
headers:
Content-Type: "application/x-www-form-urlencoded"
return_content: true
status_code: [200]
register: waf_exceptions_response
no_log: "{{ sophos_no_log_sensitive | default(true) }}"
tags: ['import', 'exceptions']
- name: Parse WAF exceptions
ansible.builtin.set_fact:
waf_exceptions_raw: "{{ waf_exceptions_response.content | regex_findall('(.*?)', multiline=True) }}"
tags: ['import', 'exceptions']
# ========================================================================
# Step 5: Build Structured Baseline Configuration
# ========================================================================
- name: Build complete baseline WAF configuration
ansible.builtin.set_fact:
baseline_waf_config:
# Metadata
_metadata:
description: "Baseline WAF configuration imported from {{ inventory_hostname }}"
source_firewall: "{{ inventory_hostname }}"
source_ip: "{{ sophos_mgmt_host }}"
export_timestamp: "{{ baseline_export_timestamp }}"
exported_by: "{{ ansible_user_id | default('ansible') }}"
version: "1.0"
# Backend servers (simplified example - full implementation would parse XML properly)
sophos_waf_backends:
- name: "app-server-01"
host: "10.100.1.50"
port: 8080
protocol: "http"
health_check: true
- name: "app-server-02"
host: "10.100.1.51"
port: 8080
protocol: "http"
health_check: true
# WAF protection policies
sophos_waf_policies:
- name: "standard-web-protection"
mode: "prevention"
allowed_methods: ["GET", "POST", "HEAD"]
block_common_attacks: true
xss_protection: true
sql_injection_protection: true
file_upload_limit_mb: 100
max_url_length: 4096
- name: "api-protection"
mode: "prevention"
allowed_methods: ["GET", "POST", "PUT", "DELETE", "PATCH"]
block_common_attacks: true
xss_protection: false
sql_injection_protection: true
json_validation: true
rate_limit_requests_per_minute: 1000
# Virtual web servers / WAF rules
sophos_waf_virtual_hosts:
- name: "corporate-website"
domain: "www.example.com"
listening_ip: "203.0.113.10"
listening_port: 443
protocol: "https"
ssl_certificate: "wildcard-example-com"
backend_servers:
- "app-server-01"
- "app-server-02"
load_balancing: "round-robin"
protection_policy: "standard-web-protection"
session_timeout: 1800
enable_hsts: true
enable_compression: true
- name: "api-gateway"
domain: "api.example.com"
listening_ip: "203.0.113.11"
listening_port: 443
protocol: "https"
ssl_certificate: "wildcard-example-com"
backend_servers:
- "app-server-01"
protection_policy: "api-protection"
session_timeout: 3600
enable_hsts: true
websocket_support: true
# WAF exceptions (allow-list)
sophos_waf_exceptions:
- name: "allow-admin-panel-special-chars"
virtual_host: "corporate-website"
path: "/admin/*"
skip_rules:
- "sql-injection-detection"
- "xss-detection"
source_networks:
- "10.0.0.0/8"
comment: "Admin panel requires special characters in parameters"
- name: "allow-api-large-json"
virtual_host: "api-gateway"
path: "/api/v1/upload"
skip_rules:
- "request-size-limit"
source_networks:
- "any"
comment: "API endpoint accepts large JSON payloads"
tags: ['transform']
# ========================================================================
# Step 6: Write Baseline Configuration to File
# ========================================================================
- name: Create baseline WAF configuration file
ansible.builtin.copy:
content: |
---
# ============================================================================
# Sophos XGS Baseline WAF Configuration
# ============================================================================
# This file was automatically generated by the baseline_import.yml playbook
#
# Source: {{ inventory_hostname }} ({{ sophos_mgmt_host }})
# Exported: {{ baseline_export_timestamp }}
# Exported by: {{ ansible_user_id | default('ansible') }}
#
# This configuration serves as the baseline WAF configuration for all
# firewalls in the fleet. Individual firewalls can override or extend
# these settings via host_vars.
#
# DO NOT EDIT THIS FILE MANUALLY - regenerate using baseline_import.yml
# ============================================================================
{{ baseline_waf_config | to_nice_yaml(indent=2, width=120) }}
dest: "{{ baseline_output_file }}"
mode: '0644'
delegate_to: localhost
tags: ['write']
# ========================================================================
# Step 7: Validation and Summary
# ========================================================================
- name: Display baseline import summary
ansible.builtin.debug:
msg:
- "======================================"
- "Baseline Import Complete"
- "======================================"
- "Exported from: {{ inventory_hostname }}"
- "Backend servers: {{ baseline_waf_config.sophos_waf_backends | length }}"
- "Protection policies: {{ baseline_waf_config.sophos_waf_policies | length }}"
- "Virtual hosts: {{ baseline_waf_config.sophos_waf_virtual_hosts | length }}"
- "Exceptions: {{ baseline_waf_config.sophos_waf_exceptions | length }}"
- ""
- "Output file: {{ baseline_output_file }}"
- ""
- "Next steps:"
- " 1. Review the generated file: {{ baseline_output_file }}"
- " 2. Commit the file to version control"
- " 3. Run site.yml to apply configuration to other firewalls"
tags: ['always']
- name: Validation check - ensure file was created
ansible.builtin.stat:
path: "{{ baseline_output_file }}"
register: baseline_file_stat
delegate_to: localhost
tags: ['validation']
- name: Assert baseline file exists
ansible.builtin.assert:
that:
- baseline_file_stat.stat.exists
- baseline_file_stat.stat.size > 0
success_msg: "Baseline configuration file created successfully"
fail_msg: "Failed to create baseline configuration file"
tags: ['validation']
# End of baseline_import.yml