RM-BLOG

IT系技術職のおっさんがIT技術とかライブとか日常とか雑多に語るブログです。* 本ブログに書かれている内容は個人の意見・感想であり、特定の組織に属するものではありません。/All opinions are my own.*

【GCP】ひなっちのおはっちのサイトをリメイクした話・続

はじめに

このブログの続き。主に「残課題」として記載した内容の対応状況について。

Staging環境がおっぴろげになってる件

App Engine Firewallルールについて(前編)

ブログにも書いた通り、 今までGCPのプロジェクトを1つでやりくりしていたのだが、この問題の対応のため、「テスト用のプロジェクト」を1つ用意する必要が出てきた。
ということで意を決してテスト用のプロジェクトを1個別に用意。
これによりApp EngineのFirewallルールが存分に使えるようになり、Staging環境を俺んちのみに閉じることに成功した。

成功したのだが、後述するCloudflareへキャッシュさせるにあたって、結果的にこれはちょっと用途が別になった。
一応、ここでは、GAEに直接アクセスするケースにおいて、自分トコのIPを設定して、「それ以外からのアクセスを防御することに成功した」ことに関する記録として載せておく。
ひとまず、このときは以下のような設定にした。

優先度10~100に許可するIP(v4、v6)を個別に指定して、1000~1100に全IPを拒否する設定を追加。
これにより許可IP以外はアクセスできない環境ができあがった。
なお、拒否IPでアクセスすると403 Forbiddenが返ってくる。(そういう仕様っぽい)

ちょっと自分でも勘違いしていたのが、IPv6の存在。
我が家のWiFiでアクセスすると、PCでもiPhoneでもIPv4は同じだが、IPv6はそれぞれ異なるIPが採番されるうえに、繋ぐたびにアドレスが変わる。
これは単に俺知らなかったというだけで、そもそもそういう仕様っぽい
IPv4のように決め打ちで設定ができそうにないので、少し困った。
このサイトとかこのサイトで自宅のグローバルIPv6のCIDRを調べて、とりあえずそのCIDRを設定したところ。
ただ、このCIDRが「うちに割り振られているグローバルIP」のものなのか「契約しているプロバイダーのもの」なのかはぶっちゃけ俺もわかってないので、仮に後者だとすると、同じプロバイダを契約している別の人も見れる可能性はある(IPv4のほうで拒否られそうではあるが)。
一応、Wifi切って、スマホのキャリア回線でアクセスしたときには、拒否られたのは確認済で、Wifi繋いでる時には自宅の機器から接続できることも確認済。
個人のテスト環境隠蔽程度ならこんなもんでいいやと思うことにした。

余談だが、現状考えている若干の不満点として、強いて言うなら、CloudflareのFirewallルールみたいに、「一時的に無効化」みたいのが出来ないことが挙げられる。
作成後に優先順位の変更が出来ないというのも融通性を欠いている。
例えば旅行先から確認したいといった場合に、そういうことができない不便さがある。
まあそうなったら旅行先でIP調べて優先順位1とかで一時的に登録しちまえばよさそうだし(用が済んだら消せばいい)やろうと思えば運用回避できなくはない…か。
そんな需要がどこまでありそうなのか自分でもよくわかってないので、そうなったときに考えればいいかと思うことにしている。

Deploy経路の変更

Staging環境が別のプロジェクトになったことで、そっちへのdeploy経路の確立が必要になった。
元々は下記の絵にもある通りCloud Build Triggerで拾ってて、これのやり方は既に心得ているので、テスト用のプロジェクトにもCloud Build Triggerを用意すれば基本的にはそれで終わりだった。

だったのだが、なんとなく個人的な好奇心でGithub Actionsを使ってみたくなった。
そもそも、システムの構成要素の一つであるCloud Functionsは、未だにGithub Actionsでdeployしてるし、リメイク前のFirebaseもGithub Actionsでdeployしてたのに、GAEになった途端にCloud Buildになったというのが、今更ながら違和感はあった。
あと、Cloud Buildは、回数を重ねると結構費用がかさむのだ。
Github Actionsの場合、Private Repoでも月2000分までは無料=日換算で1日約65分前後までは無料の計算になるので、Github Actions使う方がコスト的に安いと判断した。
というわけでGithub Actionsによるdeployをstaging及び本番環境両方に確立させ、早くもCloud Buildと縁を切った。w
結果的にはこんなイメージになった。

やってみたら意外に簡単だった。
実際、他でもやってることだし、Github ActionsのワークフローYAMLファイルを書くのはそこまで難しくない。
これ今回改めて思ったけど、感覚的にはDockerfile書いてるのに近いなと思う。(実際Actionsのフローはコンテナ上で動いてるんだろうけど)
ググれば出てくるけど、核となるのはgoogle-github-actions/deploy-appengineを使う事である。
これのオプションに色々渡すことでgcloud app deployコマンドを実行できるというわけだ。(というかgcloud app deployを実行するためのイメージだ)
GCP相手だとむしろPermission関連で躓くことのほうが多い。
本番側は既に存在するService Accountなので苦なくいけたが、今回新たに作ったテスト用のプロジェクトはそういうService Account自体存在しなかったので、まずそれを作って、必要なロールを付与して、、、って感じで2~3回リトライして成功した。
ロールの厳密性は厄介である。

テスト環境へのデータ移行

プロジェクトが分離したことで、テスト環境にはテスト環境用のFirestoreを用意する必要が出てきた。
一応Google Cloudが出しているFirestoreのデータ移行に関するDocumentがあるので、これを参考に実施。
例のごとくいくつか苦労があったのでその辺はQiitaにまとめている

あと、この件は、単純にデータを移行するのとは別に、もう一つクリアしなければならない課題が内在していた。
前のブログでも書いたが、Firestoreのデータが無料枠の5GBを超えてしまっているため、単純に本番からテストへデータを丸ごと移行してしまうと、本番・テストの両プロジェクトで同量のデータを持つことになる=つまり保持しているデータ量に対して二重課金されてしまう。
これは避けなければならなかった。
gcloud firestoreによるデータ移行に関しては、日付で区切っていい感じに移行とかはできそうになかったので、仕方ないから、一回丸ごと移行した後、テスト環境から消すことにした。
Export+Importは上記の手順で可能だが、日付による削除はコマンドラインでの操作はいい感じにはできそうになかったので、仕方なく自分でコードを書いた。
一応、それっぽく動作するのは確認できたので、今は一旦これで良いことにする。
そんなに頻繁にデータ移行を要するとも思えんしな。

ただ、この方法で一つ懸念があるのが、Importした直後は、一時的にテスト環境で無料枠を超えたデータ量が存在する時間帯ができてしまうという点である。
仮にここを切り取られて「課金対象」とされてしまうと、そもそもこの方法自体使えないことになる。
この辺は実際の所どういう考え方になってるかが調べ切れていないので、しばらく請求状況を見つつ対応要否を検討していきたいと思っている。
とはいえまだ無料枠をほんのちょびっと超えたくらいなので、誤差程度にしかわからない可能性もあるが…
このやり方がダメだとすると、特定日付分をExport+Importする処理を、完全自作する必要が出てくるんだよなあ。それはとてもやりたくない。。。

キャッシュ関連を何もやっていない件

CloudflareにDNSプロキシさせるまで

これ、知らなかったのだが(薄々そういう予感はちょっとしていたのだが)、Cloudflareにキャッシュさせる場合は、プロキシされたDNSレコードが必要になるようだ。
一方、App Engineでカスタムドメイン(のGoogleマネージドな証明書)を使用する際には、Cloudflareのプロキシを使えない制約がある(制約というかこれは自分が試してみてそうだったというだけだが)。
というわけで、Googleマネージド証明書を使ってのキャッシュ対応は無理だということがわかった。

ちょっと調べてみたら、こちらに記載の方法で、CloudflareにDNSプロキシできるようだった。
要するにマネージドじゃなくて個別の証明書用意して設定するという方式のようだ。
正直これには若干の抵抗があって、というのも証明書の更新なんて絶対忘れるに決まってて、いざ期限切れになったときにいきなり繋がりませんという事態になるのが目に見えてるからだ(だからこそマネージド証明書を使いたかったのだが)。
ただ、技術的好奇心が勝って、とりあえずやれるだけやってみようかなと思って、試してみることにした。

やってみたらわかったんだが、Cloudflareのオリジンサーバ用証明書は、デフォルトの期限が15年で設定されており、個人的には非常に長期間の印象である。
1年とか2年とかだと、上述した証明書期限切れの更新忘れ問題が起きそうな気がするんだが、15年ならまあいいか(その間にこのシステム多分破棄するしw)と思うことにした。
逆に言うと、もし15年間もこのシステムが生き続ける場合は、15年後の2037年6月に阿鼻叫喚になると思われる。
その頃CloudflareとかGCPとかそもそもまだ残ってんの?仮に残ってて同じような機能が同じように使えんの?という問題もある。
一応手順は残しておいたが、15年後に使えるものかどうか…

で、晴れてCloudflareにキャッシュさせることが可能になった。
ただどこをどうキャッシュさせるかについてはまだ手探り状態で、考え中である。
個人的にはAPIの実行結果まで含めて完全キャッシュしてもらって良いのだが、試してる感じでそう動いてるようにも見えない。
ここはもう少し色々試していく予定。

なお、これを実施するために、CloudflareのSSL/TLS設定を最低でも「フル」にする必要があったが、現行使っているドメインはぶら下がってる他のシステムの都合で「フル」にできなかったため、仕方なく新しい(専用の)ドメインを買った。
というか前からそうしておけば良かったんだな…(もともと色んなシステムをぶら下げる目的で1ドメインを使いまわすのに運用上の無理があった)
なのでリメイクから早くも1か月程度でドメイン変更と相成った。

App Engine Firewallルールについて(後編)

で、そうなると、上で書いた「App EngineのFirewallルール」が無駄になる、というか邪魔になる。
というのも、同じ機能はCloudflareのWAFに備わっているので、それで実現できるのと、そもそもCloudflareからApp Engineに流すようになった以上、App EngineにFirewallを設定してしまうと、Cloudflareからのトラフィックが流れなくなってしまう。
よって、App Engineに対して設定した「自分トコのIP」は解除して、同様の設定をCloudflareのWAFに設定。
代わりにApp EngineにはCloudflareのIPアドレスを設定することにした。
こうすることによって、App Engineへの直接アクセスは防御され、Cloudflare以外からのアクセス以外受け付けない状態にできる。セキュア!

結構数が多くて面倒くさかったんだが、あとになって調べてみたら同じようなことやってる人が既にいて、その人がスクリプト作ってくれていた。。。
これをそのまま使わせてもらえば良かった…(全部手動でやっちまって面倒くさかった)

上で書いたような使い方はできなかったが、App EngineのFirewallを有効活用できたという意味では結果オーライだろうと思うようにしている。
ただ単純にこの点だけでいうとStagingと本番で同じFirewallルールを使うことになっているので、プロジェクト間差異が出ないという意味で、なんかちょっと勿体ないなあと思ってしまう(仕方ないのだが)

gif画像がGAE上でだけ何故か表示されない件

next/imageでgifにアクセスすると500エラーになる件。ローカルでは起きず、GAE上でだけ起きる。
一応回避策はある(next/image使わずimgタグで直接参照すれば表示される)ので現時点で困ってるってわけではないのだが、ほぼ同じ問題でAzure上で起きるissueとして起票された#3410の結論 "platform issue" の詳細が単純に気になったので、とりあえずDiscussionをあげてみた。
ちょっと様子見。
恐らく#3410と同じ「問題」がGAEにもあるんだろうと踏んでいるが、仮にその問題が特定できたとしてもGAEに同様の問題があることを提起したいとか、ましてや解決させたいとか、そんな高尚な目的は今のところ俺にはない。
単純にどういう理由でこういうことが起きるのか知りたい、くらいの気持ちしか今はない。
というわけでこのDiscussionをトレースするのが今のところの状況である。
まあでも、今のところ反応もないのであまり皆さん感心ないのかもしれないが。。。

その他

他にもいくつか細かいバグっぽいやつとか変だったところを修正したりしたのだが、細かいのでここには載せない。
上で書いたようにまだ残課題として片づけなければならない部分はあるので、水面下でちょいちょい作業すると思うが、少しずつフェードアウトして、次の開発作業に移っていこうと思っております。