333 lines
14 KiB
YAML
333 lines
14 KiB
YAML
---
|
|
# ============================================================================
|
|
# 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=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><WebServer/></Get></Request>"
|
|
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('<WebServer>(.*?)</WebServer>', 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', '<Name>(.*?)</Name>') |
|
|
zip(waf_backends_raw | map('regex_search', '<Host>(.*?)</Host>')) |
|
|
zip(waf_backends_raw | map('regex_search', '<Port>(.*?)</Port>')) |
|
|
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=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><WebServerProtection/></Get></Request>"
|
|
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('<WebServerProtection>(.*?)</WebServerProtection>', 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=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><WebPolicy/></Get></Request>"
|
|
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('<WebPolicy>(.*?)</WebPolicy>', 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=<Request><Login><Username>{{ sophos_api_username }}</Username><Password>{{ sophos_api_password }}</Password></Login><Get><WebException/></Get></Request>"
|
|
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('<WebException>(.*?)</WebException>', 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
|