Files
mukul975 27c6414ca5 Add folder anatomy (scripts/agent.py + references/api-reference.md) for 648 cybersecurity skills
Complete skill folder anatomy across all cybersecurity skills:
- scripts/agent.py: 80-150 line Python agents using real libraries (impacket,
  boto3, azure-mgmt-*, kubernetes, pefile, yara, scapy, shodan, stix2, etc.)
- references/api-reference.md: real API documentation with method signatures
- LICENSE: MIT license for all skill folders
2026-03-10 21:02:12 +01:00

247 lines
8.8 KiB
Python

#!/usr/bin/env python3
"""Rsyslog Centralization Agent - Generates and deploys TLS-secured rsyslog configurations."""
import json
import logging
import argparse
import subprocess
from datetime import datetime
from jinja2 import Template
logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)
SERVER_TEMPLATE = Template("""\
# Rsyslog Server Configuration - TLS Centralized Logging
# Generated by Syslog Centralization Agent
# Load modules
module(load="imuxsock")
module(load="imklog")
module(load="imtcp"
StreamDriver.Name="gtls"
StreamDriver.Mode="1"
StreamDriver.Authmode="x509/name"
PermittedPeer=["{{ permitted_peers | join('","') }}"]
)
# TLS Certificate Configuration
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="{{ ca_cert }}"
DefaultNetstreamDriverCertFile="{{ server_cert }}"
DefaultNetstreamDriverKeyFile="{{ server_key }}"
)
# TLS Listener
input(type="imtcp" port="{{ tls_port }}")
# Templates
template(name="PerHostDir" type="string"
string="/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log")
template(name="JSONFormat" type="string"
string='{"timestamp":"%TIMESTAMP:::date-rfc3339%","host":"%HOSTNAME%","facility":"%syslogfacility-text%","severity":"%syslogseverity-text%","program":"%PROGRAMNAME%","msg":"%msg:::json%"}\\n')
template(name="PerHostJSON" type="string"
string="/var/log/remote/%HOSTNAME%/json/%PROGRAMNAME%.json")
# Rules - Store per-host with standard format
*.* ?PerHostDir
# Also store in JSON format for SIEM ingestion
*.* ?PerHostJSON;JSONFormat
# High-severity alerts to dedicated file
*.err /var/log/remote/errors.log
""")
CLIENT_TEMPLATE = Template("""\
# Rsyslog Client Configuration - TLS Forwarding
# Generated by Syslog Centralization Agent
# TLS Certificate Configuration
global(
DefaultNetstreamDriver="gtls"
DefaultNetstreamDriverCAFile="{{ ca_cert }}"
DefaultNetstreamDriverCertFile="{{ client_cert }}"
DefaultNetstreamDriverKeyFile="{{ client_key }}"
)
# Forward all logs to central server with TLS and reliable queue
action(
type="omfwd"
target="{{ server_ip }}"
port="{{ tls_port }}"
protocol="tcp"
StreamDriver="gtls"
StreamDriverMode="1"
StreamDriverAuthMode="x509/name"
StreamDriverPermittedPeers="{{ server_ip }}"
queue.type="LinkedList"
queue.filename="fwdRule1"
queue.maxdiskspace="{{ queue_disk_space }}"
queue.saveonshutdown="on"
queue.size="{{ queue_size }}"
action.resumeRetryCount="-1"
action.resumeInterval="30"
)
""")
def generate_server_config(server_ip, clients, ca_cert, server_cert, server_key, tls_port=6514):
"""Generate rsyslog server configuration with TLS."""
config = SERVER_TEMPLATE.render(
permitted_peers=clients + [server_ip],
ca_cert=ca_cert,
server_cert=server_cert,
server_key=server_key,
tls_port=tls_port,
)
logger.info("Generated server config for %s with %d permitted peers", server_ip, len(clients))
return config
def generate_client_config(server_ip, ca_cert, client_cert, client_key, tls_port=6514):
"""Generate rsyslog client configuration with TLS forwarding."""
config = CLIENT_TEMPLATE.render(
server_ip=server_ip,
ca_cert=ca_cert,
client_cert=client_cert,
client_key=client_key,
tls_port=tls_port,
queue_disk_space="1g",
queue_size="50000",
)
logger.info("Generated client config forwarding to %s:%d", server_ip, tls_port)
return config
def generate_tls_certificates(output_dir, server_cn, client_cns):
"""Generate CA, server, and client TLS certificates using OpenSSL."""
ca_key = f"{output_dir}/ca-key.pem"
ca_cert = f"{output_dir}/ca.pem"
subprocess.run([
"openssl", "req", "-x509", "-newkey", "rsa:4096", "-keyout", ca_key,
"-out", ca_cert, "-days", "3650", "-nodes",
"-subj", f"/CN=Syslog CA/O=SOC/C=US",
], capture_output=True, check=True)
logger.info("Generated CA certificate: %s", ca_cert)
for cn in [server_cn] + client_cns:
key_file = f"{output_dir}/{cn}-key.pem"
cert_file = f"{output_dir}/{cn}-cert.pem"
csr_file = f"{output_dir}/{cn}.csr"
subprocess.run([
"openssl", "req", "-newkey", "rsa:2048", "-keyout", key_file,
"-out", csr_file, "-nodes", "-subj", f"/CN={cn}/O=SOC/C=US",
], capture_output=True, check=True)
subprocess.run([
"openssl", "x509", "-req", "-in", csr_file, "-CA", ca_cert,
"-CAkey", ca_key, "-CAcreateserial", "-out", cert_file, "-days", "365",
], capture_output=True, check=True)
logger.info("Generated certificate for %s", cn)
return ca_cert
def deploy_config_ssh(host, config_content, remote_path, username="root", key_file=None):
"""Deploy rsyslog configuration to a remote host via SSH."""
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
connect_kwargs = {"hostname": host, "username": username}
if key_file:
connect_kwargs["key_filename"] = key_file
client.connect(**connect_kwargs)
sftp = client.open_sftp()
with sftp.file(remote_path, "w") as f:
f.write(config_content)
sftp.close()
_, stdout, stderr = client.exec_command("systemctl restart rsyslog")
exit_status = stdout.channel.recv_exit_status()
client.close()
logger.info("Deployed config to %s:%s (restart exit: %d)", host, remote_path, exit_status)
return exit_status == 0
def validate_tls_connection(server_ip, tls_port=6514, ca_cert=None):
"""Validate TLS connectivity to the rsyslog server."""
cmd = [
"openssl", "s_client", "-connect", f"{server_ip}:{tls_port}",
"-CAfile", ca_cert or "/etc/ssl/certs/ca-certificates.crt",
]
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10, input="")
connected = "Verify return code: 0" in result.stdout
logger.info("TLS validation to %s:%d: %s", server_ip, tls_port, "OK" if connected else "FAILED")
return connected
except subprocess.TimeoutExpired:
return False
def generate_report(server_config, client_configs, deployments, tls_valid):
"""Generate syslog centralization deployment report."""
report = {
"timestamp": datetime.utcnow().isoformat(),
"server_config_generated": bool(server_config),
"client_configs_generated": len(client_configs),
"deployments": deployments,
"tls_validated": tls_valid,
}
print(f"SYSLOG REPORT: {len(client_configs)} client configs, TLS: {'OK' if tls_valid else 'PENDING'}")
return report
def main():
parser = argparse.ArgumentParser(description="Rsyslog Centralization Agent")
parser.add_argument("--server-ip", required=True, help="Syslog server IP")
parser.add_argument("--clients", required=True, help="Comma-separated client IPs")
parser.add_argument("--ca-cert", default="/etc/rsyslog.d/ca.pem")
parser.add_argument("--server-cert", default="/etc/rsyslog.d/server-cert.pem")
parser.add_argument("--server-key", default="/etc/rsyslog.d/server-key.pem")
parser.add_argument("--tls-port", type=int, default=6514)
parser.add_argument("--deploy", action="store_true", help="Deploy configs via SSH")
parser.add_argument("--config-dir", default="./rsyslog_configs")
parser.add_argument("--output", default="syslog_report.json")
args = parser.parse_args()
clients = [c.strip() for c in args.clients.split(",")]
import os
os.makedirs(args.config_dir, exist_ok=True)
server_config = generate_server_config(
args.server_ip, clients, args.ca_cert, args.server_cert, args.server_key, args.tls_port
)
with open(f"{args.config_dir}/server.conf", "w") as f:
f.write(server_config)
client_configs = {}
for client_ip in clients:
config = generate_client_config(
args.server_ip, args.ca_cert,
f"/etc/rsyslog.d/{client_ip}-cert.pem",
f"/etc/rsyslog.d/{client_ip}-key.pem",
args.tls_port,
)
with open(f"{args.config_dir}/client-{client_ip}.conf", "w") as f:
f.write(config)
client_configs[client_ip] = config
deployments = []
if args.deploy:
for client_ip, config in client_configs.items():
ok = deploy_config_ssh(client_ip, config, "/etc/rsyslog.d/99-central.conf")
deployments.append({"host": client_ip, "success": ok})
tls_valid = validate_tls_connection(args.server_ip, args.tls_port, args.ca_cert)
report = generate_report(server_config, client_configs, deployments, tls_valid)
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
logger.info("Report saved to %s", args.output)
if __name__ == "__main__":
main()