🔀

GKE Gateway controller の新機能を試してみた HTTP リダイレクト, SSL ポリシー, Cloud Armor 編

2023/08/09に公開

こんにちは。クラウドエースの阿部です。
こちらの記事では、2023年4月11日に追加された Gateway controller の新機能について紹介します。

概要

2023年4月11日に、 GKE の Gateway controller に以下の機能が追加されました。

  • GKE Autopilot が Gateway API に対応 (GKE バージョン 1.26以降)
  • グローバルアプリケーションロードバランサ(旧称グローバル HTTP(S) ロードバランサ、Classic では無い方)の GatewayClass が GA
  • gke-l7-rilb GatewayClass (内部アプリケーションロードバランサ) のグローバルアクセス設定の追加
  • SSL ポリシーの構成
  • HTTP から HTTPS へのリダイレクトの構成
  • Cloud Armor 連携

本記事ではこのうち、「SSL ポリシーの構成」「HTTP から HTTPS へのリダイレクトの構成」「Cloud Armor 連携」の3つについて具体的なサンプルを交えて説明していきます。

GKE Gateway controller (Gateway API) って何?という方は、下記のブログ記事もご一読ください。

https://zenn.dev/cloud_ace/articles/255ccf620f7707

環境準備

Google Cloud リソース作成

Terraform で構築できます。実行には Terraform CLI と gcloud CLI が必要です。また、後述の検証で kubectl コマンドが必要になります。
下記のバージョンで動作確認しています。なお、2023年8月8日時点の Cloud Shell に、 Terraform CLI と gcloud CLI 、kubectl が導入済みであることを確認しています。

コマンド バージョン
terraform 1.5.4
gcloud 441.0.0
kubectl 1.27.4

上記確認の上、ターミナルから下記のコマンドを実行してサンプルコードをダウンロードしてください。

git clone https://github.com/cloud-ace/zenn-gke-gateway-policy-sample
cd zenn-gke-gateway-policy-sample/terraform

次に、下記のコマンドを実行し、サンプル環境を作成します。
export TF_VAR_project_id=XXXXXXXXXXXX 箇所は、使用可能なプロジェクトIDを入力してください。
terraform apply 実行後に Enter a value: が表示されたら、 yes と入力しEnterキーを押してください。

export TF_VAR_project_id=XXXXXX
terraform init
terraform apply

以下のような図のリソースが一通り作成されます。

Resource Diagram

ポイントとして、Gateway 設定で使用するグローバルアドレスやFQDN、Google Managed 証明書も Terraform で用意しているところです。FQDNは gke-gateway-********.endpoints.PROJECT_ID.cloud.goog の形式で作成されます。※********の部分はランダムな文字列、PROJECT_IDの部分はプロジェクトID
その他、主な作成リソースは下記の表の通りです。

作成リソース リソース名 ロケーション
VPC ネットワーク gke-gtw-test グローバル
サブネットワーク gke-gtw-test asia-northeast1
Cloud NAT gke-gtw-test-nat asia-northeast1
グローバルアドレス gke-gtw-test-lb グローバル
Cloud Endpoints ※前述のFQDN グローバル
マネージド証明書 gke-gtw-test-cert グローバル
SSL ポリシー gke-gtw-test-policy グローバル
Cloud Armor gke-gtw-test-security-policy グローバル
GKE クラスタ gke-gtw-test asia-northeast1

共通で使用する Kubernetes オブジェクト

GKE クラスタや関連リソースの作成が完了しましたら、 Deployment や Service といった今回検証に使用する Kubernetes オブジェクトを作成します。実行には kubectl コマンドが必要です。
先ほどのコマンドラインのカレントディレクトリ terraform から、 kubernetes ディレクトリに移動します。

cd ../kubernetes

その後、 base ディレクトリにある設定を投入します。

kubectl apply -f base

上記コマンドを実行すると、下記のオブジェクトが作成されます。
投入するYAMLファイルは、公式ドキュメントで紹介されているサンプルコードを流用しています。

Kubernetes オブジェクト オブジェクト名
Namespace gateway-infra
Deployment store-v1
Deployment store-v2
Deployment store-german
Service store-v1
Service store-v2
Service store-german

下記コマンドを実行して、上記リソースが作成されたことを確認します。

kubectl get ns
kubectl get deployment
kubectl get service

kubectl get ns

NAME              STATUS   AGE
default           Active   26m
gateway-infra     Active   6s
gmp-public        Active   25m
gmp-system        Active   25m
kube-node-lease   Active   26m
kube-public       Active   26m
kube-system       Active   26m

kubectl get deployment

NAME           READY   UP-TO-DATE   AVAILABLE   AGE
store-german   2/2     2            2           2m36s
store-v1       2/2     2            2           2m37s
store-v2       2/2     2            2           2m37s

kubectl get service

NAME           TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
kubernetes     ClusterIP   10.12.0.1     <none>        443/TCP    29m
store-german   ClusterIP   10.12.11.45   <none>        8080/TCP   2m58s
store-v1       ClusterIP   10.12.5.216   <none>        8080/TCP   2m59s
store-v2       ClusterIP   10.12.8.114   <none>        8080/TCP   2m58s

HTTP から HTTPS へのリダイレクト設定

HTTP から HTTPS へのリダイレクト設定(以降、HTTP リダイレクトと記述)は、アプリケーションロードバランサ(HTTP(S)ロードバランサ)にある機能をGateway APIで設定する機能です。

検証

以下のコマンドを実行することで、サンプル設定を投入することができます。

kubectl apply -f http_redirect

※設定を入れてから通信が有効になるまで10分程度時間がかかることがあります。

実際の動作を確認するときは、以下のコマンドを実行しましょう。

curl -i http://gke-gateway-********.endpoints.PROJECT_ID.cloud.goog

以下のように、レスポンスコードがリダイレクトを示す 302 Found になり、Location ヘッダにより転送先のURLが表示されます。

HTTP/1.1 302 Found
Cache-Control: private
Location: https://gke-gateway-********.endpoints.PROJECT_ID.cloud.goog:443/
Content-Length: 0
Date: Tue, 08 Aug 2023 09:48:17 GMT
Content-Type: text/html; charset=UTF-8

設定のポイント

なお、HTTP リダイレクト設定のポイントは、以下の箇所にあります。

https://github.com/cloud-ace/zenn-gke-gateway-policy-sample/blob/main/kubernetes/http_redirect/gateway.yaml#L9-L19

この部分を読んで頂くと、わざわざ protocolHTTP である通信の HTTPRoute 設定を許可する Namespace を otherInfra: httpToHttps というラベルが付与された箇所にのみ限定しています。
この設定は公式ドキュメントの「インフラストラクチャ名前空間からの HTTP トラフィックをリダイレクトする」の説明にある方法をとっています。
何故このような設定が必要かについて、ドキュメント上はアプリケーションチームが誤って HTTPRoute を設定しないようにすることだけ言及されていますが、実際は HTTPS リスナーと HTTP リスナーの HTTPRoute 設定が同じ名前空間上に存在すると、HTTP リダイレクト設定が優先されず、 通常の HTTPRoute 設定で HTTP の通信がバックエンドアプリケーションに通ってしまうためです。
そのため、ドキュメントにあるように、バックエンドサービスへの HTTPRoute 設定と、 HTTP リダイレクトの HTTPRoute 設定は別の名前空間にして、 Gateway 設定でも、余計な HTTPRoute を読み込まないように名前空間を限定する必要があります。

クリーンアップ

次の検証に移る前に、以下のコマンドでHTTPリダイレクトの設定を掃除してください。

kubectl delete -f http_redirect

SSL ポリシーの構成

SSL ポリシーは、こちらのドキュメントで説明されている、アプリケーションロードバランサや外部プロキシロードバランサ(SSLプロキシ)のTLSバージョンや暗号スイートのプロファイルを指定する機能です。この機能により、クライアント・サーバ双方で厳格なTLS通信方式を要求することができ、セキュリティが向上します。

検証

以下のコマンドを実行することで、サンプル設定を投入することができます。

kubectl apply -f ssl_policy

※設定を入れてから通信が有効になるまで10分程度時間がかかることがあります。

Terraformで事前に作成した SSL ポリシーは、 TLSv1.2以上、かつ、RESTRICTED プロファイルを設定しています。そのため、TLSのバージョンが1.1以下の場合は通信エラーになるはずです。

実際の動作を確認するときは、以下のように --tlsv1.1 --tls-max 1.1 オプションを付けて実行しましょう。このオプションを付けることで、 curl のTLSネゴシエーションはバージョン1.1で実行されます。なお、--tlsv1.1 --tls-max 1.1 オプションは curl のバージョンにより実装されていない場合があります。 Cloud Shell の curl バージョンは実装されていました。

curl --tlsv1.1 --tls-max 1.1 https://gke-gateway-********.endpoints.PROJECT_ID.cloud.goog

以下のような結果になるはずです。

curl: (35) error:1409442E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version

curlコマンドの --tlsv1.1 --tls-max 1.1 オプションを外すとTLSネゴシエーションのエラーは発生しません。
これにより、適切に SSL ポリシーが実装されていることが確認できました。

設定のポイント

SSL ポリシーの設定は特に難しいことはなく、事前に SSL ポリシーリソースを作成しておくこと、および、GCPGatewayPolicy オブジェクトの sslPolicy の設定で SSL ポリシー名を指定することがポイントになるでしょう。また、ドキュメントの制限事項にも記載されている通り、 GCPGatewayPolicy を連携させる Gateway オブジェクトは同じ名前空間に設定する必要があります。

https://github.com/cloud-ace/zenn-gke-gateway-policy-sample/blob/main/kubernetes/ssl_policy/ssl_policy.yaml

クリーンアップ

次の検証に移る前に、以下のコマンドで SSL ポリシーの設定を掃除してください。

kubectl delete -f ssl_policy

Cloud Armor 連携

Cloud Armor は、アプリケーションロードバランサに付与することでIPアドレス等に基づく通信制限を行うファイアウォールです。IPアドレスによる制限だけでなく、URIやロケーション、リクエストヘッダ等のクライアント属性に基づく高度な設定が可能であり、さらに、SQLインジェクションやXSSといった代表的な攻撃手法に対する防御も備えるWAF機能も備えています。

検証

Terraformで、以下のような制限を行っている Cloud Armor ポリシーを作成しています。

  • リクエストヘッダに x-secret-key: SECRET を含んでいる場合は許可
  • それ以外は拒否

以下のコマンドを実行することで、サンプル設定を投入することができます。

kubectl apply -f cloud_armor

※設定を入れてから通信が有効になるまで10分程度時間がかかることがあります。

今回の設定では、 store-v1 Service のみ Cloud Armor を設定しているため、 store-v2 Service のパスである /v2store-german Service のパスである /de にアクセスした場合は許可されます。

実際の動作を確認するときは、以下のコマンドを実行しましょう。

curl http://gke-gateway-********.endpoints.PROJECT_ID.cloud.goog

以下のような結果になるはずです。

<!doctype html><meta charset="utf-8"><meta name=viewport content="width=device-width, initial-scale=1"><title>403</title>403 Forbidden

次に、 x-secret-key: SECRET ヘッダを付けて実行してみます。

curl -H "x-secret-key: SECRET" http://gke-gateway-********.endpoints.PROJECT_ID.cloud.goog

この場合は、以下のようにアプリケーションのレスポンスが表示されます。

{"cluster_name":"gke-gtw-test","gce_instance_id":"**********","gce_service_account":"PROJECT_ID.svc.id.goog","host_header":"gke-gateway-********.endpoints.PROJECT_ID.cloud.goog","metadata":"store-v1","pod_name":"store-v1-869587c84c-psdvh","pod_name_emoji":"\ud83d\udc68\ud83c\udffd\u200d\ud83e\udd1d\u200d\ud83d\udc68\ud83c\udffc","project_id":"********","timestamp":"2023-08-08T10:30:51","zone":"asia-northeast1-a"}

この結果から、アプリケーションのアクセスは Cloud Armor で制御されていることが確認できました。

設定のポイント

Cloud Armor 連携の設定は、 Service オブジェクトに対して行う必要があり、かつ、 GCPBackendPolicy と、設定対象の Service オブジェクトは同じ名前空間に存在する必要があります。Service オブジェクトが Google Cloud のロードバランサにおけるバックエンドサービスに対応していると考えると分かりやすいのではないかと思います。

https://github.com/cloud-ace/zenn-gke-gateway-policy-sample/blob/main/kubernetes/cloud_armor/cloud_armor.yaml

クリーンアップ

以下のコマンドで Cloud Armor 連携の設定を掃除してください。

kubectl delete -f cloud_armor

環境クリーンアップ

一通り検証が完了したら、以下のコマンドを順番に実行してリソースを削除します。

Kubernetes オブジェクトの削除

kubectl delete -f base

Google Cloud リソースの削除

cd ../terraform
terraform destroy

注意事項

残念ながら、 GKE Gateway controller が作成したリソースが残存しているために terraform destroy コマンドが失敗することがあります。その場合は、以下のリソースが残存していないかを確認して個別に削除する必要があります。

  • バックエンドサービス
  • ネットワークエンドポイントグループ
  • ファイアウォールルール

まとめ

2023年4月11日に追加された GKE Gateway controller の機能について紹介しました。
Gateway API は、ポリシーというオブジェクトを利用することでプラットフォーム固有の設定を追加できるため、今後も Gateway に様々な機能が追加されていくと思います。このあたりは、 Ingress では難しかった拡張機能だと思います。
2023年7月10日にも機能追加されていますので、次回はこの時点で追加された機能に焦点を当てて紹介したいと思います。

Discussion