配置跨命名空间引用
跨命名空间引用让平台团队可以运营共享 Gateway、后端和 Secret,同时让应用团队管理各自的 Route 与 Consumer。Gateway API 要求在每一道命名空间边界上显式授权,避免在一个命名空间创建资源就自动获得另一团队资源的访问权。
不同关系所需的授权如下:
| 关系 | 授权方式 |
|---|---|
| Route 引用另一命名空间的 Gateway | Gateway 监听器通过 allowedRoutes 选择 Route 所在命名空间。 |
| Route 引用另一命名空间的后端 | 后端命名空间中的 ReferenceGrant 允许该 Route 引用。 |
| Gateway 引用另一命名空间的 TLS Secret | Secret 命名空间中的 ReferenceGrant 允许该 Gateway 引用。 |
Consumer 引用另一命名空间的凭证 Secret | Secret 命名空间中的 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:
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:
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 资源。
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 所需的其他监听器和设置:
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;Accepted 与 ResolvedRefs 都应为 True:
kubectl describe httproute httpbin-route -n tenant-a
允许 Gateway 引用 TLS Secret
Gateway 监听器使用另一命名空间中的证书 Secret 时,Secret 所有者必须授权该引用。例如,apisix Gateway 位于 aic,而 test-tls-secret Secret 位于 certificates,请在 certificates 中创建以下授权:
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:
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:
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:
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.namespace、to.name 和 metadata namespace 与 Consumer 和 Secret 一致:
kubectl describe consumer example-consumer -n consumer-ns