This is an automated email from the ASF dual-hosted git repository.
moonming pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix.git
The following commit(s) were added to refs/heads/master by this push:
new 0d0fdd7eda docs(jwt-auth): port current Vault and ADC workflow (#13943)
0d0fdd7eda is described below
commit 0d0fdd7edadc4cf7344ba89c1c11e1e74b16f6e0
Author: Traky Deng <[email protected]>
AuthorDate: Tue Nov 10 14:27:07 2026 +0800
docs(jwt-auth): port current Vault and ADC workflow (#13943)
* docs(jwt-auth): refresh Vault secret example
* docs(jwt-auth): sync current API7 Vault workflow
---
docs/en/latest/plugins/jwt-auth.md | 158 ++++++++++++++++++++++++-------------
docs/zh/latest/plugins/jwt-auth.md | 156 +++++++++++++++++++++++-------------
2 files changed, 205 insertions(+), 109 deletions(-)
diff --git a/docs/en/latest/plugins/jwt-auth.md
b/docs/en/latest/plugins/jwt-auth.md
index 818fa92bd6..fbda4ac127 100644
--- a/docs/en/latest/plugins/jwt-auth.md
+++ b/docs/en/latest/plugins/jwt-auth.md
@@ -882,27 +882,43 @@ curl -i "http://127.0.0.1:9080/get" -H "Authorization:
${jwt_token}"
You should receive an `HTTP/1.1 200 OK` response.
-### Manage Secrets in Secret Manager
+### Store a JWT Secret in HashiCorp Vault
-The following example demonstrates how to manage `jwt-auth` Consumer key in
[HashiCorp Vault](https://www.vaultproject.io) and reference it in Plugin
configuration.
+[HashiCorp Vault](https://developer.hashicorp.com/vault/docs) provides
centralized external storage for secrets. The following example stores a JWT
signing secret in Vault instead of directly in a `jwt-auth` credential and
references it from APISIX.
-Start a Vault development server in Docker:
+:::info
+
+[Vault dev
mode](https://developer.hashicorp.com/vault/docs/concepts/dev-server) stores
data in memory and uses a root token. Use this setup only for local testing. In
production, run a production deployment of Vault and give APISIX a token with
read access only to the required secret paths.
+
+:::
+
+Set `APISIX_CONTAINER` to the name of the running APISIX container. Create a
dedicated Docker network and connect APISIX to it:
+
+```shell
+export APISIX_CONTAINER=replace-with-apisix-container-name
+
+docker network create apisix-vault-net
+docker network connect apisix-vault-net "$APISIX_CONTAINER"
+```
+
+Start a Vault development server on the same network:
```shell
docker run -d \
- --name vault \
- -p 8200:8200 \
+ --name apisix-vault \
+ --network apisix-vault-net \
--cap-add IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=root \
-e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
- vault:1.9.0 \
+ hashicorp/vault:1.21.4 \
vault server -dev
```
-APISIX currently supports [Vault KV engine version
1](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1). Enable
it in Vault:
+The APISIX Vault secret provider reads from [Vault KV version
1](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1). Enable a KV
version 1 secrets engine at `kv/`:
```shell
-docker exec -i vault sh -c "VAULT_TOKEN='root'
VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv"
+docker exec apisix-vault sh -c \
+ "VAULT_TOKEN='root' VAULT_ADDR='http://127.0.0.1:8200' vault secrets enable
-path=kv -version=1 kv"
```
You should see a response similar to the following:
@@ -911,28 +927,45 @@ You should see a response similar to the following:
Success! Enabled the kv secrets engine at: kv/
```
-<Tabs
-groupId="api"
-defaultValue="dashboard"
-values={[
-{label: 'Admin API', value: 'dashboard'},
-{label: 'ADC', value: 'adc'}
-]}>
+Store the signing secret under `kv/apisix/jack`:
-<TabItem value="dashboard">
+```shell
+docker exec apisix-vault sh -c \
+ "VAULT_TOKEN='root' VAULT_ADDR='http://127.0.0.1:8200' vault kv put
kv/apisix/jack jwt-secret=vault-hs256-secret-that-is-very-long"
+```
-Create a [Secret](../terminology/secret.md) and configure the Vault address
and other connection information. Adjust the Vault address accordingly:
+You should see a response similar to the following:
+
+```text
+Success! Data written to: kv/apisix/jack
+```
+
+Create an APISIX [Secret](../terminology/secret.md) resource with the Vault
connection details. ADC does not currently synchronize Secret resources, so
create this resource through the Admin API:
```shell
curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
- "uri": "http://127.0.0.1:8200",
+ "uri": "http://apisix-vault:8200",
"prefix": "kv/apisix",
"token": "root"
}'
```
+The Vault container is reachable by name because it runs on the same Docker
network as APISIX.
+
+The Secret resource is required for both configuration methods below. ADC does
not currently synchronize Secret resources, but it can synchronize credentials
that reference an existing Secret resource.
+
+<Tabs
+groupId="api"
+defaultValue="dashboard"
+values={[
+{label: 'Admin API', value: 'dashboard'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="dashboard">
+
Create a Consumer `jack`:
```shell
@@ -943,7 +976,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
}'
```
-Create `jwt-auth` Credential for the Consumer and reference the Secret:
+Create a `jwt-auth` Credential for the Consumer and reference the Secret:
```shell
curl "http://127.0.0.1:9180/apisix/admin/consumers/jack/credentials" -X PUT \
@@ -983,25 +1016,24 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
<TabItem value="adc">
-Create a Secret and configure the Vault address. Adjust the Vault address
accordingly:
+Create `adc.yaml` with the Consumer, Vault-backed Credential, and Route:
```yaml title="adc.yaml"
-secrets:
- - name: vault-jwt
- vault:
- url: http://127.0.0.1:8200
- prefix: kv/apisix
- token: root
consumers:
- username: jack
+ labels:
+ docs-example: jwt-auth
credentials:
- - name: jwt-auth
+ - id: cred-jack-jwt-auth
+ name: jwt-auth
type: jwt-auth
config:
key: jwt-vault-key
- secret: $secret://vault-jwt/jack/jwt-secret
+ secret: $secret://vault/jwt/jack/jwt-secret
services:
- name: jwt-auth-service
+ labels:
+ docs-example: jwt-auth
routes:
- name: jwt-route
uris:
@@ -1016,47 +1048,54 @@ services:
weight: 1
```
-Synchronize the configuration to the gateway:
+ADC reconciles the selected top-level resource types as desired state. Preview
the scoped changes and confirm that they contain no unintended updates or
deletions:
```shell
-adc sync -f adc.yaml
+adc diff -f adc.yaml \
+ --include-resource-type service \
+ --include-resource-type consumer \
+ --label-selector docs-example=jwt-auth
```
-</TabItem>
-
-</Tabs>
-
-Set `jwt-auth` key value to be `vault-hs256-secret-that-is-very-long` in Vault:
+Synchronize the reviewed configuration:
```shell
-docker exec -i vault sh -c "VAULT_TOKEN='root'
VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack
jwt-secret=vault-hs256-secret-that-is-very-long"
+adc sync -f adc.yaml \
+ --include-resource-type service \
+ --include-resource-type consumer \
+ --label-selector docs-example=jwt-auth
```
-You should see a response similar to the following:
-
-```text
-Success! Data written to: kv/apisix/jack
-```
+</TabItem>
-To issue a JWT, you could use [JWT.io's JWT encoder](https://jwt.io) or other
utilities. If you are using [JWT.io's JWT encoder](https://jwt.io), do the
following:
+</Tabs>
-* Fill in `HS256` as the algorithm.
-* Update the secret in the __Valid secret__ section to be
`vault-hs256-secret-that-is-very-long`.
-* Update payload with Consumer key `jwt-vault-key`; and add `exp` or `nbf` in
UNIX timestamp.
+In both methods, the reference uses the `jwt` Secret resource to read the
`jwt-secret` field from `kv/apisix/jack`.
-Your payload should look similar to the following:
+Define a local HS256 signing helper, then generate a JWT with the key and
secret stored in Vault:
-```json
-{
- "key": "jwt-vault-key",
- "nbf": 1729132271
+```shell
+base64url() {
+ openssl base64 -A | tr '+/' '-_' | tr -d '='
}
-```
-Copy the generated JWT and save to a variable:
+sign_hs256() {
+ local secret="$1"
+ local payload="$2"
+ local encoded_header encoded_payload signature
-```shell
-export
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.i2pLj7QcQvnlSjB7iV5V522tIV43boQRtee7L0rwlkQ
+ encoded_header=$(printf '%s' '{"alg":"HS256","typ":"JWT"}' | base64url)
+ encoded_payload=$(printf '%s' "$payload" | base64url)
+ signature=$(printf '%s' "$encoded_header.$encoded_payload" | \
+ openssl dgst -sha256 -hmac "$secret" -binary | base64url)
+
+ printf '%s.%s.%s\n' "$encoded_header" "$encoded_payload" "$signature"
+}
+
+jwt_token=$(sign_hs256 \
+ 'vault-hs256-secret-that-is-very-long' \
+ '{"key":"jwt-vault-key"}')
+export jwt_token
```
Send a request with the token in the header:
@@ -1065,7 +1104,16 @@ Send a request with the token in the header:
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
```
-You should receive an `HTTP/1.1 200 OK` response.
+You should receive an `HTTP/1.1 200 OK` response. The response body should
include headers that identify the authenticated Consumer:
+
+```json
+{
+ "headers": {
+ "X-Consumer-Username": "jack",
+ "X-Credential-Identifier": "cred-jack-jwt-auth"
+ }
+}
+```
### Sign JWT with RS256 Algorithm
diff --git a/docs/zh/latest/plugins/jwt-auth.md
b/docs/zh/latest/plugins/jwt-auth.md
index a466dd45cd..f6e4478abf 100644
--- a/docs/zh/latest/plugins/jwt-auth.md
+++ b/docs/zh/latest/plugins/jwt-auth.md
@@ -882,27 +882,43 @@ curl -i "http://127.0.0.1:9080/get" -H "Authorization:
${jwt_token}"
你应收到 `HTTP/1.1 200 OK` 响应。
-### 在 Secret Manager 中管理密钥
+### 在 HashiCorp Vault 中存储 JWT 密钥
-以下示例演示如何在 [HashiCorp Vault](https://www.vaultproject.io) 中管理 `jwt-auth`
消费者密钥,并在插件配置中引用。
+[HashiCorp Vault](https://developer.hashicorp.com/vault/docs)
提供集中式外部密钥存储。以下示例将 JWT 签名密钥存储在 Vault 中,而不是直接存储在 `jwt-auth` 凭据中,并从 APISIX 引用该密钥。
-在 Docker 中启动 Vault 开发服务器:
+:::info
+
+[Vault
开发模式](https://developer.hashicorp.com/vault/docs/concepts/dev-server)将数据存储在内存中,并使用
root 令牌。此设置仅用于本地测试。在生产环境中,请部署生产级 Vault,并为 APISIX 配置一个只能读取所需密钥路径的令牌。
+
+:::
+
+将 `APISIX_CONTAINER` 设置为正在运行的 APISIX 容器名称。创建专用 Docker 网络,并将 APISIX 连接到该网络:
+
+```shell
+export APISIX_CONTAINER=replace-with-apisix-container-name
+
+docker network create apisix-vault-net
+docker network connect apisix-vault-net "$APISIX_CONTAINER"
+```
+
+在同一网络中启动 Vault 开发服务器:
```shell
docker run -d \
- --name vault \
- -p 8200:8200 \
+ --name apisix-vault \
+ --network apisix-vault-net \
--cap-add IPC_LOCK \
-e VAULT_DEV_ROOT_TOKEN_ID=root \
-e VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 \
- vault:1.9.0 \
+ hashicorp/vault:1.21.4 \
vault server -dev
```
-APISIX 目前支持 [Vault KV 引擎第 1
版](https://developer.hashicorp.com/vault/docs/secrets/kv#kv-version-1)。在 Vault
中启用它:
+APISIX 的 Vault Secret Provider 从 [Vault KV 版本
1](https://developer.hashicorp.com/vault/docs/secrets/kv/kv-v1)读取密钥。在 `kv/`
路径启用 KV 版本 1 密钥引擎:
```shell
-docker exec -i vault sh -c "VAULT_TOKEN='root'
VAULT_ADDR='http://0.0.0.0:8200' vault secrets enable -path=kv -version=1 kv"
+docker exec apisix-vault sh -c \
+ "VAULT_TOKEN='root' VAULT_ADDR='http://127.0.0.1:8200' vault secrets enable
-path=kv -version=1 kv"
```
你应收到类似如下的响应:
@@ -911,28 +927,45 @@ docker exec -i vault sh -c "VAULT_TOKEN='root'
VAULT_ADDR='http://0.0.0.0:8200'
Success! Enabled the kv secrets engine at: kv/
```
-<Tabs
-groupId="api"
-defaultValue="dashboard"
-values={[
-{label: 'Admin API', value: 'dashboard'},
-{label: 'ADC', value: 'adc'}
-]}>
+将签名密钥存储在 `kv/apisix/jack`:
-<TabItem value="dashboard">
+```shell
+docker exec apisix-vault sh -c \
+ "VAULT_TOKEN='root' VAULT_ADDR='http://127.0.0.1:8200' vault kv put
kv/apisix/jack jwt-secret=vault-hs256-secret-that-is-very-long"
+```
-创建 [Secret](../terminology/secret.md) 并配置 Vault 地址及其他连接信息,请根据实际情况调整 Vault 地址:
+你应收到类似如下的响应:
+
+```text
+Success! Data written to: kv/apisix/jack
+```
+
+创建包含 Vault 连接信息的 APISIX [Secret](../terminology/secret.md) 资源。ADC 目前无法同步
Secret 资源,因此请通过 Admin API 创建该资源:
```shell
curl "http://127.0.0.1:9180/apisix/admin/secrets/vault/jwt" -X PUT \
-H "X-API-KEY: ${admin_key}" \
-d '{
- "uri": "http://127.0.0.1:8200",
+ "uri": "http://apisix-vault:8200",
"prefix": "kv/apisix",
"token": "root"
}'
```
+Vault 容器与 APISIX 位于同一 Docker 网络中,因此 APISIX 可以通过容器名称访问 Vault。
+
+以下两种配置方式都需要此 Secret 资源。ADC 目前无法同步 Secret 资源,但可以同步引用现有 Secret 资源的凭据。
+
+<Tabs
+groupId="api"
+defaultValue="dashboard"
+values={[
+{label: 'Admin API', value: 'dashboard'},
+{label: 'ADC', value: 'adc'}
+]}>
+
+<TabItem value="dashboard">
+
创建消费者 `jack`:
```shell
@@ -983,25 +1016,24 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
<TabItem value="adc">
-创建 Secret 并配置 Vault 地址,请根据实际情况调整 Vault 地址:
+创建包含消费者、Vault 后端凭据和路由的 `adc.yaml`:
```yaml title="adc.yaml"
-secrets:
- - name: vault-jwt
- vault:
- url: http://127.0.0.1:8200
- prefix: kv/apisix
- token: root
consumers:
- username: jack
+ labels:
+ docs-example: jwt-auth
credentials:
- - name: jwt-auth
+ - id: cred-jack-jwt-auth
+ name: jwt-auth
type: jwt-auth
config:
key: jwt-vault-key
- secret: $secret://vault-jwt/jack/jwt-secret
+ secret: $secret://vault/jwt/jack/jwt-secret
services:
- name: jwt-auth-service
+ labels:
+ docs-example: jwt-auth
routes:
- name: jwt-route
uris:
@@ -1016,47 +1048,54 @@ services:
weight: 1
```
-将配置同步到网关:
+ADC 将所选顶层资源类型协调为期望状态。预览限定范围后的变更,并确认其中没有非预期的更新或删除:
```shell
-adc sync -f adc.yaml
+adc diff -f adc.yaml \
+ --include-resource-type service \
+ --include-resource-type consumer \
+ --label-selector docs-example=jwt-auth
```
-</TabItem>
-
-</Tabs>
-
-在 Vault 中设置 `jwt-auth` 密钥值为 `vault-hs256-secret-that-is-very-long`:
+同步已审核的配置:
```shell
-docker exec -i vault sh -c "VAULT_TOKEN='root'
VAULT_ADDR='http://0.0.0.0:8200' vault kv put kv/apisix/jack
jwt-secret=vault-hs256-secret-that-is-very-long"
+adc sync -f adc.yaml \
+ --include-resource-type service \
+ --include-resource-type consumer \
+ --label-selector docs-example=jwt-auth
```
-你应收到类似如下的响应:
-
-```text
-Success! Data written to: kv/apisix/jack
-```
+</TabItem>
-如需签发 JWT,可以使用 [JWT.io 的 JWT 编码器](https://jwt.io)或其他工具。若使用 [JWT.io 的 JWT
编码器](https://jwt.io),请执行以下步骤:
+</Tabs>
-* 将算法填写为 `HS256`。
-* 在 __Valid secret__ 部分将密钥更新为 `vault-hs256-secret-that-is-very-long`。
-* 在 payload 中填入消费者密钥 `jwt-vault-key`,并以 UNIX 时间戳格式添加 `exp` 或 `nbf`。
+在两种配置方式中,该引用均使用 `jwt` Secret 资源读取 `kv/apisix/jack` 中的 `jwt-secret` 字段。
-payload 应类似如下所示:
+定义本地 HS256 签名辅助函数,然后使用 Vault 中存储的 key 和 secret 生成 JWT:
-```json
-{
- "key": "jwt-vault-key",
- "nbf": 1729132271
+```shell
+base64url() {
+ openssl base64 -A | tr '+/' '-_' | tr -d '='
}
-```
-复制生成的 JWT 并保存到变量:
+sign_hs256() {
+ local secret="$1"
+ local payload="$2"
+ local encoded_header encoded_payload signature
-```shell
-export
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2V5IiwibmJmIjoxNzI5MTMyMjcxfQ.i2pLj7QcQvnlSjB7iV5V522tIV43boQRtee7L0rwlkQ
+ encoded_header=$(printf '%s' '{"alg":"HS256","typ":"JWT"}' | base64url)
+ encoded_payload=$(printf '%s' "$payload" | base64url)
+ signature=$(printf '%s' "$encoded_header.$encoded_payload" | \
+ openssl dgst -sha256 -hmac "$secret" -binary | base64url)
+
+ printf '%s.%s.%s\n' "$encoded_header" "$encoded_payload" "$signature"
+}
+
+jwt_token=$(sign_hs256 \
+ 'vault-hs256-secret-that-is-very-long' \
+ '{"key":"jwt-vault-key"}')
+export jwt_token
```
携带令牌在请求头中发送请求:
@@ -1065,7 +1104,16 @@ export
jwt_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJqd3QtdmF1bHQta2
curl -i "http://127.0.0.1:9080/get" -H "Authorization: ${jwt_token}"
```
-你应收到 `HTTP/1.1 200 OK` 响应。
+你应收到 `HTTP/1.1 200 OK` 响应。响应正文应包含用于标识已认证消费者的请求头:
+
+```json
+{
+ "headers": {
+ "X-Consumer-Username": "jack",
+ "X-Credential-Identifier": "cred-jack-jwt-auth"
+ }
+}
+```
### 使用 RS256 算法签名 JWT