Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

更新 readme #143

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 55 additions & 52 deletions sdks/apigw-manager/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ grant_permissions:

# 应用申请指定网关所有资源的权限,待网关管理员审批后,应用才可访问网关资源;
# 用于命令 `apply_apigw_permissions`
apply_permissions:
- gateway_name: "{{ settings.BK_APIGW_NAME }}"
# 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源
grant_dimension: "gateway"
# apply_permissions:
# - gateway_name: "{{ settings.BK_APIGW_NAME }}"
# # 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源
# grant_dimension: "gateway"

# 为网关添加关联应用,关联应用可以通过网关 bk-apigateway 的接口操作网关数据;每个网关最多可有 10 个关联应用;
# 用于命令 `add_related_apps`
Expand Down Expand Up @@ -174,6 +174,8 @@ resource_docs:

用于定义资源配置,建议通过网关管理端导出。为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。

样例可参考:[resources.yaml](examples/django/use-custom-script/support-files/resources.yaml)

#### 3. apidocs(可选)

资源文档,资源文档为 markdown 格式。资源文档的文件名,应为 `资源名称` + `.md` 格式,假如资源名称为 get_user,则文档文件名应为 get_user.md。
Expand Down Expand Up @@ -209,6 +211,54 @@ resource_docs:

此方案适用于非 Django 项目,具体请参考 [sync-apigateway-with-docker.md](docs/sync-apigateway-with-docker.md)


## 如何获取网关公钥

后端服务如需解析 API 网关发送的请求头 X-Bkapi-JWT,需要提前获取该网关的公钥。获取网关公钥,有以下方案。

### 1. 根据 SDK 提供的 Django Command 拉取

在同步网关数据时,直接添加以下 Command 拉取网关公钥。网关公钥将保存在 model Context 对应的库表 apigw_manager_context 中,SDK 提供的 Django 中间件将从表中读取网关公钥。

```bash
# 默认拉取 settings.BK_APIGW_NAME 对应网关的公钥
python manage.py fetch_apigw_public_key

# 拉取指定网关的公钥
python manage.py fetch_apigw_public_key --gateway-name my-gateway
```

### 2. 直接获取网关公钥,配置到项目配置文件

服务仅需接入一些固定的网关部署环境时,可在网关管理端,网关基本信息中查询网关公钥,并配置到项目配置文件。

蓝鲸官方网关,需要自动注册并获取网关公钥,可联系蓝鲸官方运营同学,在服务部署前,由官方提前创建网关,并设置网关公钥、私钥,同时将网关公钥同步给后端服务。
具体可参考 helm-charts 仓库的 README。

### 3. 通过网关公开接口,拉取网关公钥

API 网关提供了公钥查询接口,后端服务可按需根据接口拉取网关公钥,接口信息如下:
```bash
# 将 bkapi.example.com 替换为网关 API 地址,
# 将 gateway_name 替换为待查询公钥的网关名,
# 提供正确的蓝鲸应用账号
curl -X GET '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"}'
```

响应样例:

```json
{
"data": {
"public_key": "your public key"
}
}
```

注意事项:
- 拉取公钥时,不能实时拉取,需要添加缓存(实时拉取会导致整体接口性能下降)

## 校验请求来自 API 网关

### 场景一:Django 项目
Expand Down Expand Up @@ -296,7 +346,7 @@ APIGW_MANAGER_DUMMY_PAYLOAD_USERNAME # JWT payload 中的 username

### 场景二:非 Django 项目

非 Django 项目,需要项目获取网关公钥,并解析请求头中的 X-Bkapi-JWT;获取网关公钥的方案请参考下文
非 Django 项目,需要项目获取网关公钥,并解析请求头中的 X-Bkapi-JWT;获取网关公钥的方案请参考上文

解析 X-Bkapi-JWT 时,可根据 jwt header 中的 kid 获取当前网关名,例如:
```
Expand Down Expand Up @@ -324,50 +374,3 @@ APIGW_MANAGER_DUMMY_PAYLOAD_USERNAME # JWT payload 中的 username
"iss": "APIGW" # 签发者
}
```

### 如何获取网关公钥

后端服务如需解析 API 网关发送的请求头 X-Bkapi-JWT,需要提前获取该网关的公钥。获取网关公钥,有以下方案。

#### 1. 根据 SDK 提供的 Django Command 拉取

在同步网关数据时,直接添加以下 Command 拉取网关公钥。网关公钥将保存在 model Context 对应的库表 apigw_manager_context 中,SDK 提供的 Django 中间件将从表中读取网关公钥。

```bash
# 默认拉取 settings.BK_APIGW_NAME 对应网关的公钥
python manage.py fetch_apigw_public_key

# 拉取指定网关的公钥
python manage.py fetch_apigw_public_key --gateway-name my-gateway
```

#### 2. 直接获取网关公钥,配置到项目配置文件

服务仅需接入一些固定的网关部署环境时,可在网关管理端,网关基本信息中查询网关公钥,并配置到项目配置文件。

蓝鲸官方网关,需要自动注册并获取网关公钥,可联系蓝鲸官方运营同学,在服务部署前,由官方提前创建网关,并设置网关公钥、私钥,同时将网关公钥同步给后端服务。
具体可参考 helm-charts 仓库的 README。

#### 3. 通过网关公开接口,拉取网关公钥

API 网关提供了公钥查询接口,后端服务可按需根据接口拉取网关公钥,接口信息如下:
```bash
# 将 bkapi.example.com 替换为网关 API 地址,
# 将 gateway_name 替换为待查询公钥的网关名,
# 提供正确的蓝鲸应用账号
curl -X GET '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"}'
```

响应样例:

```json
{
"data": {
"public_key": "your public key"
}
}
```

注意事项:
- 拉取公钥时,不能实时拉取,需要添加缓存(实时拉取会导致整体接口性能下降)
162 changes: 88 additions & 74 deletions sdks/apigw-manager/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,10 @@ definition.yaml 中可以使用 Django 模版语法引用和渲染变量,内

# 应用申请指定网关所有资源的权限,待网关管理员审批后,应用才可访问网关资源;
# 用于命令 `apply_apigw_permissions`
apply_permissions:
- gateway_name: "{{ settings.BK_APIGW_NAME }}"
# 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源
grant_dimension: "gateway"
# apply_permissions:
# - gateway_name: "{{ settings.BK_APIGW_NAME }}"
# # 权限维度,可选值:gateway,按网关授权,包括网关下所有资源,以及未来新创建的资源
# grant_dimension: "gateway"

# 为网关添加关联应用,关联应用可以通过网关 bk-apigateway 的接口操作网关数据;每个网关最多可有 10 个关联应用;
# 用于命令 `add_related_apps`
Expand Down Expand Up @@ -195,6 +195,8 @@ definition.yaml 中可以使用 Django 模版语法引用和渲染变量,内

用于定义资源配置,建议通过网关管理端导出。为了方便用户直接使用网关导出的资源文件,资源定义默认没有命名空间。

样例可参考:\ `resources.yaml <examples/django/use-custom-script/support-files/resources.yaml>`_

3. apidocs(可选)
~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -235,31 +237,92 @@ definition.yaml 中可以使用 Django 模版语法引用和渲染变量,内

此方案适用于非 Django 项目,具体请参考 `sync-apigateway-with-docker.md <docs/sync-apigateway-with-docker.md>`_

如何获取网关公钥
----------------

后端服务如需解析 API 网关发送的请求头 X-Bkapi-JWT,需要提前获取该网关的公钥。获取网关公钥,有以下方案。

1. 根据 SDK 提供的 Django Command 拉取
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

在同步网关数据时,直接添加以下 Command 拉取网关公钥。网关公钥将保存在 model Context 对应的库表 apigw_manager_context 中,SDK 提供的 Django 中间件将从表中读取网关公钥。

.. code-block:: bash

# 默认拉取 settings.BK_APIGW_NAME 对应网关的公钥
python manage.py fetch_apigw_public_key

# 拉取指定网关的公钥
python manage.py fetch_apigw_public_key --gateway-name my-gateway

2. 直接获取网关公钥,配置到项目配置文件
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

服务仅需接入一些固定的网关部署环境时,可在网关管理端,网关基本信息中查询网关公钥,并配置到项目配置文件。

蓝鲸官方网关,需要自动注册并获取网关公钥,可联系蓝鲸官方运营同学,在服务部署前,由官方提前创建网关,并设置网关公钥、私钥,同时将网关公钥同步给后端服务。
具体可参考 helm-charts 仓库的 README。

3. 通过网关公开接口,拉取网关公钥
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

API 网关提供了公钥查询接口,后端服务可按需根据接口拉取网关公钥,接口信息如下:

.. code-block:: bash

# 将 bkapi.example.com 替换为网关 API 地址,
# 将 gateway_name 替换为待查询公钥的网关名,
# 提供正确的蓝鲸应用账号
curl -X GET '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"}'

响应样例:

.. code-block:: json

{
"data": {
"public_key": "your public key"
}
}

注意事项:


* 拉取公钥时,不能实时拉取,需要添加缓存(实时拉取会导致整体接口性能下降)

校验请求来自 API 网关
---------------------

场景一:Django 项目
^^^^^^^^^^^^^^^^^^^

如果后端服务需要认证 API 网关传递过来的请求头 X-Bkapi-JWT,可在 settings MIDDLEWARE 中加入以下 Django 中间件
要在后端服务中认证 API 网关传递过来的请求头 ``X-Bkapi-JWT``\ ,可以通过在 settings 中的 MIDDLEWARE 中添加以下 Django 中间件。这样,在请求处理过程中,会自动解析请求头中的 X-Bkapi-JWT,并将相关信息添加到 request 对象中。

.. code-block:: python

MIDDLEWARE += [
"apigw_manager.apigw.authentication.ApiGatewayJWTGenericMiddleware", # JWT 认证,解析请求头中的 X-Bkapi-JWT,获取 request.jwt 对象
"apigw_manager.apigw.authentication.ApiGatewayJWTAppMiddleware", # 根据 request.jwt,获取 request.app 对象
"apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware", # 根据 request.jwt,获取 request.user 对象
]

如需获取 request.user 对象,还需要在 settings AUTHENTICATION_BACKENDS 中加入:
添加以上两个中间件后,request 对象中将会添加 ``request.jwt`` 和 ``request.app`` 两个对象。这些对象包含了网关名、当前请求的蓝鲸应用 ID 等信息。具体内容可参考下文。

如果需要在 request 对象中获取当前请求用户 ``request.user`` 对象,除了上面的中间件外,还需要添加一个中间件以及 AUTHENTICATION_BACKENDS:

.. code-block:: python

# 添加中间件
MIDDLEWARE += [
"apigw_manager.apigw.authentication.ApiGatewayJWTUserMiddleware", # 根据 request.jwt,获取 request.user 对象
]

# 添加 AUTHENTICATION_BACKENDS
AUTHENTICATION_BACKENDS += [
"apigw_manager.apigw.authentication.UserModelBackend",
]

注意,Django 中间件 ApiGatewayJWTGenericMiddleware 解析 X-Bkapi-JWT 时,需要获取网关公钥,SDK 默认从以下两个位置获取网关公钥:
注意,Django 中间件 ApiGatewayJWTGenericMiddleware 解析 ``X-Bkapi-JWT`` 时,需要获取网关公钥,SDK 默认从以下两个位置获取网关公钥:


* SDK model Context (库表 apigw_manager_context),需提前执行 ``python manage.py fetch_apigw_public_key`` 拉取并保存网关公钥
Expand All @@ -279,7 +342,7 @@ ApiGatewayJWTGenericMiddleware
ApiGatewayJWTAppMiddleware
""""""""""""""""""""""""""

根据 request.jwt,在 ``request`` 中注入 ``app`` 对象,有以下属性:
根据 ``request.jwt``\ ,在 ``request`` 中注入 ``app`` 对象,有以下属性:


* ``bk_app_code``\ :调用接口的应用;
Expand All @@ -288,17 +351,24 @@ ApiGatewayJWTAppMiddleware
ApiGatewayJWTUserMiddleware
"""""""""""""""""""""""""""

根据 request.jwt,在 ``request`` 中注入 ``user`` 对象,该对象通过以下调用获取:
根据 ``request.jwt``\ ,在 ``request`` 中注入 ``user`` 对象:


* 如果用户通过认证:其为一个 Django User Model 对象,用户名为当前请求用户的用户名
* 如果用户未通过认证,其为一个 Django AnonymousUser 对象,用户名为当前请求用户的用户名

如果中间件 ``ApiGatewayJWTUserMiddleware`` 中获取用户的逻辑不满足需求,可以继承此中间件并自定义用户获取方法 ``get_user``\ ,例如::

.. code-block:: python

def get_user(self, request, gateway_name=None, bk_username=None, verified=False, **credentials):
return auth.authenticate(
request, gateway_name=gateway_name, bk_username=bk_username, verified=verified, **credentials
)
class MyJWTUserMiddleware(ApiGatewayJWTUserMiddleware):
def get_user(self, request, gateway_name=None, bk_username=None, verified=False, **credentials):
...
return auth.authenticate(
request, gateway_name=gateway_name, bk_username=bk_username, verified=verified, **credentials
)

因使用 auth.authenticate 获取用户,所以需要在 settings AUTHENTICATION_BACKENDS 中添加对应的用户认证后端,才能获取到 request.user 对象。
如果该中间件认证逻辑不满足需求,可继承此中间件,重载 ``get_user`` 方法。
注意:在自定义中间件 ``ApiGatewayJWTUserMiddleware`` 时,如果继续使用 ``auth.authenticate`` 获取用户,请确保正确设置用户认证后端,以遵循 Django ``AUTHENTICATION_BACKENDS`` 相关规则。

用户认证后端
~~~~~~~~~~~~
Expand All @@ -322,7 +392,7 @@ UserModelBackend

BK_APIGW_JWT_PROVIDER_CLS = "apigw_manager.apigw.providers.DummyEnvPayloadJWTProvider"

同时提供以下环境变量(非 settings)
同时提供以下环境变量(非 Django settings)

.. code-block::

Expand All @@ -333,7 +403,7 @@ UserModelBackend
场景二:非 Django 项目
^^^^^^^^^^^^^^^^^^^^^^

非 Django 项目,需要项目获取网关公钥,并解析请求头中的 X-Bkapi-JWT;获取网关公钥的方案请参考下文
非 Django 项目,需要项目获取网关公钥,并解析请求头中的 X-Bkapi-JWT;获取网关公钥的方案请参考上文

解析 X-Bkapi-JWT 时,可根据 jwt header 中的 kid 获取当前网关名,例如:

Expand Down Expand Up @@ -363,59 +433,3 @@ UserModelBackend
"nbf": 1701399303, # Not Before 时间
"iss": "APIGW" # 签发者
}

如何获取网关公钥
^^^^^^^^^^^^^^^^

后端服务如需解析 API 网关发送的请求头 X-Bkapi-JWT,需要提前获取该网关的公钥。获取网关公钥,有以下方案。

1. 根据 SDK 提供的 Django Command 拉取
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

在同步网关数据时,直接添加以下 Command 拉取网关公钥。网关公钥将保存在 model Context 对应的库表 apigw_manager_context 中,SDK 提供的 Django 中间件将从表中读取网关公钥。

.. code-block:: bash

# 默认拉取 settings.BK_APIGW_NAME 对应网关的公钥
python manage.py fetch_apigw_public_key

# 拉取指定网关的公钥
python manage.py fetch_apigw_public_key --gateway-name my-gateway

2. 直接获取网关公钥,配置到项目配置文件
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

服务仅需接入一些固定的网关部署环境时,可在网关管理端,网关基本信息中查询网关公钥,并配置到项目配置文件。

蓝鲸官方网关,需要自动注册并获取网关公钥,可联系蓝鲸官方运营同学,在服务部署前,由官方提前创建网关,并设置网关公钥、私钥,同时将网关公钥同步给后端服务。
具体可参考 helm-charts 仓库的 README。

3. 通过网关公开接口,拉取网关公钥
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

API 网关提供了公钥查询接口,后端服务可按需根据接口拉取网关公钥,接口信息如下:

.. code-block:: bash

# 将 bkapi.example.com 替换为网关 API 地址,
# 将 gateway_name 替换为待查询公钥的网关名,
# 提供正确的蓝鲸应用账号
curl -X GET '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"}'

响应样例:

.. code-block:: json

{
"data": {
"issuer": "",
"public_key": "your public key"
}
}

注意事项:


* **issuer**\ :一般情况下,签发者为空字符串;如果一个后端需要对接到多个 API 网关部署环境,可让不同部署环境的网关配置不同的 issuer(在部署网关时,可通过环境变量 BK_APIGW_JWT_ISSUER 指定),后端服务可根据 ``网关名`` + ``issuer`` 区分不同部署环境的网关公钥。
* 拉取公钥时,需要对数据进行缓存,不能高并发拉取
4 changes: 3 additions & 1 deletion sdks/apigw-manager/docs/sync-apigateway-with-django.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
# 如果任何命令返回一个非零退出状态(错误),脚本将会立即终止执行
set -e

# 待同步网关名,需修改为实际网关名;直接指定网关名,则不需要配置 Django settings BK_APIGW_NAME
# 待同步网关名,需修改为实际网关名;
# - 如在下面指令的参数中,指定了参数 --gateway-name=${gateway_name},则使用该参数指定的网关名
# - 如在下面指令的参数中,未指定参数 --gateway-name,则使用 Django settings BK_APIGW_NAME
gateway_name="bk-demo"

# 待同步网关、资源定义文件,需调整为实际的配置文件地址
Expand Down
Loading