DoiT Internationalでクラウド全般のご支援をしていると、よく話題に上るテーマがいくつかあります。なかでも、前職時代から私につきまとってきた質問がこちらです。
「GKEの(デフォルトの)GCLB Ingressコントローラーで、HTTPトラフィックをHTTPSにリダイレクトする正しい方法は?」
これまでは、リダイレクト専用のバックエンドを別途用意するといった回避策をご提案するか、GCLBの高度なトラフィック管理機能を持たないサードパーティ製のIngressソリューションに頼るしかありませんでした。
ところが、Google CloudがGKE Ingressロードバランサーでのリダイレクトをネイティブサポートしたことで、状況は大きく変わりました。
本記事では次の点を取り上げます。
- これがなぜ画期的なのか
- これを活用してInfrastructure as Codeの運用をどのようにシンプル化できるか
Photo by Jamie Street on Unsplash
なぜ重要なのか
暗号化されていないHTTPは、もはや過去のものになりつつあります。AWSやGCPといったクラウドプラットフォームの無料証明書サービスに加え、Let's Encrypt、ZeroSSL、BuyPass Go SSLなどの独立系プロバイダーも揃っている今、本番環境のフロントエンドロードバランサーでTLSを使わない理由はどこにもありません。
むしろ興味深いのは、ポート80をどう扱うか(あるいは扱わないか)という点です。ポートを閉じておき、ブラウザが次にポート443でTLSを試すのに任せる、という選択もあります。ただしこの方法は不要な遅延を招きますし、サイトを指す完全修飾のhttpリンクがどこかに紛れ込んでいれば、エラーページが表示されてしまいます。ブラウザがTLS接続を優先するようになり、さらに細かな調整ができるブラウザ拡張機能もあるとはいえ、ポート80を開けておく意義はあります。加えて、TLS接続を強制する仕組みとしてHTTP Strict Transport SecurityやUpgrade Insecure Requests宣言の存在も忘れてはなりません。
ただし、ブラウザがこれらのディレクティブを認識するには、最低でも一度はダウンロードする必要があります。ブラウザにあらかじめハードコードされたhstsアドレスという限られたグループに含まれていない限り、これは避けられません。TLSが計算負荷をほぼ上乗せしなくなった現在、同じコンテンツを暗号化版と非暗号化版の両方で提供する理由はなく、むしろ避けるべき理由はいくつもあります。
多くのユースケースで望ましいのは、HTTPからHTTPSへのHTTPステータス301または308によるリダイレクトです。では、ローカルな小細工や追加のインフラ管理に頼らず、Kubernetesでこれをスマートに実現する方法はあるのでしょうか。
Kubernetes IngressでのHTTPSリダイレクト
HTTPポートからのリダイレクトは、本来Ingressコントローラーが担うべき仕事です。Ingress仕様の初期ベータ版ではingress.kubernetes.io/ssl-redirectというアノテーションに言及がありましたが、実際の実装は各コントローラー固有のカスタムアノテーションを通じてようやく広まっていきました。
定番のnginx Ingressコントローラーは、TLSが有効ならデフォルトでリダイレクトを行います。一方Google Cloudでは、GKEのデフォルトIngressコントローラーingress-gceがGCLBロードバランサーを利用しています。GCLB自体は非常に優秀なのですが、HTTPからHTTPSへのリダイレクトには長らく対応していませんでした。これがついに、HTTPトラフィック管理におけるリダイレクトサポートの導入で解消されました。とはいえ、Ingress宣言の内側からこれを利用する方法は依然として用意されておらず、数多くの小細工や回避策、そして落胆を生み出していたのです。
そう、これまでは。🎉
対応するGKEバージョン
以下で紹介する手法が公式にサポートされるのはKubernetes 1.18.10-gke.600以降ですが、現在提供されている1.17.x-gke系でも動作します。stableリリースチャネルをお使いの場合は、クラスターを1.17系にアップグレードすることで利用可能になりますし、regularやrapidチャネルであれば任意のバージョンで利用できます。
執筆時点で対応しているGKEバージョン
GKE IngressのSSLリダイレクト対応:FrontendConfig
そしてついに、GKEがHTTPSリダイレクトをネイティブにサポートしました。実装にはFrontendConfig CRDが用いられます(ちなみに、このCRDはSSLポリシーの管理にも使われます)。
リダイレクト時のHTTPステータスコードは5種類から選択できます。
以下はステータス308(恒久的リダイレクト)を使用した例です。
apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
name: my-frontend-config
spec:
redirectToHttps:
enabled: true
responseCodeName: PERMANENT_REDIRECT
このFrontendConfigリソースとIngressオブジェクトの紐付けは、Ingress宣言のアノテーションキーnetworking.gke.io/v1beta1.FrontendConfigを通じて行います。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
networking.gke.io/v1beta1.FrontendConfig: "my-frontend-config"
...
これを動作させるにはv1beta1のapiVersionを指定する必要がある点にご注意ください。今後、非ベータ版にもサポートが広がる見込みなので、将来のクラスターアップグレードに備えて宣言の内容をチェックしておくとよいでしょう。
より完全な動作例をGitHubで公開しています。この機能の設定方法の詳細は、GoogleのIngress Features公式ドキュメントをご覧ください。
関連情報
- Ingress Featuresに関するGCP公式ドキュメント:HTTPSリダイレクト
- DoiT InternationalのGitHubで公開しているサンプルプロジェクト