Package: apigw-manager
apigw-manager蓝鲸 API 网关管理 SDK 是一个用于管理 API 网关的工具，它提供了一套完整的工具和功能，可以帮助您更轻松地管理 API 网关，提高系统的安全性和可靠性。Django Command：SDK 提供了 Django Command，支持网关注册、同步、发布等功能。您可以根据需要编排指令，以满足您的特定需求，并集成到您的项目自动执行 API 网关同步过程，以便更轻松地管理 API 网关。Docker 镜像：对于非 Django 项目，提供了 Docker 基础镜像，封装了 SDK 同步网关的相关功能，以便非 Django 项目轻松管理 API 网关。Django 中间件：SDK 还提供了 Django 中间件，用于解析 API 网关请求后端接口时添加的请求头 X-Bkapi-JWT，以方便后端服务校验请求是否来自 API 网关。这个中间件可以确保只有来自蓝鲸 API 网关的请求才能访问您的后端服务，从而提高系统的安全性。安装基础安装：pipinstallapigw-manager如果需要使用 apigw-manager 提供的 Django 中间件解析来自 API 网关的 X-Bkapi-JWT，可以安装：pipinstall"apigw-manager[cryptography]"功能通过预定义的 YAML 文件，您可以轻松地执行网关创建、更新、发布和资源同步操作，从而简化 API 网关管理过程。使用 Django 中间件，您可以解析蓝鲸 API 网关的 X-Bkapi-JWT 请求头，确保只有来自 API 网关的请求才能访问您的后端服务，提升系统安全性。根据 YAML 同步网关配置SDK 同步网关配置到 API 网关，支持多种方案:直接使用 Django Command 同步：此方案适用于 Django 项目；Django 项目，可直接执行 SDK 提供的 Django Command 指令通过镜像方式同步：此方案适用于非 Django 项目；非 Django 项目，无法直接执行 SDK 提供的 Django Command 指令准备工作同步网关配置到 API 网关，需要准备网关配置、资源配置、资源文档、自定义同步脚本等数据，可参考目录：support-files
├── definition.yaml         # 维护网关、环境、资源文档路径、主动授权、发布等配置，但不包含资源配置
├── resources.yaml          # 维护资源配置；资源配置可通过 API 网关管理端直接导出，数据量较大，因此单独管理
├── bin
│   └── sync-apigateway.sh  # 自定义同步脚本，Django 项目也可以自定义 Django Command
├── bk_apigw_docs_demo.tgz  # 资源文档归档文件，可选；可通过 API 网关管理端导出；与资源文档目录 apidocs 二选一
└── apidocs                 # 资源文档目录，可选；可通过 API 网关管理端导出并解压，或者直接维护 markdown 格式文档文件
    ├── zh                  # 中文文档目录
    │   └── anything.md
    └── en                  # 英文文档目录
        └── anything.md1. definition.yaml用于定义网关、环境等配置，为了简化使用，使用以下模型进行处理：Template(definition.yaml)                     YAML
+--------------------------+        +----------------------------+
|                          |        |                            |       +--------------------------------------+
| ns1:                     |        | ns1:                       |       |                                      |
|   key: {{environ.KEY1}}  |        |   key: value_from_environ  |------>| api1({"key": "value_from_environ"})  |
|                          | Render |                            |       |                                      |
|                          +------->+                            | Load  |                                      |
| ns2:                     |        | ns2:                       |       |                                      |
|   key: {{settings.KEY2}} |        |   key: value_from_settings |------>| api2({"key": "value_from_settings"}) |
|                          |        |                            |       |                                      |
|                          |        |                            |       +--------------------------------------+
+--------------------------+        +----------------------------+definition.yaml 中可以使用 Django 模版语法引用和渲染变量，内置以下变量：settings：Django 提供的配置对象environ：环境变量推荐在一个文件中统一进行定义，用命名空间区分不同配置间的定义，definition.yaml 样例：# definition.yaml 配置文件版本号，必填，固定值 1spec_version:1# 定义发布内容，用于命令 `create_version_and_release_apigw`release:# 发布版本号；# 资源配置更新，需更新此版本号才会发布资源版本，此版本号和 sdk 版本号一致，错误设置会影响调用方使用version:1.0.0# 版本标题title:""# 版本描述comment:""# 定义网关基本信息，用于命令 `sync_apigw_config`apigateway:description:"描述"# 网关的英文描述，蓝鲸官方网关需提供英文描述，以支持国际化description_en:"Englishdescription"# 是否公开；公开，则用户可查看资源文档、申请资源权限；不公开，则网关对用户隐藏is_public:true# 标记网关为官方网关，网关名需以 `bk-` 开头，可选；非官方网关，可去除此配置api_type:1# 应用请求网关时，是否允许从请求参数 (querystring, body) 中获取蓝鲸认证信息，默认值为 true；# 如果为 false，则只能从请求头 X-Bkapi-Authorization 获取蓝鲸认证信息；# 新接入的网关，可以设置为 false，已接入的网关，待推动所有调用者将认证信息放到请求头后，可设置为 falseallow_auth_from_params:false# 网关请求后端时，是否删除请求参数 (querystring, body) 中的蓝鲸认证敏感信息，比如 bk_token，为 true 表示允许删除；# 待请求网关的所有调用者，将认证参数放到请求头 X-Bkapi-Authorization 时，可将此值设置为 falseallow_delete_sensitive_params:false# 网关维护人员，仅维护人员有管理网关的权限maintainers:-"admin"# 定义环境信息，用于命令 `sync_apigw_stage`stage:name:"prod"description:"描述"# 环境的英文名，蓝鲸官方网关需提供，以支持国际化description_en:"Englishdescription"# 环境变量；如未使用，可去除此配置# vars:#   key: "value"# 代理配置proxy_http:timeout:60# 负载均衡类型 + Hostsupstreams:loadbalance:"roundrobin"hosts:# 网关调用后端服务的默认域名或IP，不包含Path，比如：http://api.example.com-host:""weight:100# Header转换；如未使用，可去除此配置# transform_headers:#   # 设置Headers#   set:#     X-Token: "token"# 主动授权，网关主动给应用，添加访问网关所有资源的权限；# 用于命令 `grant_apigw_permissions`grant_permissions:-bk_app_code:"{{settings.BK_APP_CODE}}"# 授权维度，可选值：gateway，按网关授权，包括网关下所有资源，以及未来新创建的资源grant_dimension:"gateway"# 应用申请指定网关所有资源的权限，待网关管理员审批后，应用才可访问网关资源；# 用于命令 `apply_apigw_permissions`# apply_permissions:#   - gateway_name: "{{ settings.BK_APIGW_NAME }}"#     # 权限维度，可选值：gateway，按网关授权，包括网关下所有资源，以及未来新创建的资源#     grant_dimension: "gateway"# 为网关添加关联应用，关联应用可以通过网关 bk-apigateway 的接口操作网关数据；每个网关最多可有 10 个关联应用；# 用于命令 `add_related_apps`related_apps:-"{{settings.BK_APP_CODE}}"# 定义资源文档路径，用于命令 `sync_resource_docs_by_archive`；# 资源文档的目录格式样例如下，en 为英文文档，zh 为中文文档，创建归档文件可使用指令 `tar czvf xxx.tgz en zh`：# ./# - en#   - get_user.md# - zh#   - get_user.mdresource_docs:# 资源文档的归档文件，可为 tar.gz，zip 格式文件archivefile:"{{settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE}}"# 资源文档目录，basedir 与 archivefile 二者至少一个有效，若同时存在，则 archivefile 优先basedir:"{{settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR}}"注意：同步资源后，需要创建版本并发布才能生效，发布数据定义于 definition.yamlrelease资源配置 resources.yaml 变更时，需要更新 definition.yamlrelease中的版本号 version，以便正确创建资源版本及 SDK2. resources.yaml用于定义资源配置，建议通过网关管理端导出。为了方便用户直接使用网关导出的资源文件，资源定义默认没有命名空间。样例可参考：resources.yaml3. apidocs（可选）资源文档，资源文档为 markdown 格式。资源文档的文件名，应为资源名称+.md格式，假如资源名称为 get_user，则文档文件名应为 get_user.md。
将资源的中文文档放到目录zh下，英文文档放到目录en下，如果某语言文档不存在，可忽略对应目录。文档文件目录样例如下：.
├── en
│   ├── create_user.md
│   └── get_user.md
└── zh
    ├── create_user.md
    └── get_user.md导入资源文档时，可以直接使用资源文档归档文件，也可以使用资源文档目录。参考上文 definition.yaml 样例，
在项目 definition.yaml 文件中，修改资源文档相关配置 resource_docs：resource_docs:# 资源文档的归档文件，可为 tar.gz，zip 格式文件；创建归档文件可使用指令 `tar czvf xxx.tgz en zh`# archivefile: "{{ settings.BK_APIGW_RESOURCE_DOCS_ARCHIVE_FILE }}"# 资源文档目录，basedir 与 archivefile 二者至少一个有效，若同时存在，则 archivefile 优先# basedir: "{{ settings.BK_APIGW_RESOURCE_DOCS_BASE_DIR }}"basedir:"support-files/apidocs/"方案一：直接使用 Django Command 同步此方案适用于 Django 项目，具体请参考sync-apigateway-with-django.md方案二：通过镜像方式同步此方案适用于非 Django 项目，具体请参考sync-apigateway-with-docker.md如何获取网关公钥后端服务如需解析 API 网关发送的请求头 X-Bkapi-JWT，需要提前获取该网关的公钥。获取网关公钥，有以下方案。1. 根据 SDK 提供的 Django Command 拉取在同步网关数据时，直接添加以下 Command 拉取网关公钥。网关公钥将保存在 model Context 对应的库表 apigw_manager_context 中，SDK 提供的 Django 中间件将从表中读取网关公钥。# 默认拉取 settings.BK_APIGW_NAME 对应网关的公钥pythonmanage.pyfetch_apigw_public_key# 拉取指定网关的公钥pythonmanage.pyfetch_apigw_public_key--gateway-namemy-gateway2. 直接获取网关公钥，配置到项目配置文件服务仅需接入一些固定的网关部署环境时，可在网关管理端，网关基本信息中查询网关公钥，并配置到项目配置文件。蓝鲸官方网关，需要自动注册并获取网关公钥，可联系蓝鲸官方运营同学，在服务部署前，由官方提前创建网关，并设置网关公钥、私钥，同时将网关公钥同步给后端服务。
具体可参考 helm-charts 仓库的 README。3. 通过网关公开接口，拉取网关公钥API 网关提供了公钥查询接口，后端服务可按需根据接口拉取网关公钥，接口信息如下：# 将 bkapi.example.com 替换为网关 API 地址，# 将 gateway_name 替换为待查询公钥的网关名，# 提供正确的蓝鲸应用账号curl-XGET'https://bkapi.example.com/api/bk-apigateway/prod/api/v1/apis/{gateway_name}/public_key/'\-H'X-Bkapi-Authorization: {"bk_app_code": "my-app", "bk_app_secret": "secret"}'响应样例：{"data":{"public_key":"your public key"}}注意事项：拉取公钥时，不能实时拉取，需要添加缓存（实时拉取会导致整体接口性能下降）校验请求来自 API 网关场景一：Django 项目要在后端服务中认证 API 网关传递过来的请求头X-Bkapi-JWT，可以通过在 settings 中的 MIDDLEWARE 中添加以下 Django 中间件。这样，在请求处理过程中，会自动解析请求头中的 X-Bkapi-JWT，并将相关信息添加到 request 对象中。MIDDLEWARE+=["apigw_manager.apigw.authentication.ApiGatewayJWTGenericMiddleware",# JWT 认证，解析请求头中的 X-Bkapi-JWT，获取 request.jwt 对象"apigw_manager.apigw.authentication.ApiGatewayJWTAppMiddleware",# 根据 request.jwt，获取 request.app 对象]添加以上两个中间件后，request 对象中将会添加request.jwt和request.app两个对象。这些对象包含了网关名、当前请求的蓝鲸应用 ID 等信息。具体内容可参考下文。如果需要在 request 对象中获取当前请求用户request.user对象，除了上面的中间件外，还需要添加一个中间件以及 AUTHENTICATION_BACKENDS：# 添加中间件MIDDLEWARE+=["apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware",# 根据 request.jwt，获取 request.user 对象]# 添加 AUTHENTICATION_BACKENDSAUTHENTICATION_BACKENDS+=["apigw_manager.apigw.authentication.UserModelBackend",]注意，Django 中间件 ApiGatewayJWTGenericMiddleware 解析X-Bkapi-JWT时，需要获取网关公钥，SDK 默认从以下两个位置获取网关公钥：SDK model Context (库表 apigw_manager_context)，需提前执行python manage.py fetch_apigw_public_key拉取并保存网关公钥settings.APIGW_PUBLIC_KEY，可在网关页面中手动获取公钥，并配置到 settings 中Django 中间件ApiGatewayJWTGenericMiddleware利用网关公钥，解析请求头中的 X-Bkapi-JWT，在request中注入jwt对象，有以下属性：gateway_name：传入的网关名称；ApiGatewayJWTAppMiddleware根据request.jwt，在request中注入app对象，有以下属性：bk_app_code：调用接口的应用；verified：应用是否经过认证；ApiGatewayJWTUserMiddleware根据request.jwt，在request中注入user对象:如果用户通过认证：其为一个 Django User Model 对象，用户名为当前请求用户的用户名如果用户未通过认证，其为一个 Django AnonymousUser 对象，用户名为当前请求用户的用户名如果中间件ApiGatewayJWTUserMiddleware中获取用户的逻辑不满足需求，可以继承此中间件并自定义用户获取方法get_user，例如：：classMyJWTUserMiddleware(ApiGatewayJWTUserMiddleware):defget_user(self,request,gateway_name=None,bk_username=None,verified=False,**credentials):...returnauth.authenticate(request,gateway_name=gateway_name,bk_username=bk_username,verified=verified,**credentials)注意：在自定义中间件ApiGatewayJWTUserMiddleware时，如果继续使用auth.authenticate获取用户，请确保正确设置用户认证后端，以遵循 DjangoAUTHENTICATION_BACKENDS相关规则。用户认证后端UserModelBackend已认证的用户名，根据UserModel创建一个用户对象，不存在时返回None；未认证的用户名，返回AnonymousUser，可通过继承后修改make_anonymous_user的实现来定制具体字段；本地开发测试本地开发测试时，接口可能未接入 API 网关，此时中间件ApiGatewayJWTGenericMiddleware无法获取请求头中的 X-Bkapi-JWT。
为方便测试，SDK 提供了一个 Dummy JWT Provider，用于根据环境变量直接构造一个 request.jwt 对象。在项目中添加本地开发配置文件local_settings.py，并将其导入到 settings；然后，在此本地开发配置文件中添加配置：BK_APIGW_JWT_PROVIDER_CLS="apigw_manager.apigw.providers.DummyEnvPayloadJWTProvider"同时提供以下环境变量（非 Django settings)APIGW_MANAGER_DUMMY_GATEWAY_NAME      # JWT 中的网关名
APIGW_MANAGER_DUMMY_PAYLOAD_APP_CODE  # JWT payload 中的 app_code
APIGW_MANAGER_DUMMY_PAYLOAD_USERNAME  # JWT payload 中的 username场景二：非 Django 项目非 Django 项目，需要项目获取网关公钥，并解析请求头中的 X-Bkapi-JWT；获取网关公钥的方案请参考上文。解析 X-Bkapi-JWT 时，可根据 jwt header 中的 kid 获取当前网关名，例如：{
    "iat": 1701399603,
    "typ": "JWT",
    "kid": "my-gateway",   # 网关名称
    "alg": "RS512"         # 加密算法
}可从 jwt 内容中获取网关认证的应用、用户信息，例如：{
  "user": {                  # 用户信息
    "bk_username": "admin",  # 用户名，解析时需同时支持 bk_username、username 两个 key，如 user.get("bk_username") or user.get("username", "")
    "verified": true         # 用户是否通过认证，true 表示通过认证，false 表示未通过认证
  },
  "app": {                    # 蓝鲸应用信息
    "bk_app_code": "my-app",  # 蓝鲸应用ID，解析时需同时支持 bk_app_code、app_code 两个 key，如 app.get("bk_app_code") or app.get("app_code", "")
    "verified": true          # 应用是否通过认证，true 表示通过认证，false 表示未通过认证
  },
  "exp": 1701401103,      # 过期时间
  "nbf": 1701399303,      # Not Before 时间
  "iss": "APIGW"          # 签发者
}