{ "cells": [ { "cell_type": "markdown", "source": [ "# Chroma Authentication\n", "\n", "This tutorial aims to explain how authentication can be setup in Chroma.\n", "\n", "> **Important**: The concept of authentication is only applicable to Client/Server deployments. If you are using Chroma in a standalone mode, authentication is not applicable.\n", "\n", "## Concepts\n", "\n", "### Architecture Overview\n", "\n", "![Authentication Architecture](assets/auth-architecture.png \"Authentication Architecture\")\n", "\n", "### Authentication Flow (Sequence)\n", "\n", "The authentication sequence is applied for every request. It is important to understand that credential computation or retrieval (e.g. from external auth providers) is only done once for the first authenticated request. Subsequent requests will use the same credentials.\n", "\n", "The authentication flow is as follows:\n", "\n", "![Authentication Flow](assets/auh-sequence.png \"Authentication Flow\")\n", "\n", "### Preemptive Authentication\n", "\n", "In its current release the authentication in Chroma works in a preemptive mode. This means that the client is responsible for sending the authentication information on every request. The server will not challenge the client for authentication.\n", "\n", "> **Warning**: There are security risks involved with preemptive authentication in that the client might unintentionally send credentials to malicious or unintended server. When deploying authentication users are encouraged to use HTTPS (always verify server certs), to use secure providers (e.g. JWT) \n", "> and apply good security practices.\n", "\n", "### Authentication Provider\n", "\n", "Authentication in Chroma is handled by Authentication Providers. Providers are pluggable modules that allow Chroma to abstract the authentication mechanism from the rest of the system.\n", "\n", "Chroma ships with the following build-in providers:\n", "- Basic Authentication\n", "- JWT Authentication (work in progress)\n", "\n", "### Client-side Authentication\n", "\n", "Client-side authentication refers to the process of preparing and communicating credentials information on the client-side and sending that information the Chroma server.\n", "\n", "### Server-side Authentication\n", "\n", "Server-side authentication refers to the process of validating the credentials information received from the client and authenticating the client.\n" ], "metadata": { "collapsed": false }, "id": "eae631e46b4c1115" }, { "cell_type": "markdown", "source": [ "## Configuration\n", "\n", "### Server Configuration\n", "\n", "In order for the server to provide auth it needs several pieces of information and depending on the authentication provider you may or may not need to provide all of them.\n", "\n", "- `CHROMA_SERVER_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthServerProvider` class (it is also possible to use `basic` as a shorthand).\n", "- `CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER` - The credentials provider is a way for the server to validate the provided auth information from the client. You can use `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` to validate against a file in htpasswd format (user:password) - single line with bcrypt hash for password. Alternatively you can use a shorthand to load providers (e.g. `htpasswd_file` for `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider`).\n", "- `CHROMA_SERVER_AUTH_CREDENTIALS_FILE` - The path to the credentials file in case the credentials provider requires it. In this case we are using the `chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider` provider which requires a file path.\n", "\n", "\n", "### Client Configuration\n", "\n", "Similarly on the client side we need to provide the following configuration parameters:\n", "\n", "- `CHROMA_CLIENT_AUTH_PROVIDER` - It indicates the authentication provider class to use. In this case we are using the `chromadb.auth.basic.BasicAuthClientProvider` class or `basic` shorthand.\n", "- `CHROMA_CLIENT_AUTH_CREDENTIALS` - The auth credentials to be passed to the provider. In this case we are using the `admin:admin` credentials as we'll be using Basic Auth.\n" ], "metadata": { "collapsed": false }, "id": "87d45f79aed65e21" }, { "cell_type": "markdown", "source": [ "## Setting Up\n", "\n", "### Before You Begin\n", "\n", "Make sure you have either `chromadb` or `chromadb-client` installed. You can do that by running the following command:\n", "\n", "```bash\n", "pip install chromadb\n", "```\n", "or\n", "\n", "```bash\n", "pip install chromadb-client\n", "```\n", "\n", "Make sure Chroma Server is running. Use one of the following methods to start the server:\n", "\n", "From the command line:\n", "\n", "> Note: The below options will configure the server to use Basic Authentication with the username `admin` and password `admin`.\n", "\n", "```bash\n", "export CHROMA_USER=admin\n", "export CHROMA_PASSWORD=admin\n", "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"./server.htpasswd\" \\\n", "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider' \\\n", "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider' \\\n", "uvicorn chromadb.app:app --workers 1 --host 0.0.0.0 --port 8000 --proxy-headers --log-config log_config.yml\n", "```\n", "\n", "With Docker Compose:\n", "\n", "> Note: You need to clone the git repository first and run the command from the repository root.\n", "\n", "```bash\n", "export CHROMA_USER=admin\n", "export CHROMA_PASSWORD=admin\n", "docker run --rm --entrypoint htpasswd httpd:2 -Bbn ${CHROMA_USER} ${CHROMA_PASSWORD} > server.htpasswd\n", "cat << EOF > .env\n", "CHROMA_SERVER_AUTH_CREDENTIALS_FILE=\"/chroma/server.htpasswd\"\n", "CHROMA_SERVER_AUTH_CREDENTIALS_PROVIDER='chromadb.auth.providers.HtpasswdFileServerAuthCredentialsProvider'\n", "CHROMA_SERVER_AUTH_PROVIDER='chromadb.auth.basic.BasicAuthServerProvider'\n", "EOF\n", "docker-compose up -d --build \n", "```\n" ], "metadata": { "collapsed": false }, "id": "af49d8c78f2f7347" }, { "cell_type": "markdown", "source": [ "### Basic Authentication" ], "metadata": { "collapsed": false }, "id": "fc77d909233f2645" }, { "cell_type": "code", "execution_count": 2, "outputs": [ { "data": { "text/plain": "[]" }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import chromadb\n", "from chromadb import Settings\n", "\n", "client = chromadb.HttpClient(\n", " settings=Settings(chroma_client_auth_provider=\"chromadb.auth.basic.BasicAuthClientProvider\",chroma_client_auth_credentials=\"admin:admin\"))\n", "client.heartbeat() # this should work with or without authentication - it is a public endpoint\n", "\n", "client.get_version() # this should work with or without authentication - it is a public endpoint\n", "\n", "client.list_collections() # this is a protected endpoint and requires authentication\n", "\n" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2023-08-22T00:33:16.354523Z", "start_time": "2023-08-22T00:33:15.715736Z" } }, "id": "8f9307acce25f672" }, { "cell_type": "markdown", "source": [ "#### Verifying Authentication (Negative Test)" ], "metadata": { "collapsed": false }, "id": "6b75f04e59cb1d42" }, { "cell_type": "code", "execution_count": 3, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "As expected, you are not authorized to access protected endpoints.\n" ] } ], "source": [ "# Try to access a protected endpoint without authentication\n", "import sys\n", "\n", "client = chromadb.HttpClient()\n", "try:\n", " client.list_collections()\n", "except Exception as e:\n", " if \"Unauthorized\" in str(e):\n", " print(\"As expected, you are not authorized to access protected endpoints.\", file=sys.stderr)\n", " else:\n", " raise e" ], "metadata": { "collapsed": false, "ExecuteTime": { "end_time": "2023-08-22T00:33:19.119718Z", "start_time": "2023-08-22T00:33:19.097558Z" } }, "id": "c0c3240ed4d70a79" }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [], "metadata": { "collapsed": false, "ExecuteTime": { "start_time": "2023-08-11T15:58:07.272237Z" } }, "id": "ab8b90d83f02eda" } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.6" } }, "nbformat": 4, "nbformat_minor": 5 }