From c59db4dad00b430e3ce1f72aa1126989ff33bc7b Mon Sep 17 00:00:00 2001 From: asmichaels <63741286+asmichaels@users.noreply.github.com> Date: Sun, 3 Aug 2025 15:10:26 -0300 Subject: [PATCH 1/2] Add SSL support for database connections --- src/config.py | 8 ++++++++ src/server.py | 39 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/config.py b/src/config.py index cc33919..2f1a0ac 100644 --- a/src/config.py +++ b/src/config.py @@ -52,6 +52,14 @@ DB_PASSWORD = os.getenv("DB_PASSWORD") DB_NAME = os.getenv("DB_NAME") +# --- SSL Configuration --- +DB_SSL = os.getenv("DB_SSL", "false").lower() == "true" +DB_SSL_CA = os.getenv("DB_SSL_CA") # Path to CA certificate +DB_SSL_CERT = os.getenv("DB_SSL_CERT") # Path to client certificate +DB_SSL_KEY = os.getenv("DB_SSL_KEY") # Path to client private key +DB_SSL_VERIFY_CERT = os.getenv("DB_SSL_VERIFY_CERT", "true").lower() == "true" +DB_SSL_VERIFY_IDENTITY = os.getenv("DB_SSL_VERIFY_IDENTITY", "false").lower() == "true" + # --- MCP Server Configuration --- # Read-only mode MCP_READ_ONLY = os.getenv("MCP_READ_ONLY", "true").lower() == "true" diff --git a/src/server.py b/src/server.py index 54c0ef9..69e7b3a 100644 --- a/src/server.py +++ b/src/server.py @@ -4,6 +4,8 @@ import argparse from typing import List, Dict, Any, Optional from functools import partial +import os +import ssl import asyncmy import anyio @@ -12,6 +14,7 @@ # Import configuration settings from config import ( DB_HOST, DB_PORT, DB_USER, DB_PASSWORD, DB_NAME, + DB_SSL, DB_SSL_CA, DB_SSL_CERT, DB_SSL_KEY, DB_SSL_VERIFY_CERT, DB_SSL_VERIFY_IDENTITY, MCP_READ_ONLY, MCP_MAX_POOL_SIZE, EMBEDDING_PROVIDER, logger ) @@ -72,6 +75,39 @@ async def initialize_pool(self): try: logger.info(f"Creating connection pool for {DB_USER}@{DB_HOST}:{DB_PORT}/{DB_NAME} (max size: {MCP_MAX_POOL_SIZE})") + + if DB_SSL: + ssl_context = ssl.create_default_context() + if DB_SSL_CA: + if os.path.exists(DB_SSL_CA): + ssl_context.load_verify_locations(cafile=DB_SSL_CA) + logger.info(f"Loaded SSL CA certificate: {DB_SSL_CA}") + else: + logger.warning(f"SSL CA certificate file not found: {DB_SSL_CA}") + + if DB_SSL_CERT and DB_SSL_KEY: + if os.path.exists(DB_SSL_CERT) and os.path.exists(DB_SSL_KEY): + ssl_context.load_cert_chain(DB_SSL_CERT, DB_SSL_KEY) + logger.info(f"Loaded SSL client certificate: {DB_SSL_CERT}") + else: + logger.warning(f"SSL client certificate files not found: cert={DB_SSL_CERT}, key={DB_SSL_KEY}") + + if not DB_SSL_VERIFY_CERT: + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + logger.info("SSL certificate verification disabled") + elif not DB_SSL_VERIFY_IDENTITY: + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_REQUIRED + logger.info("SSL hostname verification disabled, certificate verification enabled") + else: + logger.info("Full SSL verification enabled") + + logger.info("SSL enabled for database connection") + else: + ssl_context = None + logger.info("SSL disabled for database connection") + self.pool = await asyncmy.create_pool( host=DB_HOST, port=DB_PORT, @@ -81,7 +117,8 @@ async def initialize_pool(self): minsize=1, maxsize=MCP_MAX_POOL_SIZE, autocommit=self.autocommit, - pool_recycle=3600 + pool_recycle=3600, + ssl=ssl_context ) logger.info("Connection pool initialized successfully.") except AsyncMyError as e: From f488ef790443ded5a3fc5f623ba9d8f5c5e672a6 Mon Sep 17 00:00:00 2001 From: asmichaels <63741286+asmichaels@users.noreply.github.com> Date: Sun, 3 Aug 2025 15:38:08 -0300 Subject: [PATCH 2/2] update config section of README.md --- README.md | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index f7600f3..681460a 100644 --- a/README.md +++ b/README.md @@ -130,23 +130,29 @@ A vector store table has the following columns: All configuration is via environment variables (typically set in a `.env` file): -| Variable | Description | Required | Default | -|------------------------|--------------------------------------------------------|----------|--------------| -| `DB_HOST` | MariaDB host address | Yes | `localhost` | -| `DB_PORT` | MariaDB port | No | `3306` | -| `DB_USER` | MariaDB username | Yes | | -| `DB_PASSWORD` | MariaDB password | Yes | | -| `DB_NAME` | Default database (optional; can be set per query) | No | | -| `MCP_READ_ONLY` | Enforce read-only SQL mode (`true`/`false`) | No | `true` | -| `MCP_MAX_POOL_SIZE` | Max DB connection pool size | No | `10` | -| `EMBEDDING_PROVIDER` | Embedding provider (`openai`/`gemini`/`huggingface`) | No |`None`(Disabled)| -| `OPENAI_API_KEY` | API key for OpenAI embeddings | Yes (if EMBEDDING_PROVIDER=openai) | | -| `GEMINI_API_KEY` | API key for Gemini embeddings | Yes (if EMBEDDING_PROVIDER=gemini) | | -| `HF_MODEL` | Open models from Huggingface | Yes (if EMBEDDING_PROVIDER=huggingface) | | +| Variable | Description | Required | Default | +| ------------------------ | ---------------------------------------------------- | --------------------------------------- | ---------------- | +| `DB_HOST` | MariaDB host address | Yes | `localhost` | +| `DB_PORT` | MariaDB port | No | `3306` | +| `DB_USER` | MariaDB username | Yes | | +| `DB_PASSWORD` | MariaDB password | Yes | | +| `DB_NAME` | Default database (optional; can be set per query) | No | | +| `DB_SSL` | Enable SSL/TLS connections (`true`/`false`) | No | `false` | +| `DB_SSL_CA` | Path to SSL certificate authority file | No | | +| `DB_SSL_CERT` | Path to SSL client certificate file | No | | +| `DB_SSL_KEY` | Path to SSL client private key file | No | | +| `DB_SSL_VERIFY_CERT` | Verify SSL certificate (`true`/`false`) | No | `true` | +| `DB_SSL_VERIFY_IDENTITY` | Verify SSL server identity (`true`/`false`) | No | `false` | +| `MCP_READ_ONLY` | Enforce read-only SQL mode (`true`/`false`) | No | `true` | +| `MCP_MAX_POOL_SIZE` | Max DB connection pool size | No | `10` | +| `EMBEDDING_PROVIDER` | Embedding provider (`openai`/`gemini`/`huggingface`) | No | `None`(Disabled) | +| `OPENAI_API_KEY` | API key for OpenAI embeddings | Yes (if EMBEDDING_PROVIDER=openai) | | +| `GEMINI_API_KEY` | API key for Gemini embeddings | Yes (if EMBEDDING_PROVIDER=gemini) | | +| `HF_MODEL` | Open models from Huggingface | Yes (if EMBEDDING_PROVIDER=huggingface) | | #### Example `.env` file -**With Embedding Support (OpenAI):** +**With Embedding Support (OpenAI) and SSL:** ```dotenv DB_HOST=localhost DB_USER=your_db_user @@ -154,6 +160,14 @@ DB_PASSWORD=your_db_password DB_PORT=3306 DB_NAME=your_default_database +# SSL Configuration +DB_SSL=true +DB_SSL_CA=/path/to/ca-cert.pem +DB_SSL_CERT=/path/to/client-cert.pem +DB_SSL_KEY=/path/to/client-key.pem +DB_SSL_VERIFY_CERT=true +DB_SSL_VERIFY_IDENTITY=false + MCP_READ_ONLY=true MCP_MAX_POOL_SIZE=10 @@ -174,6 +188,14 @@ MCP_READ_ONLY=true MCP_MAX_POOL_SIZE=10 ``` +**SSL Configuration Notes:** + +- Set `DB_SSL=true` to enable SSL/TLS connections +- Certificate paths should be absolute paths to the certificate files +- Three levels of SSL verification: + 1. **Basic SSL** (`DB_SSL=true`, no certificates): Encrypts connection without certificate verification + 2. **Certificate verification** (`DB_SSL_VERIFY_CERT=true`): Verifies server certificate against CA + 3. **Full verification** (`DB_SSL_VERIFY_CERT=true`, `DB_SSL_VERIFY_IDENTITY=true`): Verifies certificate and server identity --- ## Installation & Setup