diff --git a/source/includes/authentication/azure-envs-connection-string.py b/source/includes/authentication/azure-envs-connection-string.py new file mode 100644 index 00000000..b0391ba0 --- /dev/null +++ b/source/includes/authentication/azure-envs-connection-string.py @@ -0,0 +1,17 @@ +from pymongo import MongoClient +from azure.identity import DefaultAzureCredential +from pymongo.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult + +# define callback, properties, URI, and MongoClient +audience = "" +client_id = "" +class MyCallback(OIDCCallback): + def fetch(self, context: OIDCCallbackContext) -> OIDCCallbackResult: + credential = DefaultAzureCredential(managed_identity_client_id=client_id) + token = credential.get_token(f"{audience}/.default").token + return OIDCCallbackResult(access_token=token) +properties = {"OIDC_CALLBACK": MyCallback()} +uri = ("mongodb://:/?" + "&authMechanism=MONGODB-OIDC" + "&authMechanismProperties=properties") +client = MongoClient(uri) \ No newline at end of file diff --git a/source/includes/authentication/azure-envs-mongoclient.py b/source/includes/authentication/azure-envs-mongoclient.py new file mode 100644 index 00000000..209d6dbf --- /dev/null +++ b/source/includes/authentication/azure-envs-mongoclient.py @@ -0,0 +1,18 @@ +from pymongo import MongoClient +from azure.identity import DefaultAzureCredential +from pymongo.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult + +# define callback, properties, and MongoClient +audience = "" +client_id = "" +class MyCallback(OIDCCallback): + def fetch(self, context: OIDCCallbackContext) -> OIDCCallbackResult: + credential = DefaultAzureCredential(managed_identity_client_id=client_id) + token = credential.get_token(f"{audience}/.default").token + return OIDCCallbackResult(access_token=token) +properties = {"OIDC_CALLBACK": MyCallback()} +client = MongoClient( + "mongodb://:", + authMechanism="MONGODB-OIDC", + authMechanismProperties=properties, +) \ No newline at end of file diff --git a/source/includes/authentication/azure-imds-connection-string.py b/source/includes/authentication/azure-imds-connection-string.py new file mode 100644 index 00000000..19c0769c --- /dev/null +++ b/source/includes/authentication/azure-imds-connection-string.py @@ -0,0 +1,9 @@ +from pymongo import MongoClient + +# define properties, URI, and MongoClient +properties = {"ENVIRONMENT": "azure", "TOKEN_RESOURCE": ""} +uri = ("mongodb://:/?" + "username=" + "&authMechanism=MONGODB-OIDC" + "&authMechanismProperties=properties") +client = MongoClient(uri) \ No newline at end of file diff --git a/source/includes/authentication/azure-imds-mongoclient.py b/source/includes/authentication/azure-imds-mongoclient.py new file mode 100644 index 00000000..3cf0ad89 --- /dev/null +++ b/source/includes/authentication/azure-imds-mongoclient.py @@ -0,0 +1,10 @@ +from pymongo import MongoClient + +# define properties and MongoClient +properties = {"ENVIRONMENT": "azure", "TOKEN_RESOURCE": ""} +client = MongoClient( + "mongodb://:", + username="", + authMechanism="MONGODB-OIDC", + authMechanismProperties=properties, +) \ No newline at end of file diff --git a/source/includes/authentication/gcp-gke-connection-string.py b/source/includes/authentication/gcp-gke-connection-string.py new file mode 100644 index 00000000..b751497b --- /dev/null +++ b/source/includes/authentication/gcp-gke-connection-string.py @@ -0,0 +1,14 @@ +from pymongo import MongoClient +from pymongo.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult + +# define callback, properties, URI, and MongoClient +class MyCallback(OIDCCallback): + def fetch(self, context: OIDCCallbackContext) -> OIDCCallbackResult: + with open("/var/run/secrets/kubernetes.io/serviceaccount/token") as fid: + token = fid.read() + return OIDCCallbackResult(access_token=token) +properties = {"OIDC_CALLBACK": MyCallback()} +uri = ("mongodb://:/?" + "&authMechanism=MONGODB-OIDC" + "&authMechanismProperties=properties") +client = MongoClient(uri) \ No newline at end of file diff --git a/source/includes/authentication/gcp-gke-mongoclient.py b/source/includes/authentication/gcp-gke-mongoclient.py new file mode 100644 index 00000000..d2ef0a62 --- /dev/null +++ b/source/includes/authentication/gcp-gke-mongoclient.py @@ -0,0 +1,15 @@ +from pymongo import MongoClient +from pymongo.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult + +# define callback, properties, and MongoClient +class MyCallback(OIDCCallback): + def fetch(self, context: OIDCCallbackContext) -> OIDCCallbackResult: + with open("/var/run/secrets/kubernetes.io/serviceaccount/token") as fid: + token = fid.read() + return OIDCCallbackResult(access_token=token) +properties = {"OIDC_CALLBACK": MyCallback()} +client = MongoClient( + "mongodb://:", + authMechanism="MONGODB-OIDC", + authMechanismProperties=properties, +) \ No newline at end of file diff --git a/source/includes/authentication/gcp-imds-connection-string.py b/source/includes/authentication/gcp-imds-connection-string.py new file mode 100644 index 00000000..26ec832b --- /dev/null +++ b/source/includes/authentication/gcp-imds-connection-string.py @@ -0,0 +1,9 @@ +from pymongo import MongoClient + +# define properties, URI, and MongoClient +properties = {"ENVIRONMENT": "gcp", "TOKEN_RESOURCE": ""} +uri = ("mongodb://:/?" + "username=" + "&authMechanism=MONGODB-OIDC" + "&authMechanismProperties=properties") +client = MongoClient(uri) \ No newline at end of file diff --git a/source/includes/authentication/gcp-imds-mongoclient.py b/source/includes/authentication/gcp-imds-mongoclient.py new file mode 100644 index 00000000..a7cf4aa3 --- /dev/null +++ b/source/includes/authentication/gcp-imds-mongoclient.py @@ -0,0 +1,10 @@ +from pymongo import MongoClient + +# define properties and MongoClient +properties = {"ENVIRONMENT": "gcp", "TOKEN_RESOURCE": ""} +client = MongoClient( + "mongodb://:", + username="", + authMechanism="MONGODB-OIDC", + authMechanismProperties=properties, +) \ No newline at end of file diff --git a/source/security.txt b/source/security.txt index eec23382..07e515d8 100644 --- a/source/security.txt +++ b/source/security.txt @@ -358,7 +358,7 @@ Unix client = pymongo.MongoClient(uri) To learn more about authenticating with Kerberos, see -:ref:`pymongo-kerberos` in the Authentication guide. +:ref:`pymongo-kerberos` in the Enterprise Authentication guide. Windows ~~~~~~~ @@ -393,7 +393,7 @@ Windows client = pymongo.MongoClient(uri) To learn more about authenticating with Kerberos, see -:ref:`pymongo-kerberos` in the Authentication guide. +:ref:`pymongo-kerberos` in the Enterprise Authentication guide. PLAIN SASL ---------- @@ -426,4 +426,95 @@ PLAIN SASL client = pymongo.MongoClient(uri) To learn more about authenticating with PLAIN SASL, see -:ref:`pymongo-sasl` in the Authentication guide. \ No newline at end of file +:ref:`pymongo-sasl` in the Enterprise Authentication guide. + +MONGODB-OIDC +------------ + +Azure IMDS +~~~~~~~~~~ + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/azure-imds-mongoclient.py + :language: python + :copyable: true + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/azure-imds-connection-string.py + :language: python + :copyable: true + +To learn more about authenticating with OIDC, see +:ref:`pymongo-mongodb-oidc-azure-imds` in the Authentication guide. + +GCP IMDS +~~~~~~~~ + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/gcp-imds-mongoclient.py + :language: python + :copyable: true + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/gcp-imds-connection-string.py + :language: python + :copyable: true + +To learn more about authenticating with OIDC, see +:ref:`pymongo-mongodb-oidc-gcp-imds` in the Authentication guide. + +Other Azure Environments +~~~~~~~~~~~~~~~~~~~~~~~~ + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/azure-envs-mongoclient.py + :language: python + :copyable: true + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/azure-envs-connection-string.py + :language: python + :copyable: true + +To learn more about authenticating with OIDC, see +:ref:`pymongo-mongodb-oidc-azure-envs` in the Authentication guide. + +GCP GKE +~~~~~~~ + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/gcp-gke-mongoclient.py + :language: python + :copyable: true + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/gcp-gke-connection-string.py + :language: python + :copyable: true + +To learn more about authenticating with OIDC, see +:ref:`pymongo-mongodb-oidc-gcp-gke` in the Authentication guide. \ No newline at end of file diff --git a/source/security/authentication.txt b/source/security/authentication.txt index b250481f..e09ff3b1 100644 --- a/source/security/authentication.txt +++ b/source/security/authentication.txt @@ -532,10 +532,259 @@ You can set this option in two ways: by passing an argument to the uri = "mongodb://:/?&authMechanism=MONGODB-AWS" client = pymongo.MongoClient(uri) +.. _pymongo-mongodb-oidc: + +MONGODB-OIDC +------------ + +.. important:: + + The MONGODB-OIDC authentication mechanism requires MongoDB v7.0 or later running + on a Linux platform. + +{+driver-short+} supports OIDC authentication for **workload identities**. A workload +identity is an identity you assign to a software workload, such as an application, +service, script, or container, to authenticate and access other services and resources. + +The following sections describe how to use the MONGODB-OIDC authentication mechanism to +authenticate to various platforms. + +For more information about the MONGODB-OIDC authentication mechanism, see +:manual:`OpenID Connect Authentication ` in the MongoDB Server +manual. + +.. _pymongo-mongodb-oidc-azure-imds: + +Azure IMDS +~~~~~~~~~~ + +If your application runs on an Azure VM, or otherwise uses the +`Azure Instance Metadata Service `__ +(IMDS), you can authenticate to MongoDB by using {+driver-short+}'s built-in Azure +support. + +First, create a Python dictionary for your authentication mechanism properties, as shown +in the following example. Replace the ```` placeholder with +the percent-encoded application or service that the OIDC access token is intended for. + +.. literalinclude:: /includes/authentication/azure-imds-mongoclient.py + :language: python + :copyable: true + :start-after: # define properties and MongoClient + :end-before: client = MongoClient( + +Then, set the following connection options: + +- ``username``: The client ID of the Azure managed identity. +- ``authMechanism``: Set to ``"MONGODB-OIDC"``. +- ``authMechanismProperties``: Set to the ``properties`` dictionary that you + created in the previous step. + +You can set these options in two ways: by passing arguments to the +``MongoClient`` constructor or through parameters in your connection string. + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/azure-imds-mongoclient.py + :language: python + :copyable: true + :emphasize-lines: 5-10 + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/azure-imds-connection-string.py + :language: python + :copyable: true + :emphasize-lines: 5-8 + +.. tip:: + + If your application is running on an Azure VM, and only one managed identity is + associated with the VM, you can omit the ``username`` connection option. + +.. _pymongo-mongodb-oidc-gcp-imds: + +GCP IMDS +~~~~~~~~ + +If your application runs on a GCP VM, or otherwise uses the +`GCP Instance Metadata Service `__, +you can authenticate to MongoDB by using {+driver-short+}'s built-in GCP +support. + +First, create a Python dictionary for your authentication mechanism properties, as shown +in the following example. Replace the ```` placeholder with +the percent-encoded application or service that the OIDC access token is intended for. + +.. literalinclude:: /includes/authentication/gcp-imds-mongoclient.py + :language: python + :copyable: true + :start-after: # define properties and MongoClient + :end-before: client = MongoClient( + +Then, set the following connection options: + +- ``username``: The client ID of the GCP managed identity. +- ``authMechanism``: Set to ``"MONGODB-OIDC"``. +- ``authMechanismProperties``: Set to the ``properties`` dictionary that you created + in the previous step. + +You can set these options in two ways: by passing arguments to the +``MongoClient`` constructor or through parameters in your connection string. + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/gcp-imds-mongoclient.py + :language: python + :copyable: true + :emphasize-lines: 5-10 + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/gcp-imds-connection-string.py + :language: python + :copyable: true + :emphasize-lines: 5-8 + +.. _pymongo-mongodb-oidc-azure-envs: + +Other Azure Environments +~~~~~~~~~~~~~~~~~~~~~~~~ + +If your application runs on Azure Functions, App Service Environment (ASE), or Azure +Kubernetes Service (AKS), you can use the +`azure-identity `__ package to fetch +authentication credentials. + +First, use pip to install the ``azure-identity`` library, as shown in the +following example: + +.. code-block:: sh + + python3 -m pip install azure-identity + +Next, define a class that inherits from the ``OIDCCallback`` class. This class must +implement a ``fetch()`` method, which returns the OIDC token in the form of an +``OIDCCallbackResult`` object. + +The following example shows how to define a callback class named ``MyCallback``. This class +includes a ``fetch()`` method that retrieves an OIDC token from a file in the standard +service-account token-file location. + +.. literalinclude:: /includes/authentication/azure-envs-mongoclient.py + :language: python + :copyable: true + :start-after: # define callback, properties, and MongoClient + :end-before: properties = {"OIDC_CALLBACK": MyCallback()} + +After you define your callback class, create a Python dictionary that contains one key, +``"OIDC_CALLBACK"``, whose value is an instance of your custom callback class: + +.. literalinclude:: /includes/authentication/azure-envs-mongoclient.py + :language: python + :copyable: true + :start-after: return OIDCCallbackResult(access_token=token) + :end-before: client = MongoClient( + +Finally, set the following connection options: + +- ``authMechanism``: Set to ``"MONGODB-OIDC"``. +- ``authMechanismProperties``: Set to the ``properties`` dictionary that you created in the + previous step. + +You can set these options in two ways: by passing arguments to the +``MongoClient`` constructor or through parameters in your connection string. + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/azure-envs-mongoclient.py + :language: python + :copyable: true + :emphasize-lines: 14-18 + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/azure-envs-connection-string.py + :language: python + :copyable: true + :emphasize-lines: 14-16 + +.. _pymongo-mongodb-oidc-gcp-gke: + +GCP GKE +~~~~~~~ + +If your application runs on a GCP Google Kubernetes Engine (GKE) cluster with a +`configured service account `__, +you can read the OIDC token from the standard service-account token-file location. + +First, define a class that inherits from the ``OIDCCallback`` class. This class must +implement a ``fetch()`` method, which returns the OIDC token in the form of an +``OIDCCallbackResult`` object. + +The following example shows how to define a callback class named ``MyCallback``. This class +includes a ``fetch()`` method that retrieves an OIDC token from a file in the standard +service-account token-file location. + +.. literalinclude:: /includes/authentication/gcp-gke-mongoclient.py + :language: python + :copyable: true + :start-after: # define callback, properties, and MongoClient + :end-before: properties = {"OIDC_CALLBACK": MyCallback()} + +After you define your callback class, create a Python dictionary that contains one key, +``"OIDC_CALLBACK"``, whose value is an instance of your custom callback class: + +.. literalinclude:: /includes/authentication/gcp-gke-mongoclient.py + :language: python + :copyable: true + :start-after: return OIDCCallbackResult(access_token=token) + :end-before: client = MongoClient( + +Finally, set the following connection options: + +- ``authMechanism``: Set to ``"MONGODB-OIDC"``. +- ``authMechanismProperties``: Set to the ``properties`` dictionary that you created + in the previous step. + +You can set these options in two ways: by passing arguments to the +``MongoClient`` constructor or through parameters in your connection string. + +.. tabs:: + + .. tab:: MongoClient + :tabid: mongoclient + + .. literalinclude:: /includes/authentication/gcp-gke-mongoclient.py + :language: python + :copyable: true + :emphasize-lines: 11-15 + + .. tab:: Connection String + :tabid: connectionstring + + .. literalinclude:: /includes/authentication/gcp-gke-connection-string.py + :language: python + :copyable: true + :emphasize-lines: 11-13 + API Documentation -~~~~~~~~~~~~~~~~~ +----------------- To learn more about authenticating your application in {+driver-short+}, see the following API documentation: -- `MongoClient <{+api-root+}pymongo/mongo_client.html#pymongo.mongo_client.MongoClient>`__ \ No newline at end of file +- `MongoClient <{+api-root+}pymongo/mongo_client.html#pymongo.mongo_client.MongoClient>`__ +- `OIDCCallback <{+api-root+}pymongo/auth_oidc.html#pymongo.auth_oidc.OIDCCallback>`__ \ No newline at end of file