自分用Cloud9をSSL化して、oauth2_proxyで自分だけの認証を追加した

この記事では、SSH使うから認証は後回しで、って書いてたんだけど、それじゃあChromebookで気軽にお遊びができないことに気づいたので、結局SSL化と認証を追加した。

ドメイン取得&SSL

certbot(Let's encrypt)を使うには、TXTレコードやCNAMEレコードをイジる必要があるので、しぶしぶ c9work.net というドメインを購入。(胡散臭いキャンペーンとか嫌いなので、AWS経由で購入した)

証明書の取得は

letsencrypt.org

にあるように、certbotで行う。

  • Cloud9 IDEを表示するURL(hogehoge.ide.c9work.net)
  • 成果物を誰かに見せる用のURL(hogehoge.preview.c9work.net)
  • 認証用その他もろもろのページのURL(auth.c9work.net, page.c9work.net, ...)

の3つを想定していたので、雑にワイルドカード証明書を3つ。

sudo certbot certonly --manual --manual-public-ip-logging-ok -d *.preview.c9work.net -m ore_ore@yahoo.co.jp
sudo certbot certonly --manual --manual-public-ip-logging-ok -d *.ide.c9work.net -m ore_ore@yahoo.co.jp
sudo certbot certonly --manual --manual-public-ip-logging-ok -d *.c9work.net -m ore_ore@yahoo.co.jp

みたいな感じで。

都度、TXTレコードに確認用文字列を入れる、みたいなことはやる必要があったけど、そこはRoute53なりAzure DNSなりで管理してたらなんの問題もなくいける。

前段にGitHub認証を入れる

これが結構つまった。(ひとえに、nginxのAuth Requestを知らなかったからなんだけどw)

SSL化をした時点で、

f:id:YusukeIwaki:20190722171647p:plain

なんとなくこんな感じに、nginx二段構えにしていた。なので、認証はとりあえずSSLオフロードをやってる前段のnginxに何かしらやればいいんだろうなーと。Cloud9 SDK自身も、なんとなく認証っぽい仕組みは内部で持っていそう( core/auth.js at master · c9/core · GitHub )だったんだけど、SSLオフロードした先に認証機構があるのはちょっと筋が悪い気がした、なのでnginxかその前段に持たせようかなと。

んで、CW社の偉大なる同期が昔書いていた記事も参考に、

qiita.com

これはとりあえずoauth2_proxyをAuth Requestと組み合わせて使えばラクかなと。

認証エンドポイントと認証した先に戻るURLでドメインが違うのをなんとかする

手っ取り早くウェブアプリケーションにOAuth2認証を導入する - その手の平は尻もつかめるさ あたりを参考にするとわかりやすいんだけど、oauth2_proxyは /oauth2/start?rd=/return_back_to/this/address のようにパスを渡すと、認証完了後に /return_back_to/this/address に帰ってきてくれる。

今回の場合は、

と想像していた。が、現実はそうはいかず。 https://auth.c9work.net/ にリダイレクトされてしまった。

oauth2_proxyのソースをみたら、「あーー」ってなんたんだけど

https://github.com/pusher/oauth2_proxy/blob/863539154366f456d8ba57142b3a66b4544fda82/oauthproxy.go#L477-L483

redirect = req.Form.Get("rd")
if !p.IsValidRedirect(redirect) {
    redirect = req.URL.Path
    if strings.HasPrefix(redirect, p.ProxyPrefix) {
        redirect = "/"
    }
}

をチェックして、NGだったら強制的に / に書き換えられてしまっているではありませんかー!

OAUTH2_PROXY_EMAIL_DOMAINS に .ide.c9work.net を設定すると解決。

GitHubユーザをYusukeIwakiに限定する

これも結構ハマった。

本当は前段の認証側でどうにかしたかったんだけど、nginx.confの記述方法わからなすぎたので、

  • 前段の認証ではGitHubユーザだったらとりあえず通すようにする
    • バックのnginxにリクエストを渡すときに X-Remote-Username というカスタムヘッダにGitHubユーザ名を渡す
  • バックに居るコンテナ振り分けをやるnginxのほうで、GitHubユーザ名が YusukeIwaki じゃなかったら強制的に403を返すようにする

という雑な方法で実現。

        location / {
            auth_request /oauth2/auth;
            error_page 401 = /oauth2/start?rd=https:///$host$request_url;

            proxy_set_header X-Forwarded-Scheme $http_x_forwarded_proto;
            proxy_set_header Host $host;
            auth_request_set $user $upstream_http_x_auth_request_user;  # ←認証完了時に、oauth_proxy2 がX-Auth-Request-UserヘッダにGitHubユーザ名をセットしてくれるのを拾う。
            proxy_set_header X-Remote-Username $user;  # ←nginx_backにリクエストをプロキシするときに、 X-Remote-Usernameというカスタムヘッダを付ける
            proxy_pass http://nginx_back:8888;
        }
    server {
        listen             8888;
          (中略)

        if ($http_x_remote_username != 'YusukeIwaki') {
            return 403;
        }

たぶんもっといいやり方はあるんだろうなぁ...。

そんなわけで

Chromebookでも開発をできるようになった。

うぇいうぇい