安全

请仔细阅读本页面。尽管有多种方法可以保护您的 Qdrant 实例,但它们默认是不安全的。您需要在生产使用前启用安全措施。否则,它们将对任何人完全开放

认证

自 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 请求中。所有官方的 Qdrant Python、Go、Rust、.NET 和 Java 客户端都支持 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 密钥可以同时使用。

使用 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 的认证,您需要将其作为 bearer token 提供在 Authorization 标头中,或作为密钥提供在请求的 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 Header - Qdrant 使用 HS256 算法解码令牌。

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    
  • JWT Payload - 您可以在 payload 中包含可用参数的任意组合。继续阅读以获取每个参数的更多信息。

    {
      "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 配置

这些是可用的选项,在 JWT 术语中称为声明。您可以在 JWT payload 中使用它们来定义其功能。

  • 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 将检查集合中是否存在具有指定键值的点。如果存在,则令牌有效。

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

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

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

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

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

    {
      "access": "r"
    }
    

    它也可以特定于一个或多个集合。每个集合的 access 级别为 r 表示只读,或 rw 表示读写,像这样

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

    您还可以通过指定点必须具有的 payload 限制来指定用户可以访问的集合的子集。

    {
      "access": [
        {
          "collection": "my_collection",
          "access": "r",
          "payload": {
            "user_id": "user_123456"
          }
        }
      ]
    }
    

    payload 声明将用于隐式过滤集合中的点。它等同于将此过滤器附加到每个请求

    { "filter": { "must": [{ "key": "user_id", "match": { "value": "user_123456" } }] } }
    

访问权限表

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

这也适用于使用 API 密钥而不是令牌。在这种情况下,api_key 映射到管理,而 read_only_api_key 映射到只读

符号: ✅ 允许 | ❌ 拒绝 | 🟡 允许,但已过滤
操作管理只读集合读写集合只读带有 payload 声明的集合 (r / rw)
列出集合🟡🟡🟡
获取集合信息
创建集合
删除集合
更新集合参数
获取集合集群信息
集合存在
更新集合集群设置
更新别名
列出集合别名🟡🟡🟡
列出别名🟡🟡🟡
创建分片键
删除分片键
创建 payload 索引
删除 payload 索引
列出集合快照
创建集合快照
删除集合快照
下载集合快照
上传集合快照
恢复集合快照
列出分片快照
创建分片快照
删除分片快照
下载分片快照
上传分片快照
恢复分片快照
列出完整快照
创建完整快照
删除完整快照
下载完整快照
获取集群信息
恢复 Raft 状态
删除对等体
获取点
获取点列表
upsert 点
批量更新点
删除点❌ / 🟡
更新向量
删除向量❌ / 🟡
设置 payload
覆盖 payload
删除 payload
清除 payload
滚动点🟡
查询点🟡
搜索点🟡
搜索组🟡
推荐点
推荐组
发现点
统计点🟡
版本
readyz, healthz, livez
遥测
指标

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

加固

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

  • 以非 root 用户身份运行 Qdrant。这有助于降低未来容器逃逸漏洞的风险。Qdrant 不需要 root 用户的任何特权。

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

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

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

此页面有用吗?

感谢您的反馈!🙏

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