Skip to content

Commit c4e408e

Browse files
committed
rsyslog: Also rotate and parse stepup-logs
1 parent fa500ab commit c4e408e

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{{ rsyslog_dir }}/log_logins/{{ item.name }}/stepup-authentication.log
2+
{
3+
missingok
4+
daily
5+
rotate 180
6+
sharedscripts
7+
dateext
8+
dateyesterday
9+
compress
10+
delaycompress
11+
create 0640 root {{ rsyslog_read_group }}
12+
postrotate
13+
/usr/local/sbin/parse_stepupauth_to_mysql_{{ item.name }}.py > /dev/null
14+
systemctl kill -s HUP rsyslog.service
15+
endscript
16+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/usr/bin/python3
2+
# This script parses rotated stepup-authentication.log files produced by engineblock.
3+
# It filters for successful logins (authentication_result:OK) and inserts the data
4+
# into the log_logins and last_login MySQL tables.
5+
# This script is intended to be run separately during logrotate.
6+
7+
import os
8+
import sys
9+
import json
10+
import MySQLdb
11+
from dateutil.parser import parse
12+
13+
# Configuration variables (to be injected by Ansible/Jinja2)
14+
mysql_host="{{ item.db_loglogins_host }}"
15+
mysql_user="{{ item.db_loglogins_user }}"
16+
mysql_password="{{ item.db_loglogins_password }}"
17+
mysql_db="{{ item.db_loglogins_name }}"
18+
workdir="{{ rsyslog_dir }}/log_logins/{{ item.name}}/"
19+
20+
# Establish database connection
21+
try:
22+
db = MySQLdb.connect(mysql_host,mysql_user,mysql_password,mysql_db )
23+
cursor = db.cursor()
24+
except Exception as e:
25+
print(f"Error connecting to MySQL: {e}")
26+
sys.exit(1)
27+
28+
# --- Database Functions ---
29+
30+
def update_lastseen(user_id, date):
31+
"""
32+
Updates the last_login table.
33+
Uses GREATEST() to ensure only newer dates overwrite the existing 'lastseen' value.
34+
"""
35+
query = """
36+
INSERT INTO last_login (userid, lastseen)
37+
VALUES (%s, %s)
38+
ON DUPLICATE KEY UPDATE
39+
lastseen = GREATEST(lastseen, VALUES(lastseen))
40+
"""
41+
try:
42+
cursor.execute(query, (user_id, date))
43+
db.commit()
44+
except Exception as e:
45+
db.rollback()
46+
print(f"Error updating last_login for user {user_id}: {e}")
47+
48+
def load_stepup_in_mysql(idp, sp, loginstamp, userid, requestid):
49+
"""
50+
Inserts Step-up login data into the log_logins table.
51+
Fills keyid, sessionid, and trustedproxyentityid with NULL.
52+
"""
53+
# Columns in log_logins: idpentityid, spentityid, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid
54+
55+
keyid = None
56+
sessionid = None
57+
trustedproxyentityid = None
58+
59+
sql = """
60+
INSERT INTO log_logins(idpentityid, spentityid, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid)
61+
VALUES(%s, %s, %s, %s, %s, %s, %s, %s)
62+
"""
63+
try:
64+
cursor.execute(sql, (idp, sp, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid))
65+
db.commit()
66+
except Exception as e:
67+
db.rollback()
68+
print(f"Error inserting stepup data: {e}")
69+
# Print the data that failed insertion
70+
print((idp, sp, loginstamp, userid, keyid, sessionid, requestid, trustedproxyentityid))
71+
72+
# --- Parsing Function ---
73+
74+
def parse_stepup_lines(a):
75+
"""
76+
Opens the stepup log file, parses each line, filters for successful logins,
77+
and loads the data into MySQL.
78+
"""
79+
input_file = open((a), 'r')
80+
for line in input_file:
81+
try:
82+
# Assumes JSON data starts after the first ']:'
83+
jsonline = line.split(']:',2)[1]
84+
data = json.loads(jsonline)
85+
except:
86+
continue
87+
88+
# 1. Filtering condition: Only parse logs having authentication_result:OK
89+
if data.get("authentication_result") != "OK":
90+
continue
91+
92+
# 2. Extract required fields
93+
user_id = data.get("identity_id")
94+
timestamp = data.get("datetime")
95+
request_id = data.get("request_id")
96+
sp_entity_id = data.get("requesting_sp")
97+
idp_entity_id = data.get("authenticating_idp")
98+
99+
# Basic data validation
100+
if not user_id or not timestamp:
101+
continue
102+
103+
try:
104+
# 3. Format date and time for MySQL
105+
loginstamp = parse(timestamp).strftime("%Y-%m-%d %H:%M:%S")
106+
last_login_date = parse(timestamp).strftime("%Y-%m-%d")
107+
except:
108+
continue
109+
110+
# 4. Insert into MySQL
111+
load_stepup_in_mysql(idp_entity_id, sp_entity_id, loginstamp, user_id, request_id)
112+
113+
# 5. Update last login date
114+
update_lastseen(user_id, last_login_date)
115+
116+
117+
# --- Main Execution ---
118+
119+
## Loop over the files and parse them one by one
120+
for filename in os.listdir(workdir):
121+
filetoparse=(os.path.join(workdir, filename))
122+
123+
# Check for Stepup files, ignore compressed files
124+
if os.path.isfile(filetoparse) and filename.startswith("stepup-authentication.log-") and not filename.endswith(".gz"):
125+
print(f"Parsing stepup log file: {filename}")
126+
parse_stepup_lines(filetoparse)
127+
else:
128+
continue
129+
130+
# Close database connection
131+
cursor.close()
132+
db.close()
133+
print("Stepup log parsing complete.")

0 commit comments

Comments
 (0)