Envoy Gateway v 1.2.0 版本发布:新功能与改进介绍

Posted by Huabing Blog on Tuesday, November 5, 2024
穿藏族服装的少女 - 理塘,甘孜

Envoy Gateway(本文中简称 EG)在 11 月 6 日发布了最新的 1.2.0 版本。该版本带来了一系列激动人心的新特性和改进,本文将为您一一介绍。

支持最新的 Gateway API v1.2.0

Envoy Gateway v1.2.0 支持了 Gateway API 最新的 v1.2.0 版本。Envoy Gateway 紧密跟踪 Gateway API 的最新版本,以便为用户提供最新的 API 特性和功能。关于 Gateway API v1.2.0 的详细信息,可以参考 Gateway API v1.2.0 的 release note¹

支持 IPv6(实验特性)

从 1.2.0 版本开始,Envoy Gateway 增加了对 IPv6 的支持。IPv6 的支持主要包含两个方面:一是支持 Envoy 的 Listener 配置 IPv6 的监听地址,以支持客户端通过 IPv6 地址访问服务;二是支持配置 IPv6 的后端服务地址,以支持 Envoy 通过 IPv6 地址访问后端服务。(目前主机部署模式还处于实验阶段,可能存在一些问题,我们欢迎用户在使用过程中向社区反馈问题和建议)

监听器支持 IPv6

通过 EnvoyProxy CR 中的 ipFamily 字段,用户可以指定使用双栈或者 IPv6 支持。下面是一个启用 IPv6 的例子:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyProxy
metadata:
  name: custom-proxy-config
  namespace: default
spec:
  ipFamily: IPv6

ipFamily 字段支持的值有 IPv4,IPv6,DualStack。当配置为 IPv6 或者 DualStack 时,Envoy Gateway 会为 Envoy 的 Listener 配置 IPv6 的监听地址,以支持客户端通过 IPv6 地址访问服务。

后端服务支持 IPv6

对于 Kubernetes 集群内部的后端服务,用户开启 Kubernetes 的 IPv6 功能后,Envoy Gateway 会自动支持 IPv6 地址,无需额外配置。对于集群外部的后端服务,用户可以通过配置 Backend 资源来指定 IPv6 地址。下面是一个配置 IPv6 后端服务地址的例子:

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: backend-ipv6
spec:
  endpoints:
    - ip:
        address: "fd00:10:96::1411"
        port: 8080

主机部署模式(实验特性)

Envoy Gateway 1.2.0 版本引入了主机部署模式。在主机部署模式下,Envoy Gateway 无需依赖 Kubernetes,可以直接部署在裸机或者虚拟机上。主机部署模式支持的功能和特性和 Kubernetes 部署模式基本一致,包括 Gateway, HTTPRoute, ClientTrafficPolicy, BackendTrafficPolicy, SecurityPolicy 等资源的定义和使用。(目前主机部署模式还处于实验阶段,可能存在一些问题,我们欢迎用户在使用过程中向社区反馈问题和建议)

需要注意的是,由于主机部署模式下无法使用 Kubernetes 的 Service 和 EndpointSlice 等资源,用户需要通过配置 Backend 资源来定义后端服务。

通过下面的命令可以启动一个主机部署模式的 Envoy Gateway:

envoy-gateway server --config-path standalone.yaml

其中 standalone.yaml 用于配主机部署模式下 Envoy Gateway 的相关参数,如从哪里加载资源文件,启用 Backend API 等。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: EnvoyGateway
gateway:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
provider:
  type: Custom
  custom:
    resource:
      type: File
      file:
        paths: ["/tmp/envoy-gateway-test"]
    infrastructure:
      type: Host
      host: {}
extensionApis:
  enableBackend: true

上面的配置文件将从 /tmp/envoy-gateway-test 目录加载资源文件。将下面的资源保存到 /tmp/envoy-gateway-test/quickstart.yaml 中,即可为 Envoy Gateway 创建一个 HTTPRoute:

apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
  name: eg
spec:
  controllerName: gateway.envoyproxy.io/gatewayclass-controller
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: eg
spec:
  gatewayClassName: eg
  listeners:
    - name: http
      protocol: HTTP
      port: 8888
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: backend
spec:
  parentRefs:
    - name: eg
  hostnames:
    - "www.example.com"
  rules:
    - backendRefs:
        - group: "gateway.envoyproxy.io"
          kind: Backend
          name: backend
      matches:
        - path:
            type: PathPrefix
            value: /
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: backend
spec:
  endpoints:
    - ip:
        address: 0.0.0.0
        port: 3000

在本地启动一个 HTTP 服务,监听 3000 端口:

python3 -m http.server 3000

然后就可以通过访问 http://www.example.com:8888 来访问这个 HTTP 服务。

curl --verbose --header "Host: www.example.com" http://0.0.0.0:8888/

基于 JWT Claim 和 Scope 的访问权限控制

JWT(JSON Web Token)是一种用于在网络上传递声明的开放标准(RFC 7519)。JWT 通常用于对用户进行认证和授权,以及在不同服务之间传递用户信息。在之前的版本中,Envoy Gateway 已经支持了基于 JWT 的认证,在 1.2.0 版本中,Envoy Gateway 对 JWT 的支持进行了进一步的增强,提供了基于 JWT Claim 和 Scope 的访问权限控制,用户可以通过配置 SecurityPolicy 来对请求进行访问控制。

例如,下面的 SecurityPolicy 对访问 http-with-authorization-jwt-claim 这个 HTTPRoute 的请求进行了访问控制。缺省的访问策略设置为 Deny,只有请求中包含一个合法的 JWT token, 并且该 JWT Token 满足以下条件时才能访问该 HTTPRoute。

  • user.name claim 的值为 John Doe
  • user.roles claim 的值包含 admin
  • token 包含 read, add, modify 这三个 scope

需要注意的是,我们需要在同一个 SecurityPolicy 中同时配置 JWT 认证,以对请求中的 JWT Token 进行验证,并提取其中的 claims 和 scopes 以进行下一步的访问控制。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: authorization-jwt-claim
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: backend
  jwt:
    providers:
    - name: example
      issuer: https://foo.bar.com
      remoteJWKS:
        uri: https://raw.githubusercontent.com/envoyproxy/gateway/refs/heads/main/examples/kubernetes/jwt/jwks.json
  authorization:
    defaultAction: Deny
    rules:
    - name: "allow"
      action: Allow
      principal:
        jwt:
          provider: example
          scopes: ["read", "add", "modify"]
          claims:
          - name: user.name
            values: ["John Doe"]
          - name: user.roles
            valueType: StringArray
            values: ["admin"]

我们甚至可以配合 OIDC 一起使用,将用户的认证和授权全部交给 Envoy Gateway 来处理。例如,下面的 SecurityPolicy 配置了 OIDC 认证,然后将通过 OIDC 认证得到的 JWT Token 用一个名为 “MyIdTokenCookie” 的 Cookie 传递给 JWT 认证,通过 JWT 认证提取其中的 claims 和 scopes,然后基于这些 claims 和 scopes 进行访问控制。

apiVersion: gateway.envoyproxy.io/v1alpha1
  kind: SecurityPolicy
    ......
    oidc:
      provider:
        issuer: "https://foo.bar.com"
      ...
      cookieNames:
        idToken: "MyIdTokenCookie"
    jwt:
      providers:
      - name: foo
        issuer: https://foo.bar.com
        remoteJWKS:
          uri: https://foo.bar.com/jwt/public-key/jwks.json
        extractFrom:
          cookies:
          - MyIdTokenCookie
    authorization:
      defaultAction: Deny
      rules:
      - name: "allow-jwt-claim"
        action: Allow
        principal:
          jwt:
            provider: foo
            scopes:
            - "foo"
            - "bar"
            claims:
            - name: "sub"
              values:
              - "1234567890"
            - name: "roles"
              valueType: "StringArray"
              values:
              - "admin"
              - "superuser"

支持 Backend 主备故障切换

在 1.2.0 版本中,Envoy Gateway 支持了 Backend 主备故障切换。用户可以通过配置 Backend CRD 来定义一个主备后端服务,当主后端服务不可用时, Envoy Gateway 会自动切换到备用后端服务。

例如,下面配置中的 HTTPRoute 会将请求转发到 backend-1,如果 backend-1 不可用,Envoy Gateway 会自动切换到其备用后端服务 backend-2。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  namespace: default
  name: httproute-1
spec:
  parentRefs:
    - namespace: envoy-gateway
      name: gateway-1
  rules:
    - matches:
        - path:
            value: "/"
      backendRefs:
        - group: gateway.envoyproxy.io
          kind: Backend
          name: backend-1
        - group: gateway.envoyproxy.io
          kind: Backend
          name: backend-2
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: backend-1
  namespace: default
spec:
  endpoints:
    - ip:
        address: 1.1.1.1
        port: 3001
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: backend-2
  namespace: default
spec:
  fallback: true
  endpoints:
    - ip:
        address: 2.2.2.2
        port: 3001

支持强会话保持

Envoy Gateway 1.1 中通过一致性哈希负载均衡算法实现的弱会话保持,来自同一个客户端的请求在一定时间内会被路由到同一个后端服务实例上,但是如果后端服务实例发生了变化,比如扩容或者缩容,那么某些保持的会话可能由于重新负载均衡的原因会失效。在 1.2.0 版本中,Envoy Gateway 支持了强会话保持,即使后端服务实例发生了变化,也可以保证请求会被路由到同一个后端服务实例上。

可以通过配置 HTTPRouteRule 中的 sessionPersistence 字段来开启会话保持。Envoy Gateway 支持采用 Cookie 或者 Header 来进行会话保持。下面是一个采用 Cookie 来进行会话保持的例子。

当 Envoy Gateway 第一次收到一个请求时,会生成一个名为 Session-Cookie 的 Cookie,并将选择的后端服务实例的地址写入到这个 Cookie 中。当后续的请求到来时,Envoy Gateway 会根据这个 Cookie 中的地址来路由请求。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: cookie-based-session-persistence
spec:
  parentRefs:
    - name: eg
  rules:
    - backendRefs:
        - name: backend
          port: 8080
      sessionPersistence:
        sessionName: Session-Cookie
        type: Cookie
        absoluteTimeout: 10s
        cookieConfig:
          lifetimeType: Permanent

需要注意的是,如果使用 header 来进行会话保持时,Envoy Gateway 会把第一次选中的后端服务实例的地址写入到 Response 的指定的 Header 中,后续的请求需要将这个 Header 带上,Envoy Gateway 才能根据这个 Header 来路由请求。

支持自定义 Response 内容

在 1.2.0 版本中,Envoy Gateway 支持了自定义 Response 内容。用户可以修改后端服务返回的 Response 内容,例如修改 Body 内容,添加 Header 等。也可以直接返回一个自定义的 Response。

通过配置 BackendTrafficPolicy 来修改后端服务返回的 Response。例如,下面的配置会将后端服务返回的 404 错误的 Response body 修改为 “The requested URL was not found on this server."。

apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
  creationTimestamp: null
  name: override-response
  namespace: default
spec:
  responseOverride:
  - match:
      statusCodes:
      - type: null
        value: 404
    response:
      body:
        inline: The requested URL was not found on this server.
        type: null
      contentType: text/plain

通过为 HTTPRoute 配置一个 HTTPRouteFilter,也可以不经过后端服务,直接返回一个自定义的 Response。例如,下面的配置会直接返回一个 “OK” 的 Response。

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: direct-response
spec:
  parentRefs:
  - name: eg
  rules:
  - filters:
    - type: ExtensionRef
      extensionRef:
        group: gateway.envoyproxy.io
        kind: HTTPRouteFilter
        name: direct-response-inline
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: HTTPRouteFilter
metadata:
  name: direct-response-inline
  namespace: default
spec:
  directResponse:
    contentType: text/plain
    statusCode: 200
    body:
      type: Inline
      inline: "OK"

总结

Envoy Gateway 1.2.0 版本带来了一系列新特性和改进,包括支持 IPv6,主机部署模式,基于 JWT Claim 和 Scope 的访问权限控制,Backend 主备故障切换,强会话保持,自定义 Response 内容等。该版本来自于社区贡献者的辛勤劳动,在此向所有参与贡献的社区成员表示感谢。欢迎大家下载使用 Envoy Gateway 1.2.0 版本³,并参与到社区的建设中来。

EG 1.2.0 版本的详细更新内容可以参考Relase 变更清单⁴

参考

  1. Gateway API v1.2.0 的 release note: https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.0
  2. RFC 7519 https://tools.ietf.org/html/rfc7519
  3. EG 1.2.0 Release 变更清单 https://github.com/envoyproxy/gateway/releases/tag/v1.2.0
  4. EG 1.2.0 版本下载 https://gateway.envoyproxy.io/news/releases/notes/v1.2.0