オールアバウトTech Blog

株式会社オールアバウトのエンジニアブログです。

Cloud RunからCloud SQLやMemorystoreへの繋ぎ方

こんにちは!@y_hideshi です。

今回はCloud RunからCloud SQLやMemorystoreにつなぐ方法について紹介します。

  • Cloud SQLへの接続方法
  • Memorystoreへの接続方法

Cloud SQLへの接続方法

検証のため、phpMyAdminからCloud SQLにつなぐシンプルな構成のシステムを作ります。

f:id:allabout-techblog:20200629200338p:plain
Cloud Run - Cloud SQL

続きを読む

データ活用を推進しようとしているお話

はじめに

初めまして、オールアバウトの @akidukin(@Akidukin14) です。 この度上手く出来たら noteで公開しようと思っていた内容を 「自社のtechblogで書いてよー」と低めに脅された依頼されたので、気持ちよく執筆させていただくことにしました。

初めてTechBlogを執筆させていただきますので、簡単に私がどんな業務を担当しているのかを説明させて下さい。

興味が無い人は ## 何をしようとしているのかの説明 に飛んでください。(データサイエンティストとして仕事している人なんだなーって認識を持っていただけたら十分です。)

: @akidukin14 https://twitter.com/Akidukin14
出身 : 福岡
現所属 : 株式会社オールアバウト 開発部 マーケティング開発 データサイエンティスト

主な業務 :
【ちょっと前まで】

  • 広告配信に利用している機械学習の改善
  • 営業向け 資料の拡充
  • 広告配信のレポーティングの拡充 ... 等

【現在】

  • 株式会社オールアバウト全体にデータ活用やっていきましょうよー と話しまわっている(非公認)
  • 出てきた活用案をプロジェクト化して
    • PMしたり
    • 分析で実際に手を動かしたり
    • ダッシュボード作ってみたり
    • 機械学習のPoC回してみたり
    • 一般で利用できるようにツール化したり ... 等

今回は 【現在】主に対応している物についてご紹介しようと思います。

何をしようとしているのかの説明

タイトルの通り「株式会社オールアバウトの各部署のデータ活用を推進しよう」としています。

きっとこの記事を読んで頂いている方は
「会社としてデータ活用を推進していく共通意思があって進めているんだ...!!」
と思われるかもしれませんが、凄く雑に言うと 個人的に 暇だから やってみたいので進めています。

オールアバウトグループという単位でどんなサービスを運営しているかを簡単に説明します。

  • 株式会社オールアバウト : メディア運営 / タイアップ広告配信の運営
  • 株式会社オールアバウトライフマーケティング : ECサイト運営
  • 株式会社オールアバウトナビ : SNSを利用したエンタメ事業の運営
  • 日テレライフマーケティング株式会社 : ECとTV放送を連動させた事業の運営
  • 株式会社オールアバウトライフワークス : 講師育成や教室運営サービスの運営

様々なサービスの運営をしており、データアナリストやデータサイエンティストといったデータを触る方々からすると垂涎物な環境なのかなーって思います。
(違う業種違う情報 のデータが比較的豊富に取得できる点が)

今回、データ活用を推進しようとしているのは メディア運営 / タイアップ広告配信運営 の事業領域になります。

※...データ活用 : データソースの整理や掃除、から、実際にデータ分析 ~ 機能の提供 を対象のイメージとしております。

現在のデータ活用フェーズについて

そもそも、現在 株式会社オールアバウト ではデータの活用が全く進んでいないのかというと、そういうわけではありません。
メディア運営に於いてはGoogle Analyticsが社内にかなり浸透し各自でDataportal等を使っていたり、タイアップ広告配信ではTreasureDataにデータがたまっており、タイアップごとの効果測定等にもデータを利用してたりします。
ECサイトを運営しているオールアバウトライフマーケティングではRe:dashを利用して定常的に数値を追う環境もあったりします。

しかし、データの活用度合いが個人の知見に任せされていたり、情報の共有があまりされていなかったり、形骸的にデータを見るだけになっていたりしていました。
いくつかの業務の中では定量的ではなく定性的な判断をすることが常になっている業務、人の知見を元に判断をしている業務等がある。。。
というのが現在の 株式会社オールアバウト のデータ活用のフェーズになります。
イメージは伝わりますかね...??

現在のフェーズにおいて、実際に作業にあたっている方やその上司の方々は大なり小なり課題感は抱えており、今までその部分に介入する+出来る人的リソースが無かった というのが背景になります。

「あれ??これデータ活用進めたら、強力に売り上げ貢献とか利益貢献出来るんじゃね??」

f:id:allabout-techblog:20200528104258p:plain
イメージ

どう進めているのか

実際にどのようにデータ活用を推進しているのかという点について、説明させてください。
プロジェクトが動き始めたのが4月からでした。

基本的には

  1. 各グループの上長や担当者にデータを利用してやってみたい事をヒアリング
  2. データ環境の情報整理
  3. 優先順位付け、プロジェクト化
  4. 分析案や仮説のブレスト
  5. タスク化
  6. 分析作業及び報告

という流れで進めています。

元々各GMや担当者はデータに対しての理解度が高かったのですが、データを使って何が出来るか分からないという壁がありました。

そこで、テーマを「ドラえもん」に設定し、「あんなこっと良いな、出来たら良いな、不思議なデータで叶えてあっげっるー」という理想ドリブンでそれぞれやってみたい事をヒアリングしていきました。
この時、ooを解決したい!!みたいな形ではなく、ooがxxみたいになればいいのになー。という形でふんわりした内容を上げてもらって、それを詳細に詰めていくという導入から始めました。

やりたい事いっぱい出た。
中には「知見に基づいてやっている作業の自動化が出来たら凄く嬉しい。」等も出てきて狙い通りでした。

そして、出てきたものに対して、優先順位をつけ PO(プロジェクトオーナー) を付け、プロジェクト化を行いました。

その後、どういった分析をすれば実現できるのか、や、どういったデータを見れば示唆が出そうなのかのブレストを行い、タスクへ落とし込み、分析の作業に移ります。

データ活用するにあたって、壁になる事の一つに担当者と作業者間の期待値コントロールがあると思います。
正直最初は「理想ドリブンでプロジェクト立ち上げちゃったけど、期待値コントロールどうしよう...」と悩んでいました。
期待値が凄く実現性と離れた時は、ミーティング外での啓蒙活動やミーティング自体の開催頻度を上げて細かくOUTPUTを出しつつ期待値や結果を下げていく方向へ持っていこうと考えてたりしました。
が、そんな心配が具現することなく、思ってたより大丈夫だった(今後出て来るかもしれませんが...)

こうしたい未来のお話

まだ走り出したばかりで100年後も変わらず、こう思っているかと言われると自信は無いですが、、、

将来的には グループ会社全体でデータ活用なら @akidukin (または付随するその組織)に相談してみよう、となるのが理想です。
後はニーズをくみ取りながら、効果的な機能の提供を自発的に出来るようになるともっと嬉しい。企画 ~ 提供を一手に担える

受けた相談を元に実際にデータを見てみたり、分析してみたり、結果を元に改善案や何かしらの機能提供まで出来るようになったら良いです。みんな幸せHappy

上記のような理想に対してはまだまだ溝があり(始めたばかりなので当たり前ですが)、その溝を埋めるためにこんなロードマップを考えています。

  1. こちらからデータ活用についてのニーズのヒアリングを行い、プロジェクト化 <- イマココ
  2. プロジェクトに対して対応、及び改善案の提案や実施
  3. 良いor悪い影響の社内共有
  4. メディア運営 / タイアップ広告配信運営 以外の事業領域へデータ活用についてのニーズのヒアリング、プロジェクト化
  5. プロジェクトに対して対応、及び改善案の提案や実施
  6. 良いor悪い影響の社内共有
  7. ... ぐーるぐる回す
  8. ニーズの策定 + 企画立案 + 企画試行

まずは ご用聞き -> 誠実に対応 -> 正しく結果を共有 のサイクルを繰り返してデータを使う事の効果を知ってもらう (と同時にそれぞれの事業部で何をしているのかをより深く知る) その後、生まれそうなニーズや生まれたニーズを元に改善できそうな部分を考えていく。 という大まかな流れになるかなーと妄想しています。

きっとその間で、

  • 一緒に分析を進めてくれる人達のレベルアップとか
  • 一緒に実装を進めてくれる人達のレベルアップとか
  • どうやって膨大になっていくプロジェクトを適宜割り振っていくかとか
  • そうなるともっと人が必要になるよなーとか
  • 分析するマシンリソースがひっ迫してくるだろうから対応考えないと行けないよなーとか
  • 複雑になっていくデータリレーションをどう管理していけばいいのかなーとか
  • etc...

多分今考えている 5倍 ぐらいは出て来るとは思いますが、来る未来を想像しながらとりあえず目先の事を頑張る。

終わりに

改めて書き出してみるとあまり固まっていない事が判明して困惑しています。

今後進めていけるのであれば、より影響範囲は広めていきたいなー、色々なデータを触ってみたいなーとか思っています。が、
グループ会社を横断するって事を考えると、良く分からない大人の事情も出て来るだろうし、、、、
じゃあ提案をして改善していきましょう、ってなったときのステークホルダーとの折衝とか、、、、

まあ未来を悲観してもしょうがないので、今は目先の事をちゃんとこなしていく事にしています。

その辺り、もし同様の経験をされた方がいらっしゃったらお話お聞きしてみたい...

拙い文章でしたが、ここまで読んでいただいてありがとうございました。
随時、経過とか得られた知見とかアウトプットしていきたいなーと思っているので、よろしくお願いします!

Cloud RunとGCPの他サービスを使って簡単なシステムを作ってみました

こんにちは!オールアバウト の @y_hideshiです。

今回は、昨年GA(General Availability)された Cloud RunGCPの各種サービスを連携させて簡単なシステムを構築、その際に得られた知見を記事にしたいと思います。

  • 作成したシステム
  • Cloud Run について
    • Cloud Runへのデプロイ
      • Webからのデプロイ
      • gloudコマンドによるデプロイ
    • 設定値について
    • Cloud Run:まとめ
  • 関連サービスを利用することによるメリット
    • Cloud Build
      • GCR、Cloud Runへのデプロイをするための認証をなるべく手軽に済ませたい
      • プロジェクトが変わってもすぐにデプロイしやすいようにしたい
    • Cloud Pub/Sub
    • Cloud Scheduler
  • 所感

作成したシステム

今回作成したシステムは「GCP確約利用割引の期日を定期的にチェックして、期日の近いものをslackに通知する」というものです。

GCP確約利用割引は1年間または3年間の支払いを確約する代わりに、特定の量のvCPU、メモリ、GPU、ローカルSSDを割引価格で利用できる仕組みです

f:id:allabout-techblog:20200420213645p:plain
作成したシステム構成

使用したサービス

※ 今回は連携するサービスの詳細については触れませんが、各サービスごとの採用理由やメリットなどを解説して行きたいと思います。

続きを読む

1ヶ月以上 在宅勤務を続けた弊社エンジニアのアンケート結果を発表します!

オールアバウトエンジニアの在宅勤務アンケート結果発表

こんにちは!オールアバウトでデータエンジニアをしている@ondaljhです。

新型コロナウィルスの影響で在宅勤務を実施している企業も多いと思います。オールアバウトグループも3月初めから在宅勤務を実施したので、実施から1か月以上になりました。
今回はオールアバウトのエンジニア達に在宅勤務による業務環境変化等をアンケートしたのでその結果を発表させていただきます!

業務関連

1.在宅勤務になってから打ち合わせの数はどう変わりましたか?

f:id:allabout-techblog:20200422162741p:plain

2.自身が開催する打ち合わせの場合、使用するツールはslackとzoom、どちらをより多く使用しますか?

f:id:allabout-techblog:20200423151351p:plain

その他を選んでいただいた方の中では下記のような意見もありましたー

  • 社外の打ち合わせはZoom、それ以外はHangout使っています

2-1.質問2で選んでいただいた項目について、その理由を教えてください

※回答からいくつか抜粋

  • Slack派

    • slackの方が常に見ているのでそっちの方が開きやすいため
    • 少人数の打ち合わせが多いため、わざわざZoomで部屋を作る必要性を感じないため。また、Zoomはセキュリティが心配&Slackのほうが画面共有時の書き込みが自由にできるので。
    • Zoomだと40分の制限があるため
  • Zoom派

    • 背景を変更できるから
    • slackよりもzoomの方が軽い気がするから
  • どっちでも良い派

    • 30分以内、3名ぐらいまではSlack。3名以上30分以上ならZoomでやっています
    • MTGによって定着している、選び直すなら安定性を感じるZoom
    • どっちでもよいので気分次第。
  • その他

    • Slackは参加者固定の打ち合わせなら会議作るのが楽だけど、定例等のスケジュールを自動化できないのがつらいため。カレンダーベースでスケジュールできるHangoutが比較的楽だと思いました。

3.割り込み作業の数はどう変わりましたか?

例えば、急な問い合わせや調査依頼、予定されていなかった打ち合わせなど、当日のスケジュールに含まれていなかった作業の増減について教えてください

f:id:allabout-techblog:20200422163008p:plain

3-1. 質問3の傾向についてご意見又は感想を聞かせてください

※回答からいくつか抜粋

  • 減った
    • うれしい。
    • 口頭で質問しにくる人が減ったから。また、ある程度情報をまとめてきてから相談してくれるので、以前よりも進めやすい
    • 通話をつなぎながらの作業が増えたので、割り込みで中断するというケースが少なくなりました。個人的には集中できて良いと思っています。
  • 変わらない
    • 業務のボリュームは変わらず。問い合わせが多いです。
    • 自分の業務的には問い合わせ等はオフライン・オンライン関係ないのが多いから
  • 増えた
    • たぶん、増えたのは、在宅だからではなくコロナ対応のせいです(コーポレートサイト担当なので、コロナ関連のお知らせで、突発サポート業務が増えています)。

4.気軽な相談の数はどう変わりましたか?

f:id:allabout-techblog:20200422163044p:plain

4-1. 質問4の傾向についてご意見又は感想を聞かせてください

※回答からいくつか抜粋

  • 減った
    • 気軽に聞けないのでまずは自分で調べるようになった
    • 口頭で質問しにくる人が減ったから。また、ある程度情報をまとめてきてから相談してくれるので、以前よりも進めやすい
    • ただの雑談や通りすがりの雑談が出来ないのは長期的にはマイナスになる。
    • 相談なしで進んでしまうと手戻りが増えやすいので、極力減らさないようにしたいと思っています。が、相手の方がオフラインだと「今日はお休みなのかな?」と思ってしまい、なかなか気軽には声をかけにくいです。
  • 変わらない
    • 相談する側であることが多いのですが、Slackのテキストベースで基本的にはやりとりするので、言語化のクオリティがお互いに上がりディスコミュニケーションが減ったような気がしています。
    • slackで気軽に連絡が取れる
    • 以前と変わらない感じで気軽に相談をするようにしているので、その辺りのハードルは高くない
  • 増えた
    • DMでのこれどうしたらいい?が増えました

5.業務への集中度の変化はありましたか?

f:id:allabout-techblog:20200422163108p:plain

5-1. 質問5の傾向についてご意見又は感想を聞かせてください

※回答からいくつか抜粋

  • 集中しやすくなった側
    • モブプロ中は余計なものが入り込まなくなって集中しやすくなった
    • マイペースで働けるようになったからある意味集中度もあがったと思う
  • 変わらない
    • 最初は個人作業は集中しやすかったのですが、その分カレンダーやSlackの通知に敏感になり、結果総合的に見ると在宅じゃないときとあまり変わらないと感じました
    • 特に在宅だからといって変わりはない
    • 特に変わらない。気軽に気分転換にお散歩に行けるようになったぐらい
    • 業務後もすぐ業務に戻れるため、公私の区別が付かなくなりがち。結果、緊張感が間延びしつつある。ただ、まとまった時間が取れるのは非常に助かる。
  • 集中し辛くなった側
    • 環境が整っていなかったので、仕事をする際の姿勢による負荷などであまり集中できていなかった
    • 自宅前の緑地で毎日子供が遊んでいる&隣のおうちに赤ちゃんがいるので、とにかく毎日騒音が……その間は、正直集中しづらいです。が、静かな時は、会社にいる時よりも集中しやすくなったと思います。
    • 会社での作業は集中したいときにイアホンで音楽聞いてのですがいまは、寂しくて集中できないです。

6.ペアプロ・モブプロを行っていた方も多いと思いますが、在宅勤務になってからどのようにやっているか教えてください

※回答からいくつか抜粋

  • 全員で通話し、約1時間くらいで休憩し、そのタイミングでドライバーも変更
  • slackの画面共有またはvscodeのliveshare
  • 基本モブプロですが、個人作業の場合もチーム内で分担してやる場合が多いので、通話をつなぎながら作業しています。
  • 朝からずっとSlack通話繋ぎっぱなしです。

業務外

7.出退勤の電車に乗らなくなった分、余裕時間が増えたと思いますが、どのように活用してますか? (複数選択可)

f:id:allabout-techblog:20200422163125p:plain

8.今後、新型コロナウィルスの影響が弱くなり、出社可能となった場合、在宅勤務をどの程度の頻度でやりたいと思いますか?

f:id:allabout-techblog:20200422163136p:plain

9.在宅勤務をする上で工夫している・気を付けていることがありましたら教えてください

※記述式回答でしたが、関連性があるものが多かったので、関連性軸で出してます

  • 作業環境整備
    • ディスプレイを追加
    • 集中するための騒音対策。(音楽を聴きながら仕事をすると集中できないので)ホワイトノイズや環境音をスピーカーから流して、集中しやすいようにしています。
    • ポモドーロタイマーの導入
  • 心構え
    • 会社に行く時と同様に身だしなみを整えるとスイッチが入る
    • MTG時は事前のフォローと事後のフォローを一層手厚くする
    • 朝起きたらとりあえず着替える、コーヒーを飲むなど出勤する感を出してます
  • その他
    • 休憩時間に筋トレをする
    • 夜は散歩に出るようにしています。
    • 同居人に仕事中だとわかるようにする。
    • 定期的に換気をする

10.在宅勤務のメリットを教えてください

※記述式回答でしたが、通勤関連の方が圧倒的に多かったので、通勤関連は別軸で出してます

  • 通勤関連
    • 出勤電車に乗らなくて済むのは結構いいこと。出勤電車による疲労が減った。
    • これまで通勤時間という無駄な時間を浪費していたことを実感
    • 出勤/退勤時間がいらない
    • 無駄時間の削減(通勤)
    • 通勤ストレスが減る。割り込みが減る。お昼代も減って経済的に優しい
    • 通勤時間の有効活用
    • 通勤時間が無くなる
    • 電車通勤しなくてよくなる
    • 通話をきったら即、帰宅できること
  • その他
    • 晩ごはんを早い時間に食べられる(すごく大きいです)
    • 宅配の荷物が受け取れる
    • 部屋がどんどん綺麗になっていきます。
    • 睡眠時間が増える
    • 割り込み作業が減ったことで、まとまった時間の確保しやすくなった
    • リラックスできる
    • 自分のベストな環境で仕事ができるところ。

11.在宅勤務のデメリットを教えてください

※記述式回答でしたが、関連性があるものが多かったので、関連性軸で出してます

  • 作業環境関連
    • (全員が)自宅の仕事環境を整えるのが手間、面倒
    • 通信インフラなどが個人環境に依存すること(品質悪い人とはビデオ会議は無理)"
    • 寂しい、インターネットの速度・安定しないとつらい
  • ダイレクトコミュニケーションロス関連
    • 同僚たちを物理的に会える機会が減ること
    • 人とのコミュニケーションを撮る機会が減るので、入社してから信頼関係を構築していきたい人にとっては大変な気がします。また、一緒にコンビニに行ったりしたり、雑談ベースでの相談をする機会が減ってしまう。外に出ないのであしこしが貧弱になっていきます。
    • ほかプロジェクトの方に、気軽な相談がしにくい
    • 作業内容が見えづらい
    • 画面越しでは表情が分かりづらい
    • 表情などの視覚情報から状況を察し難い
  • 体調関連
    • 運動不足
    • 明らかに運動不足になることです。通勤の往復2時間がどれだけいい運動だったか思い知らされました。
    • 肩こりが悪化した
  • その他
    • 会社帰属意識の希薄化
    • リラックスしすぎる
    • 出勤・退勤の移動時間が無いのと、人の目が無いせいなのか、つい仕事しすぎてしまうところ
    • だらだら仕事になりがち
    • 電車に乗れない

まとめ

如何でしたか?今回はオールアバウトのエンジニアの声をそのまま伝えたくてアンケート結果には一切コメントなしでありのままをお伝えしました。
が、個人的な感想を最後に書かせていただきますと下記の3つぐらいかなーと思いました。

  • 睡眠時間が増えた、の結果が多い → みな、普段の睡眠時間が足りてなかったなー
  • 業務への集中度が変わらない、の結果が多い → 昔からリモートワークをやれるように環境を少しずつ整備してきた結果だなー
  • 今後の在宅勤務想定頻度の結果を見ると、今後在宅勤務は日常的なことになる気がするー

今の状況が一日でも早く終息して時には仲間と直接おしゃべりしながら、また時には在宅勤務で、自分たちが仕事しやすい環境で自由に仕事ができるようになってほしいですね。

閲覧ありがとうございました!今後ともよろしくお願いいたします。

Firebase における IP アドレス制限・カスタム認証について

f:id:allabout-techblog:20200324101558p:plain

先週に続き、オールアバウトの新卒1年目エンジニアが投稿する企画「テックブログ新卒週間2020」を開催します。本記事の執筆者 okutan です。よろしくお願いします。

目次

はじめに

業務でリアルタイム掲示板を Firebase で開発することになりました。
そのシステムの技術選定や試作品開発にあたり、Firebase のドキュメントや関連記事は充実していましたが、調査・検証に時間を要した点がいくつかありました。

そこで、本記事では Firebase を利用する際、時間がかかった調査結果の共有を目的として、

  1. Firebase Hosting における IP アドレス制限
  2. Firebase Authentication のカスタム認証

の使用例を示したいと思います。

本記事によって Firebase の採用を考えている方のお役に立てれば幸いです。
また、Firebase に興味がある方へ布教ができれば嬉しいです。

開発した リアルタイム掲示板のシステム構成図

今回開発したリアルタイム掲示板のシステム構成図です。
本記事では、この図における 1. IP アドレス制限2. カスタム認証 について共有します。

f:id:allabout-techblog:20200330092312p:plainリアルタイム掲示板のシステム構成図

1. Firebase Hosting における IP アドレス制限

Firebase Hosting 自体に IP アドレス制限の機能はありません。
そのため、Firebase Hosting に対する特定ファイルパスへのリクエストを Cloud Functions for Firebase に送信するよう設定し、受信した関数内でクライアント IP アドレスに基づいて静的ファイルを返すことで IP アドレス制限を実現できます。

この方法について、いくつかの注意点と共に示していきます。

Hosting へのリクエストを Functions に送る

まず、 IP アドレス制限を行える Cloud Functions for Firebase から静的ファイルを配信するために、Firebase Hosting の特定ファイルパスへのリクエストを Functions に送るようホスティング動作を設定します。
ホスティング動作は firebase.json1 で設定することが可能なので、その例を示します。

  • 管理画面の URL における //index.html へのリクエストを関数 adminIndexHtml に送信する firebase.json の設定例
{
    "hosting": {
        ...
        "rewrites": [ 
            {
                "source": "/@(|index.html)",
                "function": "adminIndexHtml"
            }
        ],
        ...
    },
... 

この設定についての説明をしていきます。

まず、 "hosting": で firebase プロジェクトにおける Firebase Hosting のホスティング動作を設定しています。
その中で "rewrites": ルール2を用いて、 "source: " に対するリクエストを "functions" に送るようにしています。
"source": は glob パターンマッチング3で指定されるため /@(|index.html) はファイルパス / または /index.html を表しており、これらに対するリクエストを、関数 adminIndexHtml に送るよう機能します。4

ここでの注意点は 2 つあります。

1つは、IP アドレス制限を行う関数 adminIndexHtml のリージョンは us-central1 にする必要があることです。これは Firebase Hosting と Cloud Functions の接続がこのリージョンしか対応していないためです。5
ただ、Cloud Functions for Firebase では関数単位でリージョンの選択ができるため、他の関数は別のリージョンにデプロイすることができます。6

もう一つは、

Firebase Hosting は、指定された source にファイルまたはディレクトリが存在しない場合にのみリライトルールを適用します。ルールがトリガーされると、ブラウザは HTTP リダイレクトではなく、指定された destination ファイルの実際のコンテンツを返します。

と記載があるように 、URL で指定されたファイルパスが実際に存在した場合、そのファイルが関数 adminIndexHtml から配信されません。
つまり、 IP アドレス制限を行いたい静的ファイル( index.html など)は Firebase Hosting から削除し、 Cloud Function for Firebase からのレスポンスでのみ配信する必要があります。
このことから、多くの静的ファイルに対して IP アドレス制限を適用する必要がある場合、 Firebase Hosting を使うことは現実的ではないと考えられます。

Functions におけるクライアント IP アドレス取得

まず、結論から示しますと、 Hosting から受信した Functions におけるクライアント IP アドレスを取得するプログラムは、私の場合、次のようになりました。

  • Firebase Hosting から受信した Cloud Functions for Firebase における IP アドレス取得 (Node.js)
const functions = require("firebase-functions");

exports.adminIndexHtml = functions.https.onRequest((req, res) => {
    const client_ip = req.headers["fastly-temp-xff"]
        .split(",")
        .pop()
        .trim();
...

このプログラムから分かるように、 HTTP ヘッダーの fastly-temp-xff 末尾から IP アドレスを取得しています。
この形式になった過程を説明していきます。

まず、IP アドレスは HTTP ヘッダーから取得できると考え、Hosting 経由の関数におけるヘッダーの中身を次に示すプログラムで確認してみました。

  • 関数 adminIndexHtml で HTTP ヘッダー内容を確認する
const functions = require("firebase-functions");

exports.adminIndexHtml = functions.https.onRequest((req, res) => {
    console.log(req.headers);
    res.send("ログ出力を Firebase コンソールで確認する");
});
  • 上記ログ出力から一部抜粋 ( IP アドレスは XXX.XXX.XXX.XXX, YYY.YYY.YYY.YYY で表現)
{
    ...
    "cdn-loop": "Fastly, Fastly",
    "fastly-client": "1",
    "fastly-client-ip": "XXX.XXX.XXX.XXX",
    "fastly-temp-xff": "XXX.XXX.XXX.XXX, XXX.XXX.XXX.XXX",
    ...
    "x-appengine-user-ip": "YYY.YYY.YYY.YYY",
    ...
    "x-forwarded-for": "XXX.XXX.XXX.XXX,YYY.YYY.YYY.YYY",
    ...
}

XXX.XXX.XXX.XXX が今回取得したいクライアント IP アドレスでした。
ログの出力結果から、 HTTP ヘッダーの fastly-client-ip, fastly-temp-xff, x-forwarded-for のいずれかから取得できることがわかります。

また、 Firebase Hosting の CDNFastly を用いているのでしょうか?
Fastly のドキュメントには、 fastly-client-ip はクライアント IP アドレスであると記載されています7

ただ、IP アドレスの偽装が可能なのか検証してみたところ、 x-forwarded-for の IP アドレスに加えて、 fastly-client-ip も偽装することができてしまいました。取得したい IP アドレスが含まれた HTTP ヘッダーの中で fastly-temp-xff のみ、(セキュリティの知識が全くない私には)偽装ができませんでした。

したがって、クライアント IP アドレスの取得は先に示したプログラムの様に fastly-temp-xff から取得する形式にしましたが、 fastly-temp-xff についての調査が不十分で安定して機能するかが私には現状分かっていないため、IP アドレス制限ができなければ致命的な問題が発生する機能・製品に対しては、認証機能を実装する必要があると考えます。

ちなみに、Node.js のモジュール request-ip を使用して IP アドレスを取得した場合、 X-Client-IP, X-Forwarded-For, fastly-client-ip から取得される可能性が高く8、 IP アドレスの偽装に対応できないため注意が必要だと考えられます。

それと、Firebase のドキュメントにある別の文脈でのやり方では req.connection.remoteAddress で IP アドレスしていましたが9、今回の様に Hosting 経由の関数である場合、取得したいクライアント IP アドレスではありませんでした。

Functions からクライアントに静的ファイルを配信する

IP アドレス制限をして配信したい静的ファイルを index.html として、 Cloud Functions for Firebase からクライアントに配信する方法を説明していきます。

まず前述の通り、Hosting からは index.html を配信しないよう削除する必要があります。削除しない場合、 Functions へリクエストが送信されないため、 IP アドレス制限が機能しません。

次に、削除した index.html を Functions のプロジェクトへ下記のように配置し、 IP アドレス制限を通過したリクエストに対してのみ配信するよう実装します。

f:id:allabout-techblog:20200330092308p:plain

  • 関数 adminIndexHtml で IP アドレス制限を行い index.html を配信する
const functions = require("firebase-functions");
const fs = require("fs");

exports.adminIndexHtml = functions.https.onRequest((req, res) => {
    const allowed_ips = ["XXX.XXX.XXX.XXX"];
    const client_ip = req.headers["fastly-temp-xff"]
        .split(",")
        .pop()
        .trim();
    const is_allowed = allowed_ips.indexOf(client_ip) !== -1;
    let html = "";
    let status = 0;
    if (is_allowed) {
        html = fs.readFileSync("./admin/index.html").toString();
        status = 200;
    } else {
        html = "";
        status = 403;
    }
    res.status(status).send(html);
});

以上の方法で index.html に対して IP アドレス制限をかけることが可能になります。
また、これらの実装を拡張することで、任意の静的ファイルに対して IP アドレス制限を行うことが可能になると考えられます。

2. Firebase Authentication と独自認証基盤の連携

なぜ Authentication に独自の認証基盤を連携したか?

理由は独自の認証基盤によるユーザーの認証状態を、 Cloud Functions for Firebase などを経由させることなく、 Firebase Realtime Database で検証するために連携しました。

今回開発したリアルタイム掲示板では、クライアントユーザーを自社がもつ認証基盤を用いて認証する必要がありました。

ただ、リアルタイム掲示板の DB は Firebase Realtime Database を使用し、クライアントから直接参照することでその恩恵10を得たかったため、セキュリティルール11で認証状態を検証する必要がありました。

そこで、Firebase Authentication と自社の認証基盤を連携させることで、セキュリティルールにおいて自社の認証基盤を用いた認証状態の検証を実現することができるため、連携を行いました。

連携方法

Firebase のドキュメント12を参考に、認証基盤において認証完了後に Firebase Authentication 用の JWT を発行するような API を実装し、 この API で返す JWT のクレーム iss に、認証基盤におけるユーザーIDを設定することで、 Firebase Authentication のユーザーIDと 認証基盤のユーザーIDを紐づけられます。

また、リアルタイム掲示板で表示するニックネームなども Firebase Authentication のカスタムクレームに保存ができ、セキュリティルールにも適用可能です。(ただし 1,000 Byte 以下)13

ただし、独自の認証基盤からクライアントに JWT を送信するには CORS を使用したレスポンスを認証基盤に実装する必要があるかと思います。

以上の方法で Firebase Authentication と独自認証基盤を連携させることが可能になります。

おわりに

本記事では、 Firebase における IP アドレス制限と独自認証基盤との連携について、調査結果・使用例を示しました。

IP アドレス制限は、 Firebase Hosting に IP アドレス制限の機能がないため、 Hosting に対する特定静的ファイルへのアクセスを Cloud Function for Firebase に送信し、受信した関数内でクライアント IP アドレスに基づいて静的ファイルを配信するよう設定することにより実現しました。
ただ、クライアントIPアドレスを取得する実装には不確定要素があるため注意が必要です。

独自の認証基盤との連携は、認証基盤に Firebase Authentication 用の JWT を返す実装をすることにより実現しました。 JWT のクレーム sub に認証基盤におけるユーザーIDを設定することで、Firebase Authentication におけるユーザーIDと認証基盤のユーザーIDを紐付けています。