GKE Gateway controller の新機能を試してみた HTTP リダイレクト, SSL ポリシー, Cloud Armor 編
こんにちは。クラウドエースの阿部です。
こちらの記事では、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) って何?という方は、下記のブログ記事もご一読ください。
環境準備
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=XXXXXX
の XXXXXX
箇所は、使用可能なプロジェクトIDを入力してください。
terraform apply
実行後に Enter a value:
が表示されたら、 yes
と入力しEnterキーを押してください。
export TF_VAR_project_id=XXXXXX
terraform init
terraform apply
以下のような図のリソースが一通り作成されます。
ポイントとして、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 リダイレクト設定のポイントは、以下の箇所にあります。
この部分を読んで頂くと、わざわざ protocol
が HTTP
である通信の 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 オブジェクトは同じ名前空間に設定する必要があります。
クリーンアップ
次の検証に移る前に、以下のコマンドで 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 のパスである /v2
、 store-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 のロードバランサにおけるバックエンドサービスに対応していると考えると分かりやすいのではないかと思います。
クリーンアップ
以下のコマンドで 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