Datenbank-Setup: MariaDB Benutzer und Berechtigungen

Jetzt wird's richtig spannend! Wir tauchen in die Welt der Datenbanken ein und richten alles so ein, dass Dein MCP Server sicher und kontrolliert auf Deine Daten zugreifen kann. Keine Sorge, wenn Du noch nicht so viel Erfahrung mit Datenbanken hast - ich erkläre Dir jeden Schritt ausführlich und zeige Dir genau, warum wir was machen.

Was machen wir in diesem Kapitel? Wir erstellen spezielle Datenbankbenutzer mit genau definierten Rechten. Stell Dir das wie verschiedene Schlüssel vor: Ein Schlüssel kann nur Türen öffnen (lesen), der andere kann auch Möbel umstellen (schreiben). So stellen wir sicher, dass niemand mehr macht als erlaubt ist.

MariaDB Benutzer anlegen

Warum brauchen wir spezielle Benutzer? Du könntest theoretisch alles mit dem root-Benutzer machen, aber das wäre wie wenn Du jedem Besucher Deiner Website den Generalschlüssel zu Deinem Haus gibst. Stattdessen erstellen wir zwei spezialisierte Benutzer: einen für's Lesen (wie ein Bibliothekar, der Bücher zeigen aber nicht ändern darf) und einen für's Lesen und Schreiben (wie ein Redakteur, der Inhalte auch bearbeiten darf).

Zuerst verbinden wir uns als Root (Administrator) mit MariaDB:

mysql -u root -p

# Oder wenn Du sudo brauchst:
sudo mysql -u root

Jetzt erstellen wir unsere zwei Benutzer. Falls Du die Passwörter aus dem letzten Kapitel noch nicht generiert hast, keine Panik! Hier nochmal der Befehl: openssl rand -base64 32. Diese kryptisch aussehenden Passwörter sind super sicher - niemand kann sie erraten.

-- Read-Only Benutzer erstellen
CREATE USER 'content_reader'@'localhost'
IDENTIFIED BY 'DEIN_GENERIERTES_PASSWORT_HIER';

-- Read-Write Benutzer erstellen
CREATE USER 'content_writer'@'localhost'
IDENTIFIED BY 'DEIN_GENERIERTES_PASSWORT_HIER';

-- Änderungen übernehmen
FLUSH PRIVILEGES;

Wichtig: Ersetze 'DEIN_GENERIERTES_PASSWORT_HIER' mit den tatsächlichen Passwörtern aus Deiner credentials.json!

Berechtigungen vergeben

Der wichtigste Schritt für Deine Sicherheit! Jetzt definieren wir genau, was jeder Benutzer darf. Das ist wie wenn Du in Deinem Unternehmen Zugriffsrechte verteilst: Der Buchhalter darf in die Finanzdaten schauen, der Vertrieb in die Kundendaten, aber niemand darf einfach alles. Bei Datenbanken funktioniert das genauso, nur dass wir hier mit SQL-Befehlen arbeiten.

Die vier Grundoperationen (CRUD):

Hier vergeben wir die Berechtigungen ganz gezielt:

-- Read-Only Berechtigungen
GRANT SELECT
ON karlkratz_de.content_metadata
TO 'content_reader'@'localhost';

-- Read-Write Berechtigungen
GRANT SELECT, INSERT, UPDATE, DELETE
ON karlkratz_de.content_metadata
TO 'content_writer'@'localhost';

-- Änderungen aktivieren
FLUSH PRIVILEGES;

Das war's schon! Mit diesem Prinzip der minimalen Rechte (auch "Principle of Least Privilege" genannt) sorgen wir für maximale Sicherheit. Jeder Benutzer kann nur genau das, was er für seine Aufgabe braucht - nicht mehr und nicht weniger. Das ist wie in einem gut organisierten Büro: Der Praktikant hat keinen Zugriff auf die Geschäftsführung-Dokumente, und das ist auch gut so.

Tabellenstruktur analysieren

Warum ist das wichtig? Bevor Du mit Daten arbeitest, musst Du wissen, wie sie strukturiert sind. Das ist wie wenn Du ein neues Regal aufbauen willst - erst schaust Du Dir an, welche Fächer es hat und was wo reinpasst. Bei Datenbanktabellen nennen wir diese "Fächer" Spalten, und jede Spalte hat einen bestimmten Datentyp (Text, Zahlen, Datum, etc.).

Lass uns die Tabelle genau unter die Lupe nehmen:

-- Als content_reader einloggen zum Testen
mysql -u content_reader -p

-- Datenbank auswählen
USE karlkratz_de;

-- Tabellenstruktur anzeigen
DESCRIBE content_metadata;

-- Oder detaillierter:
SHOW CREATE TABLE content_metadata\G

Die Ausgabe zeigt Dir alle Spalten mit ihren Datentypen. Diese Information ist Gold wert! Du brauchst sie später für die security.json, wo Du genau festlegst, welche Spalten Dein MCP Server überhaupt ansprechen darf. Das ist eine weitere Sicherheitsebene: Selbst wenn jemand Deinen Server hackt, kann er nur auf die Spalten zugreifen, die Du explizit freigegeben hast.

Typische Tabellenstruktur:

CREATE TABLE content_metadata (
    id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    meta_keywords VARCHAR(500),
    og_title VARCHAR(255),
    og_description TEXT,
    canonical_url VARCHAR(500),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        ON UPDATE CURRENT_TIMESTAMP,
    status ENUM('draft', 'published', 'archived')
        DEFAULT 'draft',
    author_id INT,
    INDEX idx_status (status),
    INDEX idx_author (author_id),
    INDEX idx_created (created_at)
)

Test-Verbindungen

Vertrauen ist gut, Kontrolle ist besser! Jetzt testen wir systematisch, ob unsere Benutzer genau das können, was sie sollen - und vor allem auch, dass sie NICHT mehr können als erlaubt. Das ist wie ein Sicherheitscheck am Flughafen: Wir prüfen, ob alles funktioniert UND ob die Sicherheitsmechanismen greifen.

Read-Only Test

# Als content_reader verbinden
mysql -u content_reader -p -D karlkratz_de

-- SELECT sollte funktionieren
SELECT COUNT(*) FROM content_metadata;
SELECT id, title FROM content_metadata LIMIT 5;

-- INSERT sollte NICHT funktionieren
INSERT INTO content_metadata (title) VALUES ('Test');
-- Erwarteter Fehler: INSERT command denied

Read-Write Test

# Als content_writer verbinden
mysql -u content_writer -p -D karlkratz_de

-- Alle CRUD-Operationen testen
-- INSERT
INSERT INTO content_metadata (title, description, status)
VALUES ('Test Entry', 'Test Beschreibung', 'draft');

-- SELECT
SELECT * FROM content_metadata WHERE title = 'Test Entry';

-- UPDATE
UPDATE content_metadata
SET description = 'Geänderte Beschreibung'
WHERE title = 'Test Entry';

-- DELETE
DELETE FROM content_metadata WHERE title = 'Test Entry';

-- Alles sollte funktionieren!

Python-Verbindungstest

Der Praxistest! Bis jetzt haben wir alles direkt in der Datenbank getestet. Aber Dein MCP Server wird mit Python auf die Datenbank zugreifen. Deshalb testen wir jetzt, ob die Verbindung auch aus Python heraus funktioniert. Das ist der Moment der Wahrheit - wenn das klappt, ist Deine Datenbank bereit für den MCP Server!

# test_db_connection.py
#!/usr/bin/env python3
import pymysql
import json

# Config laden
with open('config/database.json', 'r') as f:
    db_config = json.load(f)

with open('config/credentials.json', 'r') as f:
    cred_config = json.load(f)

# Verbindungsparameter
connection_params = {
    'host': db_config['connections']['karlkratz_de']['host'],
    'port': db_config['connections']['karlkratz_de']['port'],
    'database': db_config['connections']['karlkratz_de']['database'],
    'user': 'content_reader',
    'password': cred_config['database_users']['content_reader']['password'],
    'charset': db_config['connections']['karlkratz_de']['charset']
}

try:
    # Verbindung aufbauen
    connection = pymysql.connect(**connection_params)
    print("OK: Verbindung erfolgreich!")

    # Test-Query
    with connection.cursor() as cursor:
        cursor.execute("SELECT COUNT(*) as count FROM content_metadata")
        result = cursor.fetchone()
        print(f"Anzahl Datensätze: {result[0]}")

    connection.close()

except pymysql.Error as e:
    print(f"FEHLER: {e}")

Ausführen mit:

cd /var/deinverzeichnis/mcp/content-metadata-server
source venv/bin/activate
python test_db_connection.py

Wenn die Verbindung klappt und Du die Anzahl der Datensätze siehst, ist alles richtig konfiguriert!

Sicherheits-Checks

Doppelt hält besser! Auch wenn wir die Berechtigungen sorgfältig vergeben haben, sollten wir nochmal kontrollieren, ob wirklich alles stimmt. Das ist wie wenn Du nach dem Verlassen des Hauses nochmal zurückgehst um zu prüfen, ob Du die Tür abgeschlossen hast. Bei Datenbanksicherheit kann man nicht paranoid genug sein!

-- Als Root einloggen
mysql -u root -p

-- Berechtigungen prüfen
SHOW GRANTS FOR 'content_reader'@'localhost';
SHOW GRANTS FOR 'content_writer'@'localhost';

-- Benutzer auflisten
SELECT User, Host FROM mysql.user
WHERE User IN ('content_reader', 'content_writer');

Die Ausgabe sollte zeigen, dass beide Benutzer nur localhost-Zugriff haben und nur auf die eine Tabelle zugreifen können.

Performance-Indizes

Was sind Indizes und warum sind sie so wichtig? Stell Dir eine Bibliothek mit tausenden Büchern vor. Ohne Katalog müsstest Du jedes einzelne Buch durchschauen, um das richtige zu finden. Ein Index in der Datenbank ist wie so ein Katalog - er sagt der Datenbank, wo sie bestimmte Informationen schnell findet. Der Unterschied? Mit Index: 0,01 Sekunden. Ohne Index: 10 Sekunden oder mehr!

Faustregel: Für jede Spalte, nach der Du oft suchst oder sortierst, solltest Du einen Index anlegen. Aber Vorsicht: Zu viele Indizes machen das Schreiben langsamer, weil die Datenbank bei jeder Änderung auch alle Indizes aktualisieren muss. Es ist wie mit Ordnern im Büro - ein paar gut organisierte sind super, aber wenn Du für jedes Blatt Papier einen eigenen Ordner anlegst, verlierst Du den Überblick.

Schauen wir uns an, welche Indizes sinnvoll sind und wie wir sie anlegen:

-- Als root oder mit ALTER-Rechten
USE karlkratz_de;

-- Vorhandene Indizes anzeigen
SHOW INDEX FROM content_metadata;

-- Falls nötig, Indizes hinzufügen
ALTER TABLE content_metadata ADD INDEX idx_status (status);
ALTER TABLE content_metadata ADD INDEX idx_created (created_at);
ALTER TABLE content_metadata ADD INDEX idx_updated (updated_at);

-- Für Volltextsuche (optional)
ALTER TABLE content_metadata
ADD FULLTEXT(title, description);

Wann merkst Du den Unterschied? Bei kleinen Tabellen (unter 1000 Einträgen) merkst Du kaum einen Unterschied. Aber sobald Deine Tabelle wächst - und das wird sie, glaub mir - werden Indizes zum Lebensretter. Ich hatte mal eine Tabelle mit 2 Millionen Einträgen ohne Index. Eine einfache Suche dauerte 45 Sekunden. Mit Index? 0,003 Sekunden. Das ist der Unterschied zwischen einem frustrierten und einem zufriedenen Nutzer.

Backup-Strategie

Die wichtigste Regel der Datenbankarbeit: Kein Backup, kein Mitleid! Bevor wir mit dem MCP Server experimentieren, sichern wir unsere Daten. Das ist wie eine Versicherung - Du hoffst, sie nie zu brauchen, aber wenn doch mal was schiefgeht, bist Du unendlich dankbar, dass Du sie hast.

# Tabelle sichern
mysqldump -u root -p karlkratz_de content_metadata > \
    content_metadata_backup_$(date +%Y%m%d).sql

# Oder nur die Struktur
mysqldump -u root -p --no-data karlkratz_de content_metadata > \
    content_metadata_structure.sql

Speichere diese Backups an einem sicheren Ort - am besten sogar an mehreren! Ein Backup auf demselben Server ist besser als nichts, aber ein Backup auf einem anderen System ist Gold wert. Denk dran: Ein Backup, das Du nicht zurückspielen kannst, ist kein Backup. Teste regelmäßig, ob Deine Backups auch wirklich funktionieren!

Fehlersuche

Keine Panik, wenn's nicht sofort klappt! Datenbankverbindungen können zickig sein. Hier sind die häufigsten Probleme und ihre Lösungen - sozusagen meine "Greatest Hits" der Fehlermeldungen, die mir schon begegnet sind:

Access denied for user:

Can't connect to MySQL server:

Table doesn't exist:

Was haben wir erreicht?

Die Datenbank ist jetzt bereit:

Fantastisch, Deine Datenbank ist jetzt bereit für den MCP Server! Aber halt - bevor wir uns ins Coding stürzen, müssen wir noch für Sicherheit sorgen. Im nächsten Kapitel bauen wir gemeinsam das Security-Modul auf. Das wird Dein digitaler Bodyguard: Es schützt vor SQL-Injection (das sind die fiesen Angriffe, wo jemand versucht, Deinen SQL-Code zu manipulieren), begrenzt übereifrige Nutzer mit Rate-Limiting und prüft bei jeder Aktion die Berechtigung. Glaub mir, dieses Kapitel ist wichtig - Sicherheit ist kein Feature, das man später nachrüstet, sondern die Basis für alles andere. Weiter zum Security-Modul mit allen Schutzmaßnahmen