You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MongoDB Certificate authentication seems to be broken. The core issue seems to be that with MongoDB 4.0 and greater you have to explicitly pass the following params:
- ``ssl_certfile`` and ``ssl_keyfile`` were deprecated in favor
of ``tlsCertificateKeyFile``.
- ``ssl_cert_reqs`` was deprecated in favor of
``tlsAllowInvalidCertificates``.
- ``ssl_match_hostname`` was deprecated in favor of
``tlsAllowInvalidHostnames``.
- ``ssl_ca_certs`` was deprecated in favor of ``tlsCAFile``.
- ``ssl_certfile`` was deprecated in favor of
``tlsCertificateKeyFile``.
- ``ssl_crlfile`` was deprecated in favor of ``tlsCRLFile``.
- ``ssl_pem_passphrase`` was deprecated in favor of
``tlsCertificateKeyFilePassword``.
Directly using the same modules we use i was able to connect to the DB using certificate authentication using the following code:
# st2 --version
st2 3.7.0, on Python 3.8.12
# cat /etc/*release
NAME="Red Hat Enterprise Linux"
VERSION="8.6 (Ootpa)"
ID="rhel"
ID_LIKE="fedora"
VERSION_ID="8.6"
PLATFORM_ID="platform:el8"
PRETTY_NAME="Red Hat Enterprise Linux 8.6 (Ootpa)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:redhat:enterprise_linux:8::baseos"
HOME_URL="https://www.redhat.com/"
DOCUMENTATION_URL="https://access.redhat.com/documentation/red_hat_enterprise_linux/8/"
BUG_REPORT_URL="https://bugzilla.redhat.com/"
REDHAT_BUGZILLA_PRODUCT="Red Hat Enterprise Linux 8"
REDHAT_BUGZILLA_PRODUCT_VERSION=8.6
REDHAT_SUPPORT_PRODUCT="Red Hat Enterprise Linux"
REDHAT_SUPPORT_PRODUCT_VERSION="8.6"
Red Hat Enterprise Linux release 8.6 (Ootpa)
Red Hat Enterprise Linux release 8.6 (Ootpa)
MongoDB server version: 4.0.28
Steps to reproduce:
/etc/mongo.conf
# mongod.conf
# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/
# where to write logging data.
systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log
# Where and how to store data.
storage:
dbPath: /var/lib/mongo
journal:
enabled: true
# engine:
# mmapv1:
# wiredTiger:
# how the process runs
processManagement:
fork: true # fork and run in background
pidFilePath: /var/run/mongodb/mongod.pid # location of pidfile
timeZoneInfo: /usr/share/zoneinfo
# network interfaces
net:
port: 27017
bindIp: 127.0.0.1
ssl:
mode: requireSSL
PEMKeyFile: /var/lib/mongo/certs/mongo.pem
CAFile: /var/lib/mongo/certs/ca.pem
allowInvalidCertificates: true
#security:
#operationProfiling:
#replication:
#sharding:
## Enterprise-Only Options
#auditLog:
#snmp:
security:
authorization: enabled
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,040 INFO [-] Using Python: 3.8.12 (/opt/stackstorm/st2/bin/python)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,040 INFO [-] Using fs encoding: utf-8, default encoding: utf-8, locale: en_US.UTF-8, LANG env variable: en_US.UTF-8, PYTHONIOENCODING env variable: notset
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,040 INFO [-] Using config files: /etc/st2/st2.conf
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,040 INFO [-] Using logging config: /etc/st2/logging.sensorcontainer.conf
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,041 INFO [-] Using coordination driver: redis
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,041 INFO [-] Using metrics driver: noop
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,090 INFO [-] Connecting to database "st2" @ "127.0.0.1:27017" as user "None".
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,325 INFO [-] Successfully connected to database "st2" @ "127.0.0.1:27017" as user "None".
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: 2022-10-05 12:22:13,357 ERROR [-] (PID:1401793) SensorContainer quit due to exception.
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: Traceback (most recent call last):
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2reactor/cmd/sensormanager.py", line 66, in main
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: _setup()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2reactor/cmd/sensormanager.py", line 48, in _setup
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: common_setup(
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/service_setup.py", line 252, in setup
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: db_setup()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/database_setup.py", line 55, in db_setup
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: connection = db_init.db_setup_with_retry(**db_cfg)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/persistence/db_init.py", line 79, in db_setup_with_retry
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return db_func_with_retry(
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/persistence/db_init.py", line 58, in db_func_with_retry
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return retrying_obj.call(db_func, *args, **kwargs)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/retrying.py", line 206, in call
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return attempt.get(self._wrap_exception)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/retrying.py", line 247, in get
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: six.reraise(self.value[0], self.value[1], self.value[2])
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/six.py", line 696, in reraise
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: raise value
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/retrying.py", line 200, in call
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/models/db/__init__.py", line 257, in db_setup
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: db_ensure_indexes()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/models/db/__init__.py", line 298, in db_ensure_indexes
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: raise e
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/st2common/models/db/__init__.py", line 287, in db_ensure_indexes
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: model_class.ensure_indexes()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/mongoengine/document.py", line 867, in ensure_indexes
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: collection = cls._get_collection()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/mongoengine/document.py", line 215, in _get_collection
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: cls.ensure_indexes()
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/mongoengine/document.py", line 894, in ensure_indexes
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: collection.create_index(fields, background=background, **opts)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/collection.py", line 2059, in create_index
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return self.__create_indexes([index], session, **cmd_options)[0]
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/collection.py", line 1949, in __create_indexes
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: self._command(
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/collection.py", line 238, in _command
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return sock_info.command(
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/pool.py", line 683, in command
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: return command(self, dbname, spec, slave_ok,
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/network.py", line 159, in command
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: helpers._check_command_response(
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: File "/opt/stackstorm/st2/lib/python3.8/site-packages/pymongo/helpers.py", line 164, in _check_command_response
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: raise OperationFailure(errmsg, code, response, max_wire_version)
Oct 5 12:22:13 bradltest7020 st2sensorcontainer[1401793]: pymongo.errors.OperationFailure: command createIndexes requires authentication, full error: {'ok': 0.0, 'errmsg': 'command createIndexes requires authentication', 'code': 13, 'codeName': 'Unauthorized'}
Manual code (not working):
In [1]: import ssl as ssl_lib
...:
...: import mongoengine
...: import pymongo
...:
...:
...: def _get_ssl_kwargs(
...: ssl=False,
...: ssl_keyfile=None,
...: ssl_certfile=None,
...: ssl_cert_reqs=None,
...: ssl_ca_certs=None,
...: authentication_mechanism=None,
...: ssl_match_hostname=True,
...: authentication_source=None,
...: ):
...: # NOTE: In pymongo 3.9.0 some of the ssl related arguments have been renamed -
...: # https://api.mongodb.com/python/current/changelog.html#changes-in-version-3-9-0
...: # Old names still work, but we should eventually update to new argument names.
...: ssl_kwargs = {
...: "ssl": ssl,
...: }
...: if ssl_keyfile:
...: ssl_kwargs["ssl"] = True
...: ssl_kwargs["ssl_keyfile"] = ssl_keyfile
...: if ssl_certfile:
...: ssl_kwargs["ssl"] = True
...: ssl_kwargs["ssl_certfile"] = ssl_certfile
...: if ssl_cert_reqs:
...: if ssl_cert_reqs == "none":
...: ssl_cert_reqs = ssl_lib.CERT_NONE
...: elif ssl_cert_reqs == "optional":
...: ssl_cert_reqs = ssl_lib.CERT_OPTIONAL
...: elif ssl_cert_reqs == "required":
...: ssl_cert_reqs = ssl_lib.CERT_REQUIRED
...: ssl_kwargs["ssl_cert_reqs"] = ssl_cert_reqs
...: if ssl_ca_certs:
...: ssl_kwargs["ssl"] = True
...: ssl_kwargs["ssl_ca_certs"] = ssl_ca_certs
...: if authentication_mechanism:
...: ssl_kwargs["ssl"] = True
...: ssl_kwargs["authentication_mechanism"] = authentication_mechanism
...: if ssl_kwargs.get("ssl", False):
...: # pass in ssl_match_hostname only if ssl is True. The right default value
...: # for ssl_match_hostname in almost all cases is True.
...: ssl_kwargs["ssl_match_hostname"] = ssl_match_hostname
...: if authentication_source:
...: ssl_kwargs["ssl"] = True
...: ssl_kwargs["authentication_source"] = authentication_source
...: return ssl_kwargs
...:
...:
...: ssl_kwargs = _get_ssl_kwargs(
...: ssl=True,
...: ssl_keyfile='/etc/st2/mongo_certs/client.key',
...: ssl_certfile='/etc/st2/mongo_certs/client-signed.crt',
...: ssl_cert_reqs='required',
...: ssl_ca_certs='/etc/st2/mongo_certs/ca.pem',
...: ssl_match_hostname=False,
...: )
...:
...: connection = mongoengine.connection.connect(
...: 'st2',
...: host='127.0.0.1',
...: port=27017,
...: tz_aware=True,
...: username=None,
...: password=None,
...: connectTimeoutMS=3000,
...: serverSelectionTimeoutMS=3000,
...: **ssl_kwargs
...: )
In [2]: connection.admin.command("ping")
Out[2]: {'ok': 1.0}
In [3]: connection.st2.list_collections()
---------------------------------------------------------------------------
OperationFailure Traceback (most recent call last)
Cell In [3], line 1
----> 1 connection.st2.list_collections()
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/database.py:825, in Database.list_collections(self, session, filter, **kwargs)
820 def _cmd(session, server, sock_info, slave_okay):
821 return self._list_collections(
822 sock_info, slave_okay, session, read_preference=read_pref,
823 **kwargs)
--> 825 return self.__client._retryable_read(
826 _cmd, read_pref, session)
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/mongo_client.py:1471, in MongoClient._retryable_read(self, func, read_pref, session, address, retryable, exhaust)
1467 if retrying and not retryable:
1468 # A retry is not possible because this server does
1469 # not support retryable reads, raise the last error.
1470 raise last_error
-> 1471 return func(session, server, sock_info, slave_ok)
1472 except ServerSelectionTimeoutError:
1473 if retrying:
1474 # The application may think the write was never attempted
1475 # if we raise ServerSelectionTimeoutError on the retry
1476 # attempt. Raise the original exception instead.
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/database.py:821, in Database.list_collections.<locals>._cmd(session, server, sock_info, slave_okay)
820 def _cmd(session, server, sock_info, slave_okay):
--> 821 return self._list_collections(
822 sock_info, slave_okay, session, read_preference=read_pref,
823 **kwargs)
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/database.py:770, in Database._list_collections(self, sock_info, slave_okay, session, read_preference, **kwargs)
767 cmd.update(kwargs)
768 with self.__client._tmp_session(
769 session, close=False) as tmp_session:
--> 770 cursor = self._command(
771 sock_info, cmd, slave_okay,
772 read_preference=read_preference,
773 session=tmp_session)["cursor"]
774 return CommandCursor(
775 coll,
776 cursor,
777 sock_info.address,
778 session=tmp_session,
779 explicit_session=session is not None)
780 else:
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/database.py:626, in Database._command(self, sock_info, command, slave_ok, value, check, allowable_errors, read_preference, codec_options, write_concern, parse_write_concern_error, session, **kwargs)
624 command.update(kwargs)
625 with self.__client._tmp_session(session) as s:
--> 626 return sock_info.command(
627 self.__name,
628 command,
629 slave_ok,
630 read_preference,
631 codec_options,
632 check,
633 allowable_errors,
634 write_concern=write_concern,
635 parse_write_concern_error=parse_write_concern_error,
636 session=s,
637 client=self.__client)
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/pool.py:683, in SocketInfo.command(self, dbname, spec, slave_ok, read_preference, codec_options, check, allowable_errors, check_keys, read_concern, write_concern, parse_write_concern_error, collation, session, client, retryable_write, publish_events, user_fields, exhaust_allowed)
681 self._raise_if_not_writable(unacknowledged)
682 try:
--> 683 return command(self, dbname, spec, slave_ok,
684 self.is_mongos, read_preference, codec_options,
685 session, client, check, allowable_errors,
686 self.address, check_keys, listeners,
687 self.max_bson_size, read_concern,
688 parse_write_concern_error=parse_write_concern_error,
689 collation=collation,
690 compression_ctx=self.compression_context,
691 use_op_msg=self.op_msg_enabled,
692 unacknowledged=unacknowledged,
693 user_fields=user_fields,
694 exhaust_allowed=exhaust_allowed)
695 except OperationFailure:
696 raise
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/network.py:159, in command(sock_info, dbname, spec, slave_ok, is_mongos, read_preference, codec_options, session, client, check, allowable_errors, address, check_keys, listeners, max_bson_size, read_concern, parse_write_concern_error, collation, compression_ctx, use_op_msg, unacknowledged, user_fields, exhaust_allowed)
157 client._process_response(response_doc, session)
158 if check:
--> 159 helpers._check_command_response(
160 response_doc, sock_info.max_wire_version, allowable_errors,
161 parse_write_concern_error=parse_write_concern_error)
162 except Exception as exc:
163 if publish:
File /opt/stackstorm/virtualenvs/bolt/lib64/python3.8/site-packages/pymongo/helpers.py:164, in _check_command_response(response, max_wire_version, allowable_errors, parse_write_concern_error)
161 elif code == 43:
162 raise CursorNotFound(errmsg, code, response, max_wire_version)
--> 164 raise OperationFailure(errmsg, code, response, max_wire_version)
OperationFailure: command listCollections requires authentication, full error: {'ok': 0.0, 'errmsg': 'command listCollections requires authentication', 'code': 13, 'codeName': 'Unauthorized'}
SUMMARY
MongoDB Certificate authentication seems to be broken. The core issue seems to be that with MongoDB 4.0 and greater you have to explicitly pass the following params:
We have the ability to pass
authentication_mechanism
from the config but the auth source is missing.Looking into the code a bit i think other values need updated due to deprecations.
https://github.com/mongodb/mongo-python-driver/blob/78476d0217289e5a3fafb5c599a8a88558d87d92/pymongo/mongo_client.py#L559-L584
Directly using the same modules we use i was able to connect to the DB using certificate authentication using the following code:
STACKSTORM VERSION
Steps to reproduce:
/etc/mongo.conf
/etc/st2/st2.conf
error:
Manual code (not working):
Manual code (working):
The text was updated successfully, but these errors were encountered: