使用 RDS MySQL 存储 API Key

更新时间:
复制 MD 格式

将 Agent Sandbox 的 API Key 存储后端由默认的 Secret 切换为云数据库 RDS MySQL,适用于多租户或 Key 数量较多的生产环境。

背景信息

ack-sandbox-manager 支持 Secret 和 MySQL 两种 API Key 存储后端,由 keyStorage.mode 配置项控制,取值为 secret(默认)或 mysql。Secret 后端在开发测试和 Key 数量较少的场景下已可满足需求;如果需要在多租户或 Key 数量较多的生产环境中使用,可切换为 RDS MySQL,此时数据规模不再受单个 Secret 大小限制。

对比项

Secret(默认)

MySQL

外部依赖

需要 MySQL 实例,并配置 DSN 和 hashPepper

存储位置

sandbox-system 命名空间中的 Kubernetes Secret e2b-key-store

外部 MySQL 数据库。

Key 存储形式

存储可恢复的 API Key 原文。

仅存储 HMAC-SHA256(pepper, rawKey) 哈希,不保存原文。

容量

受 Kubernetes 单个 Secret 1 MiB 上限约束。

不受单个 Secret 大小限制,容量取决于数据库实例。

读写方式

每次增删均更新整个 Secret,记录增多后读写开销上升。

按 Key 哈希查询,读写开销相对稳定。

多副本

多个副本共享同一个 Secret。

多个副本共享同一个数据库。

适用场景

开发测试、单租户或 Key 数量较少的场景。

生产环境、多租户或 Key 数量较多的场景。

根据集群中的 API Key 总数选择后端:

  • 不超过 500 条:可以使用 Secret。

  • 501~1000 条:建议规划迁移至 MySQL。

  • 超过 1000 条:应使用 MySQL,避免 Secret 因接近 1 MiB 上限而写入失败。

适用范围

  • 已完成 Agent Sandbox 多租户管理配置,安装 ack-sandbox-manager(v0.6.7 及以上版本)并启用 API Key 鉴权。具体操作,请参见多租户管理

创建并配置 RDS MySQL 实例

API Key 存储属于数据量小、以哈希点查为主的 OLTP(Online Transaction Processing,联机事务处理)负载。购买 RDS MySQL 实例前,可展开下方选型建议规划实例配置。

RDS MySQL 选型建议

配置项

建议

实例系列

生产环境使用高可用系列;开发测试环境可以使用基础系列

数据库版本

推荐 MySQL 8.0,最低支持 MySQL 5.7。

实例规格

可从 1 核 2 GB 规格起步;租户数量或并发较高时,可选择 2 核 4 GB 或更高规格。

存储

选择 ESSD 云盘及售卖页支持的最小容量,后续可按需扩容。

网络

建议与 ACS 集群位于同一地域和同一 VPC。

付费方式

长期使用选择包年包月;短期测试选择按量付费。

实际可选规格和存储容量因地域、可用区及实例系列而异,请以购买页面为准。
  1. 访问 RDS 购买页面,创建 RDS MySQL 实例。建议选择与 ACS 集群相同的地域和 VPC,并参考上方选型建议配置实例。

  2. 创建数据库和账号。在 RDS 实例的数据库管理账号管理页面中完成以下操作。具体操作,请参见创建账号

    1. 创建一个数据库,例如 e2b

    2. 创建一个普通数据库账号,并记录账号名和密码。

    3. 授予该账号对目标数据库的读写(DDL+DML)权限。

  3. 配置 IP 白名单。

    sandbox-manager 等控制面组件的访问流量从控制面交换机发出,因此需要将控制面交换机网段加入 RDS 白名单。
    1. 登录容器计算服务控制台,进入目标集群的基本信息页面。

    2. 网络区块,单击控制面交换机右侧的编辑,复制所有勾选状态的交换机的CIDR(网段)。

    3. 登录 RDS 管理控制台,进入目标实例的白名单与安全组页面。

    4. 修改 default 白名单分组,将控制面交换机的 IPv4 网段添加到组内白名单。

  4. 在 RDS 实例的数据库连接页面中,记录内网地址内网端口,例如:

    rm-******************.mysql.rds.aliyuncs.com:3306
  5. 手动初始化表结构。执行 OpenKruise 社区提供的 mysql-schema.sql 脚本初始化数据库表结构:

    mysql -h <RDS内网地址> \
      -P <端口> \
      -u <数据库账号> \
      -p \
      <数据库名> < mysql-schema.sql

    该脚本会创建 teamsteam_api_keys 表,并初始化内置的 admin Team。admin API Key 的哈希无需迁移,ack-sandbox-manager 启动时会根据当前 hashPepper 自动计算并写入 team_api_keys

配置 MySQL 存储后端

  1. 登录容器计算服务控制台,进入目标集群。

  2. 组件管理页面找到 ack-sandbox-manager,单击配置

  3. 配置以下参数:

    配置项

    配置值或说明

    keyStorage.mode

    设置为 mysql

    keyStorage.mysql.dsn

    MySQL 数据源名称(Data Source Name,DSN),描述连接目标数据库的账号、密码、地址、端口及连接参数,格式见下方示例。

    keyStorage.mysql.hashPepper

    用于计算 API Key 哈希的长期密钥。

  4. 按以下格式填写 DSN:

    <账号>:<密码>@tcp(<RDS内网地址>:<端口>)/<数据库名>?charset=utf8mb4&parseTime=true&loc=Local

    示例:

    e2b_user:********@tcp(rm-******************.mysql.rds.aliyuncs.com:3306)/e2b?charset=utf8mb4&parseTime=true&loc=Local

    使用以下命令生成一个 32 字节(256 bit)的随机字符串作为 hashPepper

    openssl rand -hex 32

    命令输出为 64 个十六进制字符,直接作为 keyStorage.mysql.hashPepper 的取值。

    重要

    请长期、安全地保存 hashPepper,不要将其与数据库密码设置为相同的值。更换该值后,现有租户 API Key 将无法通过鉴权,需要重新签发。

  5. 保存配置。ack-sandbox-manager 将自动重启并连接 RDS MySQL。

    keyStorage.mode 设置为 mysql 时,如果未配置 DSN 或 hashPepper,组件将启动失败。

验证配置

  1. 确认 ack-sandbox-manager Pod 正常运行:

    kubectl get pods -n sandbox-system -l component=sandbox-manager

    预期输出:

    NAME                             READY   STATUS    RESTARTS   AGE
    sandbox-manager-79b7449778-xxx   2/2     Running   0          78m
    sandbox-manager-79b7449778-yyy   2/2     Running   0          79m
    sandbox-manager-79b7449778-zzz   2/2     Running   0          78m
  2. 创建、查询并删除一个临时 API Key,以验证 MySQL 后端可正常读写。执行前请根据实际环境替换以下变量:

    • BASE_URLack-sandbox-gateway 对外访问地址。

    • ADMIN_KEYack-sandbox-manager 配置的 admin API Key。

    以下脚本依赖 jq(命令行 JSON 处理器)解析响应,执行前请确认本地已安装。
    BASE_URL="https://api.your.domain.com"
    ADMIN_KEY="your-admin-key"
    
    TEST_KEY_ID=$(
      curl -fsS -X POST \
        -H "X-API-KEY: ${ADMIN_KEY}" \
        -H "Content-Type: application/json" \
        -d '{"name":"mysql-storage-verification"}' \
        "${BASE_URL}/api-keys" |
        jq -r '.id'
    )
    echo "Created: ${TEST_KEY_ID}"
    
    curl -fsS \
      -H "X-API-KEY: ${ADMIN_KEY}" \
      "${BASE_URL}/api-keys" |
      jq -e --arg id "${TEST_KEY_ID}" \
        'any(.[]; .id == $id)' >/dev/null && echo "Query OK"
    
    curl -fsS -X DELETE \
      -H "X-API-KEY: ${ADMIN_KEY}" \
      "${BASE_URL}/api-keys/${TEST_KEY_ID}" && echo "Deleted: ${TEST_KEY_ID}"

    预期输出:

    Created: 4f2ab49a-aced-4830-b5da-5d382xxxxxxx
    Query OK
    Deleted: 4f2ab49a-aced-4830-b5da-5d382xxxxxxx

迁移已有 API Key(可选)

切换到 MySQL 后端后,如果原 Secret 后端中已有 API Key 需要在新后端继续使用,可以使用 OpenKruise 社区提供的 migrate_secret_keys_to_mysql.py 脚本生成 MySQL 迁移 SQL。迁移脚本会:

  • 通过 kubectl 读取 e2b-key-store Secret。

  • 使用与 keyStorage.mysql.hashPepper 相同的值计算 API Key 的 HMAC-SHA256 哈希。

  • 生成建表 DDL,以及 Team 和 API Key 的 Upsert 语句。

  • 保留原有 Team、Key 名称、创建信息和配额配置。

脚本仅依赖Python 3标准库和 kubectl

重要

迁移开始后,请暂停调用 POST /api-keysDELETE /api-keys/{id},直至完成数据导入,避免迁移期间产生的数据变更丢失。

  1. 校验 Secret 数据:

    python3 migrate_secret_keys_to_mysql.py \
      --namespace sandbox-system \
      --dry-run

    该命令会解析 Secret 中的所有条目,校验 idnamekey 等字段的合法性,检查 Team 元数据是否一致以及原始 Key 是否唯一,任何一项不通过都会中止迁移,避免生成不完整的 SQL。

  2. 通过隐藏输入设置 hashPepper(值必须与已配置的 keyStorage.mysql.hashPepper 完全一致),并生成迁移 SQL:

    read -rsp "请输入 hashPepper: " E2B_KEY_HASH_PEPPER
    echo
    export E2B_KEY_HASH_PEPPER
    
    python3 migrate_secret_keys_to_mysql.py \
      --namespace sandbox-system \
      --output e2b_key_migration.sql
  3. 将迁移 SQL 导入 RDS MySQL:

    mysql -h <RDS内网地址> \
      -P <端口> \
      -u <数据库账号> \
      -p \
      <数据库名> < e2b_key_migration.sql
  4. 清理环境变量和迁移文件:

    unset E2B_KEY_HASH_PEPPER
    rm -f e2b_key_migration.sql
重要

生成 SQL 时使用的 hashPepper 必须与已配置的 keyStorage.mysql.hashPepper 完全一致,否则迁移后的 API Key 无法通过鉴权。

迁移脚本常用参数

参数

说明

默认值

--namespace

e2b-key-store 所在的 Kubernetes 命名空间,必填。

--secret-name

Secret 名称。

e2b-key-store

--pepper

hashPepper 值;未指定时读取环境变量 E2B_KEY_HASH_PEPPER

--output

输出 SQL 文件;设置为 - 时输出至标准输出。

e2b_key_migration.sql

--dry-run

仅校验 Secret 数据,不生成 SQL。

false