Microservices的なシステムを作ると、IngressがNamespaceを跨げないことが問題となることがある。
ExternalNameを活用するなどすれば跨げなくもないのだが、セキュリティ的に問題となることもあるらしい。
そのため別のNamespaceのServiceを参照したい、というニーズに応えるために、Gateway APIではReferencePolicyというリソースが用意され、これを使うとHTTPRouteが別のNamespaceのServiceを参照できるようになる。

(ReferenceGrantより引用)
今回はReferencePolicyの動作を確認するために、前回検証したnginxとhttbinのNamespaceを変えて以下のような構成で意図通りに通信できるかを検証する。

なお、検証は前回の環境を使い回すため、クラスタの準備やGateway API、Gateway Controllerの導入は終わっているところからスタートする。
ReferenceGrantの概要
ReferenceGrantは名前の通り参照権限を与えるためのリソースであり、Namespaceをまたいだ場合の各種リソースの権限を管理する。
仕様はこちらにあるが、実物を見た方がわかりやすいので以下サンプルを示す。
kind: ReferenceGrant
metadata:
name: bar
namespace: bar
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: foo
to:
- group: ""
kind: Service
spec.fromで権限をリクエストする側を指定し、spec.toで参照先を指定する。
リソース名やNamespace名などもここで細かく指定することが出来、権限の付与に関して細かく設定できるようになっている。
なお、ここではHTTPRouteのためにReferenceGrantを使っているが、ストレージ(PVC)に適用した事例もあるため、ネットワークに限らず様々なリソースに応用することも出来そうだ。
参考:CNDT 2022、日立のエンジニアによるKubernetesに新機能をマージした経験を語るセッション
検証
最初に検証用のnginxを起動する。
kubectl create ns demo-back
kubectl run nginx --image nginx --port 80 -n demo-back
kubectl expose pod nginx --port 80 -n demo-back
httpbinをつなぐServiceを作成する。
kubectl create ns demo-external
kubectl create svc externalname httpbin --external-name httpbin.org -n demo-external
Gatewayリソースを作成する。
kubectl create ns demo-front
cat <<EOF | kubectl apply -n demo-front -f -
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
spec:
gatewayClassName: kong
listeners:
- name: http
port: 80
protocol: HTTP
EOF
HTTPRouteを作成する。
PROXY_IP=$(kubectl get gateway gateway -n demo -o jsonpath={.status.addresses[].value})
export HOSTNAME="my-service.$(sed "s/\./-/g" <<< $PROXY_IP).nip.io"
cat <<EOF | kubectl apply -n demo-front -f -
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: route
annotations:
konghq.com/strip-path: 'true'
spec:
hostnames:
- $HOSTNAME
parentRefs:
- name: gateway
rules:
- matches:
- path:
type: PathPrefix
value: /service
backendRefs:
- name: nginx
kind: Service
namespace: demo-back
port: 80
weight: 50
- name: httpbin
kind: Service
namespace: demo-external
port: 80
weight: 50
EOF
前回との違いとして、backendRefs内のService指定時にnamespaceも指定するようにした。
この状態だとまだReferenceGrantがないため、参照する権限がない。
試しにサービスのエンドポイントにアクセスしても、"no existing backendRef provided"と怒られてしまう。
$ curl my-service.192-168-64-202.nip.io/service
{"message":"no existing backendRef provided"}
ここでReferenceGrantを適用してみる。まずはnginxのServiceにのみ適用する。
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: nginx-grant
namespace: demo-back
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: demo-front
to:
- group: ""
kind: Service
EOF
この状態でエンドポイントにアクセスすると、nginxへのアクセスのみ発生する。
$ curl my-service.192-168-64-202.nip.io/service
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
:(省略)
httpbin側の方も許可を与える。
cat <<EOF | kubectl apply -f -
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: httpbin-grant
namespace: demo-external
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: demo-front
to:
- group: ""
kind: Service
EOF
こうすると、nginx, httpbinそれぞれにアクセスするようになる。
$ curl my-service.192-168-64-202.nip.io/service
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>httpbin.org</title>
:(省略)
適切に参照権限が与えられることが確認できた。