SOC Notes Python SOC Automation
SOC Notes Python SOC Automation
Layer 2 (Technical): Python scripts read raw log files line by line, apply regular
expressions to extract structured fields (timestamps, IP addresses, usernames, event
types), count occurrences using data structures like [Link], apply risk
thresholds to flag high-frequency sources, and write the results to a CSV file that can be
ingested by a SIEM (Security Information and Event Management) tool or shared with the
incident response team.
Layer 3 (Senior Analyst Insight): Mature SOC automation pipelines treat Python scripts
as microservices in a broader detection pipeline. The log parser becomes an ETL
(Extract, Transform, Load) component feeding into SOAR (Security Orchestration,
Automation, and Response) platforms. Version-controlling your scripts on GitHub enables
peer review, change tracking, and automated testing of detection logic — treating security
rules as code.
Analogy: Parsing [Link] with Python is like running a speed camera on a busy
motorway. Instead of an officer watching every car pass, the camera automatically reads
every plate (IP address), counts how many times it has appeared (failed attempts), and
flags plates that exceed a threshold (risk level) for a human officer to investigate. Python
is the camera; you are still the officer making the judgment call.
TIP:
Always parse logs in UTC. The [Link] syslog timestamp does not include a time zone offset.
Normalise all timestamps to UTC using datetime. Time zone. utc before writing to CSV to avoid
confusion when correlating across multiple systems in different time zones.
1. Step 1: Read the File — Open the log file — Use open() with a context manager (with
open(...) as f) to safely read /var/log/[Link] line by line without loading the entire file
into memory. For large production logs this is critical.
2. Step 2: Compile Regex — Compile your regex patterns — Use [Link]() once
before the loop to pre-compile patterns for "Failed password", "Invalid user", and the
IPv4 address capture group. Pre-compilation provides a measurable speed improvement
over [Link]() on each line.
3. Step 3: Parse Each Line — Iterate line by line — Loop through each line. Apply
[Link]() to determine if the line is a failed-login event. If it matches, extract the IP
address using a capture group such as r"from\s+(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})".
4. Step 4: Tally Failures — Count with Counter — Append the extracted IP to a list or feed
it directly to a [Link] object. Counter automatically tallies frequency for each
unique IP without requiring manual dictionary management.
5. Step 5: Score Risk — Apply risk thresholds — Iterate over the Counter results and
assign a risk level: CRITICAL (50+ failures), HIGH (20-49), MEDIUM (5-19), LOW (1-4).
These thresholds should match your organisation's security policy and can be made
configurable via argparse.
6. Step 6: Export CSV — Write CSV output — Use the csv module's [Link] to write a
header row (timestamp, ip_address, fail_count, risk_level) and then one data row per IP.
Always include [Link]().isoformat() as the report timestamp.
7. Step 7: Extract IOCs — Extend to IOC extraction — Add a second pass that also
extracts usernames from "Invalid user <X>" lines and domains from DNS lookup failures.
Build a separate IOC CSV or JSON file for threat intel platform ingestion.
8. Step 8: Make it Reusable — Add command-line arguments — Wrap the script with
argparse so it accepts --log-file, --output, and --threshold flags. This makes the script
reusable across different environments without editing source code.
9. Step 9: Document and Publish — Commit to GitHub with sample output — Create a
repository under soc-notes/python-tools/. Include a sample sanitised log file, the
generated CSV, a README explaining usage, and a [Link] (empty for this
script since only stdlib is used).
10. Step 10: Automate Execution — Schedule and automate — On production systems,
add the script to cron (e.g., 0 * * * * python3 /opt/soc/log_parser.py) or a GitHub Actions
workflow to run automatically and email/Slack results to the SOC team.
COMMON MISTAKE:
Do not use [Link]() on every line inside a loop without pre-compiling. Calling
[Link](r"pattern", line) inside a loop recompiles the regex on every iteration. With 500,000
log lines this can make your script 3-5x slower. Always use pattern = [Link](r"...") once,
then [Link](line).
TIP:
When sharing IOC extraction scripts on GitHub, always sanitise sample log files by replacing
real IP addresses with RFC 5737 documentation ranges (192.0.2.x, 198.51.100.x,
203.0.113.x). Never commit real internal IP addresses, hostnames, or usernames to a public
repository.
Detection Phase
• Schedule the Python log parser to run hourly via cron or a task scheduler.
• Set thresholds appropriate to your environment — a jump-box might legitimately see 10-
15 failed attempts per day; a public-facing SSH server should have thresholds much lower.
• Monitor the script's own output: if the CSV is empty or has zero rows, check that the log
file path is correct and the regex matches the actual log format on your OS distribution.
Triage Phase
• Sort the output CSV by fail_count descending to identify the top offenders immediately.
• Cross-reference the top IPs against threat intelligence feeds such as AbuseIPDB,
VirusTotal, or Shodan using the requests module to enrich the CSV output.
• Check whether the flagged IPs belong to cloud provider ranges (AWS, Azure, GCP) — if
so, an internal service or container may be misconfigured rather than an external attacker.
Containment Phase
• For CRITICAL-risk IPs, generate a firewall block rule automatically using the script's
output. For iptables: iptables -A INPUT -s <IP> -j DROP.
• If the brute-force succeeded (check for a subsequent "Accepted password" line after a
series of failures), escalate immediately to Incident Response.
Escalation Decision
• Escalate to Tier 2 if: successful login found after failures, IP is on a threat intel blocklist,
attack targets privileged accounts (root, admin, service accounts), or volume exceeds
CRITICAL threshold within a 1-hour window.
BEST PRACTICE:
Maintain a Git commit history for all parser scripts. When detection logic changes (new regex,
adjusted thresholds), the commit message should document WHY the change was made, not
just what changed. This creates an audit trail showing how your detection capabilities evolved
over time.
COMMON MISTAKE:
Do not hardcode the log file path (/var/log/[Link]) in the script. Different Linux distributions
use different paths (Ubuntu: /var/log/[Link], CentOS/RHEL: /var/log/secure). Use argparse
with a --log-file argument so the same script works across environments without modification.
Figure 1: Python SOC Automation Pipeline — from raw [Link] to structured CSV output
def get_risk(count):
if count >= 50: return "CRITICAL"
if count >= 20: return "HIGH"
if count >= 5: return "MEDIUM"
return "LOW"
ts = [Link]([Link]).isoformat()
with open(output_path, "w", newline="") as csvfile:
writer = [Link](csvfile)
[Link](["timestamp", "ip_address", "fail_count", "risk_level"])
for ip, count in counter.most_common():
if count >= threshold:
[Link]([ts, ip, count, get_risk(count)])
if __name__ == "__main__":
parser = [Link](description="Parse [Link] for failed logins")
parser.add_argument("--log-file", default="/var/log/[Link]")
parser.add_argument("--output", default="failed_logins.csv")
parser.add_argument("--threshold",type=int, default=1)
args = parser.parse_args()
parse_auth_log(args.log_file, [Link], [Link])
print(f"Done. Output: {[Link]}")
BEST PRACTICE:
Use Python's built-in unittest module to write test cases for your regex patterns. Create a tests/
folder in your GitHub repo with sample log lines and expected output. Run python -m pytest
before every commit to ensure new regex changes do not break existing detection logic. This
is production-grade SOC tool development.
Q1 (Easy): What Python module would you use to count failed SSH login
attempts per IP address from a log file?
Answer: [Link]. The Counter class is a dictionary subclass that automatically
tallies the frequency of items. After extracting IP addresses from each matching log line
using a regex, you can either pass a list to Counter() directly or use counter[ip] += 1 in a
loop. Calling counter.most_common() returns IPs sorted from highest to lowest
frequency, ideal for identifying the top attackers.
Q4 (Medium): A colleague's log parser script is very slow on a 2GB log file.
What are three performance improvements you would suggest?
Answer: First, pre-compile regex patterns with [Link]() outside the loop instead of
calling [Link](r"pattern", line) on every iteration. Second, read the file line by line using
open() as a generator rather than loading the entire 2GB into memory with [Link]().
Third, consider using Python's multiprocessing module to split the log file into chunks and
process them in parallel across multiple CPU cores, then merge the Counter results at
the end. These three changes can reduce processing time by an order of magnitude on
large production log files.
Q5 (Hard): How would you modify the log parser to also detect a successful
login following a series of failures from the same IP — a classic brute-force
success pattern — and automatically escalate it?
Answer: Track failed logins in a Counter as normal. Simultaneously, scan for "Accepted
password" lines and extract the source IP using a second regex. After processing the
entire file, compute the intersection: any IP that appears in both the failed_counter (above
threshold) AND the successful_logins set is a high-confidence brute-force success
indicator. This IP should be written to a separate critical_escalations.csv. The script can
then send an automated alert via the smtplib module (email) or a Slack webhook using
[Link]() to the SOC channel, bypassing the normal ticket queue and triggering an
immediate Tier 2 response. This pattern maps directly to MITRE ATT&CK T1110.001
(Brute Force: Password Guessing) followed by T1078 (Valid Accounts).