From 165036faed16694509b249a5b027e94d5b712739 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Dec 2025 11:16:51 +0100 Subject: [PATCH 1/3] add username and password to supervisor.ini --- Config/config.php | 2 ++ bin/misp_create_configs.py | 2 ++ supervisor.ini | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Config/config.php b/Config/config.php index f29a455..14c3d7d 100644 --- a/Config/config.php +++ b/Config/config.php @@ -137,6 +137,8 @@ 'max_job_history_ttl' => 86400, 'supervisor_host' => 'unix:/run/supervisor/supervisor.sock', 'supervisor_port' => 9001, + 'supervisor_username' => '{{ SUPERVISOR_USERNAME | default("supervisor") }}', + 'supervisor_password' => '{{ SUPERVISOR_PASSWORD | default("changeme") }}', ], 'GnuPG' => [ 'onlyencrypted' => false, diff --git a/bin/misp_create_configs.py b/bin/misp_create_configs.py index 89395eb..6c0240b 100644 --- a/bin/misp_create_configs.py +++ b/bin/misp_create_configs.py @@ -281,6 +281,8 @@ def parse_mysql_settings(variable_name: str, value: str) -> dict: "PRIO_WORKERS": Option(typ=int, default=3, validation=check_uint), "UPDATE_WORKERS": Option(typ=int, default=1, validation=check_uint), "SCHEDULER_WORKERS": Option(typ=int, default=1, validation=check_uint), + "SUPERVISOR_USERNAME": Option(default="supervisor"), + "SUPERVISOR_PASSWORD": Option(default="changeme", sensitive=True), } CONFIG_CREATED_CANARY_FILE = "/.misp-configs-created" diff --git a/supervisor.ini b/supervisor.ini index 1b60ffb..772066f 100644 --- a/supervisor.ini +++ b/supervisor.ini @@ -7,6 +7,8 @@ user=root file=/run/supervisor/supervisor.sock chmod=0770 chown=root:apache +username={{ SUPERVISOR_USERNAME | default("supervisor") }} +password={{ SUPERVISOR_PASSWORD | default("changeme") }} {% if SYSLOG_ENABLED %} [program:rsyslog] From aeb4297e345dd46ea4075885d823121dcf530b76 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Dec 2025 11:17:22 +0100 Subject: [PATCH 2/3] rework misp_status.py to use auth with supervisor --- bin/misp_status.py | 63 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/bin/misp_status.py b/bin/misp_status.py index 00e0fe7..dee5071 100644 --- a/bin/misp_status.py +++ b/bin/misp_status.py @@ -10,6 +10,7 @@ import logging import subprocess import requests +import base64 import misp_redis_ready @@ -22,20 +23,47 @@ def connect(self): class UnixStreamTransport(xmlrpc.client.Transport, object): - def __init__(self, socket_path): + def __init__(self, socket_path, username=None, password=None): self.socket_path = socket_path + self.username = username + self.password = password + self.verbose = False super().__init__() def make_connection(self, host): return UnixStreamHTTPConnection(self.socket_path) + def request(self, host, handler, request_body, verbose=False): + # Build connection and headers similar to xmlrpc.client.Transport.request + conn = self.make_connection(host) + if verbose: + conn.set_debuglevel(1) -class UnixStreamXMLRPCClient(xmlrpc.client.ServerProxy): - def __init__(self, addr, **kwargs): - transport = UnixStreamTransport(addr) - super().__init__( - "http://", transport=transport, **kwargs - ) + headers = { + "Content-Type": "text/xml", + "User-Agent": self.user_agent, + "Content-Length": str(len(request_body)), + } + + if self.username and self.password: + credentials = base64.b64encode(f"{self.username}:{self.password}".encode()).decode() + headers["Authorization"] = f"Basic {credentials}" + logging.debug(f"[Supervisor] Sending auth header: Authorization: Basic {credentials[:20]}...") + else: + logging.debug("[Supervisor] No credentials configured") + + logging.debug(f"[Supervisor] Headers: {headers}") + conn.request("POST", handler, request_body, headers) + response = conn.getresponse() + + logging.debug(f"[Supervisor] Response status: {response.status} {response.reason}") + logging.debug(f"[Supervisor] Response headers: {response.getheaders()}") + + if response.status != 200: + # Match xmlrpc.client.Transport.request behavior by raising ProtocolError + raise xmlrpc.client.ProtocolError(host + handler, response.status, response.reason, response.getheaders()) + + return self.parse_response(response) class SubprocessException(Exception): @@ -46,7 +74,15 @@ def __init__(self, process: subprocess.CompletedProcess): s = requests.Session() -supervisor_api = UnixStreamXMLRPCClient("/run/supervisor/supervisor.sock") + +# Get supervisor credentials from environment +SUPERVISOR_USERNAME = os.environ.get('SUPERVISOR_USERNAME', 'supervisor') +SUPERVISOR_PASSWORD = os.environ.get('SUPERVISOR_PASSWORD', 'changeme') +SUPERVISOR_SOCKET = "/run/supervisor/supervisor.sock" + +# Create transport with authentication +transport = UnixStreamTransport(SUPERVISOR_SOCKET, SUPERVISOR_USERNAME, SUPERVISOR_PASSWORD) +supervisor_api = xmlrpc.client.ServerProxy("http://", transport=transport) def check_supervisor(): @@ -116,6 +152,17 @@ def check_redis(): def main() -> dict: + # Enable DEBUG logging only when MISP_DEBUG is set to a truthy value + misp_debug = os.environ.get("MISP_DEBUG", "").lower() + debug_enabled = misp_debug in ("1", "true", "yes", "on") + level = logging.DEBUG if debug_enabled else logging.INFO + logging.basicConfig(level=level, format='%(levelname)s:%(name)s:%(message)s') + + # Reduce noisy library logs when not debugging + if not debug_enabled: + logging.getLogger('urllib3').setLevel(logging.WARNING) + logging.getLogger('xmlrpc').setLevel(logging.WARNING) + output = { "supervisor": False, "httpd": False, From 4b04748a075ab81c91d07ecc21275bfc271d8aad Mon Sep 17 00:00:00 2001 From: David Date: Wed, 3 Dec 2025 11:17:55 +0100 Subject: [PATCH 3/3] add supervisor params to readme and compose --- README.md | 12 +++++++++++- docker-compose.yml | 2 ++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1c836b7..f1ebd8d 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,15 @@ MISP requires MySQL or MariaDB database. * `MYSQL_DATABASE` (required, string) - database name * `MYSQL_SETTINGS` (optional, string) - database settings, which should be set for each db connection (JSON dict, or semicolon separated key value pairs) * `MYSQL_FLAGS` (required, string) - PDO flags which should be set for each db connection (JSON dict, or semicolon separated key value pairs) +* `MYSQL_TLS_CA_PATH` (optional, string) - Path to Certificate authority that is used to validate TLS connections with the database (See below) +* `MYSQL_TLS_CERT` (optional, string) - Path to Certificate that is used to identify mTLS connections with the database (See below) +* `MYSQL_TLS_KEY` (optional, string) - Path to Key that is used to identify mTLS connections with the database (See below) + +#### TLS with MySQL + +In order to use TLS when communicating with MySQL you need to have a path to a CA in `MYSQL_TLS_CA_PATH`. You also need to have corresponding PDO flags set: `MYSQL_FLAGS: "PDO::ATTR_STRINGIFY_FETCHES=true;PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT=true;PDO::MYSQL_ATTR_SSL_CA='/path/to/ca.crt'"` (Note: You may need to escape the single quotes depending on how you implement the container). + +To use mTLS you also need to add the cert and keys and the PDO flags (`PDO::MYSQL_ATTR_SSL_CERT` and `PDO::MYSQL_ATTR_SSL_KEY`) as well as configure your MySQL settings to ensure TLS is used. ### Redis @@ -208,7 +217,8 @@ If provided time string is empty, the job will be disabled. ### Supervisor Supervisor is used to run all processes within the container, you can adjust the amount of workers that should be started by modifying these variables: - +* `SUPERVISOR_USERNAME` (required, string, default `supervisor`) - Username for the supervisor user +* `SUPERVISOR_PASSWORD` (required, string, default `changeme`) - Password for the supervisor user * `DEFAULT_WORKERS` (optional, int, default `1`) - number of default workers to start * `EMAIL_WORKERS` (optional, int, default `3`) - number of email workers to start * `CACHE_WORKERS` (optional, int, default `1`) - number of cache workers to start diff --git a/docker-compose.yml b/docker-compose.yml index c7ea38a..3550934 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -65,6 +65,8 @@ services: MISP_MODULE_URL: http://misp-modules MISP_EMAIL: ahoj@example.com # Please change for production SECURITY_SALT: PleaseChangeForProduction # Please change for production + SUPERVISOR_USERNAME: supervisor + SUPERVISOR_PASSWORD: PleaseChangeForProduction # Please change for production ZEROMQ_ENABLED: yes SYSLOG_ENABLED: no ECS_LOG_ENABLED: yes