跳到主要内容

配置跨命名空间引用

跨命名空间引用让平台团队可以运营共享 Gateway、后端和 Secret,同时让应用团队管理各自的 Route 与 Consumer。Gateway API 要求在每一道命名空间边界上显式授权,避免在一个命名空间创建资源就自动获得另一团队资源的访问权。

不同关系所需的授权如下:

关系授权方式
Route 引用另一命名空间的 GatewayGateway 监听器通过 allowedRoutes 选择 Route 所在命名空间。
Route 引用另一命名空间的后端后端命名空间中的 ReferenceGrant 允许该 Route 引用。
Gateway 引用另一命名空间的 TLS SecretSecret 命名空间中的 ReferenceGrant 允许该 Gateway 引用。
Consumer 引用另一命名空间的凭证 SecretSecret 命名空间中的 ReferenceGrant 允许该 Consumer 引用。

跨命名空间流量引用通过 Gateway API 资源支持;Ingress 资源与 APISIX 路由 CRD 不支持跨命名空间流量引用。Consumer 凭证引用是 ReferenceGrant 的实现特定用法。

这些机制用于授权资源之间的关系,并不会授予用户创建或修改这些资源的权限。配置跨命名空间引用之前,请先使用 Kubernetes RBAC 委派 Gateway API 访问权限

前置条件

  • 使用 Gateway API 资源完成设置 Ingress Controller 和网关
  • 安装此版本 Ingress Controller 支持的 Gateway API CRD。
  • 使用有权创建各示例命名空间与资源的账号。

示例使用 aic 命名空间中名为 apisix 的 Gateway 和名为 apisix-config 的 GatewayProxy,这与 APISIX 设置教程创建的名称一致。

允许 Route 使用另一命名空间的后端

以下示例在 tenant-a 中创建 HTTPRoute,将它挂载到 aic 中的 Gateway,并把请求转发到 backend-ns 中的 Service:

Gateway 所有者授权来自 tenant-a 的挂载,后端所有者则单独授权访问 httpbin Service。

创建命名空间

创建租户命名空间和后端命名空间:

kubectl create namespace tenant-a
kubectl create namespace backend-ns

Kubernetes 会自动为每个命名空间添加不可变的 kubernetes.io/metadata.name 标签。Gateway 监听器将用该标签选择 tenant-a,无需自定义命名空间标签。

创建后端服务

在后端命名空间中创建 Deployment 和 Service:

httpbin-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
namespace: backend-ns
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin
image: kennethreitz/httpbin
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
namespace: backend-ns
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: httpbin

将配置应用到集群:

kubectl apply -f httpbin-deployment.yaml

授权后端引用

ReferenceGrant 必须创建在被引用对象所在的命名空间。请在 backend-ns 中创建以下授权,允许 tenant-a 中的 HTTPRoute 引用 httpbin Service:

backend-referencegrant.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-httpbin-from-tenant-a
namespace: backend-ns
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: tenant-a
to:
- group: ""
kind: Service
name: httpbin

from 条目信任 tenant-a 中的 HTTPRoute;to 条目将信任限制为 ReferenceGrant 所在命名空间中的 httpbin Service。to.name 可选,但省略它会允许引用 backend-ns 中所有被匹配授权覆盖的 Service。

将配置应用到集群:

kubectl apply -f backend-referencegrant.yaml

创建路由

在租户命名空间 tenant-a 中创建 HTTPRoute,并引用 backend-ns 中的后端服务。该 HTTPRoute 会挂载到 aic 命名空间中的 apisix Gateway 资源。

httpbin-route.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: httpbin-route
namespace: tenant-a
spec:
parentRefs:
- name: apisix
namespace: aic
rules:
- matches:
- path:
type: PathPrefix
value: /ip
backendRefs:
- kind: Service
name: httpbin
namespace: backend-ns
port: 80
weight: 1

将配置应用到集群:

kubectl apply -f httpbin-route.yaml

授权 Route 挂载

默认情况下,Gateway 监听器只允许来自 Gateway 所在命名空间的路由(from: Same)挂载。如需允许其他命名空间中的路由,请通过 allowedRoutes 更新 Gateway 监听器,并保留现有 Gateway 所需的其他监听器和设置:

gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: apisix
namespace: aic
spec:
gatewayClassName: apisix
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: tenant-a
infrastructure:
parametersRef:
group: apisix.apache.org
kind: GatewayProxy
name: apisix-config

使用不可变的命名空间名称标签,可避免有权修改普通标签的用户改变哪些命名空间可以挂载 Route。

将配置应用到集群:

kubectl apply -f gateway.yaml

你也可以配置 Gateway 监听器,允许来自所有命名空间的路由:

allowedRoutes:
namespaces:
from: All
警告

在多租户或不受信任的环境中使用 from: All,会允许任何命名空间将 HTTPRoute 资源挂载到该 Gateway 监听器。这可能导致不受信任的命名空间劫持流量,或暴露其无权访问的后端。

验证路由

将网关 Service 端口暴露到本地机器:

kubectl port-forward -n <gateway-service-namespace> \
svc/<gateway-service-name> 9080:80 &

向路由发送请求:

curl -i "http://127.0.0.1:9080/ip"

你应收到类似如下的 HTTP/1.1 200 OK 响应:

{
"origin": "127.0.0.1"
}

如果请求失败,请检查 Route 的 parent condition;AcceptedResolvedRefs 都应为 True

kubectl describe httproute httpbin-route -n tenant-a

允许 Gateway 引用 TLS Secret

Gateway 监听器使用另一命名空间中的证书 Secret 时,Secret 所有者必须授权该引用。例如,apisix Gateway 位于 aic,而 test-tls-secret Secret 位于 certificates,请在 certificates 中创建以下授权:

certificate-referencegrant.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-gateway-from-aic
namespace: certificates
spec:
from:
- group: gateway.networking.k8s.io
kind: Gateway
namespace: aic
to:
- group: ""
kind: Secret
name: test-tls-secret

更新 Gateway 前先应用授权:

kubectl apply -f certificate-referencegrant.yaml

然后在监听器的 certificateRefs 中写入 Secret 命名空间:

listeners:
- name: https
protocol: HTTPS
port: 443
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: test-tls-secret
namespace: certificates

应用 Gateway 后,验证 HTTPS 监听器报告 ResolvedRefs=True

kubectl describe gateway apisix -n aic

完整证书与 HTTPS Route 配置请参阅配置客户端与网关之间的 TLS

允许 Consumer 引用凭证 Secret

Consumer 与凭证 Secret 位于不同命名空间时,Secret 所有者必须授权该引用。请在应用或升级 Consumer 前创建 ReferenceGrant。启用准入 Webhook 时,缺少匹配授权会导致 Consumer 被拒绝;若 Consumer 未经授权仍被接纳,Controller 会报告 Available=False,且不会下发凭证。

创建 Consumer 与 Secret 命名空间:

kubectl create namespace consumer-ns
kubectl create namespace secret-ns

secret-ns 中创建 key-auth 凭证 Secret:

consumer-credential.yaml
apiVersion: v1
kind: Secret
metadata:
name: consumer-credentials
namespace: secret-ns
type: Opaque
stringData:
key: example-api-key

secret-ns 中创建 ReferenceGrant,允许 consumer-ns 中的 Consumer 引用该 Secret:

consumer-referencegrant.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: ReferenceGrant
metadata:
name: allow-consumers-from-consumer-ns
namespace: secret-ns
spec:
from:
- group: apisix.apache.org
kind: Consumer
namespace: consumer-ns
to:
- group: ""
kind: Secret
name: consumer-credentials

consumer-ns 中创建 Consumer。gatewayRef 指定要下发凭证的 Gateway:

consumer.yaml
apiVersion: apisix.apache.org/v1alpha1
kind: Consumer
metadata:
name: example-consumer
namespace: consumer-ns
spec:
gatewayRef:
name: apisix
namespace: aic
credentials:
- type: key-auth
name: primary-key
secretRef:
name: consumer-credentials
namespace: secret-ns

先应用 Secret 和授权,再应用 Consumer:

kubectl apply -f consumer-credential.yaml
kubectl apply -f consumer-referencegrant.yaml
kubectl apply -f consumer.yaml

等待 Consumer 报告凭证已成功下发:

kubectl wait --for=condition=Available \
consumers.apisix.apache.org/example-consumer \
-n consumer-ns \
--timeout=60s

若 condition 仍为 False,请检查消息,并确认授权中的 from.namespaceto.name 和 metadata namespace 与 Consumer 和 Secret 一致:

kubectl describe consumer example-consumer -n consumer-ns