lynx   »   [go: up one dir, main page]

freeeの開発情報ポータルサイト

新卒研修で作ったプロダクトを本番で運用している話

こんにちは!24 新卒で freee に入社した kochan です! 以前投稿した新卒研修の事例紹介の記事では、freee の新卒研修で社内のコミュニケーションに関する課題を解決するために、ショート動画プラットフォームを作成したことをお伝えしました。今回の記事では、新卒研修後に本番運用に乗せるまでにどんなことをしたのかを説明し、新卒研修後の取り組みで学んだことをお伝えします。

また、この記事に関する内容は 5/9 に freee tech night で話す予定ですので詳細が気になる方はぜひご参加ください!

freee-tech-night.connpass.com

本番運用にあたって行ったこと

本番運用するにあたって、まずセキュリティを専門とするPSIRTチームと、プロダクトのインフラを管理するSREチームに、何をすれば安全に社内サービスをリリースできるのか確認しました。そこで出てきたシステム的な要件としては主に 2 つです

  • ロギングを行い、アクセスに対してトレーサビリティを確保すること(誰がいつどの API にアクセスしたか、どのような操作を行ったかを詳細に追跡できるようにする)
  • 認証を Google OIDC から OneLogin に置き換えること

上記の要件を満たすために以下の 2 つの大規模なリプレイスを行いました。なぜこれらが必要だったのかは、それぞれの章で詳しく説明します。

  • フレームワークを echo から社内標準のものに載せ替える
  • 認証を OneLogin での SAML SSO に置き換える

フレームワークを社内標準に置き換える

研修時点での技術選定では、ORMには社内標準のライブラリを使用していましたが、HTTP サーバ機能やルーティング処理には社内標準のライブラリを使用せず、Go言語のWebフレームワークであるechoを使用していました。Webフレームワークも社内標準のライブラリに置き換えるメリットは以下の通りです。

  • 社内標準のログ出力をすることができる
    • 社内のセキュリティレベルに沿って適切にマスキングされたログを出力できる(echo でもログは出力できますが、個人情報や機密情報を適切にマスキングする仕組みが社内標準には組み込まれています)
    • アクセスログやアクティビティログを統一された形式で出力でき、監査やインシデント調査時のトレーサビリティが向上します
    • Datadog との連携が簡単にでき、トレース情報を効率的に可視化できます
  • 社内に知見が溜まっているため脆弱性診断など社内での連携が円滑であります
  • 研修の開発チーム以外のメンバーにも比較的保守しやすい

私たちのチームは研修の時からクリーンアーキテクチャを意識していたので、echo は adapter 層に閉じ込めていました。そのため「フレームワークの載せ替えなんて余裕!」と、考えていました。実際、クリーンアーキテクチャを採用していたおかげでドメインロジックに修正を加えずに HTTP サーバ機能を入れ替える事ができました!

しかし、実際に置き換えていく中で別の問題が浮上しました。OpenAPI に記載している内容とサーバが返すデータが異なることがわかったのです。 私たちが OpenAPI の記述に慣れていなかったこともあり、また手動で OpenAPI とコードを二重管理していたため、ズレが発生しやすい状態でした。コードを修正しても OpenAPI の定義を更新し忘れる、あるいはその逆のケースが頻繁に発生し、リクエスト・レスポンスと OpenAPI の定義がズレていないか目視で確認するのはかなり辛いものがありました。

この問題を解決するために、二重管理をなくす方法を検討しました。まず、TypeSpec を導入して OpenAPI を生成するように変更しました。さらに、ogen というツールを導入してサーバ側のコードを自動生成することで、OpenAPI の定義とコードの間にズレが発生しないようにしました。

TypeSpecからOpenAPIを生成し、OpenAPIからOrvalを用いてReactのコード、ogenを用いてGoのコードを生成する
TypeSpecを利用してOpenAPIを生成し、OpenAPIからReactとGoのコードを生成する

TypeSpecは Microsoft によって開発されたインターフェース定義言語(IDL)で、TypeSpec で記述すると OpenAPI を出力してくれるため、既存の OpenAPI エコシステムに乗っかりつつ OpenAPI とにらめっこする必要がなくなる便利なツールです。TypeSpec はまだそこまでメジャーではありませんが、型安全性が高く、可読性も良いため、API の定義を管理するのに適しています。

ogen は Go のコード生成ツールで、OpenAPI の定義からサーバ側のコードを自動生成してくれます。これにより、API の定義とサーバの実装が常に一致するようになり、二重管理の問題を解消することができました。

このように紆余曲折ありながら差分が約 4 万行まで膨れ上がった feature branch をマージすることができました。 研修が終わってからはメイン業務の合間を縫って進めていたこともあり、フレームワークの載せ替え作業には 3 ヶ月かかりました。

認証を OneLogin に置き換える

認証を統制の観点から研修時点で作成したGoogle OIDCではなく、社内でツールの認証認可に使用されているOneLoginに置き換えるように要件を伝えられました。これは一見、単純に認証先が変わるだけに思えますが、この要件は開発した動画プラットフォームが持っていた、認可(誰が何をできるのか)の手動運用を解決する可能性を秘めていました。

研修で開発した動画プラットフォームでは、ユーザー (社員) の認可情報を、アプリ側のDBで管理していました。そのため、社員が入社または退社した時に、手動で情報を更新する必要があったのです。

一方、要件であったOneLoginでは、社内のマスタ情報が最新の状態で紐づけられているので、手動で更新せずとも、OneLoginの認証情報を参照することで常に最新の権限でユーザーに利用してもらえます。 認証このような、認証情報を取得する際に、認可情報もOneLoginから取得できる仕組みにメリットを感じ、OneLogin SAML SSOに置き換えることにしました。

しかし、容易ではありませんでした。

まず、社内で Go を使った OneLogin SAML SSO の実装例はありませんでした。 また、OneLogin 側が提供している Wrapper の実装例にも Go の実装はありません。

加えて、そもそもチームの誰も、SAML の知識がなかったのです。 そこでメンバーの takemi が、SAML の概念を学びながら、社内で初めて Go を利用した OneLogin SAML SSO の実装に挑戦しました。

そこからは無心で道なき道を歩み、着実に道を作っていました。 結果、締め切りよりも早く、実装まで漕ぎ着けました。またここで得られた知見の多くが、同じく新卒研修で作られたプロダクトであるzone の認証認可の実装にも大きく貢献しました。 0 から社内ノウハウを作ることができた体験は、何にも代え難い体験でしたと実装者は語っていました。

脆弱性診断

本番運用を開始する前に脆弱性がないことを確認するために脆弱性診断を実施します。

今回作成したアプリケーションの規模だと社外に診断を依頼すると数百万かかります。 また、PSIRT に脆弱性診断をお願いするとしても、通常のプロダクトの脆弱性診断スケジュールとの兼ね合いがあります。

今回はアクセス制限として社内ネットワーク(VPN 経由)からのみ利用可能にするという対策を取ることもあり、勉強も兼ねてセルフで脆弱性診断を行い、結果を PSIRTにチェックしていただく形式を取りました。

脆弱性診断では API に対して様々なリクエストを送って SQL インジェクションや XSS、本来閲覧権限のない情報の取得などアプリケーション側で意図しない挙動が起こせないかを確認します。 リクエストの改ざんには Burp Suite を利用しました。

脆弱性診断を網羅的に行ってみると、バリデーションが不十分で、適切なステータスコードではなく 500(Internal Server Error)を返す箇所が多数あることがわかりました。500(Internal Server Error)では攻撃者にシステムの脆弱性に関するヒントを与えるのできちんとバリデーションして400(Bad Request)に倒すことで攻撃者のキルチェーンを早期段階で防止する必要性を学びました。また、一番危険なシナリオを最初に考えて重点的に確認することの重要性も学びました。

脆弱性診断の結果、SAML レポンスの改ざんや SQL インジェクション、XSS などのメジャーな攻撃は刺さらないことが確認できました。 しかし、動画ファイルのリソースを直接リクエストすると認可制御がかからずにアクセスできてしまう脆弱性が見つかり、急いで修正しました。この問題は自作で頑張って作った認可レイヤに起因していたため、セキュアな実装をするには車輪の再発明ではなく、確立された基盤を利用することの重要性を学びました。セキュリティ機能は特に、自作するよりも十分にテストされた既存のライブラリや基盤を活用する方が安全です。

リリース前に脆弱性診断を実施することの重要性を学びました。もし社外向けのプロダクトで脆弱性を埋め込んでしまったら、と想像するとゾッとします。

リリース

全社忘年会に向けたカウントダウンとして社内で利用してもらいました! リリースから半年たった現在でも社内イベントの告知など短時間で気軽に社内の情報をキャッチアップすることができるサービスとして利用してもらっています!

全社忘年会のカウントダウン動画として30秒の動画が投稿されている。
全社忘年会のカウントダウン動画の投稿

感想・学んだこと

新卒研修で作ったプロダクトを本番運用に載せるまでの取り組みを通して、良いユーザー体験を作るための要件定義やペルソナ設定の重要性、作った価値をユーザーに届けるための普及活動の必要性、そしてサービスをリリースする際のセキュリティを担保することの重要性を学びました。

この過程で、とりあえず動くものを作ることと本番運用までのギャップを実感することができました。また、研修で作って終わりではなく本番運用まで行うことで、自分たちの技術選定の甘さも理解できました。ここまで学べる freee の新卒研修はすごいと感じますし、プロダクトを長期的に開発・保守運用していく SaaS という領域は、エンジニアにとって非常にチャレンジングで面白いと実感しました。

最後に

ここまでの話や、ここに書ききれなかった話を 5/9 の freee tech night で話します!ぜひご参加ください! freee-tech-night.connpass.com

Лучший частный хостинг