diff --git a/docs/en/latest/plugins/basic-auth.md b/docs/en/latest/plugins/basic-auth.md index a82424c3f72b..b0fd55f03b7a 100644 --- a/docs/en/latest/plugins/basic-auth.md +++ b/docs/en/latest/plugins/basic-auth.md @@ -32,30 +32,31 @@ description: The basic-auth Plugin adds basic access authentication for Consumer +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + ## Description The `basic-auth` Plugin adds [basic access authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) for [Consumers](../terminology/consumer.md) to authenticate themselves before being able to access Upstream resources. -When a Consumer is successfully authenticated, APISIX adds additional headers, such as `X-Consumer-Username`, `X-Credential-Indentifier`, and other Consumer custom headers if configured, to the request, before proxying it to the Upstream service. The Upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added. +When a Consumer is successfully authenticated, APISIX adds additional headers, such as `X-Consumer-Username`, `X-Credential-Identifier`, and other Consumer custom headers if configured, to the request, before proxying it to the Upstream service. The Upstream service will be able to differentiate between consumers and implement additional logics as needed. If any of these values is not available, the corresponding header will not be added. ## Attributes For Consumer/Credentials: -| Name | Type | Required | Description | -|----------|--------|----------|------------------------------------------------------------------------------------------------------------------------| -| username | string | True | Unique basic auth username for a consumer. | -| password | string | True | Basic auth password for the consumer. | - -NOTE: `encrypt_fields = {"password"}` is also defined in the schema, which means that the field will be stored encrypted in etcd. See [encrypted storage fields](../plugin-develop.md#encrypted-storage-fields). +| Name | Type | Required | Default | Valid values | Description | +|------|------|----------|---------|--------------|-------------| +| username | string | True | | | Unique basic auth username for a Consumer. | +| password | string | True | | | Basic auth password for the Consumer. The password is encrypted with AES before being stored in etcd. You can also store it in an environment variable and reference it using the `env://` prefix, or in a secret manager such as HashiCorp Vault's KV secrets engine, and reference it using the `secret://` prefix. | For Route: -| Name | Type | Required | Default | Description | -|------------------|---------|----------|---------|------------------------------------------------------------------------| -| hide_credentials | boolean | False | false | If true, do not pass the authorization request header to Upstream services. | -| anonymous_consumer | boolean | False | false | Anonymous Consumer name. If configured, allow anonymous users to bypass the authentication. | -| realm | string | False | basic | The realm to include in the `WWW-Authenticate` header when authentication fails. | +| Name | Type | Required | Default | Valid values | Description | +|------|------|----------|---------|--------------|-------------| +| hide_credentials | boolean | False | false | | If true, do not pass the authorization request header to Upstream services. | +| anonymous_consumer | string | False | | | Anonymous Consumer name. If configured, allow anonymous users to bypass the authentication. | +| realm | string | False | basic | | Realm in the [`WWW-Authenticate`](https://datatracker.ietf.org/doc/html/rfc7235#section-4.1) response header returned with a `401 Unauthorized` response due to authentication failure. Available in Apache APISIX version 3.15.0 and later. | ## Examples @@ -63,8 +64,6 @@ The examples below demonstrate how you can work with the `basic-auth` Plugin for :::note -You can fetch the `admin_key` from `config.yaml` and save to an environment variable with the following command: - ```bash admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g') ``` @@ -75,6 +74,17 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ The following example demonstrates how to implement basic authentication on a Route. + + + + Create a Consumer `johndoe`: ```shell @@ -85,7 +95,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ }' ``` -Create `basic-auth` Credential for the consumer: +Create `basic-auth` Credential for the Consumer: ```shell curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ @@ -121,9 +131,191 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -#### Verify with a Valid Key + + + + +Create a Consumer with `basic-auth` Credential and a Route with `basic-auth` Plugin configured: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: {} + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +Create a Consumer with `basic-auth` Credential and a Route with `basic-auth` Plugin configured: + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-cred + config: + username: johndoe + password: john-key +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixConsumer +metadata: + namespace: aic + name: johndoe +spec: + ingressClassName: apisix + authParameter: + basicAuth: + value: + username: johndoe + password: john-key +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixUpstream +metadata: + namespace: aic + name: httpbin-external-domain +spec: + ingressClassName: apisix + externalNodes: + - type: Domain + name: httpbin.org +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true +``` -Send a request to with the valid key: +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +#### Verify with Valid Credentials + +Send a request to the Route with valid Credentials: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key @@ -136,26 +328,25 @@ You should see an `HTTP/1.1 200 OK` response similar to the following: "args": {}, "headers": { "Accept": "*/*", - "Apikey": "john-key", "Authorization": "Basic am9obmRvZTpqb2huLWtleQ==", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 205.198.122.37", - "url": "http://127.0.0.1/get" + "url": "http://127.0.0.1/anything" } ``` -#### Verify with an Invalid Key +#### Verify with Invalid Credentials -Send a request with an invalid key: +Send a request with invalid Credentials: ```shell -curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-key +curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-password ``` You should see an `HTTP/1.1 401 Unauthorized` response with the following: @@ -164,9 +355,9 @@ You should see an `HTTP/1.1 401 Unauthorized` response with the following: {"message":"Invalid user authorization"} ``` -#### Verify without a Key +#### Verify without Credentials -Send a request to without a key: +Send a request without Credentials: ```shell curl -i "http://127.0.0.1:9080/anything" @@ -180,7 +371,18 @@ You should see an `HTTP/1.1 401 Unauthorized` response with the following: ### Hide Authentication Information From Upstream -The following example demonstrates how to prevent the key from being sent to the Upstream services by configuring `hide_credentials`. In APISIX, the authentication key is forwarded to the Upstream services by default, which might lead to security risks in some circumstances and you should consider updating `hide_credentials`. +The following example demonstrates how to prevent the client's Credentials (the `Authorization` header) from being sent to the Upstream services by configuring `hide_credentials`. If you are using APISIX, the `Authorization` header containing the client's Credentials is forwarded to the Upstream services by default, which might lead to security risks in some circumstances and you should consider updating `hide_credentials` as shown in this example. + + + + Create a Consumer `johndoe`: @@ -192,7 +394,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ }' ``` -Create `basic-auth` Credential for the consumer: +Create `basic-auth` Credential for the Consumer: ```shell curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ @@ -232,7 +434,193 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -Send a request with the valid key: + + + + +Create a Consumer with `basic-auth` Credential and a Route with `basic-auth` Plugin configured: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + hide_credentials: false + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +Create a Consumer with `basic-auth` Credential and a Route with `basic-auth` Plugin configured: + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-cred + config: + username: johndoe + password: john-key +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false + hide_credentials: false +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixConsumer +metadata: + namespace: aic + name: johndoe +spec: + ingressClassName: apisix + authParameter: + basicAuth: + value: + username: johndoe + password: john-key +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixUpstream +metadata: + namespace: aic + name: httpbin-external-domain +spec: + ingressClassName: apisix + externalNodes: + - type: Domain + name: httpbin.org +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true + config: + hide_credentials: false +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +Send a request with the valid Credentials: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key @@ -252,8 +640,8 @@ You should see an `HTTP/1.1 200 OK` response with the following: "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc2195-22bd5f401b13480e63c498c6", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, @@ -263,21 +651,26 @@ You should see an `HTTP/1.1 200 OK` response with the following: } ``` -Note that the credentials are visible to the Upstream service in base64-encoded format. - -:::tip - -You can also pass the base64-encoded credentials in the request using the `Authorization` header as such: +Note that the Credentials are visible to the Upstream service in base64-encoded format. You can also pass the base64-encoded Credentials in the request using the `Authorization` header: ```shell curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ==" ``` -::: - #### Hide Credentials -Update the plugin's `hide_credentials` to `true`: + + + + +Update the Plugin's `hide_credentials` to `true`: ```shell curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \ @@ -291,7 +684,122 @@ curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \ }' ``` -Send a request with the valid key: + + + + +Update the Route configuration: + +```yaml title="adc.yaml" +# other configs +# ... +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + hide_credentials: true + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +Update the PluginConfig to set `hide_credentials` to `true`: + +```yaml title="basic-auth-ic.yaml" +# other configs +# --- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false + hide_credentials: true +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +Update the ApisixRoute to set `hide_credentials` to `true`: + +```yaml title="basic-auth-ic.yaml" +# other configs +# --- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true + config: + hide_credentials: true +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +Send a request with the valid Credentials: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key @@ -310,8 +818,8 @@ You should see an `HTTP/1.1 200 OK` response with the following: "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc21a7-4f6ac87946e25f325167d53a", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, @@ -321,12 +829,23 @@ You should see an `HTTP/1.1 200 OK` response with the following: } ``` -Note that the credentials are no longer visible to the Upstream service. +Note that the Credentials are no longer visible to the Upstream service. ### Add Consumer Custom ID to Header The following example demonstrates how you can attach a Consumer custom ID to authenticated request in the `Consumer-Custom-Id` header, which can be used to implement additional logics as needed. + + + + Create a Consumer `johndoe` with a custom ID label: ```shell @@ -340,7 +859,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ }' ``` -Create `basic-auth` Credential for the consumer: +Create `basic-auth` Credential for the Consumer: ```shell curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ @@ -376,13 +895,62 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -To verify, send a request to the Route with the valid key: + + + + +Create a Consumer with `basic-auth` Credential and a Route with `basic-auth` Plugin enabled: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + labels: + custom_id: "495aec6a" + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: {} + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +Consumer custom labels are currently not supported when configuring resources through the Ingress Controller, and the `X-Consumer-Custom-Id` header is not included in requests. At the moment, this example cannot be completed with the Ingress Controller. + + + + + +To verify, send a request to the Route with the valid Credentials: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` -You should see an `HTTP/1.1 200 OK` response with the `X-Consumer-Custom-Id` similar to the following: +You should see an `HTTP/1.1 200 OK` response similar to the following: ```json { @@ -410,7 +978,18 @@ You should see an `HTTP/1.1 200 OK` response with the `X-Consumer-Custom-Id` sim ### Rate Limit with Anonymous Consumer -The following example demonstrates how you can configure different rate limiting policies by regular and anonymous consumers, where the anonymous Consumer does not need to authenticate and has less quotas. +The following example demonstrates how you can configure different rate limiting policies by regular and anonymous consumers, where the anonymous Consumer does not need to authenticate and has less quota. + + + + Create a regular Consumer `johndoe` and configure the `limit-count` Plugin to allow for a quota of 3 within a 30-second window: @@ -423,7 +1002,8 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ "limit-count": { "count": 3, "time_window": 30, - "rejected_code": 429 + "rejected_code": 429, + "policy": "local" } } }' @@ -456,7 +1036,8 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ "limit-count": { "count": 1, "time_window": 30, - "rejected_code": 429 + "rejected_code": 429, + "policy": "local" } } }' @@ -484,7 +1065,177 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -To verify, send five consecutive requests with `john`'s key: + + + + +Configure Consumers with different rate limits and a Route that accepts anonymous users: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + plugins: + limit-count: + count: 3 + time_window: 30 + rejected_code: 429 + policy: local + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key + - username: anonymous + plugins: + limit-count: + count: 1 + time_window: 30 + rejected_code: 429 + policy: local +services: + - name: anonymous-rate-limit-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + anonymous_consumer: anonymous + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +Configure Consumers with different rate limits and a Route that accepts anonymous users: + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-key + config: + username: johndoe + password: john-key + plugins: + - name: limit-count + config: + count: 3 + time_window: 30 + rejected_code: 429 + policy: local +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: anonymous +spec: + gatewayRef: + name: apisix + plugins: + - name: limit-count + config: + count: 1 + time_window: 30 + rejected_code: 429 + policy: local +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + anonymous_consumer: aic_anonymous # namespace_consumername +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +The ApisixConsumer CRD currently does not support configuring plugins on consumers, except for the authentication plugins allowed in `authParameter`. This example cannot be completed with APISIX CRDs. + + + + + + + + + +To verify, send five consecutive requests with `johndoe`'s Credentials: ```shell resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john-key -o /dev/null -s -w "%{http_code}\n") && \ diff --git a/docs/zh/latest/plugins/basic-auth.md b/docs/zh/latest/plugins/basic-auth.md index f7a70b76c0ce..8ca2b1c266e0 100644 --- a/docs/zh/latest/plugins/basic-auth.md +++ b/docs/zh/latest/plugins/basic-auth.md @@ -32,30 +32,31 @@ description: basic-auth 插件为消费者添加了基本访问身份验证, +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + ## 描述 -`basic-auth` 插件为 [消费者](../terminology/consumer.md) 添加了 [基本访问身份验证](https://en.wikipedia.org/wiki/Basic_access_authentication),以便消费者在访问上游资源之前进行身份验证。 +`basic-auth` 插件为[消费者](../terminology/consumer.md)添加了[基本访问身份验证](https://en.wikipedia.org/wiki/Basic_access_authentication),以便消费者在访问上游资源之前进行身份验证。 -当消费者成功通过身份验证后,APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username`、`X-Credential-Indentifier` 和其他消费者自定义标头(如果已配置)。上游服务将能够区分消费者并根据需要实现其他逻辑。如果这些值中的任何一个不可用,则不会添加相应的标头。 +当消费者成功通过身份验证后,APISIX 会在将请求代理到上游服务之前向请求添加其他标头,例如 `X-Consumer-Username`、`X-Credential-Identifier` 和其他消费者自定义标头(如果已配置)。上游服务将能够区分消费者并根据需要实现其他逻辑。如果这些值中的任何一个不可用,则不会添加相应的标头。 ## 属性 -Consumer/Credentials 端: - -| 名称 | 类型 | 必选项 | 描述 | -| -------- | ------ | -----| ----------------------------------------------------------------------------------------------- | -| username | string | 是 | Consumer 的用户名并且该用户名是唯一,如果多个 Consumer 使用了相同的 `username`,将会出现请求匹配异常。| -| password | string | 是 | 用户的密码。该字段支持使用 [APISIX Secret](../terminology/secret.md) 资源,将值保存在 Secret Manager 中。 | +消费者/凭证端: -注意:schema 中还定义了 `encrypt_fields = {"password"}`,这意味着该字段将会被加密存储在 etcd 中。具体参考 [加密存储字段](../plugin-develop.md#加密存储字段)。 +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +|------|------|--------|--------|--------|------| +| username | string | 是 | | | 消费者的唯一基本认证用户名。 | +| password | string | 是 | | | 消费者的基本认证密码。密码在存储到 etcd 之前会使用 AES 加密。你也可以将其存储在环境变量中并使用 `env://` 前缀引用,或存储在 HashiCorp Vault 等密钥管理器中并使用 `secret://` 前缀引用。 | Route 端: -| 名称 | 类型 | 必选项 | 默认值 | 描述 | -| ---------------- | ------- | ------ | ------ | --------------------------------------------------------------- | -| hide_credentials | boolean | 否 | false | 该参数设置为 `true` 时,则不会将 Authorization 请求头传递给 Upstream。| -| anonymous_consumer | boolean | 否 | false | 匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。 | -| realm | string | 否 | basic |在身份验证失败时,应包含在 `WWW-Authenticate` 标头中的域。| +| 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | +|------|------|--------|--------|--------|------| +| hide_credentials | boolean | 否 | false | | 若为 `true`,则不将 Authorization 请求标头传递给上游服务。 | +| anonymous_consumer | string | 否 | | | 匿名消费者名称。如果已配置,则允许匿名用户绕过身份验证。 | +| realm | string | 否 | basic | | 在身份验证失败时,`401 Unauthorized` 响应中 [`WWW-Authenticate`](https://datatracker.ietf.org/doc/html/rfc7235#section-4.1) 标头的域值。该参数在 Apache APISIX 3.15.0 及以上版本中可用。 | ## 示例 @@ -63,16 +64,27 @@ Route 端: :::note -您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量: - ```bash admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g') ``` +::: + ### 在路由上实现基本身份验证 以下示例演示如何在路由上实现基本身份验证。 + + + + 创建消费者 `johndoe`: ```shell @@ -119,58 +131,239 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -#### 使用有效密钥进行验证 + + + + +创建带有 `basic-auth` 凭证的消费者以及配置了 `basic-auth` 插件的路由: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: {} + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +将配置同步到网关: -使用有效密钥发送请求至: +```shell +adc sync -f adc.yaml +``` + + + + + +创建带有 `basic-auth` 凭证的消费者以及配置了 `basic-auth` 插件的路由: + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-cred + config: + username: johndoe + password: john-key +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixConsumer +metadata: + namespace: aic + name: johndoe +spec: + ingressClassName: apisix + authParameter: + basicAuth: + value: + username: johndoe + password: john-key +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixUpstream +metadata: + namespace: aic + name: httpbin-external-domain +spec: + ingressClassName: apisix + externalNodes: + - type: Domain + name: httpbin.org +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +#### 使用有效凭证进行验证 + +使用有效凭证发送请求: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` -您应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应: +你应该会看到类似于以下内容的 `HTTP/1.1 200 OK` 响应: ```json { "args": {}, "headers": { "Accept": "*/*", - "Apikey": "john-key", "Authorization": "Basic am9obmRvZTpqb2huLWtleQ==", "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66e5107c-5bb3e24f2de5baf733aec1cc", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "origin": "192.168.65.1, 205.198.122.37", - "url": "http://127.0.0.1/get" + "url": "http://127.0.0.1/anything" } ``` -#### 使用无效密钥进行验证 +#### 使用无效凭证进行验证 -使用无效密钥发送请求: +使用无效凭证发送请求: ```shell -curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-key +curl -i "http://127.0.0.1:9080/anything" -u johndoe:invalid-password ``` -您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应: +你应该看到以下 `HTTP/1.1 401 Unauthorized` 响应: ```text {"message":"Invalid user authorization"} ``` -#### 无需密钥即可验证 +#### 不使用凭证进行验证 -无需密钥即可发送请求: +发送不携带凭证的请求: ```shell curl -i "http://127.0.0.1:9080/anything" ``` -您应该看到以下 `HTTP/1.1 401 Unauthorized` 响应: +你应该看到以下 `HTTP/1.1 401 Unauthorized` 响应: ```text {"message":"Missing authorization in request"} @@ -178,9 +371,20 @@ curl -i "http://127.0.0.1:9080/anything" ### 隐藏上游的身份验证信息 -以下示例演示了如何通过配置 `hide_credentials` 来防止密钥被发送到上游服务。APISIX 默认情况下会将身份验证密钥转发到上游服务,这在某些情况下可能会导致安全风险,您应该考虑更新 `hide_credentials`。 +以下示例演示了如何通过配置 `hide_credentials` 来防止客户端凭证(`Authorization` 标头)被发送到上游服务。APISIX 默认情况下会将包含客户端凭证的 `Authorization` 标头转发到上游服务,这在某些情况下可能会导致安全风险,你应该考虑按本示例更新 `hide_credentials`。 + + -创建消费者 `johndoe` : + + +创建消费者 `johndoe`: ```shell curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ @@ -208,7 +412,7 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \ #### 不隐藏凭据 -使用 `basic-auth` 创建路由,并将 `hide_credentials` 配置为 `false`,这是默认配置: +使用 `basic-auth` 创建路由,并将 `hide_credentials` 配置为 `false`(默认配置): ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -230,13 +434,199 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -发送带有有效密钥的请求: + + + + +创建带有 `basic-auth` 凭证的消费者以及配置了 `basic-auth` 插件的路由: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + hide_credentials: false + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +将配置同步到网关: + +```shell +adc sync -f adc.yaml +``` + + + + + +创建带有 `basic-auth` 凭证的消费者以及配置了 `basic-auth` 插件的路由: + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-cred + config: + username: johndoe + password: john-key +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false + hide_credentials: false +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixConsumer +metadata: + namespace: aic + name: johndoe +spec: + ingressClassName: apisix + authParameter: + basicAuth: + value: + username: johndoe + password: john-key +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixUpstream +metadata: + namespace: aic + name: httpbin-external-domain +spec: + ingressClassName: apisix + externalNodes: + - type: Domain + name: httpbin.org +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true + config: + hide_credentials: false +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +发送带有有效凭证的请求: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` -您应该看到以下 `HTTP/1.1 200 OK` 响应: +你应该看到以下 `HTTP/1.1 200 OK` 响应: ```json { @@ -250,8 +640,8 @@ curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc2195-22bd5f401b13480e63c498c6", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, @@ -261,20 +651,25 @@ curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key } ``` -请注意,凭证以 base64 编码格式对上游服务可见。 - -:::tip - -您还可以使用 `Authorization` 标头在请求中传递 base64 编码的凭据,如下所示: +请注意,凭证以 base64 编码格式对上游服务可见。你也可以使用 `Authorization` 标头在请求中传递 base64 编码的凭据: ```shell curl -i "http://127.0.0.1:9080/anything" -H "Authorization: Basic am9obmRvZTpqb2huLWtleQ==" ``` -::: - #### 隐藏凭据 + + + + 将插件的 `hide_credentials` 更新为 `true`: ```shell @@ -289,13 +684,128 @@ curl "http://127.0.0.1:9180/apisix/admin/routes/basic-auth-route" -X PATCH \ }' ``` -发送带有有效密钥的请求: + + + + +更新路由配置: + +```yaml title="adc.yaml" +# 其他配置 +# ... +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + hide_credentials: true + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +将配置同步到网关: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +更新 PluginConfig,将 `hide_credentials` 设置为 `true`: + +```yaml title="basic-auth-ic.yaml" +# 其他配置 +# --- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + _meta: + disable: false + hide_credentials: true +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +更新 ApisixRoute,将 `hide_credentials` 设置为 `true`: + +```yaml title="basic-auth-ic.yaml" +# 其他配置 +# --- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + ingressClassName: apisix + http: + - name: basic-auth-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: basic-auth + enable: true + config: + hide_credentials: true +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + + + + + +发送带有有效凭证的请求: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` -您应该看到以下 `HTTP/1.1 200 OK` 响应: +你应该看到以下 `HTTP/1.1 200 OK` 响应: ```json { @@ -308,8 +818,8 @@ curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key "Host": "127.0.0.1", "User-Agent": "curl/8.6.0", "X-Amzn-Trace-Id": "Root=1-66cc21a7-4f6ac87946e25f325167d53a", - "X-Consumer-Username": "john", - "X-Credential-Indentifier": "cred-john-basic-auth", + "X-Consumer-Username": "johndoe", + "X-Credential-Identifier": "cred-john-basic-auth", "X-Forwarded-Host": "127.0.0.1" }, "json": null, @@ -325,6 +835,17 @@ curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key 以下示例演示了如何在 `Consumer-Custom-Id` 标头中将消费者自定义 ID 附加到经过身份验证的请求,该 ID 可用于根据需要实现其他逻辑。 + + + + 创建带有自定义 ID 标签的消费者 `johndoe`: ```shell @@ -374,13 +895,62 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -使用有效密钥向路由发送请求: + + + + +创建带有 `basic-auth` 凭证的消费者以及启用 `basic-auth` 插件的路由: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + labels: + custom_id: "495aec6a" + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key +services: + - name: basic-auth-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: {} + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +将配置同步到网关: + +```shell +adc sync -f adc.yaml +``` + + + + + +通过 Ingress Controller 配置资源时,目前不支持消费者自定义标签,请求中不会包含 `X-Consumer-Custom-Id` 标头。暂时无法通过 Ingress Controller 完成此示例。 + + + + + +使用有效凭证向路由发送请求进行验证: ```shell curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key ``` -您应该看到一个带有 `X-Consumer-Custom-Id` 的 `HTTP/1.1 200 OK` 响应,类似于以下内容: +你应该看到一个带有 `X-Consumer-Custom-Id` 的 `HTTP/1.1 200 OK` 响应,类似于以下内容: ```json { @@ -410,6 +980,17 @@ curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-key 以下示例演示了如何为普通消费者和匿名消费者配置不同的速率限制策略,其中匿名消费者不需要进行身份验证,并且配额较少。 + + + + 创建普通消费者 `johndoe` 并配置 `limit-count` 插件以允许 30 秒内的配额为 3: ```shell @@ -421,7 +1002,8 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ "limit-count": { "count": 3, "time_window": 30, - "rejected_code": 429 + "rejected_code": 429, + "policy": "local" } } }' @@ -454,7 +1036,8 @@ curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \ "limit-count": { "count": 1, "time_window": 30, - "rejected_code": 429 + "rejected_code": 429, + "policy": "local" } } }' @@ -482,7 +1065,177 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -为了验证,请使用 `john` 的密钥发送五个连续的请求: + + + + +配置具有不同速率限制的消费者以及接受匿名用户的路由: + +```yaml title="adc.yaml" +consumers: + - username: johndoe + plugins: + limit-count: + count: 3 + time_window: 30 + rejected_code: 429 + policy: local + credentials: + - name: basic-auth + type: basic-auth + config: + username: johndoe + password: john-key + - username: anonymous + plugins: + limit-count: + count: 1 + time_window: 30 + rejected_code: 429 + policy: local +services: + - name: anonymous-rate-limit-service + routes: + - name: basic-auth-route + uris: + - /anything + plugins: + basic-auth: + anonymous_consumer: anonymous + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +将配置同步到网关: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +配置具有不同速率限制的消费者以及接受匿名用户的路由: + +```yaml title="basic-auth-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: johndoe +spec: + gatewayRef: + name: apisix + credentials: + - type: basic-auth + name: primary-key + config: + username: johndoe + password: john-key + plugins: + - name: limit-count + config: + count: 3 + time_window: 30 + rejected_code: 429 + policy: local +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + namespace: aic + name: anonymous +spec: + gatewayRef: + name: apisix + plugins: + - name: limit-count + config: + count: 1 + time_window: 30 + rejected_code: 429 + policy: local +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: basic-auth-plugin-config +spec: + plugins: + - name: basic-auth + config: + anonymous_consumer: aic_anonymous # namespace_consumername +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: basic-auth-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: basic-auth-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +将配置应用到集群: + +```shell +kubectl apply -f basic-auth-ic.yaml +``` + + + + + +ApisixConsumer CRD 目前不支持在消费者上配置插件(`authParameter` 中允许的身份验证插件除外)。此示例无法通过 APISIX CRD 完成。 + + + + + + + + + +为了验证,请使用 `johndoe` 的凭证发送五个连续的请求: ```shell resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john-key -o /dev/null -s -w "%{http_code}\n") && \ @@ -491,7 +1244,7 @@ resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -u johndoe:john- echo "200": $count_200, "429": $count_429 ``` -您应该看到以下响应,显示在 5 个请求中,3 个请求成功(状态代码 200),而其他请求被拒绝(状态代码 429)。 +你应该看到以下响应,显示在 5 个请求中,3 个请求成功(状态代码 200),而其他请求被拒绝(状态代码 429)。 ```text 200: 3, 429: 2 @@ -506,7 +1259,7 @@ resp=$(seq 5 | xargs -I{} curl "http://127.0.0.1:9080/anything" -o /dev/null -s echo "200": $count_200, "429": $count_429 ``` -您应该看到以下响应,表明只有一个请求成功: +你应该看到以下响应,表明只有一个请求成功: ```text 200: 1, 429: 4