BSI CERT-Bund RSS Feed mittels Python in Teams-Kanal erhalten

Das BSI CERT-Bund stellt für viele Unternehmen eine zentrale Informationsquelle für präventive und reaktive Maßnahmen bei sicherheitsrelevanten Vorfällen in Computer-Systemen dar. Mit der Einstellung des Newsletters stellt sich für viele Unternehmen und IT-Professionals die Herausforderung, wie sie effektiv und ohne zusätzlichen administrativen Aufwand informiert bleiben können.

Microsoft Teams ist in unserem Unternehmen das zentrale Kommunikationsmittel. Aus diesem Grund habe ich mir die Frage gestellt, ob ich die Informationen des CERT nicht auch hier zentral einlaufen lassen kann. Für diesen Zweck bietet Python die ideale Möglichkeit, einen RSS-Feeds zu lesen, zu filtern und die Informationen direkt in einen Microsoft Teams-Kanal zu posten. Durch Webhooks habe ich nun auch diese wichtigen Informationen zentral zur Hand, ohne eine zusätzliche Anwendung nutzen zu müssen.

Warum Python und Microsoft Teams?

Python:

  • Vielseitigkeit: Python ist eine der vielseitigsten Programmiersprachen und eignet sich hervorragend für das Web Scraping, das Arbeiten mit APIs und die Automatisierung von Routineaufgaben.
  • Einfachheit: Python ist bekannt für seine Lesbarkeit und einfache Syntax, was die Entwicklung und Wartung von Skripten erleichtert.
  • Breite Community: Eine umfangreiche Community unterstützt Python, was bedeutet, dass zahlreiche Bibliotheken und Tools zur Verfügung stehen, um Projekte wie dieses zu erleichtern.

Microsoft Teams:

  • Zentralisierung: Teams dient als zentrale Plattform für Kommunikation und Kollaboration in vielen Unternehmen.
  • Integration: Die Möglichkeit, benutzerdefinierte Webhooks zu verwenden, macht Teams zu einer idealen Plattform, um automatisierte Benachrichtigungen zu integrieren.
  • Zugänglichkeit: Informationen können leicht geteilt und diskutiert werden, wodurch ein schneller Informationsfluss innerhalb des Unternehmens gewährleistet wird.

Das Skript

Das vorgeschlagene Skript nutzt die Fähigkeiten von Python, den RSS-Feed des BSI CERT-Bund zu lesen, relevante Informationen herauszufiltern und diese dann automatisch in einem spezifischen Teams-Kanal zu posten. Durch die Filterung von weniger kritischen Warnungen ([niedrig] und [UPDATE]) kann ich mich auf die wesentlichen und handlungsbedürftigen Sicherheitswarnungen konzentrieren.

Zur Nutzung des Skripts ist es erforderlich zuerst feedparser mittels pio zu installieren.

pip install feedparser

Python-Skript

# Beschreibung: Python Automatisierungsskript zum Abruf des BSI CERT-Bund RSS-Reefs und anschließendem Posting in einem Teams-Kanal
# Autor: Danny Korpan; Version 1.0 vom 09.09.2023;
import requests
import feedparser
import os

def load_previous_entries(file_path):
    if os.path.exists(file_path):
        with open(file_path, 'r') as f:
            return set(line.strip() for line in f.readlines())
    return set()

def save_posted_entries(file_path, entry_ids):
    with open(file_path, 'w') as f:
        for entry_id in entry_ids:
            f.write(f"{entry_id}\n")

def fetch_rss_feed(url):
    try:
        return feedparser.parse(url)
    except Exception as e:
        return None

def post_to_teams(webhook_url, message_text):
    try:
        message = {"text": message_text}
        r = requests.post(webhook_url, json=message)
        r.raise_for_status()
    except Exception as e:
        pass

def main():
    # Constants and settings
    rss_url = "https://wid.cert-bund.de/content/public/securityAdvisory/rss"
    webhook_url = "WEBHOOK_URL_HIER_EINFÜGEN"
    posted_entries_file = "posted_entries.txt"
    max_stored_entries = 500  # Adjust based on the maximum entries your RSS feed holds

    # Load previous state
    posted_entry_ids = load_previous_entries(posted_entries_file)

    # Fetch RSS feed
    feed = fetch_rss_feed(rss_url)
    if feed is None:
        print("Failed to fetch the RSS feed.")
        return

    # Initialize new messages list
    new_messages = []

    # Iterate through each entry in the feed
    for entry in feed.entries:
        entry_id = entry.get("id", entry.get("link", ""))

        # Skip entries that have already been posted
        if entry_id in posted_entry_ids:
            continue

        title = entry.title
        link = entry.link

        # Filter messages
        if "[UPDATE]" in title or "[niedrig]" in title:
            continue

        # Add the message to the list of new messages
        new_messages.append(f"{title}\n[Weiterlesen]({link})")

        # Add the ID to the set of posted entries
        posted_entry_ids.add(entry_id)

        # Remove the oldest entry if the set size exceeds max_stored_entries
        if len(posted_entry_ids) > max_stored_entries:
            posted_entry_ids.pop()

    # Save the state
    save_posted_entries(posted_entries_file, posted_entry_ids)

    # Divide the messages into chunks under 27 KB
    chunk_messages = []
    chunk = ""
    for message in new_messages:
        if len(chunk + message) > 27000:
            chunk_messages.append(chunk)
            chunk = ""
        chunk += message + "\n\n"

    # Add the remaining chunk
    if chunk:
        chunk_messages.append(chunk)

    # Post the messages
    if chunk_messages:
        for message_text in chunk_messages:
            post_to_teams(webhook_url, message_text)
        print("New articles have been posted to Teams.")
    else:
        print("No new articles to post to Teams.")

if __name__ == "__main__":
    main()

Zuletzt ist es noch erforderlich einen Cronjob einzurichten, der mir in diesem Fall von Montag bis Freitag entsprechende Meldungen direkt in den gewünschten Teams-Kanal postet.

0 9 * * 1-5 cd /opt/python-scripts && /usr/bin/python3 /opt/python-scripts/bsi-cert-bund.py

Das Ergebnis sieht so aus

Screenshot Teams