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>
:(省略)
適切に参照権限が与えられることが確認できた。