diff --git a/airflow/providers/mongo/CHANGELOG.rst b/airflow/providers/mongo/CHANGELOG.rst index eb629d052830..f7953ef77af2 100644 --- a/airflow/providers/mongo/CHANGELOG.rst +++ b/airflow/providers/mongo/CHANGELOG.rst @@ -27,6 +27,17 @@ Changelog --------- +3.7.0 +...... + +Breaking changes +~~~~~~~~~~~~~~~~ + +Introduced the allow_insecure flag in the extras field of for the MongoDB connection. This flag allows users to control +whether insecure connections are permitted when using SSL encryption. By default, the allow_insecure flag is +set to False. This means that when SSL encryption is enabled (ssl=True), insecure connections are not allowed unless +explicitly specified by the user. + 3.6.0 ..... diff --git a/airflow/providers/mongo/hooks/mongo.py b/airflow/providers/mongo/hooks/mongo.py index 857bbc312ff6..66bc54d010ec 100644 --- a/airflow/providers/mongo/hooks/mongo.py +++ b/airflow/providers/mongo/hooks/mongo.py @@ -19,7 +19,6 @@ from __future__ import annotations import warnings -from ssl import CERT_NONE from typing import TYPE_CHECKING, Any, overload from urllib.parse import quote_plus, urlunsplit @@ -49,6 +48,28 @@ class MongoHook(BaseHook): ex. {"srv": true, "replicaSet": "test", "ssl": true, "connectTimeoutMS": 30000} + For enabling SSL, the `"ssl": true` option can be used within the connection string options, under extra. + In scenarios where SSL is enabled, `allow_insecure` option is not included by default in the connection + unless specified. This is so that we ensure a secure medium while handling connections to MongoDB. + + The `allow_insecure` only makes sense in ssl context and is configurable and can be used in one of + the following scenarios: + + HTTP (ssl = False) + Here, `ssl` is disabled and using `allow_insecure` doesn't make sense. + Example connection extra: {"ssl": false} + + HTTPS, but insecure (ssl = True, allow_insecure = True) + Here, `ssl` is enabled, and the connection allows insecure connections. + Example connection extra: {"ssl": true, "allow_insecure": true} + + HTTPS, but secure (ssl = True, allow_insecure = False - default when SSL enabled): + Here, `ssl` is enabled, and the connection does not allow insecure connections (default behavior when + SSL is enabled). Example connection extra: {"ssl": true} or {"ssl": true, "allow_insecure": false} + + Note: `tls` is an alias to `ssl` and can be used in place of `ssl`. Example: {"ssl": false} or + {"tls": false}. + :param mongo_conn_id: The :ref:`Mongo connection id ` to use when connecting to MongoDB. """ @@ -75,6 +96,27 @@ def __init__(self, mongo_conn_id: str = default_conn_name, *args, **kwargs) -> N self.client: MongoClient | None = None self.uri = self._create_uri() + self.allow_insecure = self.extras.pop("allow_insecure", "false").lower() == "true" + self.ssl_enabled = ( + self.extras.get("ssl", "false").lower() == "true" + or self.extras.get("tls", "false").lower() == "true" + ) + + if self.ssl_enabled and not self.allow_insecure: + # Case: HTTPS + self.allow_insecure = False + elif self.ssl_enabled and self.allow_insecure: + # Case: HTTPS + allow_insecure + self.allow_insecure = True + self.extras.pop("ssl", None) + elif not self.ssl_enabled and "allow_insecure" in self.extras: + # Case: HTTP (ssl=False) with allow_insecure specified + self.log.warning("allow_insecure is only applicable when ssl is set") + self.extras.pop("allow_insecure", None) + elif not self.ssl_enabled: + # Case: HTTP (ssl=False) with allow_insecure not specified + self.allow_insecure = False + def __enter__(self): return self @@ -96,14 +138,9 @@ def get_conn(self) -> MongoClient: # Mongo Connection Options dict that is unpacked when passed to MongoClient options = self.extras - # If we are using SSL disable requiring certs from specific hostname - if options.get("ssl", False): - if pymongo.__version__ >= "4.0.0": - # In pymongo 4.0.0+ `tlsAllowInvalidCertificates=True` - # replaces `ssl_cert_reqs=CERT_NONE` - options.update({"tlsAllowInvalidCertificates": True}) - else: - options.update({"ssl_cert_reqs": CERT_NONE}) + # Set tlsAllowInvalidCertificates based on allow_insecure + if self.allow_insecure: + options["tlsAllowInvalidCertificates"] = True self.client = MongoClient(self.uri, **options) return self.client