Ansible for SOC and SIEM: Automate Security Operations Complete Guide
By Luca Berton · Published 2024-01-01 · Category: installation
Complete guide to Ansible for Security Operations Centers (SOC) and SIEM integration. Automate incident response playbooks, log forwarding.
Security Operations Centers run on speed — detect, investigate, contain, remediate. Ansible automates every phase. Block malicious IPs in seconds, collect forensic data across hundreds of hosts simultaneously, push SIEM configurations consistently, and run compliance scans on demand. Here's how.
Why Ansible for Security Operations
| Manual SOC | Automated with Ansible | |-----------|----------------------| | SSH into each host to block IP | Block IP on all firewalls in 10 seconds | | Manually collect logs for investigation | Gather forensic data from 500 hosts in parallel | | Update SIEM agents one by one | Push config to all agents simultaneously | | Hours to contain an incident | Minutes from detection to containment | | Inconsistent hardening | Identical baseline across all systems |
See also: Ansible for SIEM and SOC: Automate Security Operations, Incident Response, and Compliance
Incident Response Automation
Automated Threat Containment
---
- name: Contain compromised host
hosts: "{{ compromised_host }}"
become: true
vars:
incident_id: "{{ incident }}"
quarantine_vlan: 999
tasks:
- name: Kill malicious processes
ansible.builtin.shell: |
for pid in $(ps aux | grep -i "{{ malicious_process }}" | grep -v grep | awk '{print $2}'); do
kill -9 $pid
done
when: malicious_process is defined
changed_when: true
- name: Block outbound connections from compromised host
ansible.builtin.iptables:
chain: OUTPUT
destination: "{{ item }}"
jump: DROP
comment: "INC-{{ incident_id }}: Block C2 server"
loop: "{{ c2_servers | default([]) }}"
- name: Disable compromised user accounts
ansible.builtin.user:
name: "{{ item }}"
password_lock: true
shell: /sbin/nologin
loop: "{{ compromised_users | default([]) }}"
- name: Collect forensic snapshot
ansible.builtin.shell: |
mkdir -p /tmp/forensics-{{ incident_id }}
ps auxf > /tmp/forensics-{{ incident_id }}/processes.txt
netstat -tulpn > /tmp/forensics-{{ incident_id }}/connections.txt
last -50 > /tmp/forensics-{{ incident_id }}/logins.txt
cat /etc/passwd > /tmp/forensics-{{ incident_id }}/passwd.txt
find /tmp /var/tmp -mtime -1 -ls > /tmp/forensics-{{ incident_id }}/recent_tmp.txt
journalctl --since "24 hours ago" > /tmp/forensics-{{ incident_id }}/journal.txt
changed_when: true
- name: Fetch forensic data
ansible.builtin.fetch:
src: "/tmp/forensics-{{ incident_id }}/"
dest: "/evidence/{{ incident_id }}/{{ inventory_hostname }}/"
flat: false
Block Indicators of Compromise (IOCs)
---
- name: Block IOCs across infrastructure
hosts: all
become: true
vars:
malicious_ips:
- 198.51.100.23
- 203.0.113.45
- 192.0.2.100
malicious_domains:
- evil-c2.example.com
- malware-drop.example.net
tasks:
- name: Block malicious IPs in iptables
ansible.builtin.iptables:
chain: "{{ item.0 }}"
source: "{{ item.1 }}"
jump: DROP
comment: "IOC block - automated"
loop: "{{ ['INPUT', 'OUTPUT'] | product(malicious_ips) | list }}"
- name: Block domains in /etc/hosts
ansible.builtin.lineinfile:
path: /etc/hosts
line: "127.0.0.1 {{ item }}"
state: present
loop: "{{ malicious_domains }}"
- name: Update firewalld (RHEL/CentOS)
ansible.posix.firewalld:
rich_rule: "rule family='ipv4' source address='{{ item }}' drop"
permanent: true
immediate: true
state: enabled
loop: "{{ malicious_ips }}"
when: ansible_facts['os_family'] == 'RedHat'
Fleet-Wide Forensic Collection
---
- name: Collect forensic data across fleet
hosts: all
become: true
gather_facts: true
tasks:
- name: Search for IOC file hashes
ansible.builtin.find:
paths:
- /tmp
- /var/tmp
- /home
recurse: true
file_type: file
size: "1k-10m"
register: suspicious_files
- name: Calculate hashes of suspicious files
ansible.builtin.stat:
path: "{{ item.path }}"
checksum_algorithm: sha256
register: file_hashes
loop: "{{ suspicious_files.files[:100] }}"
- name: Check for known malicious hashes
ansible.builtin.set_fact:
ioc_matches: >-
{{ file_hashes.results
| selectattr('stat.checksum', 'in', known_bad_hashes)
| list }}
vars:
known_bad_hashes: "{{ lookup('file', 'ioc_hashes.txt').splitlines() }}"
- name: Alert on IOC matches
ansible.builtin.debug:
msg: "🚨 IOC MATCH on {{ inventory_hostname }}: {{ item.stat.path }} ({{ item.stat.checksum }})"
loop: "{{ ioc_matches }}"
when: ioc_matches | length > 0
- name: Check for unauthorized SSH keys
ansible.builtin.find:
paths: /home
patterns: "authorized_keys"
recurse: true
register: ssh_keys
- name: Collect SSH key contents
ansible.builtin.slurp:
src: "{{ item.path }}"
register: key_contents
loop: "{{ ssh_keys.files }}"
- name: Check for unauthorized cron jobs
ansible.builtin.command: find /var/spool/cron -type f
register: cron_files
changed_when: false
- name: Collect cron contents
ansible.builtin.slurp:
src: "{{ item }}"
register: cron_contents
loop: "{{ cron_files.stdout_lines }}"
when: cron_files.stdout_lines | length > 0
SIEM Integration
Splunk Forwarder Deployment
---
- name: Deploy Splunk Universal Forwarder
hosts: all
become: true
vars:
splunk_version: "9.3.0"
splunk_server: splunk-indexer.example.com:9997
splunk_deploy_server: splunk-deploy.example.com:8089
tasks:
- name: Download Splunk UF
ansible.builtin.get_url:
url: "https://download.splunk.com/products/universalforwarder/releases/{{ splunk_version }}/linux/splunkforwarder-{{ splunk_version }}-linux-amd64.deb"
dest: /tmp/splunkforwarder.deb
checksum: "sha256:{{ splunk_uf_checksum }}"
- name: Install Splunk UF
ansible.builtin.apt:
deb: /tmp/splunkforwarder.deb
when: ansible_facts['os_family'] == 'Debian'
- name: Configure outputs
ansible.builtin.template:
src: splunk-outputs.conf.j2
dest: /opt/splunkforwarder/etc/system/local/outputs.conf
owner: splunk
mode: '0600'
notify: restart splunkforwarder
- name: Configure inputs (log sources)
ansible.builtin.template:
src: splunk-inputs.conf.j2
dest: /opt/splunkforwarder/etc/system/local/inputs.conf
owner: splunk
mode: '0600'
notify: restart splunkforwarder
- name: Enable and start Splunk UF
ansible.builtin.service:
name: SplunkForwarder
state: started
enabled: true
handlers:
- name: restart splunkforwarder
ansible.builtin.service:
name: SplunkForwarder
state: restarted
Elasticsearch/ELK Stack Agents
---
- name: Deploy Filebeat for ELK
hosts: all
become: true
vars:
elastic_version: "8.15"
elasticsearch_hosts:
- "https://es01.example.com:9200"
- "https://es02.example.com:9200"
tasks:
- name: Add Elastic repository
ansible.builtin.apt_repository:
repo: "deb https://artifacts.elastic.co/packages/{{ elastic_version }}/apt stable main"
state: present
filename: elastic
- name: Install Filebeat
ansible.builtin.apt:
name: filebeat
state: present
- name: Configure Filebeat
ansible.builtin.template:
src: filebeat.yml.j2
dest: /etc/filebeat/filebeat.yml
mode: '0600'
notify: restart filebeat
- name: Enable modules
ansible.builtin.command: >
filebeat modules enable system auditd
changed_when: true
notify: restart filebeat
- name: Start Filebeat
ansible.builtin.service:
name: filebeat
state: started
enabled: true
handlers:
- name: restart filebeat
ansible.builtin.service:
name: filebeat
state: restarted
Wazuh Agent Deployment
---
- name: Deploy Wazuh SIEM agent
hosts: all
become: true
vars:
wazuh_manager: wazuh.example.com
wazuh_version: "4.9"
tasks:
- name: Add Wazuh repository
ansible.builtin.apt_repository:
repo: "deb https://packages.wazuh.com/4.x/apt/ stable main"
state: present
filename: wazuh
- name: Install Wazuh agent
ansible.builtin.apt:
name: wazuh-agent
state: present
environment:
WAZUH_MANAGER: "{{ wazuh_manager }}"
- name: Configure Wazuh agent
ansible.builtin.template:
src: ossec.conf.j2
dest: /var/ossec/etc/ossec.conf
mode: '0640'
notify: restart wazuh-agent
- name: Start Wazuh agent
ansible.builtin.service:
name: wazuh-agent
state: started
enabled: true
handlers:
- name: restart wazuh-agent
ansible.builtin.service:
name: wazuh-agent
state: restarted
See also: New Ansible Content Collections 2026: Cloud, Networking, Security, Observability, and Windows
Compliance Scanning
CIS Benchmark Enforcement
---
- name: CIS benchmark hardening
hosts: all
become: true
tasks:
- name: "CIS 1.1.1 - Disable cramfs"
ansible.builtin.lineinfile:
path: /etc/modprobe.d/cis.conf
line: "install cramfs /bin/true"
create: true
mode: '0644'
- name: "CIS 1.4.1 - Ensure permissions on bootloader config"
ansible.builtin.file:
path: /boot/grub2/grub.cfg
owner: root
group: root
mode: '0600'
when: ansible_facts['os_family'] == 'RedHat'
- name: "CIS 5.2.1 - Ensure SSH protocol 2"
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?Protocol'
line: 'Protocol 2'
notify: restart sshd
- name: "CIS 5.2.4 - Disable SSH root login"
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart sshd
- name: "CIS 5.2.11 - Set SSH MaxAuthTries"
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?MaxAuthTries'
line: 'MaxAuthTries 4'
notify: restart sshd
- name: "CIS 4.2.1 - Ensure auditd is installed"
ansible.builtin.apt:
name:
- auditd
- audispd-plugins
state: present
- name: "CIS 4.2.3 - Configure audit rules"
ansible.builtin.template:
src: audit-cis.rules.j2
dest: /etc/audit/rules.d/cis.rules
mode: '0640'
notify: restart auditd
handlers:
- name: restart sshd
ansible.builtin.service:
name: sshd
state: restarted
- name: restart auditd
ansible.builtin.service:
name: auditd
state: restarted
Vulnerability Scanning Integration
- name: Run OpenSCAP compliance scan
hosts: all
become: true
tasks:
- name: Install OpenSCAP
ansible.builtin.dnf:
name:
- openscap-scanner
- scap-security-guide
state: present
- name: Run CIS scan
ansible.builtin.command: >
oscap xccdf eval
--profile xccdf_org.ssgproject.content_profile_cis
--results /tmp/scan-results-{{ inventory_hostname }}.xml
--report /tmp/scan-report-{{ inventory_hostname }}.html
/usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
register: scan_result
failed_when: false
changed_when: false
- name: Fetch scan reports
ansible.builtin.fetch:
src: "/tmp/scan-report-{{ inventory_hostname }}.html"
dest: "reports/compliance/"
flat: true
Security Event Response Workflows
Automated Response to Failed Login Attempts
---
- name: Respond to brute force attacks
hosts: all
become: true
tasks:
- name: Get failed login attempts (last hour)
ansible.builtin.shell: |
journalctl -u sshd --since "1 hour ago" |
grep "Failed password" |
awk '{print $(NF-3)}' |
sort | uniq -c | sort -rn |
awk '$1 >= 10 {print $2}'
register: brute_force_ips
changed_when: false
- name: Block brute force IPs
ansible.builtin.iptables:
chain: INPUT
source: "{{ item }}"
jump: DROP
comment: "Auto-blocked: brute force {{ ansible_date_time.iso8601 }}"
loop: "{{ brute_force_ips.stdout_lines }}"
when: brute_force_ips.stdout_lines | length > 0
- name: Report blocked IPs
ansible.builtin.debug:
msg: "Blocked {{ brute_force_ips.stdout_lines | length }} IPs for brute force on {{ inventory_hostname }}"
when: brute_force_ips.stdout_lines | length > 0
See also: Ansible for AI Security: Protect Models, APIs & Data Pipelines (2026 Guide)
FAQ
How does Ansible compare to SOAR platforms like Phantom or XSOAR?
SOAR platforms provide visual playbook builders, case management, and SIEM integration out of the box. Ansible is more flexible and cheaper — it automates the actual remediation actions that SOAR platforms trigger. Many organizations use both: SOAR for orchestration and case management, Ansible for execution.
Can Ansible replace a SIEM?
No. Ansible deploys and configures SIEM agents, collects forensic data, and executes remediation actions. But SIEMs (Splunk, ELK, QRadar) handle log aggregation, correlation, alerting, and investigation — capabilities Ansible doesn't provide.
How fast can Ansible respond to incidents?
With pre-built playbooks and AAP webhooks, Ansible can execute containment actions within 30-60 seconds of detection. The limiting factor is usually detection speed (SIEM alert latency), not execution speed.
Is it safe to automate incident response?
Start with low-risk automations (data collection, reporting) before automating containment actions (blocking IPs, disabling accounts). Always include manual approval gates for destructive actions in production environments.
Conclusion
Ansible bridges the gap between security detection and response. Deploy SIEM agents consistently, collect forensic data at scale, block IOCs across your entire infrastructure in seconds, and enforce compliance baselines automatically. Start with forensic collection and SIEM agent deployment — they're high-value, low-risk automation targets.
Related Articles
• Ansible Vault Deep Dive • Ansible for Linux System Administration • Ansible Cloud Automation • Ansible Error Handling Guide • Managing Compliance Drift with Ansible • Installing and Enabling SELinux with Ansible on RHEL 8Category: installation