From c0338648aef753b1e1f743f0e46799cedfc8c6d5 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 7 May 2026 10:45:18 +0800 Subject: [PATCH 1/7] docs: update plugin docs with ADC and Ingress Controller examples Update plugin documentation for aws-lambda, public-api, real-ip, authz-keycloak, and serverless plugins with: - Add ADC (API7 Declarative Config) configuration examples - Add Ingress Controller (Gateway API and APISIX CRD) configuration examples - Update examples with admin_key environment variable usage - Improve example descriptions and formatting - Add multi-tab interface for different configuration methods These updates enhance the documentation by providing examples for multiple ways to configure APISIX plugins, making it easier for users working with different deployment methods. Related: api7/docs#1554, api7/docs#1556 --- docs/en/latest/plugins/authz-keycloak.md | 971 ++++++++++++++++++---- docs/en/latest/plugins/aws-lambda.md | 522 +++++++++++- docs/en/latest/plugins/public-api.md | 490 ++++++++++- docs/en/latest/plugins/real-ip.md | 603 +++++++++++++- docs/en/latest/plugins/serverless.md | 992 ++++++++++++++++++++++- 5 files changed, 3362 insertions(+), 216 deletions(-) diff --git a/docs/en/latest/plugins/authz-keycloak.md b/docs/en/latest/plugins/authz-keycloak.md index e9da7c41e30e..00539445a0e4 100644 --- a/docs/en/latest/plugins/authz-keycloak.md +++ b/docs/en/latest/plugins/authz-keycloak.md @@ -34,15 +34,9 @@ description: The authz-keycloak Plugin supports the integration with Keycloak to ## Description -The `authz-keycloak` Plugin supports the integration with [Keycloak](https://www.keycloak.org/) to authenticate and authorize users. See [Keycloak's Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/) for more information about the configuration options available in this Plugin. +The `authz-keycloak` Plugin integrates with [Keycloak](https://www.keycloak.org/) to authenticate and authorize users. See Keycloak's [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/) for more information about the configuration options available in this Plugin. -:::tip - -Although this Plugin was developed to work with Keycloak, it should work with any OAuth/OIDC and UMA compliant identity providers as well. - -::: - -Refer to [Authorization Services Guide](https://www.keycloak.org/docs/latest/authorization_services/) for more information on Keycloak. +While the Plugin was developed for Keycloak, it could theoretically be used with other OAuth/OIDC and UMA-compliant identity providers. ## Attributes @@ -52,7 +46,7 @@ Refer to [Authorization Services Guide](https://www.keycloak.org/docs/latest/aut | token_endpoint | string | False | | https://host.domain/realms/foo/protocol/openid-connect/token | An OAuth2-compliant token endpoint that supports the `urn:ietf:params:oauth:grant-type:uma-ticket` grant type. If provided, overrides the value from discovery. | | resource_registration_endpoint | string | False | | https://host.domain/realms/foo/authz/protection/resource_set | A UMA-compliant resource registration endpoint. If provided, overrides the value from discovery. | | client_id | string | True | | | The identifier of the resource server to which the client is seeking access. | -| client_secret | string | False | | | The client secret, if required. You can use APISIX secret to store and reference this value. APISIX currently supports storing secrets in two ways: [Environment Variables and HashiCorp Vault](../terminology/secret.md). | +| client_secret | string | False | | | The client secret, if required. You can use APISIX Secret to store and reference this value. APISIX currently supports storing secrets in two ways: [Environment Variables and HashiCorp Vault](../terminology/secret.md). | | grant_type | string | False | "urn:ietf:params:oauth:grant-type:uma-ticket" | ["urn:ietf:params:oauth:grant-type:uma-ticket"] | | | policy_enforcement_mode | string | False | "ENFORCING" | ["ENFORCING", "PERMISSIVE"] | | | permissions | array[string] | False | | | An array of strings, each representing a set of one or more resources and scopes the client is seeking access. | @@ -156,7 +150,17 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ #### Start Keycloak -Start a Keycloak instance named `apisix-quickstart-keycloak` with the administrator name `quickstart-admin` and password `quickstart-admin-pass` in [development mode](https://www.keycloak.org/server/configuration#_starting_keycloak_in_development_mode) in Docker: + + + + +Start a Keycloak instance named `apisix-quickstart-keycloak` with the administrator name `quickstart-admin` and password `quickstart-admin-pass` in [development mode](https://www.keycloak.org/server/configuration#_starting_keycloak_in_development_mode): ```shell docker run -d --name "apisix-quickstart-keycloak" \ @@ -166,57 +170,159 @@ docker run -d --name "apisix-quickstart-keycloak" \ quay.io/keycloak/keycloak:18.0.2 start-dev ``` -Save the Keycloak IP to an environment variable to be referenced in future configuration: + + + + +Deploy Keycloak to Kubernetes: + +```yaml title="keycloak.yaml" +apiVersion: apps/v1 +kind: Deployment +metadata: + namespace: aic + name: keycloak +spec: + replicas: 1 + selector: + matchLabels: + app: keycloak + template: + metadata: + labels: + app: keycloak + spec: + containers: + - name: keycloak + image: quay.io/keycloak/keycloak:18.0.2 + args: + - start-dev + env: + - name: KEYCLOAK_ADMIN + value: quickstart-admin + - name: KEYCLOAK_ADMIN_PASSWORD + value: quickstart-admin-pass + ports: + - containerPort: 8080 +--- +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: keycloak +spec: + selector: + app: keycloak + ports: + - port: 8080 + targetPort: 8080 +``` + +Apply the manifest: ```shell -KEYCLOAK_IP=192.168.42.145 # replace with your host IP +kubectl apply -f keycloak.yaml ``` -Navigate to `http://localhost:8080` in browser and click **Administration Console**: +If you would like to open the Keycloak console locally, port-forward the Service: -![admin-console](https://static.api7.ai/uploads/2024/01/12/yEKlaSf5_admin-console.png) +```shell +kubectl port-forward -n aic svc/keycloak 8080:8080 +``` -Enter the administrator's username `quickstart-admin` and password `quickstart-admin-pass` to sign in: + -![admin-signin](https://static.api7.ai/uploads/2024/01/12/GYIVrPyb_signin.png) + -#### Create a Realm +#### Save Keycloak URL -In the left menu, hover over **Master**, and select **Add realm** in the dropdown: +Save the Keycloak URL to an environment variable to be referenced in future configuration: -![create-realm](https://static.api7.ai/uploads/2024/01/12/563XIJPK_add-realm.png) + -Enter the realm name `quickstart-realm` and click **Create** to create it: + -![add-realm](https://static.api7.ai/uploads/2024/01/12/0lD21Z8R_create-realm.png) +```shell +KEYCLOAK_URL=http://192.168.42.145:8080 # replace with your Keycloak URL +``` -#### Create a Client + -Click **Clients** > **Create** to open the **Add Client** page: + + +```shell +KEYCLOAK_URL=http://keycloak.aic.svc.cluster.local:8080 +``` -![create-client](https://static.api7.ai/uploads/2024/01/12/nHxgXyd9_create-client.png) + -Enter **Client ID** as `apisix-quickstart-client`, keep the **Client Protocol** as `openid-connect` and **Save**: + + +#### Create a Realm, Client, and Authorization Objects + +Navigate to `http://localhost:8080` and click __Administration Console__: + +![admin-console](https://static.api7.ai/uploads/2024/01/12/yEKlaSf5_admin-console.png) + +Sign in with the administrator username `quickstart-admin` and password `quickstart-admin-pass`: + +![admin-signin](https://static.api7.ai/uploads/2024/01/12/GYIVrPyb_signin.png) + +Create a realm named `quickstart-realm`: + +![add-realm](https://static.api7.ai/uploads/2024/01/12/0lD21Z8R_create-realm.png) + +Create a client named `apisix-quickstart-client`: ![add-client](https://static.api7.ai/uploads/2024/01/12/7YSCHCnp_add-client.png) -The client `apisix-quickstart-client` is created. After redirecting to the detailed page, select `confidential` as the **Access Type**: +On the client settings page, select `confidential` as the access type: ![client-access-type-confidential](https://static.api7.ai/uploads/2024/01/12/L7cahPUe_confidential.png) -When the user login is successful during the SSO, Keycloak will carry the state and code to redirect the client to the addresses in **Valid Redirect URIs**. For simplicity of demonstration, enter wildcard `*` to accept any redirect URI: +Enable authorization for the client and save the configuration. This should also enable the client service account and assign the `uma_protection` role automatically: -![client-redirect](https://static.api7.ai/uploads/2024/01/12/B3VGbQbW_redirect-uri.png) +![enable-authorization](https://static.api7.ai/uploads/2024/01/05/S4we4KO9_enable-auth.png) -Enable authorization for the client, which should also enable service accounts with an assigned role `uma_protection` automatically: +Create a client scope named `httpbin-access`: -![enable-authorization](https://static.api7.ai/uploads/2024/01/05/S4we4KO9_enable-auth.png) +![save-client-scope](https://static.api7.ai/uploads/2024/01/12/5xQl0Xbx_save-client-scope.png) + +In the client's **Authorization** section, create the authorization scope `access`: + +![add-scope](https://static.api7.ai/uploads/2024/01/06/bVHhiALe_auth-scope.png) -Select **Save** to apply custom configurations. +Create the resource `httpbin-anything` with URI `/anything` and scope `access`: -#### Save Client ID and Secret +![create-resource](https://static.api7.ai/uploads/2024/01/06/15DJ9HAU_create-resource.png) -Click on **Clients** > `apisix-quickstart-client` > **Credentials**, and copy the client secret from **Secret**: +Create the client scope policy `access-client-scope-policy` that requires `httpbin-access`: + +![create-policy](https://static.api7.ai/uploads/2024/01/06/7UtT3cF6_create-policy.png) + +Create the scope-based permission `access-scope-perm` that uses the `access` scope and `access-client-scope-policy`: + +![add-scope-permission](https://static.api7.ai/uploads/2024/01/12/Y0vlk1Tj_add-scope-permission.png) + +Add `httpbin-access` to the default client scopes of `apisix-quickstart-client`: + +![add-client-scope](https://static.api7.ai/uploads/2024/01/06/sJKUMUcP_add-client-scope.png) + +Create a user named `quickstart-user`: + +![save-user](https://static.api7.ai/uploads/2024/01/12/3fUQOFWg_save-user.png) + +Set the password to `quickstart-user-pass` and turn off **Temporary**: + +![set-password](https://static.api7.ai/uploads/2024/01/12/aoabcBbC_set-password.png) + +Save the client secret from **Clients** > `apisix-quickstart-client` > **Credentials**: ![client-secret](https://static.api7.ai/uploads/2024/01/12/3VqiXdf9_client-secret.png) @@ -227,35 +333,66 @@ OIDC_CLIENT_ID=apisix-quickstart-client OIDC_CLIENT_SECRET=bSaIN3MV1YynmtXvU8lKkfeY0iwpr9cH # replace with your value ``` +:::tip + +If APISIX runs in Kubernetes, use the same Keycloak hostname consistently in both the Plugin configuration and the token request. Otherwise, Keycloak may reject the bearer token because the token issuer does not match the configured authorization endpoints. + +::: + #### Request Access Token -Request an access token from Keycloak: +Request an access token from Keycloak and save it to `ACCESS_TOKEN`: + + + + ```shell -curl -i "http://$KEYCLOAK_IP:8080/realms/quickstart-realm/protocol/openid-connect/token" -X POST \ +ACCESS_TOKEN=$(curl -sS "$KEYCLOAK_URL/realms/quickstart-realm/protocol/openid-connect/token" \ -d 'grant_type=client_credentials' \ -d 'client_id='$OIDC_CLIENT_ID'' \ - -d 'client_secret='$OIDC_CLIENT_SECRET'' + -d 'client_secret='$OIDC_CLIENT_SECRET'' | jq -r '.access_token') ``` -You should see a response similar to the following: + -```text -{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJoT3ludlBPY2d6Y3VWWnYtTU42bXZKMUczb0dOX2d6MFo3WFl6S2FSa1NBIn0...","expires_in":300,"refresh_expires_in":0,"token_type":"Bearer","not-before-policy":0,"scope":"email profile"} -``` + -Save the token to an environment variable: +Run the token request inside the Keycloak pod and save the result to `ACCESS_TOKEN`: ```shell -# replace with your access token -ACCESS_TOKEN= +ACCESS_TOKEN=$(kubectl exec -n aic deploy/keycloak -- env OIDC_CLIENT_SECRET="$OIDC_CLIENT_SECRET" sh -lc 'curl -sS "http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token" \ + -d grant_type=client_credentials \ + -d client_id=apisix-quickstart-client \ + -d client_secret="$OIDC_CLIENT_SECRET"' | jq -r '.access_token') ``` + + + + ### Use Lazy Load Path and Resource Registration Endpoint -The examples below demonstrate how you can configure the plugin to dynamically resolve the request URI to resource(s) using the resource registration endpoint instead of the static permissions. +The examples below demonstrate how you can configure `authz-keycloak` to dynamically resolve the request URI to one or more resources using the resource registration endpoint instead of static permissions. + + -Create a route with `authz-keycloak-route` as follows: + + +Create a Route with `authz-keycloak-route` as follows: ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -264,118 +401,272 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "authz-keycloak-route", "uri": "/anything", "plugins": { + # highlight-start "authz-keycloak": { + // Annotate 1 "lazy_load_paths": true, - "resource_registration_endpoint": "http://'"$KEYCLOAK_IP"':8080/realms/quickstart-realm/authz/protection/resource_set", - "discovery": "http://'"$KEYCLOAK_IP"':8080/realms/quickstart-realm/.well-known/uma2-configuration", + // Annotate 2 + "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", + // Annotate 3 + "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", + // Annotate 4 "client_id": "'"$OIDC_CLIENT_ID"'", + // Annotate 5 "client_secret": "'"$OIDC_CLIENT_SECRET"'" } + # highlight-end }, "upstream": { "type": "roundrobin", "nodes": { - "httpbin.org": 1 + "httpbin.org:80": 1 } } }' ``` -- Set `lazy_load_paths` to `true`. -- Set `resource_registration_endpoint` to Keycloak's UMA-compliant resource registration endpoint. Required when `lazy_load_paths` is `true` and `discovery` is not provided. -- Set `discovery` to the discovery document endpoint of Keycloak authorization services. -- Set `client_id` to client ID created previously. -- Set `client_secret` to client secret created previously. Required when `lazy_load_paths` is `true`. - -Send a request to the route: - -```shell -curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN" + + + + +Create a Route with `authz-keycloak` configured in ADC: + +```yaml title="adc.yaml" +services: + - name: authz-keycloak-service + routes: + - name: authz-keycloak-route + uris: + - /anything + plugins: + # highlight-start + authz-keycloak: + // Annotate 1 + lazy_load_paths: true + // Annotate 2 + resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set + // Annotate 3 + discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 4 + client_id: ${OIDC_CLIENT_ID} + // Annotate 5 + client_secret: ${OIDC_CLIENT_SECRET} + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 ``` -You should see an `HTTP/1.1 200 OK` response similar to the following: +Synchronize the configuration to the gateway: -```json -{ - "args": {}, - "data": "", - "files": {}, - "form": {}, - "headers": { - "Accept": "*/*", - "Authorization": "Bearer eyJhbGciOiJSU...", - ... - }, - "json": null, - "method": "GET", - "origin": "127.0.0.1, 108.180.51.111", - "url": "http://127.0.0.1/anything" -} +```shell +adc sync -f adc.yaml ``` -### Use Static Permissions - -The examples below demonstrate how you can configure Keycloak for scope-based permission associated with a client scope policy, and configure the `authz-keycloak` plugin to use static permissions. + -#### Create Scope in Keycloak - -Go to **Clients** > **`apisix-quickstart-client`** > **Authorization** > **Authorization Scopes**, and click **Create** to open the **Add Scope** page: - -![add-scope](https://static.api7.ai/uploads/2024/01/06/bVHhiALe_auth-scope.png) + -Enter the scope names as `access` and click **Save**: +Configure `authz-keycloak` on the Route: -![create-new-scope](https://static.api7.ai/uploads/2024/01/06/xPorYwK3_save-scope.png) + -#### Create Resource in Keycloak + -Go to **Clients** > **`apisix-quickstart-client`** > **Authorization** > **Resources** and click **Create** to open the **Add Resource** page: +```yaml title="authz-keycloak-ic.yaml" +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: authz-keycloak-plugin-config +spec: + plugins: + - name: authz-keycloak + config: + # highlight-start + // Annotate 1 + lazy_load_paths: true + // Annotate 2 + resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set + // Annotate 3 + discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 4 + client_id: apisix-quickstart-client + // Annotate 5 + client_secret: replace-with-your-client-secret + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: authz-keycloak-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` -![create-resource](https://static.api7.ai/uploads/2024/01/06/15DJ9HAU_create-resource.png) +Apply the configuration to your cluster: -Enter the resource names `httpbin-anything`, URI `/anything`, scope `access`, and click **Save**: +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` -![save-resource](https://static.api7.ai/uploads/2024/01/06/epuAPgos_save-resource.png) + + + + +```yaml title="authz-keycloak-ic.yaml" +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: ApisixPluginConfig +metadata: + namespace: aic + name: authz-keycloak-plugin-config +spec: + ingressClassName: apisix + plugins: + - name: authz-keycloak + enable: true + config: + # highlight-start + // Annotate 1 + lazy_load_paths: true + // Annotate 2 + resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set + // Annotate 3 + discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 4 + client_id: apisix-quickstart-client + // Annotate 5 + client_secret: replace-with-your-client-secret + # highlight-end +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + ingressClassName: apisix + http: + - name: authz-keycloak-route + match: + paths: + - /anything + methods: + - GET + upstreams: + - name: httpbin-external-domain + plugin_config_name: authz-keycloak-plugin-config +``` -#### Create Client Scope in Keycloak +Apply the configuration to your cluster: -Go to **Client Scopes** and click **Create** to open the **Add client scope** page: +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` -![create-client-scope](https://static.api7.ai/uploads/2024/01/11/PyseoG7T_creat-client-scope.png) + -Enter the scope name `httpbin-access` and click **Save**: + -![save-client-scope](https://static.api7.ai/uploads/2024/01/12/5xQl0Xbx_save-client-scope.png) + -#### Create Policy in Keycloak + -Go to **Clients** > **`apisix-quickstart-client`** > **Authorization** > **Policies** > **Create Policies** and select **Client Scope** from the dropdown to open the **Add Client Scope Policy** page: +❶ Set `lazy_load_paths` to `true`. -![create-policy](https://static.api7.ai/uploads/2024/01/06/7UtT3cF6_create-policy.png) +❷ Set `resource_registration_endpoint` to Keycloak's UMA-compliant resource registration endpoint. Required when `lazy_load_paths` is `true`. -Enter the policy name `access-client-scope-policy` for client scope `httpbin-access`, check the **Required** box, and click **Save**: +❸ Set `discovery` to the discovery document endpoint of Keycloak authorization services. -![save-policy](https://static.api7.ai/uploads/2024/12/12/2DR0K39f_add_client_scope.png) +❹ Set `client_id` to the client ID created previously. -#### Create Permission in Keycloak +❺ Set `client_secret` to the client secret created previously. Required when `lazy_load_paths` is `true`. -Go to **Clients** > **`apisix-quickstart-client`** > **Authorization** > **Permissions** > **Create Permissions** and select **Scope-Based** from the dropdown to open the **Add Scope Permission** page: +Send a request to the Route: -![create-permission](https://static.api7.ai/uploads/2024/12/12/0PWsJUti_create_permission.png) +```shell +curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN" +``` -Enter the permission name `access-scope-perm`, select the `access` scope, apply the policy `access-client-scope-policy`, and click **Save**: +You should see an `HTTP/1.1 200 OK` response similar to the following: -![add-scope-permission](https://static.api7.ai/uploads/2024/01/12/Y0vlk1Tj_add-scope-permission.png) +```json +{ + "args": {}, + "data": "", + "files": {}, + "form": {}, + "headers": { + "Accept": "*/*", + "Authorization": "Bearer eyJhbGciOiJSU..." + }, + "json": null, + "method": "GET", + "url": "http://127.0.0.1/anything" +} +``` -#### Assign Client Scope +### Use Static Permissions -Go to **Clients** > **`apisix-quickstart-client`** > **Client Scopes** and add `httpbin-access` to the default client scopes: +The examples below demonstrate how you can configure `authz-keycloak` to use the static permission `httpbin-anything#access`. -![add-client-scope](https://static.api7.ai/uploads/2024/01/06/sJKUMUcP_add-client-scope.png) + -#### Configure APISIX + -Create a route with `authz-keycloak-route` as follows: +Create a Route with `authz-keycloak-route` as follows: ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -384,77 +675,245 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "authz-keycloak-route", "uri": "/anything", "plugins": { + # highlight-start "authz-keycloak": { + // Annotate 1 "lazy_load_paths": false, - "discovery": "http://'"$KEYCLOAK_IP"':8080/realms/quickstart-realm/.well-known/uma2-configuration", + // Annotate 2 + "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", + // Annotate 3 "permissions": ["httpbin-anything#access"], - "client_id": "apisix-quickstart-client" + "client_id": "'"$OIDC_CLIENT_ID"'" } + # highlight-end }, "upstream": { "type": "roundrobin", "nodes": { - "httpbin.org": 1 + "httpbin.org:80": 1 } } }' ``` -- Set `lazy_load_paths` to `false`. -- Set `discovery` to the discovery document endpoint of Keycloak authorization services. -- Set `permissions` to resource `httpbin-anything` and scope `access`. + + + + +Create a Route with `authz-keycloak` configured in ADC: + +```yaml title="adc.yaml" +services: + - name: authz-keycloak-service + routes: + - name: authz-keycloak-route + uris: + - /anything + plugins: + # highlight-start + authz-keycloak: + // Annotate 1 + lazy_load_paths: false + // Annotate 2 + discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 3 + permissions: + - "httpbin-anything#access" + client_id: ${OIDC_CLIENT_ID} + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` -Send a request to the route: +Synchronize the configuration to the gateway: ```shell -curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN" +adc sync -f adc.yaml ``` -You should see an `HTTP/1.1 200 OK` response similar to the following: + -```json -{ - "args": {}, - "data": "", - "files": {}, - "form": {}, - "headers": { - "Accept": "*/*", - "Authorization": "Bearer eyJhbGciOiJSU...", - ... - }, - "json": null, - "method": "GET", - "origin": "127.0.0.1, 108.180.51.111", - "url": "http://127.0.0.1/anything" -} + + +Configure `authz-keycloak` on the Route: + + + + + +```yaml title="authz-keycloak-ic.yaml" +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: authz-keycloak-plugin-config +spec: + plugins: + - name: authz-keycloak + config: + # highlight-start + // Annotate 1 + lazy_load_paths: false + // Annotate 2 + discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 3 + permissions: + - "httpbin-anything#access" + client_id: apisix-quickstart-client + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: authz-keycloak-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 ``` -If you remove the client scope `httpbin-access` for `apisix-quickstart-client`, you should receive a `401 Unauthorized` response when requesting the resource. +Apply the configuration to your cluster: -### Generate Token with Password Grant at Custom Token Endpoint +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` -The examples below demonstrate how you can generate a token using the password grant at a custom endpoint. + + + + +```yaml title="authz-keycloak-ic.yaml" +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: ApisixPluginConfig +metadata: + namespace: aic + name: authz-keycloak-plugin-config +spec: + ingressClassName: apisix + plugins: + - name: authz-keycloak + enable: true + config: + # highlight-start + // Annotate 1 + lazy_load_paths: false + // Annotate 2 + discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration + // Annotate 3 + permissions: + - "httpbin-anything#access" + client_id: apisix-quickstart-client + # highlight-end +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + ingressClassName: apisix + http: + - name: authz-keycloak-route + match: + paths: + - /anything + methods: + - GET + upstreams: + - name: httpbin-external-domain + plugin_config_name: authz-keycloak-plugin-config +``` -#### Create User in Keycloak +Apply the configuration to your cluster: -To use the password grant, you should first create a user. +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` -Go to **Users** > **Add user** and click on **Add user**: + -![add-user](https://static.api7.ai/uploads/2024/01/12/IBCav8aa_add-user.png) + -Enter the **Username** as `quickstart-user` and select **Save**: + -![save-user](https://static.api7.ai/uploads/2024/01/12/3fUQOFWg_save-user.png) + -Click on **Credentials**, then set the **Password** as `quickstart-user-pass`. Switch **Temporary** to `OFF` so that you do not need to change the password the first time you log in: +❶ Set `lazy_load_paths` to `false`. -![set-password](https://static.api7.ai/uploads/2024/01/12/aoabcBbC_set-password.png) +❷ Set `discovery` to the discovery document endpoint of Keycloak authorization services. -#### Configure APISIX +❸ Set `permissions` to resource `httpbin-anything` and scope `access`. -Create a route with `authz-keycloak-route` as follows: +Send a request to the Route: + +```shell +curl "http://127.0.0.1:9080/anything" -H "Authorization: Bearer $ACCESS_TOKEN" +``` + +You should see an `HTTP/1.1 200 OK` response. + +If you remove the client scope `httpbin-access` from `apisix-quickstart-client`, you should receive a `401 Unauthorized` response when requesting the resource. + +### Generate Token with Password Grant at Custom Token Endpoint + +The examples below demonstrate how you can configure `authz-keycloak` to request a token with the password grant at a custom endpoint. + + + + + +Create a Route with `authz-keycloak-route` as follows: ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -463,28 +922,220 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "authz-keycloak-route", "uri": "/api/*", "plugins": { + # highlight-start "authz-keycloak": { "lazy_load_paths": true, - "resource_registration_endpoint": "http://'"$KEYCLOAK_IP"':8080/realms/quickstart-realm/authz/protection/resource_set", + "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", "client_id": "'"$OIDC_CLIENT_ID"'", "client_secret": "'"$OIDC_CLIENT_SECRET"'", - "token_endpoint": "http://'"$KEYCLOAK_IP"':8080/realms/quickstart-realm/protocol/openid-connect/token", + // Annotate 1 + "token_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/protocol/openid-connect/token", + // Annotate 2 "password_grant_token_generation_incoming_uri": "/api/token" } + # highlight-end }, "upstream": { "type": "roundrobin", "nodes": { - "httpbin.org": 1 + "httpbin.org:80": 1 } } }' ``` -- Set `token_endpoint` to the Keycloak token endpoint. Required when discovery document is not provided. -- Set `password_grant_token_generation_incoming_uri` to a custom URI path users can obtain tokens from. + + + + +Create a Route with `authz-keycloak` configured in ADC: + +```yaml title="adc.yaml" +services: + - name: authz-keycloak-service + routes: + - name: authz-keycloak-route + uris: + - /api/* + plugins: + # highlight-start + authz-keycloak: + lazy_load_paths: true + resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set + client_id: ${OIDC_CLIENT_ID} + client_secret: ${OIDC_CLIENT_SECRET} + // Annotate 1 + token_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/protocol/openid-connect/token + // Annotate 2 + password_grant_token_generation_incoming_uri: /api/token + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +Configure `authz-keycloak` on the Route: + + + + + +```yaml title="authz-keycloak-ic.yaml" +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: authz-keycloak-plugin-config +spec: + plugins: + - name: authz-keycloak + config: + lazy_load_paths: true + resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set + client_id: apisix-quickstart-client + client_secret: replace-with-your-client-secret + # highlight-start + // Annotate 1 + token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token + // Annotate 2 + password_grant_token_generation_incoming_uri: /api/token + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: PathPrefix + value: /api/ + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: authz-keycloak-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + +Apply the configuration to your cluster: -Send a request to the configured token endpoint. Note that the request should use the POST method and `application/x-www-form-urlencoded` as the `Content-Type`: +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` + + + + + +```yaml title="authz-keycloak-ic.yaml" +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: ApisixPluginConfig +metadata: + namespace: aic + name: authz-keycloak-plugin-config +spec: + ingressClassName: apisix + plugins: + - name: authz-keycloak + enable: true + config: + lazy_load_paths: true + resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set + client_id: apisix-quickstart-client + client_secret: replace-with-your-client-secret + # highlight-start + // Annotate 1 + token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token + // Annotate 2 + password_grant_token_generation_incoming_uri: /api/token + # highlight-end +--- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: authz-keycloak-route +spec: + ingressClassName: apisix + http: + - name: authz-keycloak-route + match: + paths: + - /api/* + methods: + - GET + - POST + upstreams: + - name: httpbin-external-domain + plugin_config_name: authz-keycloak-plugin-config +``` + +Apply the configuration to your cluster: + +```shell +kubectl apply -f authz-keycloak-ic.yaml +``` + + + + + + + + + +❶ Set `token_endpoint` to the Keycloak token endpoint. Required when the discovery document is not provided. + +❷ Set `password_grant_token_generation_incoming_uri` to a custom URI path where users can obtain tokens. + +Send a request to the configured token endpoint. The request should use the POST method and `application/x-www-form-urlencoded` as the `Content-Type`: ```shell OIDC_USER=quickstart-user @@ -497,8 +1148,14 @@ curl "http://127.0.0.1:9080/api/token" -X POST \ -d 'password='$OIDC_PASSWORD'' ``` -You should see a JSON response with the access token, similar to the following: +You should see a JSON response with an access token similar to the following: -```text -{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6U3FFaXN6VlpuYi1sRWMzZkp0UHNpU1ZZcGs4RGN3dXI1Mkx5V05aQTR3In0...","expires_in":300,"refresh_expires_in":1800,"refresh_token":"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI0YjFiNTQ3Yi0zZmZjLTQ5YzQtYjE2Ni03YjdhNzIxMjk1ODcifQ...","token_type":"Bearer","not-before-policy":0,"session_state":"b16b262e-1056-4515-a455-f25e077ccb76","scope":"profile email"} +```json +{ + "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIi...", + "expires_in": 300, + "refresh_expires_in": 1800, + "token_type": "Bearer", + "scope": "profile email httpbin-access" +} ``` diff --git a/docs/en/latest/plugins/aws-lambda.md b/docs/en/latest/plugins/aws-lambda.md index 101befc4f4f5..93ccd48ea3f8 100644 --- a/docs/en/latest/plugins/aws-lambda.md +++ b/docs/en/latest/plugins/aws-lambda.md @@ -59,7 +59,7 @@ The Plugin supports authentication and authorization with AWS via IAM user crede The examples below demonstrate how you can configure `aws-lambda` for different scenarios. -To follow along the examples, first log into your AWS console and create a Lambda function with any runtime. By default, the function should return `Hello from Lambda!` when called. +To follow along the examples, please first log into your AWS console and create a Lambda function with any runtime. You do not need to customize the function and by default, the function should return `Hello from Lambda!` when called. :::note @@ -73,7 +73,7 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ### Invoke Lambda Function Securely using IAM Access Keys -The following example demonstrates how you can integrate APISIX with the Lambda function and configure IAM access keys for authorization. The `aws-lambda` Plugin implements [AWS Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html) for IAM access keys. +The following example demonstrates how you can integrate APISIX with the Lambda function and configure IAM access keys for authorization. The `aws-lambda` Plugin implements [AWS Signature Version 4](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-signing.html) for IAM access keys. You will be first creating IAM access keys and the Lambda function URL on AWS console. For IAM access keys, go to **AWS Identity and Access Management (IAM)** and click into the user you would like to use for integration. @@ -95,26 +95,204 @@ To create the Lambda function URL, go to the **Configuration** tab of the Lambda Finally, create a Route in APISIX with your function URL and IAM access keys: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ -d '{ - "id": "aws-lambda-iam-route", + "id": "aws-lambda-route", + "uri": "/aws-lambda", + "plugins": { + # highlight-start + "aws-lambda": { + // Annotate 1 + "function_uri": "https://your-lambda-function-url.lambda-url.us-west-2.on.aws/", "authorization": { "iam": { - "accesskey": "", - "secretkey": "", - "aws_region": "", + // Annotate 2 + "accesskey": "YOUR_IAM_ACCESS_KEY", + // Annotate 3 + "secretkey": "YOUR_IAM_SECRET_KEY", + // Annotate 4 + "aws_region": "us-west-2", + // Annotate 5 "service": "lambda" } }, "ssl_verify": false + # highlight-end } } }' ``` -Replace `function_uri`, `accesskey`, `secretkey`, and `aws_region` with your actual values. Set `service` to `lambda` when integrating with a Lambda function directly. + + + + +```yaml title="adc.yaml" +services: + - name: aws-lambda-service + routes: + - name: aws-lambda-route + uris: + - /aws-lambda + plugins: + aws-lambda: + # highlight-start + // Annotate 1 + function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ + authorization: + iam: + // Annotate 2 + accesskey: YOUR_IAM_ACCESS_KEY + // Annotate 3 + secretkey: YOUR_IAM_SECRET_KEY + // Annotate 4 + aws_region: us-west-2 + // Annotate 5 + service: lambda + # highlight-end +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: aws-lambda-plugin-config +spec: + plugins: + - name: aws-lambda + config: + # highlight-start + // Annotate 1 + function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ + authorization: + iam: + // Annotate 2 + accesskey: YOUR_IAM_ACCESS_KEY + // Annotate 3 + secretkey: YOUR_IAM_SECRET_KEY + // Annotate 4 + aws_region: us-west-2 + // Annotate 5 + service: lambda + ssl_verify: false + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /aws-lambda + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: aws-lambda-plugin-config +``` + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + ingressClassName: apisix + http: + - name: aws-lambda-route + match: + paths: + - /aws-lambda + plugins: + - name: aws-lambda + enable: true + config: + # highlight-start + // Annotate 1 + function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ + authorization: + iam: + // Annotate 2 + accesskey: YOUR_IAM_ACCESS_KEY + // Annotate 3 + secretkey: YOUR_IAM_SECRET_KEY + // Annotate 4 + aws_region: us-west-2 + // Annotate 5 + service: lambda + ssl_verify: false + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f aws-lambda-ic.yaml +``` + + + + + +❶ replace with your Lambda function URL + +❷ replace with your IAM access key + +❸ replace with your IAM secret access key + +❹ replace with the AWS region of your Lambda function + +❺ set to `lambda` when integrating with Lambda function Send a request to the Route: @@ -138,11 +316,18 @@ To configure an API Gateway as a Lambda trigger, go to your Lambda function and Next, select **API Gateway** as the trigger and **REST API** as the API type, and finish adding the trigger: -![select REST to be the API type and secure the API with API key](https://static.api7.ai/uploads/2024/04/25/4Bp9r3UP_rest-api-key.png) +
+select REST to be the API type and secure the API with API key +
+
-:::note +:::info -Amazon API Gateway supports two types of RESTful APIs: HTTP APIs and REST APIs. Only REST APIs offer API key and IAM as security measures. +Amazon API Gateway supports HTTP APIs and REST APIs. API key support is available only for REST APIs, which is why this example uses a REST API trigger. ::: @@ -152,24 +337,157 @@ You should now be redirected back to the Lambda interface. To find the API key a Finally, create a Route in APISIX with your gateway endpoint and API key: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ -d '{ - "id": "aws-lambda-apikey-route", + "id": "aws-lambda-route", "uri": "/aws-lambda", "plugins": { + # highlight-start "aws-lambda": { - "function_uri": "https:///default/api7-docs", + "function_uri": "https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource", "authorization": { - "apikey": "" + "apikey": "YOUR_API_GATEWAY_API_KEY" }, "ssl_verify": false } + # highlight-end } }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: aws-lambda-service + routes: + - name: aws-lambda-route + uris: + - /aws-lambda + plugins: + aws-lambda: + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: aws-lambda-plugin-config +spec: + plugins: + - name: aws-lambda + config: + # highlight-start + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /aws-lambda + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: aws-lambda-plugin-config +``` + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + ingressClassName: apisix + http: + - name: aws-lambda-route + match: + paths: + - /aws-lambda + plugins: + - name: aws-lambda + enable: true + config: + # highlight-start + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default/your-resource + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f aws-lambda-ic.yaml +``` + + + + + Send a request to the Route: ```shell @@ -186,7 +504,7 @@ If your API key is invalid, you should receive an `HTTP/1.1 403 Forbidden` respo ### Forward Requests to Amazon API Gateway Sub-Paths -The following example demonstrates how you can forward requests to a sub-path of the Amazon API Gateway and configure the API to trigger the execution of Lambda function. +The following example demonstrates how you can forward requests to a sub-path of the Amazon API Gateway API and configure the API to trigger the execution of Lambda function. Please follow the [previous example](#integrate-with-amazon-api-gateway-securely-with-api-key) to set up an API Gateway first. @@ -200,7 +518,13 @@ Next, select **Create resource** to create a sub-path: Enter the sub-path information and complete creation: -![complete resource creation](https://static.api7.ai/uploads/2024/04/26/7t1yiWjl_create-resource-2.png) +
+complete resource creation +
Once redirected back to the main gateway console, you should see the newly created path. Select **Create method** to configure HTTP methods for the path and the associated action: @@ -208,38 +532,194 @@ Once redirected back to the main gateway console, you should see the newly creat Select the allowed HTTP method in the dropdown. For the purpose of demonstration, this example continues to use the same Lambda function as the triggered action when the path is requested: -![create method and lambda function](https://static.api7.ai/uploads/2024/04/26/vni7yS2q_create%20method%202.png) +
+create method and lambda function +
Finish the method creation. Once redirected back to the main gateway console, click on **Deploy API** to deploy the path and method changes: ![deploy changes to API gateway](https://static.api7.ai/uploads/2024/04/26/2vrqnVPB_deploy-api.png) -Finally, create a Route in APISIX with your gateway endpoint and API key. The `uri` must end with `*` so that any sub-path is matched to the same Route, and the matched sub-path will be appended to `function_uri`: +Finally, create a Route in APISIX with your gateway endpoint and API key: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ -d '{ - "id": "aws-lambda-subpath-route", + "id": "aws-lambda-route", + # highlight-start + // Annotate 1 + "uri": "/aws-lambda/*", "plugins": { "aws-lambda": { - "function_uri": "https:///default", + // Annotate 2 + "function_uri": "https://your-api-id.execute-api.us-west-2.amazonaws.com/default", "authorization": { - "apikey": "" + "apikey": "YOUR_API_GATEWAY_API_KEY" }, "ssl_verify": false } } + # highlight-end }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: aws-lambda-service + routes: + - name: aws-lambda-route + # highlight-start + // Annotate 1 + uris: + - /aws-lambda/* + plugins: + aws-lambda: + // Annotate 2 + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false + # highlight-end +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: aws-lambda-plugin-config +spec: + plugins: + # highlight-start + - name: aws-lambda + config: + // Annotate 2 + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: PathPrefix + // Annotate 1 + value: /aws-lambda/ + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: aws-lambda-plugin-config +``` + + + + + +```yaml title="aws-lambda-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: aws-lambda-route +spec: + ingressClassName: apisix + http: + - name: aws-lambda-route + match: + # highlight-start + paths: + // Annotate 1 + - /aws-lambda/* + # highlight-end + plugins: + # highlight-start + - name: aws-lambda + enable: true + config: + // Annotate 2 + function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default + authorization: + apikey: YOUR_API_GATEWAY_API_KEY + ssl_verify: false + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f aws-lambda-ic.yaml +``` + + + + + +❶ match all sub-paths of `/aws-lambda/` + +❷ For Admin API, ADC, and APISIX CRD examples, the sub-paths matched by the wildcard `*` will be appended to the end of the `function_uri`. In the Gateway API example, `PathPrefix` matches requests under `/aws-lambda/`, so the forwarded request path continues after the configured `function_uri` prefix. + Send a request to the Route: ```shell curl -i "http://127.0.0.1:9080/aws-lambda/api7-docs" ``` -APISIX will forward the request to `https:///default/api7-docs` and you should receive an `HTTP/1.1 200 OK` response with the following message: +APISIX will forward the request to `https://your-api-id.execute-api.us-west-2.amazonaws.com/default/api7-docs` and you should receive an `HTTP/1.1 200 OK` response with the following message: ```text "Hello from Lambda!" diff --git a/docs/en/latest/plugins/public-api.md b/docs/en/latest/plugins/public-api.md index c9c62c5e5786..82d242a4c4ec 100644 --- a/docs/en/latest/plugins/public-api.md +++ b/docs/en/latest/plugins/public-api.md @@ -44,6 +44,16 @@ The `public-api` Plugin exposes an internal API endpoint, making it publicly acc The examples below demonstrate how you can configure `public-api` in different scenarios. +:::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') +``` + +::: + ### Expose Prometheus Metrics at Custom Endpoint The following example demonstrates how you can disable the Prometheus export server that, by default, exposes an endpoint on port `9091`, and expose APISIX Prometheus metrics on a new public API endpoint on port `9080`, which APISIX uses to listen to other client requests. @@ -58,7 +68,7 @@ To address this issue, APISIX uses [privileged agent](https://github.com/openres ::: -Disable the Prometheus export server in the configuration file and reload APISIX for changes to take effect: +Disable the Prometheus export server in the configuration file and [reload APISIX](../apisix-cli.md#apisix-reload) for changes to take effect: ```yaml title="conf/config.yaml" plugin_attr: @@ -66,7 +76,18 @@ plugin_attr: enable_export_server: false ``` -Next, create a Route with the `public-api` Plugin and expose a public API endpoint for APISIX metrics. You should set the Route `uri` to the custom endpoint path and set the Plugin `uri` to the internal endpoint to be exposed. +Next, create a Route with `public-api` Plugin and expose a public API endpoint for APISIX metrics: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -82,6 +103,113 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: public-api-metrics-service + routes: + - name: prometheus-metrics + uris: + - /prometheus_metrics + plugins: + public-api: + uri: /apisix/prometheus/metrics +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="public-api-ic.yaml" +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: prometheus-metrics +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /prometheus_metrics + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: public-api-metrics-plugin-config +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: public-api-metrics-plugin-config +spec: + plugins: + - name: public-api + config: + uri: /apisix/prometheus/metrics +``` + + + + + +```yaml title="public-api-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: prometheus-metrics +spec: + ingressClassName: apisix + http: + - name: prometheus-metrics + match: + paths: + - /prometheus_metrics + plugins: + - name: public-api + enable: true + config: + uri: /apisix/prometheus/metrics +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f public-api-ic.yaml +``` + + + + + Send a request to the custom metrics endpoint: ```shell @@ -113,6 +241,17 @@ The following example demonstrates how you can use the `public-api` Plugin to ex Create a sample Route to httpbin's `/anything` endpoint for verification purpose: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ @@ -128,8 +267,132 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: httpbin-anything + uris: + - /anything + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="public-api-httpbin-ic.yaml" +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: httpbin-anything +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="public-api-httpbin-ic.yaml" +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: httpbin-anything +spec: + ingressClassName: apisix + http: + - name: httpbin-anything + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f public-api-httpbin-ic.yaml +``` + + + + + Create a Route with `public-api` Plugin and set the Route `uri` to the internal endpoint to be exposed: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ @@ -142,6 +405,109 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: public-api-batch-service + routes: + - name: batch-requests + uris: + - /apisix/batch-requests + plugins: + public-api: {} +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="public-api-batch-ic.yaml" +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: public-api-batch-plugin-config +spec: + plugins: + - name: public-api + config: {} +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: batch-requests +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /apisix/batch-requests + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: public-api-batch-plugin-config +``` + + + + + +```yaml title="public-api-batch-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: batch-requests +spec: + ingressClassName: apisix + http: + - name: batch-requests + match: + paths: + - /apisix/batch-requests + plugins: + - name: public-api + enable: true +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f public-api-batch-ic.yaml +``` + + + + + Send a pipelined request consisting of a GET and a POST request to the exposed batch requests endpoint: ```shell @@ -184,7 +550,18 @@ You should receive responses from both requests, similar to the following: ] ``` -If you would like to expose the batch requests endpoint at a custom endpoint, create a Route with `public-api` Plugin as such. You should set the Route `uri` to the custom endpoint path and set the plugin `uri` to the internal endpoint to be exposed. +If you would like to expose the batch requests endpoint at a custom endpoint, create a Route with `public-api` Plugin as such: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -200,6 +577,113 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: public-api-batch-service + routes: + - name: batch-requests + uris: + - /batch-requests + plugins: + public-api: + uri: /apisix/batch-requests +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="public-api-batch-ic.yaml" +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: batch-requests +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /batch-requests + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: public-api-batch-plugin-config +--- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: public-api-batch-plugin-config +spec: + plugins: + - name: public-api + config: + uri: /apisix/batch-requests +``` + + + + + +```yaml title="public-api-batch-ic.yaml" +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: batch-requests +spec: + ingressClassName: apisix + http: + - name: batch-requests + match: + paths: + - /batch-requests + plugins: + - name: public-api + enable: true + config: + uri: /apisix/batch-requests +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f public-api-batch-ic.yaml +``` + + + + + The batch requests endpoint should now be exposed as `/batch-requests`, instead of `/apisix/batch-requests`. Send a pipelined request consisting of a GET and a POST request to the exposed batch requests endpoint: diff --git a/docs/en/latest/plugins/real-ip.md b/docs/en/latest/plugins/real-ip.md index 147ad73d6689..76549820b8ec 100644 --- a/docs/en/latest/plugins/real-ip.md +++ b/docs/en/latest/plugins/real-ip.md @@ -33,9 +33,9 @@ description: The real-ip plugin allows Apache APISIX to set the client's real IP ## Description -The `real-ip` Plugin allows APISIX to set the client's real IP by the IP address passed in the HTTP header or HTTP query string. This is particularly useful when APISIX is behind a reverse proxy since the proxy could act as the request-originating client otherwise. +The `real-ip` Plugin allows APISIX to set the client's real IP by IP address passed in the HTTP header or HTTP query string. This is particularly useful when APISIX is behind a reverse proxy, since the proxy could act as the request originating client otherwise. -The Plugin is functionally similar to NGINX's [ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html) but offers more flexibility. +The Plugin is functionally similar to NGINX's [ngx_http_realip_module](https://nginx.org/en/docs/http/ngx_http_realip_module.html) but offers more flexibilities. ## Attributes @@ -69,9 +69,20 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ### Obtain Real Client Address From URI Parameter -The following example demonstrates how to update the client IP address with a URI parameter. +The following example demonstrates how to update client IP address with an URI parameter. -Create a Route as follows. You should configure `source` to obtain value from the URL parameter `realip` using [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). Use the `response-rewrite` Plugin to set response headers to verify if the client IP and port were actually updated. +Create a Route as follows: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -80,16 +91,20 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "real-ip-route", "uri": "/get", "plugins": { + # highlight-start "real-ip": { + // Annotate 1 "source": "arg_realip", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { + // Annotate 2 "headers": { "remote_addr": "$remote_addr", "remote_port": "$remote_port" } } + # highlight-end }, "upstream": { "type": "roundrobin", @@ -100,24 +115,208 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: real-ip-route + uris: + - /get + plugins: + real-ip: + # highlight-start + // Annotate 1 + source: arg_realip + trusted_addresses: + - 127.0.0.0/24 + response-rewrite: + // Annotate 2 + headers: + remote_addr: $remote_addr + remote_port: $remote_port + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-plugin-config +spec: + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: arg_realip + trusted_addresses: + - 127.0.0.0/24 + - name: response-rewrite + config: + // Annotate 2 + headers: + remote_addr: $remote_addr + remote_port: $remote_port + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: real-ip-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /get + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: real-ip-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-route +spec: + ingressClassName: apisix + http: + - name: real-ip-route + match: + paths: + - /get + upstreams: + - name: httpbin-external-domain + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: arg_realip + trusted_addresses: + - 127.0.0.0/24 + - name: response-rewrite + config: + // Annotate 2 + headers: + remote_addr: $remote_addr + remote_port: $remote_port + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f real-ip-ic.yaml +``` + + + + + +❶ Configure `source` to obtain value from the URL parameter `realip` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). + +❷ Use the `response-rewrite` Plugin to set response headers to verify if the client IP and port were actually updated. + Send a request to the Route with real IP and port in the URL parameter: ```shell curl -i "http://127.0.0.1:9080/get?realip=1.2.3.4:9080" ``` -You should see the response includes the following header: +You should see the response includes the following headers: ```text -remote-addr: 1.2.3.4 -remote-port: 9080 +remote_addr: 1.2.3.4 +remote_port: 9080 ``` ### Obtain Real Client Address From Header -The following example shows how to set the real client IP when APISIX is behind a reverse proxy, such as a load balancer when the proxy exposes the real client IP in the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header. +The following example shows how to set the real client IP when APISIX is behind a reverse proxy, such as a load balancer, when the proxy exposes the real client IP in the [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header. -Create a Route as follows. You should configure `source` to obtain value from the request header `X-Forwarded-For` using [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. +Create a Route as follows: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -126,15 +325,19 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "real-ip-route", "uri": "/get", "plugins": { + # highlight-start "real-ip": { + // Annotate 1 "source": "http_x_forwarded_for", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { "headers": { + // Annotate 2 "remote_addr": "$remote_addr" } } + # highlight-end }, "upstream": { "type": "roundrobin", @@ -145,25 +348,207 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: real-ip-route + uris: + - /get + plugins: + real-ip: + # highlight-start + // Annotate 1 + source: http_x_forwarded_for + trusted_addresses: + - 127.0.0.0/24 + response-rewrite: + headers: + // Annotate 2 + remote_addr: $remote_addr + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-plugin-config +spec: + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: http_x_forwarded_for + trusted_addresses: + - 127.0.0.0/24 + - name: response-rewrite + config: + headers: + // Annotate 2 + remote_addr: $remote_addr + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: real-ip-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /get + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: real-ip-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-route +spec: + ingressClassName: apisix + http: + - name: real-ip-route + match: + paths: + - /get + upstreams: + - name: httpbin-external-domain + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: http_x_forwarded_for + trusted_addresses: + - 127.0.0.0/24 + - name: response-rewrite + config: + headers: + // Annotate 2 + remote_addr: $remote_addr + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f real-ip-ic.yaml +``` + + + + + +❶ Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). + +❷ Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. + Send a request to the Route: ```shell -curl -i "http://127.0.0.1:9080/get" +curl -i "http://127.0.0.1:9080/get" \ + -H "X-Forwarded-For: 10.26.3.19" ``` You should see a response including the following header: ```text -remote-addr: 10.26.3.19 +remote_addr: 10.26.3.19 ``` -The IP address should correspond to the IP address of the request-originating client. +The IP address should correspond to the IP address of the request originating client. ### Obtain Real Client Address Behind Multiple Proxies The following example shows how to get the real client IP when APISIX is behind multiple proxies, which causes [`X-Forwarded-For`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For) header to include a list of proxy IP addresses. -Create a Route as follows. You should configure `source` to obtain value from the request header `X-Forwarded-For` using [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). Set `recursive` to `true` so that the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the configured `source`. Then, use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. +Create a Route as follows: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ @@ -172,16 +557,21 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id": "real-ip-route", "uri": "/get", "plugins": { + # highlight-start "real-ip": { + // Annotate 1 "source": "http_x_forwarded_for", + // Annotate 2 "recursive": true, - "trusted_addresses": ["192.128.0.0/16", "127.0.0.0/24"] + "trusted_addresses": ["192.128.0.0/16", "127.0.0.1/32"] }, "response-rewrite": { + // Annotate 3 "headers": { "remote_addr": "$remote_addr" } } + # highlight-end }, "upstream": { "type": "roundrobin", @@ -192,15 +582,196 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: real-ip-route + uris: + - /get + plugins: + real-ip: + # highlight-start + // Annotate 1 + source: http_x_forwarded_for + // Annotate 2 + recursive: true + trusted_addresses: + - 192.128.0.0/16 + - 127.0.0.1/32 + response-rewrite: + // Annotate 3 + headers: + remote_addr: $remote_addr + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-plugin-config +spec: + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: http_x_forwarded_for + // Annotate 2 + recursive: true + trusted_addresses: + - 192.128.0.0/16 + - 127.0.0.1/32 + - name: response-rewrite + config: + // Annotate 3 + headers: + remote_addr: $remote_addr + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: real-ip-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /get + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: real-ip-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="real-ip-ic.yaml" +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: real-ip-route +spec: + ingressClassName: apisix + http: + - name: real-ip-route + match: + paths: + - /get + upstreams: + - name: httpbin-external-domain + plugins: + # highlight-start + - name: real-ip + config: + // Annotate 1 + source: http_x_forwarded_for + // Annotate 2 + recursive: true + trusted_addresses: + - 192.128.0.0/16 + - 127.0.0.1/32 + - name: response-rewrite + config: + // Annotate 3 + headers: + remote_addr: $remote_addr + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f real-ip-ic.yaml +``` + + + + + +❶ Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). + +❷ Set `recursive` to `true` so that the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the configured `source`. + +❸ Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. + Send a request to the Route: ```shell curl -i "http://127.0.0.1:9080/get" \ - -H "X-Forwarded-For: 127.0.0.2, 192.128.1.1, 127.0.0.1" + -H "X-Forwarded-For: 127.0.0.2, 192.128.1.1, 127.0.0.1" ``` You should see a response including the following header: ```text -remote-addr: 127.0.0.2 +remote_addr: 127.0.0.2 ``` diff --git a/docs/en/latest/plugins/serverless.md b/docs/en/latest/plugins/serverless.md index e460b249cc31..d58f02abdc0e 100644 --- a/docs/en/latest/plugins/serverless.md +++ b/docs/en/latest/plugins/serverless.md @@ -27,11 +27,13 @@ description: The serverless plugins, `serverless-pre-function` and `serverless-p # --> -## Description + + + -There are two `serverless` Plugins in APISIX: `serverless-pre-function` and `serverless-post-function`. The former runs at the beginning of the specified phase, while the latter runs at the end of the specified phase. +## Description -Both Plugins have the same attributes. +The serverless functions consist of two plugins, `serverless-pre-function` and `serverless-post-function`. These plugins enable the execution of user-defined logic at the beginning and end of the [execution phases](../terminology/plugin.md#plugins-execution-lifecycle) the functions hook to. ## Attributes @@ -40,9 +42,9 @@ Both Plugins have the same attributes. | phase | string | False | "access" | ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"] | Phase before or after which the serverless function is executed. | | functions | array[string] | True | | | List of functions that are executed sequentially. | -:::note +## Tips for Writing Functions -Only Lua functions are allowed here and not other Lua code. +Only Lua functions are allowed in the serverless plugins and not other Lua code. For example, anonymous functions are legal: @@ -69,12 +71,6 @@ local count = 1 ngx.say(count) ``` -From v2.6, `conf` and `ctx` are passed as the first two arguments to a serverless function like regular Plugins. - -Prior to v2.12.0, the phase `before_proxy` was called `balancer`. This was updated considering that this method would run after `access` and before the request goes Upstream and is unrelated to `balancer`. - -::: - ## Examples :::note @@ -87,37 +83,995 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: -The following example enables `serverless-pre-function` and `serverless-post-function` Plugins on a Route: +The examples below demonstrate how you can configure the `serverless-pre-function` and `serverless-post-function` plugins for different scenarios. + +### Log Information before and after a Phase + +The example below demonstrates how you can configure the serverless plugins to execute custom logics to log information to error logs before and after the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). + +Create a Route as such: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ -d '{ - "id": "serverless-route", - "uri": "/index.html", + "id": "serverless-pre-route", + "uri": "/anything", "plugins": { + # highlight-start "serverless-pre-function": { + // Annotate 1 "phase": "rewrite", - "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre function\"); end"] + // Annotate 2 + "functions" : [ + "return function() + ngx.log(ngx.ERR, \"serverless pre function\"); + end" + ] }, "serverless-post-function": { + // Annotate 3 "phase": "rewrite", - "functions": ["return function(conf, ctx) ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); end"] + // Annotate 4 + "functions" : [ + "return function(conf, ctx) + ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); + end" + ] } + # highlight-end }, "upstream": { "type": "roundrobin", "nodes": { - "127.0.0.1:1980": 1 + "httpbin.org:80": 1 + } + } + }' +``` + + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: serverless-pre-route + uris: + - /anything + plugins: + # highlight-start + serverless-pre-function: + // Annotate 1 + phase: rewrite + // Annotate 2 + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + serverless-post-function: + // Annotate 3 + phase: rewrite + // Annotate 4 + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="serverless-functions-ic.yaml" +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: serverless-functions-plugin-config +spec: + plugins: + # highlight-start + - name: serverless-pre-function + config: + // Annotate 1 + phase: rewrite + // Annotate 2 + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + - name: serverless-post-function + config: + // Annotate 3 + phase: rewrite + // Annotate 4 + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: serverless-pre-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: serverless-functions-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="serverless-functions-ic.yaml" +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: serverless-pre-route +spec: + ingressClassName: apisix + http: + - name: serverless-pre-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + # highlight-start + - name: serverless-pre-function + config: + // Annotate 1 + phase: rewrite + // Annotate 2 + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + - name: serverless-post-function + config: + // Annotate 3 + phase: rewrite + // Annotate 4 + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f serverless-functions-ic.yaml +``` + + + + + +❶ Hook the serverless pre-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). + +❷ Define a Lua function that logs a message of `serverless pre function` in the error log. + +❸ Hook the serverless post-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). + +❹ Define a Lua function that logs the matched URI in the error log. `conf` and `ctx` can be passed as the first two arguments like other plugins, where `conf` is the plugin configurations and `ctx` is the request context. + +Send the request to the Route: + +```shell +curl -i "http://127.0.0.1:9080/anything" +``` + +You should receive an `HTTP/1.1 200 OK` response and see the following entries in the error log: + +```text +2024/05/09 15:07:09 [error] 51#51: *3963 [lua] [string "return function() ngx.log(ngx.ERR, "serverles..."]:1: func(): serverless pre function, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" +2024/05/09 15:16:58 [error] 50#50: *9343 [lua] [string "return function(conf, ctx) ngx.log(ngx.ERR, "..."]:1: func(): match uri /anything, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" +``` + +The first entry is added by the pre-function and the second entry is added by the post-function. + +### Register Custom Variables + +The example below demonstrates how you can register custom built-in variables using the serverless plugins and use the newly created variable in logs. + +:::info + +This example cannot be completed with the Ingress Controller because it does not support configuring Route labels. + +::: + +Start an example rsyslog server: + +```shell +docker run -d -p 514:514 --name example-rsyslog-server rsyslog/syslog_appliance_alpine +``` + +Create a [Service](../terminology/service.md) with a serverless function to register a custom variable `a6_route_labels`, enable a logging plugin to later log the custom variable, and configure an upstream: + + + + + +```shell +curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id":"srv_custom_var", + "plugins": { + # highlight-start + "serverless-pre-function": { + "phase": "rewrite", + // Annotate 1 + "functions": [ + "return function() + local core = require \"apisix.core\" + core.ctx.register_var(\"a6_route_labels\", function(ctx) + local route = ctx.matched_route and ctx.matched_route.value + if route and route.labels then + return route.labels + end + return nil + end); + end" + ] + }, + "syslog": { + // Annotate 2 + "host" : "172.0.0.1", + "port" : 514, + // Annotate 3 + "flush_limit" : 1 + } + # highlight-end + }, + "upstream": { + "nodes": { + "httpbin.org:80": 1 } } }' ``` + + + + +```yaml title="adc.yaml" +services: + - name: srv-custom-var + plugins: + # highlight-start + serverless-pre-function: + phase: rewrite + // Annotate 1 + functions: + - | + return function() + local core = require("apisix.core") + core.ctx.register_var("a6_route_labels", function(ctx) + local route = ctx.matched_route and ctx.matched_route.value + if route and route.labels then + return route.labels + end + return nil + end) + end + syslog: + // Annotate 2 + host: 172.0.0.1 + port: 514 + // Annotate 3 + flush_limit: 1 + # highlight-end + upstream: + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +❶ `functions`: register a custom variable `a6_route_labels` and fetch the variable value from the matched Route's `labels` property. + +❷ `host` and `port`: replace with the address of your syslog server. + +❸ `flush_limit`: set to 1 to push log to the syslog server immediately. + +Next, update the log format for all `syslog` instances with the new variable by configuring the [Plugin metadata](../terminology/plugin.md#plugin-metadata): + + + + + +```shell +curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "log_format": { + # highlight-start + // Annotate 1 + "host": "$host", + "client_ip": "$remote_addr", + // Annotate 2 + "labels": "$a6_route_labels" + # highlight-end + } + }' +``` + + + + + +```yaml title="adc.yaml" +plugin_metadata: + syslog: + log_format: + # highlight-start + // Annotate 1 + host: "$host" + client_ip: "$remote_addr" + // Annotate 2 + labels: "$a6_route_labels" + # highlight-end +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +❶ `$host` and `$remote_addr`: NGINX variables. + +❷ `$a6_route_labels`: custom variable. + +Finally, create a Route: + + + + + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id":"route_custom_var", + "uri":"/get", + # highlight-start + // Annotate 1 + "service_id": "srv_custom_var", + // Annotate 2 + "labels": { + "key": "test_a6_route_labels" + } + # highlight-end +}' +``` + + + + + +```yaml title="adc.yaml" +# Other Configs +services: + - name: srv-custom-var + routes: + - name: route-custom-var + uris: + - /get + # highlight-start + labels: + // Annotate 2 + key: test_a6_route_labels + # highlight-end +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + +❶ In the Admin API example, set `service_id` to associate the Route with the existing Service. In ADC, the Route is nested under the Service definition. + +❷ Add Route `labels` so the custom variable can log them. + +To verify the variable registration, send a request to the Route: + +```shell +curl "http://127.0.0.1:9080/get" +``` + +You should see a log entry in your syslog server similar to the following: + +```json +{ + "host":"127.0.0.1", + "route_id":"route_custom_var", + "client_ip":"172.19.0.1", + # highlight-start + "labels":{ + "key":"test_a6_route_labels" + }, + # highlight-end + "service_id":"srv_custom_var" +} +``` + +This verifies the custom variable was registered and it logs the `labels` information in a Route successfully. + +### Modify a Specific Field in Response Body + +The example below demonstrates how you can use the serverless plugins to remove a specific field from a JSON response body. + +Before proceeding with the removal, first configure a Route as follows to see the unmodified response: + + + + + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "id":"serverless-remove-body-info", + "uri": "/get", + "upstream": { + "type": "roundrobin", + "nodes": { + "httpbin.org:80": 1 + } + } + }' +``` + + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: serverless-remove-body-info + uris: + - /get + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="serverless-remove-body-ic.yaml" +apiVersion: v1 +kind: Service +metadata: + namespace: aic + name: httpbin-external-domain +spec: + type: ExternalName + externalName: httpbin.org +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: serverless-remove-body-info +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /get + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="serverless-remove-body-ic.yaml" +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: serverless-remove-body-info +spec: + ingressClassName: apisix + http: + - name: serverless-remove-body-info + match: + paths: + - /get + upstreams: + - name: httpbin-external-domain +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f serverless-remove-body-ic.yaml +``` + + + + + Send a request to the Route: ```shell -curl -i "http://127.0.0.1:9080/index.html" +curl "http://127.0.0.1:9080/get" +``` + +You should see a response similar to the following with your host and proxy's IP information: + +```json +{ + "args": {}, + "headers": { + "Accept": "*/*", + "Host": "127.0.0.1", + "User-Agent": "curl/8.4.0", + "X-Amzn-Trace-Id": "Root=1-663db30f-51448a1b635f2f4338a4fcfc", + "X-Forwarded-Host": "127.0.0.1" + }, + # highlight-next-line + "origin": "172.19.0.1, 43.252.208.84", + "url": "http://127.0.0.1/get" +} +``` + +To remove the `origin` field from the response, update the Route with serverless plugins: + + + + + +```shell +curl "http://127.0.0.1:9180/apisix/admin/routes/serverless-remove-body-info" -X PATCH \ + -H "X-API-KEY: ${admin_key}" \ + -d '{ + "plugins": { + # highlight-start + "serverless-pre-function": { + // Annotate 1 + "phase": "header_filter", + "functions" : [ + "return function(conf, ctx) + local core = require(\"apisix.core\") + core.response.clear_header_as_body_modified() + end" + ] + }, + "serverless-post-function": { + // Annotate 2 + "phase": "body_filter", + "functions" : [ + "return function(conf, ctx) + local cjson = require(\"cjson\") + local core = require(\"apisix.core\") + local body = core.response.hold_body_chunk(ctx) + if not body then + return + end + body = cjson.decode(body) + body.origin = nil + body = cjson.encode(body) + ngx.arg[1] = body + end" + ] + } + } + # highlight-end + }' +``` + + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: serverless-remove-body-info + uris: + - /get + plugins: + # highlight-start + serverless-pre-function: + // Annotate 1 + phase: header_filter + functions: + - | + return function(conf, ctx) + local core = require("apisix.core") + core.response.clear_header_as_body_modified() + end + serverless-post-function: + // Annotate 2 + phase: body_filter + functions: + - | + return function(conf, ctx) + local cjson = require("cjson") + local core = require("apisix.core") + local body = core.response.hold_body_chunk(ctx) + if not body then + return + end + body = cjson.decode(body) + body.origin = nil + body = cjson.encode(body) + ngx.arg[1] = body + end + # highlight-end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +Synchronize the configuration to the gateway: + +```shell +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="serverless-remove-body-ic.yaml" +# Other Configs +# --- +apiVersion: apisix.apache.org/v1alpha1 +kind: PluginConfig +metadata: + namespace: aic + name: serverless-remove-body-plugin-config +spec: + plugins: + # highlight-start + - name: serverless-pre-function + config: + // Annotate 1 + phase: header_filter + functions: + - | + return function(conf, ctx) + local core = require("apisix.core") + core.response.clear_header_as_body_modified() + end + - name: serverless-post-function + config: + // Annotate 2 + phase: body_filter + functions: + - | + return function(conf, ctx) + local cjson = require("cjson") + local core = require("apisix.core") + local body = core.response.hold_body_chunk(ctx) + if not body then + return + end + body = cjson.decode(body) + body.origin = nil + body = cjson.encode(body) + ngx.arg[1] = body + end + # highlight-end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: serverless-remove-body-info +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /get + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: serverless-remove-body-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="serverless-remove-body-ic.yaml" +# Other Configs +# --- +apiVersion: apisix.apache.org/v2 +kind: ApisixRoute +metadata: + namespace: aic + name: serverless-remove-body-info +spec: + ingressClassName: apisix + http: + - name: serverless-remove-body-info + match: + paths: + - /get + upstreams: + - name: httpbin-external-domain + plugins: + # highlight-start + - name: serverless-pre-function + config: + // Annotate 1 + phase: header_filter + functions: + - | + return function(conf, ctx) + local core = require("apisix.core") + core.response.clear_header_as_body_modified() + end + - name: serverless-post-function + config: + // Annotate 2 + phase: body_filter + functions: + - | + return function(conf, ctx) + local cjson = require("cjson") + local core = require("apisix.core") + local body = core.response.hold_body_chunk(ctx) + if not body then + return + end + body = cjson.decode(body) + body.origin = nil + body = cjson.encode(body) + ngx.arg[1] = body + end + # highlight-end +``` + + + + + +Apply the configuration: + +```shell +kubectl apply -f serverless-remove-body-ic.yaml +``` + + + + + +❶ Execute a pre-function in the `header_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). + +❷ Execute a post-function in the `body_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). + +The pre-function calls `clear_header_as_body_modified` to clear body-related response headers such as `Content-Length`. The post-function collects the response body with `hold_body_chunk`, decodes the JSON payload, removes the `origin` field, and writes the updated body back to the response. + +Send another request to the Route: + +```shell +curl "http://127.0.0.1:9080/get" +``` + +You should see a response without the `origin` information: + +```json +{ + "url":"http://127.0.0.1/get", + "args":{}, + "headers":{ + "X-Forwarded-Host":"127.0.0.1", + "Host":"127.0.0.1", + "Accept":"*/*", + "User-Agent":"curl/8.4.0", + "X-Amzn-Trace-Id":"Root=1-663db276-1c15276864294d963c6e1755" + } +} ``` -You will find messages `serverless pre function` and `match uri /index.html` in the error log. +For simpler response modifications, such as modifying HTTP status codes, request headers, or the entire response body, please use the [`response-rewrite`](./response-rewrite.md) plugin. From 5e0702ad7cc7ac7844bf9f9deef6a4ac7138cd39 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 7 May 2026 11:32:31 +0800 Subject: [PATCH 2/7] docs: sync Chinese documentation with ADC and Ingress Controller examples Update Chinese documentation for aws-lambda, public-api, real-ip, authz-keycloak, and serverless plugins to match the English version updates: - Add ADC (API7 Declarative Config) configuration examples - Add Ingress Controller (Gateway API and APISIX CRD) examples - Add multi-tab interface for different configuration methods - Translate new example descriptions and instructions to Chinese - Keep code blocks and YAML configurations in English - Update curl commands to use admin_key environment variable This ensures Chinese-speaking users have the same comprehensive documentation as English-speaking users. --- docs/zh/latest/plugins/authz-keycloak.md | 1043 ++++++++++++++++++---- docs/zh/latest/plugins/aws-lambda.md | 534 +++++++++-- docs/zh/latest/plugins/public-api.md | 531 ++++++++++- docs/zh/latest/plugins/real-ip.md | 571 +++++++++++- docs/zh/latest/plugins/serverless.md | 263 +++++- 5 files changed, 2619 insertions(+), 323 deletions(-) diff --git a/docs/zh/latest/plugins/authz-keycloak.md b/docs/zh/latest/plugins/authz-keycloak.md index 5f912dbf776c..c7b7f6ca5013 100644 --- a/docs/zh/latest/plugins/authz-keycloak.md +++ b/docs/zh/latest/plugins/authz-keycloak.md @@ -1,12 +1,12 @@ --- -title: authz-keycloak +title: Keycloak Authorization (authz-keycloak) keywords: - Apache APISIX - API 网关 - Plugin - Authz Keycloak - authz-keycloak -description: authz-keycloak 插件与 Keycloak 集成,用于用户认证和授权,增强 API 的安全性和管理能力。 +description: authz-keycloak 插件与 Keycloak 集成,用于用户认证和授权,增强 API 的安全性和管理能力。 --- -## 描述 + + + -APISIX 有两个 `serverless` 插件:`serverless-pre-function` 和 `serverless-post-function`。 +## 描述 -`serverless-pre-function` 插件会在指定阶段开始时运行,`serverless-post-function` 插件会在指定阶段结束时运行。这两个插件使用相同的属性。 +无服务器函数由两个插件组成:`serverless-pre-function` 和 `serverless-post-function`。这些插件支持在[执行阶段](../terminology/plugin.md#plugins-execution-lifecycle)的开始和结束时执行用户定义的逻辑。 ## 属性 | 名称 | 类型 | 必选项 | 默认值 | 有效值 | 描述 | | --------- | ------------- | ----- | -------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | -| phase | string | 否 | "access" | ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"] | 执行 serverless 函数的阶段。 | -| functions | array[string] | 是 | | | 指定运行的函数列表。该属性可以包含一个函数,也可以是多个函数,按照先后顺序执行。 | +| phase | string | 否 | "access" | ["rewrite", "access", "header_filter", "body_filter", "log", "before_proxy"] | 执行 serverless 函数之前或之后的阶段。 | +| functions | array[string] | 是 | | | 按顺序执行的函数列表。 | -:::note 注意 +## 编写函数的提示 -此处仅接受函数,不接受其他类型的 Lua 代码。 +serverless 插件中只允许使用 Lua 函数,不允许使用其他 Lua 代码。 -比如匿名函数是合法的: +例如,匿名函数是合法的: ```lua return function() @@ -52,7 +54,7 @@ return function() end ``` -闭包也是合法的: +闭包也是合法的: ```lua local count = 1 @@ -62,24 +64,18 @@ return function() end ``` -但不是函数类型的代码就是非法的: +但不是函数类型的代码就是非法的: ```lua local count = 1 ngx.say(count) ``` -从 `v2.6` 版本开始,`conf` 和 `ctx` 作为前两个参数传递给 `serverless` 函数。 - -在 `v2.12.0` 版本之前,`before_proxy` 阶段曾被称作 `balancer`。考虑到这一方法是在 `access` 阶段之后、请求到上游之前运行,并且与 `balancer` 没有关联,因此已经更新为 `before_proxy`。 - -::: - ## 示例 :::note -您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量: +您可以这样从 `config.yaml` 中获取 `admin_key` 并存入环境变量: ```bash admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"//g') @@ -87,37 +83,252 @@ admin_key=$(yq '.deployment.admin.admin_key[0].key' conf/config.yaml | sed 's/"/ ::: -以下示例在路由上启用 `serverless-pre-function` 和 `serverless-post-function` 插件: +以下示例演示如何在不同场景中配置 `serverless-pre-function` 和 `serverless-post-function` 插件。 + +### 在阶段前后记录信息 + +以下示例演示如何配置 serverless 插件,在 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)之前和之后执行自定义逻辑,将信息记录到错误日志中。 + +创建如下路由: + + + + ```shell curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -H "X-API-KEY: ${admin_key}" \ -d '{ - "id": "serverless-route", - "uri": "/index.html", + "id": "serverless-pre-route", + "uri": "/anything", "plugins": { "serverless-pre-function": { "phase": "rewrite", - "functions": ["return function() ngx.log(ngx.ERR, \"serverless pre function\"); end"] + "functions" : [ + "return function() + ngx.log(ngx.ERR, \"serverless pre function\"); + end" + ] }, "serverless-post-function": { "phase": "rewrite", - "functions": ["return function(conf, ctx) ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); end"] + "functions" : [ + "return function(conf, ctx) + ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); + end" + ] } }, "upstream": { "type": "roundrobin", "nodes": { - "127.0.0.1:1980": 1 + "httpbin.org:80": 1 } } }' ``` -向路由发送请求: +❶ 将 serverless pre-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 + +❷ 定义一个 Lua 函数,在错误日志中记录 `serverless pre function` 消息。 + +❸ 将 serverless post-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 + +❹ 定义一个 Lua 函数,在错误日志中记录匹配的 URI。`conf` 和 `ctx` 可以像其他插件一样作为前两个参数传递,其中 `conf` 是插件配置,`ctx` 是请求上下文。 + + + + + +```yaml title="adc.yaml" +services: + - name: httpbin + routes: + - name: serverless-pre-route + uris: + - /anything + plugins: + serverless-pre-function: + phase: rewrite + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + serverless-post-function: + phase: rewrite + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end + upstream: + type: roundrobin + nodes: + - host: httpbin.org + port: 80 + weight: 1 +``` + +同步配置到网关: ```shell -curl -i "http://127.0.0.1:9080/index.html" +adc sync -f adc.yaml +``` + + + + + + + + + +```yaml title="serverless-functions-ic.yaml" +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: serverless-functions-plugin-config +spec: + plugins: + - name: serverless-pre-function + config: + phase: rewrite + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + - name: serverless-post-function + config: + phase: rewrite + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + namespace: aic + name: serverless-pre-route +spec: + parentRefs: + - name: apisix + rules: + - matches: + - path: + type: Exact + value: /anything + filters: + - type: ExtensionRef + extensionRef: + group: apisix.apache.org + kind: PluginConfig + name: serverless-functions-plugin-config + backendRefs: + - name: httpbin-external-domain + port: 80 +``` + + + + + +```yaml title="serverless-functions-ic.yaml" +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: serverless-pre-route +spec: + ingressClassName: apisix + http: + - name: serverless-pre-route + match: + paths: + - /anything + upstreams: + - name: httpbin-external-domain + plugins: + - name: serverless-pre-function + config: + phase: rewrite + functions: + - | + return function() + ngx.log(ngx.ERR, "serverless pre function") + end + - name: serverless-post-function + config: + phase: rewrite + functions: + - | + return function(conf, ctx) + ngx.log(ngx.ERR, "match uri ", ctx.curr_req_matched and ctx.curr_req_matched._path) + end +``` + + + + + +应用配置: + +```shell +kubectl apply -f serverless-functions-ic.yaml +``` + + + + + +向路由发送请求: + +```shell +curl -i "http://127.0.0.1:9080/anything" +``` + +你应该会收到 `HTTP/1.1 200 OK` 响应,并在错误日志中看到以下条目: + +```text +2024/05/09 15:07:09 [error] 51#51: *3963 [lua] [string "return function() ngx.log(ngx.ERR, "serverles..."]:1: func(): serverless pre function, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" +2024/05/09 15:16:58 [error] 50#50: *9343 [lua] [string "return function(conf, ctx) ngx.log(ngx.ERR, "..."]:1: func(): match uri /anything, client: 172.21.0.1, server: _, request: "GET /anything HTTP/1.1", host: "127.0.0.1:9080" ``` -你将在错误日志中看到 `serverless pre function` 和 `match uri /index.html` 两条日志。 +第一条记录由 pre-function 添加,第二条记录由 post-function 添加。 From 8d54bd98c2ab915dd76ee35d97a642fa790f8b85 Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 7 May 2026 11:43:46 +0800 Subject: [PATCH 3/7] docs: remove API7-style annotations from plugin docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove '// Annotate N' style comments and convert circled number annotations (❶ ❷ ❸) to standard list format with dashes. APISIX documentation does not use API7's annotation style with inline comments and circled numbers. Instead, use standard markdown lists or inline explanations. Changes: - Remove all '// Annotate N' comments from code blocks - Convert ❶ ❷ ❸ ❹ ❺ etc. to standard '- ' list items - Applied to both English and Chinese documentation This ensures consistency with APISIX documentation standards. --- docs/en/latest/plugins/authz-keycloak.md | 60 ++++------------------ docs/en/latest/plugins/aws-lambda.md | 42 +++------------- docs/en/latest/plugins/real-ip.md | 42 +++------------- docs/en/latest/plugins/serverless.md | 63 +++++------------------- docs/zh/latest/plugins/authz-keycloak.md | 60 ++++------------------ docs/zh/latest/plugins/aws-lambda.md | 14 +++--- docs/zh/latest/plugins/real-ip.md | 14 +++--- docs/zh/latest/plugins/serverless.md | 8 +-- 8 files changed, 65 insertions(+), 238 deletions(-) diff --git a/docs/en/latest/plugins/authz-keycloak.md b/docs/en/latest/plugins/authz-keycloak.md index 00539445a0e4..9e0f6099af5d 100644 --- a/docs/en/latest/plugins/authz-keycloak.md +++ b/docs/en/latest/plugins/authz-keycloak.md @@ -403,15 +403,10 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "authz-keycloak": { - // Annotate 1 "lazy_load_paths": true, - // Annotate 2 "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", - // Annotate 3 "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", - // Annotate 4 "client_id": "'"$OIDC_CLIENT_ID"'", - // Annotate 5 "client_secret": "'"$OIDC_CLIENT_SECRET"'" } # highlight-end @@ -441,15 +436,10 @@ services: plugins: # highlight-start authz-keycloak: - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: ${OIDC_CLIENT_ID} - // Annotate 5 client_secret: ${OIDC_CLIENT_SECRET} # highlight-end upstream: @@ -502,15 +492,10 @@ spec: - name: authz-keycloak config: # highlight-start - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: apisix-quickstart-client - // Annotate 5 client_secret: replace-with-your-client-secret # highlight-end --- @@ -572,15 +557,10 @@ spec: enable: true config: # highlight-start - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: apisix-quickstart-client - // Annotate 5 client_secret: replace-with-your-client-secret # highlight-end --- @@ -617,15 +597,15 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ Set `lazy_load_paths` to `true`. +- Set `lazy_load_paths` to `true`. -❷ Set `resource_registration_endpoint` to Keycloak's UMA-compliant resource registration endpoint. Required when `lazy_load_paths` is `true`. +- Set `resource_registration_endpoint` to Keycloak's UMA-compliant resource registration endpoint. Required when `lazy_load_paths` is `true`. -❸ Set `discovery` to the discovery document endpoint of Keycloak authorization services. +- Set `discovery` to the discovery document endpoint of Keycloak authorization services. -❹ Set `client_id` to the client ID created previously. +- Set `client_id` to the client ID created previously. -❺ Set `client_secret` to the client secret created previously. Required when `lazy_load_paths` is `true`. +- Set `client_secret` to the client secret created previously. Required when `lazy_load_paths` is `true`. Send a request to the Route: @@ -677,11 +657,8 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "authz-keycloak": { - // Annotate 1 "lazy_load_paths": false, - // Annotate 2 "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", - // Annotate 3 "permissions": ["httpbin-anything#access"], "client_id": "'"$OIDC_CLIENT_ID"'" } @@ -712,11 +689,8 @@ services: plugins: # highlight-start authz-keycloak: - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: ${OIDC_CLIENT_ID} @@ -771,11 +745,8 @@ spec: - name: authz-keycloak config: # highlight-start - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: apisix-quickstart-client @@ -839,11 +810,8 @@ spec: enable: true config: # highlight-start - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: apisix-quickstart-client @@ -882,11 +850,11 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ Set `lazy_load_paths` to `false`. +- Set `lazy_load_paths` to `false`. -❷ Set `discovery` to the discovery document endpoint of Keycloak authorization services. +- Set `discovery` to the discovery document endpoint of Keycloak authorization services. -❸ Set `permissions` to resource `httpbin-anything` and scope `access`. +- Set `permissions` to resource `httpbin-anything` and scope `access`. Send a request to the Route: @@ -928,9 +896,7 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", "client_id": "'"$OIDC_CLIENT_ID"'", "client_secret": "'"$OIDC_CLIENT_SECRET"'", - // Annotate 1 "token_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/protocol/openid-connect/token", - // Annotate 2 "password_grant_token_generation_incoming_uri": "/api/token" } # highlight-end @@ -964,9 +930,7 @@ services: resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set client_id: ${OIDC_CLIENT_ID} client_secret: ${OIDC_CLIENT_SECRET} - // Annotate 1 token_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end upstream: @@ -1023,9 +987,7 @@ spec: client_id: apisix-quickstart-client client_secret: replace-with-your-client-secret # highlight-start - // Annotate 1 token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end --- @@ -1091,9 +1053,7 @@ spec: client_id: apisix-quickstart-client client_secret: replace-with-your-client-secret # highlight-start - // Annotate 1 token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end --- @@ -1131,9 +1091,9 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ Set `token_endpoint` to the Keycloak token endpoint. Required when the discovery document is not provided. +- Set `token_endpoint` to the Keycloak token endpoint. Required when the discovery document is not provided. -❷ Set `password_grant_token_generation_incoming_uri` to a custom URI path where users can obtain tokens. +- Set `password_grant_token_generation_incoming_uri` to a custom URI path where users can obtain tokens. Send a request to the configured token endpoint. The request should use the POST method and `application/x-www-form-urlencoded` as the `Content-Type`: diff --git a/docs/en/latest/plugins/aws-lambda.md b/docs/en/latest/plugins/aws-lambda.md index 93ccd48ea3f8..f348ef1cd489 100644 --- a/docs/en/latest/plugins/aws-lambda.md +++ b/docs/en/latest/plugins/aws-lambda.md @@ -115,17 +115,12 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "aws-lambda": { - // Annotate 1 "function_uri": "https://your-lambda-function-url.lambda-url.us-west-2.on.aws/", "authorization": { "iam": { - // Annotate 2 "accesskey": "YOUR_IAM_ACCESS_KEY", - // Annotate 3 "secretkey": "YOUR_IAM_SECRET_KEY", - // Annotate 4 "aws_region": "us-west-2", - // Annotate 5 "service": "lambda" } }, @@ -150,17 +145,12 @@ services: plugins: aws-lambda: # highlight-start - // Annotate 1 function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ authorization: iam: - // Annotate 2 accesskey: YOUR_IAM_ACCESS_KEY - // Annotate 3 secretkey: YOUR_IAM_SECRET_KEY - // Annotate 4 aws_region: us-west-2 - // Annotate 5 service: lambda # highlight-end ``` @@ -196,17 +186,12 @@ spec: - name: aws-lambda config: # highlight-start - // Annotate 1 function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ authorization: iam: - // Annotate 2 accesskey: YOUR_IAM_ACCESS_KEY - // Annotate 3 secretkey: YOUR_IAM_SECRET_KEY - // Annotate 4 aws_region: us-west-2 - // Annotate 5 service: lambda ssl_verify: false # highlight-end @@ -254,17 +239,12 @@ spec: enable: true config: # highlight-start - // Annotate 1 function_uri: https://your-lambda-function-url.lambda-url.us-west-2.on.aws/ authorization: iam: - // Annotate 2 accesskey: YOUR_IAM_ACCESS_KEY - // Annotate 3 secretkey: YOUR_IAM_SECRET_KEY - // Annotate 4 aws_region: us-west-2 - // Annotate 5 service: lambda ssl_verify: false # highlight-end @@ -284,15 +264,15 @@ kubectl apply -f aws-lambda-ic.yaml -❶ replace with your Lambda function URL +- replace with your Lambda function URL -❷ replace with your IAM access key +- replace with your IAM access key -❸ replace with your IAM secret access key +- replace with your IAM secret access key -❹ replace with the AWS region of your Lambda function +- replace with the AWS region of your Lambda function -❺ set to `lambda` when integrating with Lambda function +- set to `lambda` when integrating with Lambda function Send a request to the Route: @@ -563,11 +543,9 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ -d '{ "id": "aws-lambda-route", # highlight-start - // Annotate 1 "uri": "/aws-lambda/*", "plugins": { "aws-lambda": { - // Annotate 2 "function_uri": "https://your-api-id.execute-api.us-west-2.amazonaws.com/default", "authorization": { "apikey": "YOUR_API_GATEWAY_API_KEY" @@ -589,12 +567,10 @@ services: routes: - name: aws-lambda-route # highlight-start - // Annotate 1 uris: - /aws-lambda/* plugins: aws-lambda: - // Annotate 2 function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY @@ -633,7 +609,6 @@ spec: # highlight-start - name: aws-lambda config: - // Annotate 2 function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY @@ -652,7 +627,6 @@ spec: - matches: - path: type: PathPrefix - // Annotate 1 value: /aws-lambda/ filters: - type: ExtensionRef @@ -679,7 +653,6 @@ spec: match: # highlight-start paths: - // Annotate 1 - /aws-lambda/* # highlight-end plugins: @@ -687,7 +660,6 @@ spec: - name: aws-lambda enable: true config: - // Annotate 2 function_uri: https://your-api-id.execute-api.us-west-2.amazonaws.com/default authorization: apikey: YOUR_API_GATEWAY_API_KEY @@ -709,9 +681,9 @@ kubectl apply -f aws-lambda-ic.yaml -❶ match all sub-paths of `/aws-lambda/` +- match all sub-paths of `/aws-lambda/` -❷ For Admin API, ADC, and APISIX CRD examples, the sub-paths matched by the wildcard `*` will be appended to the end of the `function_uri`. In the Gateway API example, `PathPrefix` matches requests under `/aws-lambda/`, so the forwarded request path continues after the configured `function_uri` prefix. +- For Admin API, ADC, and APISIX CRD examples, the sub-paths matched by the wildcard `*` will be appended to the end of the `function_uri`. In the Gateway API example, `PathPrefix` matches requests under `/aws-lambda/`, so the forwarded request path continues after the configured `function_uri` prefix. Send a request to the Route: diff --git a/docs/en/latest/plugins/real-ip.md b/docs/en/latest/plugins/real-ip.md index 76549820b8ec..5d11bf14742b 100644 --- a/docs/en/latest/plugins/real-ip.md +++ b/docs/en/latest/plugins/real-ip.md @@ -93,12 +93,10 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "real-ip": { - // Annotate 1 "source": "arg_realip", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { - // Annotate 2 "headers": { "remote_addr": "$remote_addr", "remote_port": "$remote_port" @@ -129,12 +127,10 @@ services: plugins: real-ip: # highlight-start - // Annotate 1 source: arg_realip trusted_addresses: - 127.0.0.0/24 response-rewrite: - // Annotate 2 headers: remote_addr: $remote_addr remote_port: $remote_port @@ -187,13 +183,11 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: arg_realip trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: - // Annotate 2 headers: remote_addr: $remote_addr remote_port: $remote_port @@ -257,13 +251,11 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: arg_realip trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: - // Annotate 2 headers: remote_addr: $remote_addr remote_port: $remote_port @@ -284,9 +276,9 @@ kubectl apply -f real-ip-ic.yaml -❶ Configure `source` to obtain value from the URL parameter `realip` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). +- Configure `source` to obtain value from the URL parameter `realip` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). -❷ Use the `response-rewrite` Plugin to set response headers to verify if the client IP and port were actually updated. +- Use the `response-rewrite` Plugin to set response headers to verify if the client IP and port were actually updated. Send a request to the Route with real IP and port in the URL parameter: @@ -327,13 +319,11 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "real-ip": { - // Annotate 1 "source": "http_x_forwarded_for", "trusted_addresses": ["127.0.0.0/24"] }, "response-rewrite": { "headers": { - // Annotate 2 "remote_addr": "$remote_addr" } } @@ -362,13 +352,11 @@ services: plugins: real-ip: # highlight-start - // Annotate 1 source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 response-rewrite: headers: - // Annotate 2 remote_addr: $remote_addr # highlight-end upstream: @@ -419,14 +407,12 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: - // Annotate 2 remote_addr: $remote_addr # highlight-end --- @@ -488,14 +474,12 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: http_x_forwarded_for trusted_addresses: - 127.0.0.0/24 - name: response-rewrite config: headers: - // Annotate 2 remote_addr: $remote_addr # highlight-end ``` @@ -514,9 +498,9 @@ kubectl apply -f real-ip-ic.yaml -❶ Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). +- Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). -❷ Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. +- Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. Send a request to the Route: @@ -559,14 +543,11 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "real-ip": { - // Annotate 1 "source": "http_x_forwarded_for", - // Annotate 2 "recursive": true, "trusted_addresses": ["192.128.0.0/16", "127.0.0.1/32"] }, "response-rewrite": { - // Annotate 3 "headers": { "remote_addr": "$remote_addr" } @@ -596,15 +577,12 @@ services: plugins: real-ip: # highlight-start - // Annotate 1 source: http_x_forwarded_for - // Annotate 2 recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 response-rewrite: - // Annotate 3 headers: remote_addr: $remote_addr # highlight-end @@ -656,16 +634,13 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: http_x_forwarded_for - // Annotate 2 recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 - name: response-rewrite config: - // Annotate 3 headers: remote_addr: $remote_addr # highlight-end @@ -728,16 +703,13 @@ spec: # highlight-start - name: real-ip config: - // Annotate 1 source: http_x_forwarded_for - // Annotate 2 recursive: true trusted_addresses: - 192.128.0.0/16 - 127.0.0.1/32 - name: response-rewrite config: - // Annotate 3 headers: remote_addr: $remote_addr # highlight-end @@ -757,11 +729,11 @@ kubectl apply -f real-ip-ic.yaml -❶ Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). +- Configure `source` to obtain value from the request header `X-Forwarded-For` using the built-in [APISIX variable](https://apisix.apache.org/docs/apisix/apisix-variable/) or [NGINX variable](https://nginx.org/en/docs/varindex.html). -❷ Set `recursive` to `true` so that the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the configured `source`. +- Set `recursive` to `true` so that the original client address that matches one of the trusted addresses is replaced by the last non-trusted address sent in the configured `source`. -❸ Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. +- Use the `response-rewrite` Plugin to set a response header to verify if the client IP was actually updated. Send a request to the Route: diff --git a/docs/en/latest/plugins/serverless.md b/docs/en/latest/plugins/serverless.md index d58f02abdc0e..4b68146b9537 100644 --- a/docs/en/latest/plugins/serverless.md +++ b/docs/en/latest/plugins/serverless.md @@ -111,9 +111,7 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "serverless-pre-function": { - // Annotate 1 "phase": "rewrite", - // Annotate 2 "functions" : [ "return function() ngx.log(ngx.ERR, \"serverless pre function\"); @@ -121,9 +119,7 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ ] }, "serverless-post-function": { - // Annotate 3 "phase": "rewrite", - // Annotate 4 "functions" : [ "return function(conf, ctx) ngx.log(ngx.ERR, \"match uri \", ctx.curr_req_matched and ctx.curr_req_matched._path); @@ -155,18 +151,14 @@ services: plugins: # highlight-start serverless-pre-function: - // Annotate 1 phase: rewrite - // Annotate 2 functions: - | return function() ngx.log(ngx.ERR, "serverless pre function") end serverless-post-function: - // Annotate 3 phase: rewrite - // Annotate 4 functions: - | return function(conf, ctx) @@ -221,9 +213,7 @@ spec: # highlight-start - name: serverless-pre-function config: - // Annotate 1 phase: rewrite - // Annotate 2 functions: - | return function() @@ -231,9 +221,7 @@ spec: end - name: serverless-post-function config: - // Annotate 3 phase: rewrite - // Annotate 4 functions: - | return function(conf, ctx) @@ -299,9 +287,7 @@ spec: # highlight-start - name: serverless-pre-function config: - // Annotate 1 phase: rewrite - // Annotate 2 functions: - | return function() @@ -309,9 +295,7 @@ spec: end - name: serverless-post-function config: - // Annotate 3 phase: rewrite - // Annotate 4 functions: - | return function(conf, ctx) @@ -334,13 +318,13 @@ kubectl apply -f serverless-functions-ic.yaml -❶ Hook the serverless pre-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). +- Hook the serverless pre-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). -❷ Define a Lua function that logs a message of `serverless pre function` in the error log. +- Define a Lua function that logs a message of `serverless pre function` in the error log. -❸ Hook the serverless post-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). +- Hook the serverless post-function logic to the `rewrite` [phase](../terminology/plugin.md#plugins-execution-lifecycle). -❹ Define a Lua function that logs the matched URI in the error log. `conf` and `ctx` can be passed as the first two arguments like other plugins, where `conf` is the plugin configurations and `ctx` is the request context. +- Define a Lua function that logs the matched URI in the error log. `conf` and `ctx` can be passed as the first two arguments like other plugins, where `conf` is the plugin configurations and `ctx` is the request context. Send the request to the Route: @@ -394,7 +378,6 @@ curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ # highlight-start "serverless-pre-function": { "phase": "rewrite", - // Annotate 1 "functions": [ "return function() local core = require \"apisix.core\" @@ -409,10 +392,8 @@ curl "http://127.0.0.1:9180/apisix/admin/services" -X PUT \ ] }, "syslog": { - // Annotate 2 "host" : "172.0.0.1", "port" : 514, - // Annotate 3 "flush_limit" : 1 } # highlight-end @@ -436,7 +417,6 @@ services: # highlight-start serverless-pre-function: phase: rewrite - // Annotate 1 functions: - | return function() @@ -450,10 +430,8 @@ services: end) end syslog: - // Annotate 2 host: 172.0.0.1 port: 514 - // Annotate 3 flush_limit: 1 # highlight-end upstream: @@ -473,11 +451,11 @@ adc sync -f adc.yaml -❶ `functions`: register a custom variable `a6_route_labels` and fetch the variable value from the matched Route's `labels` property. +- `functions`: register a custom variable `a6_route_labels` and fetch the variable value from the matched Route's `labels` property. -❷ `host` and `port`: replace with the address of your syslog server. +- `host` and `port`: replace with the address of your syslog server. -❸ `flush_limit`: set to 1 to push log to the syslog server immediately. +- `flush_limit`: set to 1 to push log to the syslog server immediately. Next, update the log format for all `syslog` instances with the new variable by configuring the [Plugin metadata](../terminology/plugin.md#plugin-metadata): @@ -497,10 +475,8 @@ curl "http://127.0.0.1:9180/apisix/admin/plugin_metadata/syslog" -X PUT \ -d '{ "log_format": { # highlight-start - // Annotate 1 "host": "$host", "client_ip": "$remote_addr", - // Annotate 2 "labels": "$a6_route_labels" # highlight-end } @@ -516,10 +492,8 @@ plugin_metadata: syslog: log_format: # highlight-start - // Annotate 1 host: "$host" client_ip: "$remote_addr" - // Annotate 2 labels: "$a6_route_labels" # highlight-end ``` @@ -534,9 +508,9 @@ adc sync -f adc.yaml -❶ `$host` and `$remote_addr`: NGINX variables. +- `$host` and `$remote_addr`: NGINX variables. -❷ `$a6_route_labels`: custom variable. +- `$a6_route_labels`: custom variable. Finally, create a Route: @@ -557,9 +531,7 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "id":"route_custom_var", "uri":"/get", # highlight-start - // Annotate 1 "service_id": "srv_custom_var", - // Annotate 2 "labels": { "key": "test_a6_route_labels" } @@ -581,7 +553,6 @@ services: - /get # highlight-start labels: - // Annotate 2 key: test_a6_route_labels # highlight-end ``` @@ -596,9 +567,9 @@ adc sync -f adc.yaml -❶ In the Admin API example, set `service_id` to associate the Route with the existing Service. In ADC, the Route is nested under the Service definition. +- In the Admin API example, set `service_id` to associate the Route with the existing Service. In ADC, the Route is nested under the Service definition. -❷ Add Route `labels` so the custom variable can log them. +- Add Route `labels` so the custom variable can log them. To verify the variable registration, send a request to the Route: @@ -813,7 +784,6 @@ curl "http://127.0.0.1:9180/apisix/admin/routes/serverless-remove-body-info" -X "plugins": { # highlight-start "serverless-pre-function": { - // Annotate 1 "phase": "header_filter", "functions" : [ "return function(conf, ctx) @@ -823,7 +793,6 @@ curl "http://127.0.0.1:9180/apisix/admin/routes/serverless-remove-body-info" -X ] }, "serverless-post-function": { - // Annotate 2 "phase": "body_filter", "functions" : [ "return function(conf, ctx) @@ -859,7 +828,6 @@ services: plugins: # highlight-start serverless-pre-function: - // Annotate 1 phase: header_filter functions: - | @@ -868,7 +836,6 @@ services: core.response.clear_header_as_body_modified() end serverless-post-function: - // Annotate 2 phase: body_filter functions: - | @@ -926,7 +893,6 @@ spec: # highlight-start - name: serverless-pre-function config: - // Annotate 1 phase: header_filter functions: - | @@ -936,7 +902,6 @@ spec: end - name: serverless-post-function config: - // Annotate 2 phase: body_filter functions: - | @@ -1003,7 +968,6 @@ spec: # highlight-start - name: serverless-pre-function config: - // Annotate 1 phase: header_filter functions: - | @@ -1013,7 +977,6 @@ spec: end - name: serverless-post-function config: - // Annotate 2 phase: body_filter functions: - | @@ -1046,9 +1009,9 @@ kubectl apply -f serverless-remove-body-ic.yaml -❶ Execute a pre-function in the `header_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). +- Execute a pre-function in the `header_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). -❷ Execute a post-function in the `body_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). +- Execute a post-function in the `body_filter` [phase](../terminology/plugin.md#plugins-execution-lifecycle). The pre-function calls `clear_header_as_body_modified` to clear body-related response headers such as `Content-Length`. The post-function collects the response body with `hold_body_chunk`, decodes the JSON payload, removes the `origin` field, and writes the updated body back to the response. diff --git a/docs/zh/latest/plugins/authz-keycloak.md b/docs/zh/latest/plugins/authz-keycloak.md index c7b7f6ca5013..fa442e5cc80e 100644 --- a/docs/zh/latest/plugins/authz-keycloak.md +++ b/docs/zh/latest/plugins/authz-keycloak.md @@ -403,15 +403,10 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "authz-keycloak": { - // Annotate 1 "lazy_load_paths": true, - // Annotate 2 "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", - // Annotate 3 "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", - // Annotate 4 "client_id": "'"$OIDC_CLIENT_ID"'", - // Annotate 5 "client_secret": "'"$OIDC_CLIENT_SECRET"'" } # highlight-end @@ -441,15 +436,10 @@ services: plugins: # highlight-start authz-keycloak: - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: ${OIDC_CLIENT_ID} - // Annotate 5 client_secret: ${OIDC_CLIENT_SECRET} # highlight-end upstream: @@ -502,15 +492,10 @@ spec: - name: authz-keycloak config: # highlight-start - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: apisix-quickstart-client - // Annotate 5 client_secret: replace-with-your-client-secret # highlight-end --- @@ -572,15 +557,10 @@ spec: enable: true config: # highlight-start - // Annotate 1 lazy_load_paths: true - // Annotate 2 resource_registration_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/authz/protection/resource_set - // Annotate 3 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 4 client_id: apisix-quickstart-client - // Annotate 5 client_secret: replace-with-your-client-secret # highlight-end --- @@ -617,15 +597,15 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ 将 `lazy_load_paths` 设置为 `true`。 +- 将 `lazy_load_paths` 设置为 `true`。 -❷ 将 `resource_registration_endpoint` 设置为 Keycloak 符合 UMA 规范的资源注册端点。当 `lazy_load_paths` 为 `true` 时必填。 +- 将 `resource_registration_endpoint` 设置为 Keycloak 符合 UMA 规范的资源注册端点。当 `lazy_load_paths` 为 `true` 时必填。 -❸ 将 `discovery` 设置为 Keycloak 授权服务的发现文档端点。 +- 将 `discovery` 设置为 Keycloak 授权服务的发现文档端点。 -❹ 将 `client_id` 设置为之前创建的客户端 ID。 +- 将 `client_id` 设置为之前创建的客户端 ID。 -❺ 将 `client_secret` 设置为之前创建的客户端密钥。当 `lazy_load_paths` 为 `true` 时必填。 +- 将 `client_secret` 设置为之前创建的客户端密钥。当 `lazy_load_paths` 为 `true` 时必填。 向路由发送请求: @@ -677,11 +657,8 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "plugins": { # highlight-start "authz-keycloak": { - // Annotate 1 "lazy_load_paths": false, - // Annotate 2 "discovery": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/.well-known/uma2-configuration", - // Annotate 3 "permissions": ["httpbin-anything#access"], "client_id": "'"$OIDC_CLIENT_ID"'" } @@ -712,11 +689,8 @@ services: plugins: # highlight-start authz-keycloak: - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: ${KEYCLOAK_URL}/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: ${OIDC_CLIENT_ID} @@ -771,11 +745,8 @@ spec: - name: authz-keycloak config: # highlight-start - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: apisix-quickstart-client @@ -839,11 +810,8 @@ spec: enable: true config: # highlight-start - // Annotate 1 lazy_load_paths: false - // Annotate 2 discovery: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/.well-known/uma2-configuration - // Annotate 3 permissions: - "httpbin-anything#access" client_id: apisix-quickstart-client @@ -882,11 +850,11 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ 将 `lazy_load_paths` 设置为 `false`。 +- 将 `lazy_load_paths` 设置为 `false`。 -❷ 将 `discovery` 设置为 Keycloak 授权服务的发现文档端点。 +- 将 `discovery` 设置为 Keycloak 授权服务的发现文档端点。 -❸ 将 `permissions` 设置为资源 `httpbin-anything` 和作用域 `access`。 +- 将 `permissions` 设置为资源 `httpbin-anything` 和作用域 `access`。 向路由发送请求: @@ -928,9 +896,7 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ "resource_registration_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/authz/protection/resource_set", "client_id": "'"$OIDC_CLIENT_ID"'", "client_secret": "'"$OIDC_CLIENT_SECRET"'", - // Annotate 1 "token_endpoint": "'"$KEYCLOAK_URL"'/realms/quickstart-realm/protocol/openid-connect/token", - // Annotate 2 "password_grant_token_generation_incoming_uri": "/api/token" } # highlight-end @@ -964,9 +930,7 @@ services: resource_registration_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/authz/protection/resource_set client_id: ${OIDC_CLIENT_ID} client_secret: ${OIDC_CLIENT_SECRET} - // Annotate 1 token_endpoint: ${KEYCLOAK_URL}/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end upstream: @@ -1023,9 +987,7 @@ spec: client_id: apisix-quickstart-client client_secret: replace-with-your-client-secret # highlight-start - // Annotate 1 token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end --- @@ -1091,9 +1053,7 @@ spec: client_id: apisix-quickstart-client client_secret: replace-with-your-client-secret # highlight-start - // Annotate 1 token_endpoint: http://keycloak.aic.svc.cluster.local:8080/realms/quickstart-realm/protocol/openid-connect/token - // Annotate 2 password_grant_token_generation_incoming_uri: /api/token # highlight-end --- @@ -1131,9 +1091,9 @@ kubectl apply -f authz-keycloak-ic.yaml -❶ 将 `token_endpoint` 设置为 Keycloak 令牌端点。当未提供发现文档时必填。 +- 将 `token_endpoint` 设置为 Keycloak 令牌端点。当未提供发现文档时必填。 -❷ 将 `password_grant_token_generation_incoming_uri` 设置为用户可获取令牌的自定义 URI 路径。 +- 将 `password_grant_token_generation_incoming_uri` 设置为用户可获取令牌的自定义 URI 路径。 向已配置的令牌端点发送请求。请求应使用 POST 方法,并将 `Content-Type` 设置为 `application/x-www-form-urlencoded`: diff --git a/docs/zh/latest/plugins/aws-lambda.md b/docs/zh/latest/plugins/aws-lambda.md index 9d0b3022133f..5d32485a4d0a 100644 --- a/docs/zh/latest/plugins/aws-lambda.md +++ b/docs/zh/latest/plugins/aws-lambda.md @@ -129,15 +129,15 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 替换为你的 Lambda 函数 URL +- 替换为你的 Lambda 函数 URL -❷ 替换为你的 IAM 访问密钥 +- 替换为你的 IAM 访问密钥 -❸ 替换为你的 IAM 秘密访问密钥 +- 替换为你的 IAM 秘密访问密钥 -❹ 替换为 Lambda 函数所在的 AWS 区域 +- 替换为 Lambda 函数所在的 AWS 区域 -❺ 直接与 Lambda 函数集成时设置为 `lambda` +- 直接与 Lambda 函数集成时设置为 `lambda` @@ -541,9 +541,9 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 匹配 `/aws-lambda/` 的所有子路径 +- 匹配 `/aws-lambda/` 的所有子路径 -❷ 对于 Admin API、ADC 和 APISIX CRD 示例,通配符 `*` 匹配的子路径将追加到 `function_uri` 的末尾。在 Gateway API 示例中,`PathPrefix` 匹配 `/aws-lambda/` 下的请求,因此转发的请求路径在配置的 `function_uri` 前缀之后继续。 +- 对于 Admin API、ADC 和 APISIX CRD 示例,通配符 `*` 匹配的子路径将追加到 `function_uri` 的末尾。在 Gateway API 示例中,`PathPrefix` 匹配 `/aws-lambda/` 下的请求,因此转发的请求路径在配置的 `function_uri` 前缀之后继续。 diff --git a/docs/zh/latest/plugins/real-ip.md b/docs/zh/latest/plugins/real-ip.md index b405b5ceb3a4..3ccf3a94f132 100644 --- a/docs/zh/latest/plugins/real-ip.md +++ b/docs/zh/latest/plugins/real-ip.md @@ -111,9 +111,9 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从 URL 参数 `realip` 获取值。 +- 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从 URL 参数 `realip` 获取值。 -❷ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 和端口是否实际更新。 +- 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 和端口是否实际更新。 @@ -328,9 +328,9 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。 +- 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。 -❷ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际更新。 +- 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际更新。 @@ -545,11 +545,11 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。 +- 配置 `source` 以使用 [APISIX 变量](https://apisix.apache.org/docs/apisix/apisix-variable/)或者 [NGINX 变量](https://nginx.org/en/docs/varindex.html)从请求头 `X-Forwarded-For` 获取值。 -❷ 将 `recursive` 设置为 `true`,以便将匹配可信地址之一的原始客户端地址替换为配置的 `source` 中发送的最后一个非可信地址。 +- 将 `recursive` 设置为 `true`,以便将匹配可信地址之一的原始客户端地址替换为配置的 `source` 中发送的最后一个非可信地址。 -❸ 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际更新。 +- 使用 `response-rewrite` 插件设置响应头,以验证客户端 IP 是否实际更新。 diff --git a/docs/zh/latest/plugins/serverless.md b/docs/zh/latest/plugins/serverless.md index d664c3da7c23..d325b14cf2fd 100644 --- a/docs/zh/latest/plugins/serverless.md +++ b/docs/zh/latest/plugins/serverless.md @@ -135,13 +135,13 @@ curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \ }' ``` -❶ 将 serverless pre-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 +- 将 serverless pre-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 -❷ 定义一个 Lua 函数,在错误日志中记录 `serverless pre function` 消息。 +- 定义一个 Lua 函数,在错误日志中记录 `serverless pre function` 消息。 -❸ 将 serverless post-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 +- 将 serverless post-function 逻辑挂钩到 `rewrite` [阶段](../terminology/plugin.md#plugins-execution-lifecycle)。 -❹ 定义一个 Lua 函数,在错误日志中记录匹配的 URI。`conf` 和 `ctx` 可以像其他插件一样作为前两个参数传递,其中 `conf` 是插件配置,`ctx` 是请求上下文。 +- 定义一个 Lua 函数,在错误日志中记录匹配的 URI。`conf` 和 `ctx` 可以像其他插件一样作为前两个参数传递,其中 `conf` 是插件配置,`ctx` 是请求上下文。 From 389ae907c5d796d77f545fd4c15e85f161d5146c Mon Sep 17 00:00:00 2001 From: OpenCode Date: Thu, 7 May 2026 12:12:04 +0800 Subject: [PATCH 4/7] docs: fix Chinese punctuation in plugin docs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace English punctuation with Chinese punctuation in Chinese documentation where appropriate: - , (comma) → ,(Chinese comma) - : (colon) → :(Chinese colon) - ; (semicolon) → ;(Chinese semicolon) Chinese documentation should use Chinese punctuation marks to follow proper Chinese writing conventions. Affected plugins: - authz-keycloak (116 changes) - aws-lambda (80 changes) - public-api (56 changes) - real-ip (52 changes) - serverless (30 changes) --- docs/zh/latest/plugins/authz-keycloak.md | 116 +++++++++++------------ docs/zh/latest/plugins/aws-lambda.md | 80 ++++++++-------- docs/zh/latest/plugins/public-api.md | 56 +++++------ docs/zh/latest/plugins/real-ip.md | 52 +++++----- docs/zh/latest/plugins/serverless.md | 30 +++--- 5 files changed, 167 insertions(+), 167 deletions(-) diff --git a/docs/zh/latest/plugins/authz-keycloak.md b/docs/zh/latest/plugins/authz-keycloak.md index fa442e5cc80e..46a467f34405 100644 --- a/docs/zh/latest/plugins/authz-keycloak.md +++ b/docs/zh/latest/plugins/authz-keycloak.md @@ -6,7 +6,7 @@ keywords: - Plugin - Authz Keycloak - authz-keycloak -description: authz-keycloak 插件与 Keycloak 集成,用于用户认证和授权,增强 API 的安全性和管理能力。 +description: authz-keycloak 插件与 Keycloak 集成,用于用户认证和授权,增强 API 的安全性和管理能力。 ---