entry-header-eye-catch.html
entry-title-container.html

entry-header-author-info.html
Article by

GCLBに実装されたHTTPSリダイレクト機能を使ってみました

メディア・プロモーション事業部でpixivの広告配信システムを開発しているあやぬんです。

今回pixivの広告システムで利用しているGCPのロードバランサ(以下GCLB)で待望のHTTPS・URLリダイレクト機能が4/14にGA1となったので、本番環境・開発環境へ導入した方法を紹介します。

従来のGCLBに対する課題

今までGCLBはHTTPおよびHTTPSのバックエンドサービスに対して、ただトラフィックを流すだけで、リダイレクトの機能はありませんでした。

Google Issue Trackerには2015年からHTTPSリダイレクトの要望が上がっており世界中のユーザーが待ち望んでいました。 https://issuetracker.google.com/issues/35904733

HTTPSリダイレクトを自分で実装する場合は内部でNginxを起動させてリダイレクトをさせるか、アプリケーション側でリダイレクトをする処理を埋め込む他なかったため非常にコストが高い作業となっていました。

GCLBにおけるHTTPSリダイレクトの仕組み

f:id:pxvpxv:20200508105954p:plain
図 1. GCLB における HTTPS リダイレクト(https://cloud.google.com/load-balancing/docs/https/setting-up-traffic-management#http-to-https-redirect より引用)

HTTPSリダイレクトには以下の2つの役割をもつロードバランサを定義することで実現を行なっています。

  1. 80ポートに来るHTTPトラフィックを受け取って301などのリダイレクトをするレスポンスを返すロードバランサ(図1上側)
  2. 443ポートに来るHTTPSトラフィックを受け取ってアプリケーションに流すロードバランサ(図1下側)

今回のポイントは「80ポートに来るHTTPトラフィックを受け取って302などを返すLB」です。 HTTPのリクエストは全てこのロードバランサへ流すようにします。 これまではHTTPトラフィックをバックエンドサーバーで処理していましたが、ロードバランサ側でトラフィックをリダイレクトすることにより、アプリケーションの負荷を下げることができます。 さらにアプリケーションに繋がるロードバランサでHTTPトラフィックを許可しなくてもよくなるのでアプリケーション自体のセキュリティを高めることができます。

このように2つのロードバランサを作ることによって今までに構築したロードバランサに手を入れることなくHTTPSリダイレクト機能を使えることも大きいですね。

gcloudコマンドを使ってHTTPSリダイレクトをする

httpのリダイレクト用の設定ファイルをつくる

今回はサンプルとして https-redirect というurl-mapを作成するので、そのための設定ファイルを作成します。

yamlとして書くと以下のようになります。

kind: compute#urlMap
name: https-redirect
defaultUrlRedirect:
  redirectResponseCode: "MOVED_PERMANENTLY_DEFAULT"
  httpsRedirect: True

compute#urlMap リソースにはGCLBのurl-mapに関する全ての設定を記述できます。 HTTPSリダイレクトを行うには defaultUrlRedirect という設定を追加することで利用が可能です。

defaultUrlRedirect にはリダイレクトをするときのResponseCodeを指定するredirectResponseCode とHTTPSリダイレクトをするかどうかを決めるhttpsRedirect という項目があります。 httpsRedirectはHTTPSリダイレクトをさせたいので今回固定でtrue にします。

redirectResponseCode は以下のものから選ぶことができます。 この項目を指定しなかった場合のデフォルトは MOVED_PERMANENTLY_DEFAULT(301)です。

  1. FOUND
  2. MOVED_PERMANENTLY_DEFAULT
  3. PERMANENT_REDIRECT
  4. SEE_OTHER
  5. TEMPORARY_REDIRECT

上記で作成したyamlをもとにURL Mapを作成する

gcloud compute url-maps import コマンドを使って先ほど作った設定ファイルを基にしたurl-mapを作成します。

ここで指定するurl-mapの名前はyamlで指定したnameと同じものを指定してください。

gcloud compute url-maps import https-redirect \
  --source path/to/設定ファイル.yaml \
  --global

target-http-proxiesを作る

forwarding-rulesとurl-mapsをつなぐためのtarget-http-proxiesを cloud compute target-http-proxies create コマンドを使って作ります。 今回は例として http-lb-proxyという名前にしてあります。

gcloud compute target-http-proxies create http-lb-proxy \
  --url-map=https-redirect \
  --global

リダイレクトさせるIPアドレスを指定する

実際にHTTPSへリダイレクトさせるIPアドレスをgcloud compute forwarding-rules createコマンドを使って、先ほど作ったtarget-http-proxiesに紐付けます。 名前はtest-app-forwarding-rules としましょう。 ここでHTTPのトラフィックを受け付けるため、--portsに80番を指定します。

このforwarding-rulesは複数紐付けることができるので1つ作るだけで全てのサイトに対応させることができます。

このコマンドを実行する前には必ず静的IPアドレスの予約をしておいてください。

gcloud compute forwarding-rules create test-app-forwarding-rules \
  --target-http-proxy=http-lb-proxy \
  --address=[取得した静的IPアドレスの名前] \
  --ports=80 \
  --global

確認

指定したIPアドレスに紐付いているドメインへHTTPでリクエストするとHTTPSにリダイレクトされていることが確認できました。

Terraformを使う

今まで読んできた人には自動化のために毎回コマンドを叩かないといけないのか…みたいな気持ちになった人がいるかと思いますが、Terraformを使ってHTTPSリダイレクトのロードバランサを作ることができます。

Terraformのバージョンは2020/04/30現在の最新であるv0.12.24を使っています。

TerraformでHTTPSリダイレクトを構成するには Terraform Google Provider 3.20 以上のバージョンが必要です。

Terraformのコードを書く

基本的なコードの構成や手順はgcloud コマンドを使う時と同じです。

まずTerraformのproviderを定義します。

provider "google" {
  version = ">= 3.20.0"
  project = "test-project"
}

google-beta のproviderでは先ほどファイルを移動した時に指定したバージョンを指定してください。

静的IPアドレスを作る

google_compute_global_address を使って静的IPアドレスを予約します。

resource "google_compute_global_address" "default" {
  name = "test-address"
}

url-mapを作る

url-mapはgoogle_compute_url_map というリソースで作成できます。 google_compute_url_mapには default_url_redirect というブロックがあるのでここにリダイレクトの設定を書いていきます。

redirect_response_code の設定はgcloudコマンドの時と同じものです。

ここではgoogle-beta のproviderを使用するため、provider = google-beta を追加してください。

resource "google_compute_url_map" "default" {
  name = "https-redirect"
  default_url_redirect {
    redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
    https_redirect         = true
  }
}

target-proxyを作る

google_compute_target_http_proxy というリソースを使ってtarget-proxyを作ります。 url_map には先ほど作ったgoogle_compute_url_map リソースのself linkを指定します。

resource "google_compute_target_http_proxy" "default" {
  name     = "https-redirect-proxy"
  url_map  = google_compute_url_map.default.self_link
}

forwarding-ruleを作る

forwarding-ruleはgoogle_compute_global_forwarding_ruleリソースを用いて作成します。 targetにはgoogle_compute_target_http_proxy のself linkを、ip_addressにはgoogle_compute_global_address のself linkを指定します。

HTTPのトラフィックを受け付けるため、port_rangeに80番を指定します。

resource "google_compute_global_forwarding_rule" "default" {
  name       = "website-forwarding-rule"
  target     = google_compute_target_http_proxy.default.self_link
  ip_address = google_compute_global_address.default.address
  port_range = "80"
}

terrafrom apply をする

実際にできたTerraformのコードはこのようになりました。

provider "google" {
  version = ">= 3.20.0"
  project = "test-project"
}

resource "google_compute_global_address" "default" {
  name = "test-address"
}

resource "google_compute_global_forwarding_rule" "default" {
  name       = "website-forwarding-rule"
  target     = google_compute_target_http_proxy.default.self_link
  ip_address = google_compute_global_address.default.address
  port_range = "80"
}

resource "google_compute_target_http_proxy" "default" {
  name     = "https-redirect-proxy"
  url_map  = google_compute_url_map.default.self_link
}

resource "google_compute_url_map" "default" {
  name = "https-redirect"
  default_url_redirect {
    redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
    https_redirect         = true
  }
}

これをファイルに保存し、terraform applyを実行することでHTTPSリダイレクトを行うロードバランサが作成されます。

リージョナルのロードバランサを作りたい場合

リージョナルのロードバランサを作りたい場合は以下のように書き換えると動いてくれます。

- resource "google_compute_global_address" "default" {
+ resource "google_compute_address" "default" {
    name   = "test-address"
+   region = "us-central1"
  }

- resource "google_compute_global_forwarding_rule" "default" {
+ resource "google_compute_forwarding_rule" "default" {
    name       = "website-forwarding-rule"
-   target     = google_compute_target_http_proxy.default.self_link
-   ip_address = google_compute_global_address.default.address
+   target     = google_compute_region_target_http_proxy.default.self_link
+   ip_address = google_compute_address.default.address
    port_range = "80"
+   region     = "us-central1"
  }

- resource "google_compute_target_http_proxy" "default" {
+ resource "google_compute_region_target_http_proxy" "default" {
    name     = "https-redirect-proxy"
-   url_map  = google_compute_url_map.default.self_link
+   url_map  = google_compute_region_url_map.default.self_link
+   region   = "us-central1"
  }

- resource "google_compute_url_map" "default" {
+ resource "google_compute_region_url_map" "default" {
    name   = "https-redirect"
+   region = "us-central1"
    default_url_redirect {
      redirect_response_code = "MOVED_PERMANENTLY_DEFAULT"
      https_redirect         = true
    }
  }

まとめ

pixivの広告配信システムではこのHTTPSリダイレクト機能を無停止で本番環境・開発環境を共に導入できました。 すでに動いているロードバランサを書き換えることなくHTTPSリダイレクトの機能を使えるよう設計されていたので本番のプロダクトに全く影響なく導入ができて感動しています。

GCLBにはHTTPSリダイレクトの他にもURLリダイレクトやURL rewriteなどの機能があります。より詳しく知りたい方は https://cloud.google.com/load-balancing/docs/https/setting-up-traffic-management を参考にすると良いでしょう。

広告開発チームではGCPの能力を無限に引き出せるエンジニアを募集しています。ここまで読んだあなたはきっとGCPがチョットデキルはずなのでご応募お待ちしております。

https://recruit.jobcan.jp/pixiv/show/b001/191659

https://www.wantedly.com/projects/123095

icon
あやぬん
広告のインフラ・バックエンドをやっています。主にgolangやKubernetesのyamlを書いたりしていますが、フロントエンドやAndroidアプリも書きます。好きなものはKawaii Future Bassです。