LoginSignup
1
1

More than 3 years have passed since last update.

GoogleAppEngineでサーバをSSL化する

Last updated at Posted at 2018-10-14

概要

ReverseProxyをGAEで作成すると、既設のサーバを簡単にSSL対応にできる。
ここでいう簡単とは...
- サーバ証明書取得が不要
- httpサーバ(nginx/apache)の設定が不要
- (GCP上にプロジェクトを作成して)30分程度あればSSL化可能

経緯

Androidアプリを作成するチームから下記の困りごとを相談された。
「Android Pでアプリの動作確認をしていたら評価用サーバとの接続に問題が生じた。商用サーバでは問題ないんだけど...」

ここで、商用サーバはSSL化済み。評価用サーバは非SSL。

原因

Android P で TLS のデフォルト化によるユーザー保護

上記のページに記載されている通り、Android PではアプリがアクセスするサイトがSSLでない場合、アクセスを拒否する模様。これはアプリが使用するWeb上のAPIだけでなくWebViewに表示するコンテンツも対象になる模様?

もちろん回避方法はあるけど、せっかく商用サーバがSSL化しているのに評価用サーバが非SSLのままなのはよろしくない。じゃ評価用サーバもサーバ証明書を取得するかというと事務手続きも面倒だ。費用がかかるなら決済も必要だし...

対策

GAEでReverse Proxyを立てることにした。
GCP上にプロジェクトを作って下記の2つのファイルを用意しデプロイするだけ。

app.yaml

runtime: go112

handlers:
  - url: /.*
    script: auto
    secure: always

main.go

package main

import (
    "context"
    "log"
    "net/http"
    "net/http/httputil"
    "os"
)

// TargetHost はhttps化する対象のホスト
var TargetHost = "your.host"

type myTransport struct {
    Transport http.RoundTripper
    Context   context.Context
}

func main() {
    http.HandleFunc("/", handleFunc)

    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
        log.Printf("Defaulting to port %s", port)
    }

    log.Printf("Listening on port %s", port)
    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal(err)
    }
}

func handleFunc(w http.ResponseWriter, r *http.Request) {
    ctx := context.Background()

    director := func(request *http.Request) {
        request.URL.Scheme = "http"
        request.URL.Host = TargetHost
    }
    client := http.DefaultClient
    transport := &myTransport{
        Transport: client.Transport,
        Context:   ctx,
    }
    rp := &httputil.ReverseProxy{
        Director:  director,
        Transport: transport,
    }
    rp.ServeHTTP(w, r)
}

func (t *myTransport) transport() http.RoundTripper {
    if t.Transport == nil {
        return http.DefaultTransport
    }
    return t.Transport
}

func (t *myTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    return t.transport().RoundTrip(req)
}

main.go内のTargetHostに対象のhttpサイトを指定する。

以下のコマンドでデプロイ

gcloud app deploy --project [project-id]

上記のデプロイが完了したらブラウザに"https://[project-id].appspot.com"を入力してSSL化できているか確認する。
なお、プロジェクトの課金設定を変更して「非課金」にしても評価目的であれば耐えられるはず。

タイトルに「GoogleAppEngineでサーバをSSL化する」とか書いちゃったけど、主な対象としてはグローバルIPだけ取得して、ドメイン取得していない評価用サーバ等になります。
Web上のAPIなら上記で問題ないと思いますが、WebViewに表示するコンテンツの場合、追加でリンクを適切に修正しないといけないですね。

更新

2020/08/18
元々 Go1.9(appengine 1st gen)用に書いていたコードをGo1.12(appengine 2nd gen)用に改めました。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1