安全

Qdrant 支持多种安全功能,旨在帮助您保护其实例。为了使您的实例达到生产就绪状态,其中大多数功能需要进行明确配置。请仔细阅读以下部分。

保障实例安全

默认情况下,所有自托管的 Qdrant 实例都是不安全的。它们向所有网络接口开放,且未配置任何身份验证。它们可能会在没有任何限制的情况下向互联网上的任何人开放。因此,您必须采取安全措施,使您的实例达到生产就绪状态。请仔细阅读本节,了解如何保护您的实例。

通过 Qdrant Cloud 部署的实例默认始终是安全的。请参阅身份验证客户端 IP 限制

为了妥善保护您自己的实例,我们强烈建议采取以下步骤

  1. 身份验证:设置 API 密钥以防止未经授权的访问。
    这是防止未经身份验证的参与者访问您数据的最重要步骤。
  2. 网络绑定:绑定到特定的网络接口或 IP 地址。
    本地开发时,请绑定到 127.0.0.1 以防止所有外部访问。部署到生产环境时,请绑定到私有网络接口或 IP。
  3. TLS:使用 TLS 在所有地方启用加密流量。

认证

自 v1.2.0 起可用

Qdrant 支持使用静态 API 密钥进行简单的客户端身份验证。这可用于保护您的实例。

要在您自己的 Qdrant 实例中启用基于 API 密钥的身份验证,您必须在配置中指定一个密钥

service:
  # Set an api-key.
  # If set, all requests must include a header with the api-key.
  # example header: `api-key: <API-KEY>`
  #
  # If you enable this you should also enable TLS.
  # (Either above or via an external service like nginx.)
  # Sending an api-key over an unencrypted channel is insecure.
  api_key: your_secret_api_key_here

或者,您可以使用环境变量

docker run -p 6333:6333 \
    -e QDRANT__SERVICE__API_KEY=your_secret_api_key_here \
    qdrant/qdrant

有关在 Qdrant Cloud 中使用基于 API 密钥的身份验证的信息,请参阅云平台的身份验证部分。

随后,API 密钥必须存在于发往您实例的所有 REST 或 gRPC 请求中。所有官方的 Python、Go、Rust、.NET 和 Java 的 Qdrant 客户端均支持 API 密钥参数。

curl \
  -X GET https://:6333 \
  --header 'api-key: your_secret_api_key_here'
from qdrant_client import QdrantClient

client = QdrantClient(
    url="https://:6333",
    api_key="your_secret_api_key_here",
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({
  url: "https://",
  port: 6333,
  apiKey: "your_secret_api_key_here",
});
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://xyz-example.eu-central.aws.cloud.qdrant.io:6334")
    .api_key("<paste-your-api-key-here>")
    .build()?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

QdrantClient client =
    new QdrantClient(
        QdrantGrpcClient.newBuilder(
                "xyz-example.eu-central.aws.cloud.qdrant.io",
                6334,
                true)
            .withApiKey("<paste-your-api-key-here>")
            .build());
using Qdrant.Client;

var client = new QdrantClient(
  host: "xyz-example.eu-central.aws.cloud.qdrant.io",
  https: true,
  apiKey: "<paste-your-api-key-here>"
);
import "github.com/qdrant/go-client/qdrant"

client, err := qdrant.NewClient(&qdrant.Config{
	Host:   "xyz-example.eu-central.aws.cloud.qdrant.io",
	Port:   6334,
	APIKey: "<paste-your-api-key-here>",
	UseTLS: true,
})

只读 API 密钥

自 v1.7.0 起可用

除了常规 API 密钥外,Qdrant 还支持只读 API 密钥。该密钥可用于访问实例上的只读操作。

service:
  read_only_api_key: your_secret_read_only_api_key_here

或通过环境变量

export QDRANT__SERVICE__READ_ONLY_API_KEY=your_secret_read_only_api_key_here

这两个 API 密钥可以同时使用。

轮换 API 密钥

从 v1.17.0 开始提供

在分布式部署中,您可以轮换 API 密钥而无需停机。使用 alt_api_key 设置临时配置第二个 API 密钥,其作用与主 api_key 相同,从而允许旧密钥和新密钥同时处于活动状态。

service:
  api_key: your_current_api_key_here
  alt_api_key: your_new_api_key_here

要在不中断服务的情况下轮换 API 密钥

  1. 为每个对等节点配置新密钥作为 alt_api_key。每次仅重启一个节点以避免停机(滚动重启)。在轮换窗口期间,接受使用任一密钥进行身份验证的请求。
  2. 将客户端切换到新密钥。
  3. 对对等节点执行另一次滚动重启,将新密钥提升为 api_key 并移除 alt_api_key

基于 JWT 的细粒度访问控制

v1.9.0 版本起提供

对于更复杂的情况,Qdrant 支持使用 JSON Web Tokens (JWT) 进行细粒度访问控制。这允许您创建限制对集群中存储数据访问的令牌,并在此基础上构建基于角色的访问控制 (RBAC)。通过这种方式,您可以定义用户权限并限制对敏感端点的访问。

要在您自己的 Qdrant 实例中启用基于 JWT 的身份验证,您需要在配置中指定 api-key 并启用 jwt_rbac 功能

service:
  api_key: you_secret_api_key_here
  jwt_rbac: true

或通过环境变量

export QDRANT__SERVICE__API_KEY=your_secret_api_key_here
export QDRANT__SERVICE__JWT_RBAC=true

配置中设置的 api_key 将用于对 JWT 进行编码和解码,因此——不用多说——请务必妥善保管。如果您的 api_key 发生更改,所有现有令牌都将失效。

要使用基于 JWT 的身份验证,您需要在请求的 Authorization 标头中以 Bearer Token 的形式提供它,或者在 Api-Key 标头中作为密钥提供。

Authorization: Bearer <JWT>

// or

Api-Key: <JWT>
from qdrant_client import QdrantClient

qdrant_client = QdrantClient(
    "xyz-example.eu-central.aws.cloud.qdrant.io",
    api_key="<JWT>",
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({
  host: "xyz-example.eu-central.aws.cloud.qdrant.io",
  apiKey: "<JWT>",
});
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://xyz-example.eu-central.aws.cloud.qdrant.io:6334")
    .api_key("<JWT>")
    .build()?;
import io.qdrant.client.QdrantClient;
import io.qdrant.client.QdrantGrpcClient;

QdrantClient client =
    new QdrantClient(
        QdrantGrpcClient.newBuilder(
                "xyz-example.eu-central.aws.cloud.qdrant.io",
                6334,
                true)
            .withApiKey("<JWT>")
            .build());
using Qdrant.Client;

var client = new QdrantClient(
  host: "xyz-example.eu-central.aws.cloud.qdrant.io",
  https: true,
  apiKey: "<JWT>"
);
import "github.com/qdrant/go-client/qdrant"

client, err := qdrant.NewClient(&qdrant.Config{
	Host:   "xyz-example.eu-central.aws.cloud.qdrant.io",
	Port:   6334,
	APIKey: "<JWT>",
	UseTLS: true,
})

生成 JSON Web Tokens

由于 JWT 的特性,任何知道 api_key 的人都可以使用现有的库和工具生成令牌,他们无需访问 Qdrant 实例即可生成。

为方便起见,我们在 Qdrant Web UI 的 🔑 选项卡下添加了一个 JWT 生成工具。如果您使用默认 URL,它位于 https://:6333/dashboard#/jwt

  • JWT 标头 - Qdrant 使用 HS256 算法来解码令牌。

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • JWT 有效载荷 - 您可以在有效载荷中包含可用参数的任意组合。请继续阅读以了解每个参数的详细信息。

    {
      "exp": 1640995200, // Expiration time
      "value_exists": ..., // Validate this token by looking for a point with a payload value
      "access": "r", // Define the access level.
    }
    

签名令牌 - 为确认生成的令牌有效,它必须使用您在配置中设置的 api_key 进行签名。这意味着,知道 api_key 的人可以授权新令牌在 Qdrant 实例中使用。Qdrant 可以验证签名,因为它知道 api_key 并可以解码该令牌。

令牌生成过程可以在客户端离线完成,无需与 Qdrant 实例进行任何通信。

以下是可以用于生成 JWT 令牌的库示例

以下是使用 jwt-cli 的示例

jwt encode --payload '{
  "access": "r",
  "exp": 1766055305
}' --secret 'your-api-key'

JWT 配置

这些是可用选项,即 JWT 术语中的声明 (claims)。您可以在 JWT 有效载荷中使用它们来定义其功能。

  • exp - 令牌的过期时间。这是一个以秒为单位的 Unix 时间戳。此时间后令牌将失效。此声明的检查包含 30 秒的宽限期,以考虑时钟偏差。

    {
      "exp": 1640995200, // Expiration time
    }
    
  • value_exists - 此声明可用于根据集合中存储的数据验证令牌。此声明的结构如下

    {
      "value_exists": {
        "collection": "my_validation_collection",
        "matches": [
          { "key": "my_key", "value": "value_that_must_exist" }
        ],
      },
    }
    

    如果存在此声明,Qdrant 将检查集合中是否存在具有指定键值的点 (point)。如果存在,则令牌有效。

    如果您希望能够在不更改 api_key 的情况下撤销令牌,此声明特别有用。考虑这样一种情况:您拥有一个用户集合,并且想要撤销对特定用户的访问权限。

    {
      "value_exists": {
        "collection": "users",
        "matches": [
          { "key": "user_id", "value": "andrey" },
          { "key": "role", "value": "manager" }
        ],
      },
    }
    

    您可以创建一个带有此声明的令牌,当您想要撤销访问权限时,可以将该用户的 role 更改为其他内容,令牌将失效。

  • access - 此声明定义了令牌的访问级别。如果存在此声明,Qdrant 将检查令牌是否具有执行该操作所需的访问级别。如果存在此声明,则假定为 manage(管理)访问权限。

    它可以提供全局访问权限,使用 r 表示只读,或 m 表示管理。例如

    {
      "access": "r"
    }
    

    它也可以针对一个或多个集合。每个集合的 access 级别为 r(只读)或 rw(读写),如下所示

    {
      "access": [
        {
          "collection": "my_collection",
          "access": "rw"
        }
      ]
    }
    

访问权限表

查看此表以了解根据访问级别允许或拒绝哪些操作。

这也适用于使用 API 密钥而非令牌的情况。在这种情况下,api_key 映射到 manage(管理),而 read_only_api_key 映射到 read-only(只读)。

符号: ✅ 允许 | ❌ 拒绝 | 🟡 允许,但已过滤
操作管理 (manage)只读 (read-only)集合读写 (collection read-write)集合只读 (collection read-only)
列出集合🟡🟡
获取集合信息
创建集合
删除集合
更新集合参数
获取集合集群信息
检查集合是否存在
更新集合集群设置
更新别名
列出集合别名🟡🟡
列出所有别名🟡🟡
创建分片键
删除分片键
创建负载索引
删除负载索引
列出集合快照
创建集合快照
删除集合快照
下载集合快照
上传集合快照
恢复集合快照
列出分片快照
创建分片快照
删除分片快照
下载分片快照
上传分片快照
恢复分片快照
列出完整快照
创建完整快照
删除完整快照
下载完整快照
获取集群信息
恢复 Raft 状态
删除节点
获取点 (Get point)
获取多个点 (Get points)
更新点 (Upsert points)
批量更新点
删除点
更新向量
删除向量
设置负载 (Set payload)
覆盖负载 (Overwrite payload)
删除负载
清除负载
滚动扫描点 (Scroll points)
查询点 (Query points)
搜索点 (Search points)
搜索分组 (Search groups)
推荐点 (Recommend points)
推荐分组 (Recommend groups)
发现点 (Discover points)
计数点 (Count points)
版本
readyz, healthz, livez
遥测
指标

审计日志

从 v1.17.0 开始提供

审计日志记录所有需要身份验证或授权的 API 操作,并将它们以 JSON 格式写入日志文件。

默认情况下不启用审计日志。要启用它,请使用以下配置选项

audit:
  enabled: false
  dir: ./storage/audit
  rotation: daily
  max_log_files: 7

默认情况下,审计日志每日轮换,并保留最近七个日志文件。要配置按小时轮换,请将 rotation 设置为 hourly。当日志文件数量超过 max_log_files 时,最旧的日志文件将被删除。

网络绑定

默认情况下,自定义的 Qdrant 部署会绑定到所有网络接口。您的实例可能会向互联网上的任何人开放。在本地开发机器上,您可能有防火墙来防止公共访问,但在公共 VPS 或专用服务器上情况可能并非如此。

强烈建议绑定到特定的接口或 IP 地址以防止未经授权的访问

  • 本地开发时,绑定到 127.0.0.1,这样无法进行外部访问
  • 或者,部署到生产环境时,绑定到私有网络接口或 IP

使用 Docker 时,您可以使用发布标志 (publish flag) 绑定到特定接口。例如

docker run -p 127.0.0.1:6333:6333 qdrant/qdrant

如果使用其他类型的部署,您可以在 Qdrant 本身中配置绑定地址。要么在配置中设置 service.host: 127.0.0.1,要么使用环境变量,如下所示

QDRANT__SERVICE__HOST=127.0.0.1 ./qdrant

托管的 Qdrant Cloud 部署默认始终是安全的。它们是公开可访问的,并绑定到分配给集群的端点。您可以使用API 密钥配置身份验证,并通过客户端 IP 限制将访问权限限制为特定 IP 地址。混合云 (Hybrid Cloud)私有云 (Private Cloud) 部署有其各自的配置方式。

TLS

自 v1.2.0 起可用

可以在您的 Qdrant 实例上启用用于加密连接的 TLS,以保护连接安全。

首先确保您拥有用于 TLS 的证书和私钥,通常为 .pem 格式。在本地机器上,您可以使用 mkcert 生成自签名证书。

要启用 TLS,请在 Qdrant 配置中设置以下属性并使用正确的路径,然后重启

service:
  # Enable HTTPS for the REST and gRPC API
  enable_tls: true

# TLS configuration.
# Required if either service.enable_tls or cluster.p2p.enable_tls is true.
tls:
  # Server certificate chain file
  cert: ./tls/cert.pem

  # Server private key file
  key: ./tls/key.pem

对于运行集群模式时的内部通信,可以通过以下方式启用 TLS

cluster:
  # Configuration of the inter-cluster communication
  p2p:
    # Use TLS for communication between peers
    enable_tls: true

启用 TLS 后,您必须开始使用 HTTPS 连接。例如

curl -X GET https://:6333
from qdrant_client import QdrantClient

client = QdrantClient(
    url="https://:6333",
)
import { QdrantClient } from "@qdrant/js-client-rest";

const client = new QdrantClient({ url: "https://", port: 6333 });
use qdrant_client::Qdrant;

let client = Qdrant::from_url("https://:6334").build()?;

证书轮换默认启用,刷新时间为一小时。这意味着 Qdrant 在运行时每小时会重新加载一次证书文件。这样,当外部更新证书时,更改后的证书会被获取。可以通过更改 tls.cert_ttl 设置来调整刷新时间。即使您不打算更新证书,也可以保持此功能开启。目前这仅支持 REST API。

(可选)您可以针对本地证书颁发机构在服务器上启用客户端证书验证。设置以下属性并重启

service:
  # Check user HTTPS client certificate against CA file specified in tls config
  verify_https_client_certificate: false

# TLS configuration.
# Required if either service.enable_tls or cluster.p2p.enable_tls is true.
tls:
  # Certificate authority certificate file.
  # This certificate will be used to validate the certificates
  # presented by other nodes during inter-cluster communication.
  #
  # If verify_https_client_certificate is true, it will verify
  # HTTPS client certificate
  #
  # Required if cluster.p2p.enable_tls is true.
  ca_cert: ./tls/cacert.pem

加固 (Hardening)

我们建议减少授予 Qdrant 容器的权限量,以降低利用风险。以下是减少 Qdrant 容器权限的一些方法

  • 以非 root 用户身份运行 Qdrant。这有助于降低未来容器逃逸漏洞的风险。Qdrant 无需 root 用户权限即可运行。

    • 您可以使用镜像 qdrant/qdrant:<version>-unprivileged 而不是默认的 Qdrant 镜像。
    • 运行 docker run 时,可以使用 --user=1000:2000 标志。
    • 使用 Docker Compose 时,可以设置 user: 1000
    • 在 Kubernetes 中运行时,可以设置 runAsUser: 1000(我们的 Helm 图表默认执行此操作)。
  • 使用只读根文件系统运行 Qdrant。这有助于缓解需要修改系统文件才能利用的漏洞,而 Qdrant 不需要此权限。只要容器使用挂载卷进行存储(默认情况下为 /qdrant/storage/qdrant/snapshots),Qdrant 就可以继续运行,同时被阻止写入这些卷之外的数据。

  • 阻止 Qdrant 的外部网络访问。这有助于缓解服务端请求伪造 (SSRF) 攻击,例如通过快照恢复 API。单节点 Qdrant 集群不需要任何出站网络访问。多节点 Qdrant 集群只需要能够通过 TCP 端口 6333、6334 和 6335 连接到其他 Qdrant 节点。

根据您的部署方法,还有其他减少权限的技术,例如放弃 Linux 权能 (capabilities),但上述方法是最重要的。

此页面有用吗?

感谢您的反馈!🙏

很遗憾听到这个消息。😔 您可以在 GitHub 上编辑此页面,或创建一个 GitHub Issue。