この記事は、freee Developers Advent Calendar 2021 - Adventarの8日目です。
こんにちは、PSIRT 機関長*1の杉浦英史です。
12月8日といえば、真珠湾攻撃の日です。一昔前であれば、史実に関連づけた攻撃が観測されましたが、最近は少なくなってきたように感じていますが、今年はどうなんでしょう?
freeeでは、多層防御の考え方を用いて、日々やってくる攻撃からお客様の情報を守っています。
想定している攻撃経路は、serviceそのものに対して外部からやってくる経路、開発者や運用者がserviceをdeployする経路、社内の関係者が内部から至る経路の3つです。
本稿では、外部からの攻撃経路を中心に、freeeのproduct securityが、これまでどう進化してきたのか、これからどうするのか、について触れていきます。
CSIRT
2017年12月
私が、securityを専任で担当する1人目のengineerとしてfreeeにjoinしたのは、2017年12月、今から4年前のことでした。
当時は、優秀なfreeeのservice aplicationに頼った構成で、設置されていたsecurity sensorは、お世辞にも役に立っているとは言えない状況でした。- AWS WAF
設定されてはいましたが、ゆるめのratelimitのruleだけでした - IPS
ruleが設定されていませんでした - VirusScanner
realtime scanが不完全でした - Risk based authentication
realtimeでのblockは行えませんでした
まずは、DeepSecurity IPSのrecommended ruleをcountで有効化し、誤検知が起きないことを確認してからblockに移行する、必要であればparameterをtuningする、といった作業を地道に繰り返しました。
並行して、DeepSecurity AntiMalwareのrealtime scan検証を進め、年が明けた2018年1月に有効化作業を行うこととしました。
お昼過ぎに有効化し、しばらくは何事もなかったのですが、夕方にdeployを実施したところ、serviceに非常につながりにくい状態に陥ってしまいました。
原因は、service accessを受ける状態でapplicationのfileを展開したため、AntiMalwareがCPUを食い潰し、応答できなくなってしまったことなのですが、私は入社1カ月でserviceを止めた人として名を馳せることになりました。
freeeは、失敗して攻めようという文化なので、間違っても個人が責められることはありません。失敗の原因を解析して、間違いを起こさない仕組みを組み上げることが称賛されます。
この時は、deploy時間はそのままで、serviceも止めない仕組みを組み上げることで対処しました。
次に、WAFのruleに手をつけました。
AWS managed ruleや自作のregex ruleを作成して、検知状況を確認する作業を繰り返しましたが、誤検知を最小化すると検知率が0.01%を上回ることはなく、ruleの改修作業の工数だけがかさむ状態となってしまいました。そこで、ruleの提供はWafCharmを頼ることにしました。
WafCharmの詳細については、明日 2021-12-09に開催される以下で解説していますので、興味があれば参照してください。
WafCharmは、「最適化されたruleが自動的に設定される」+「ruleの内容を確認できる」の両方が満たされる稀有なserviceです!
さらに、risk based authenticationの見直しを行いました。
元々、login pageへのbrute force attackによる障害を防ぐために導入されていたのですが、DoSであればWAFのratelimit rule、list型の攻撃であればIPSのruleで対処ができるようになったため、適用対象を変えることとしました。
2019年7月 Security Sensorの設置が一段落、SIEM構築開始
ここまでのsecurity sensor見直しがひと段落したのが、2019年7月でした。
たとえ、applicationに間違いがあったとしても、それを突こうとする怪しいアクセスを検知できるようになった、という状態です。
- AWS WAF
WafCharmのrule + 自作のratelimit ruleを組み合わせることにより、検知率は0.2%を維持できるようになりました - DeepSecurity IPS
WAFで止められなかったものを検知し、WAFにfeedbackをおこなえるようにしました Amazon Elastisearch Serviceで作ったSIEMにDeepSecurityのログを統合する - freee Developers Hub - Risk based authentictation
login成功後の不正検知に軸足を置いた構成に変更しました
これらのログを解析するために、SIEM*2の構築をこの頃に開始しました。
当時、この領域を見ていたのは、私と"いとうちゃん"の2人だけでした。誤検知の精査とruleの修正だけで、1週間が終わってしまう作業量でしたので、どうにかして作業効率を上げなければなりません。
まずは、WAFの誤検知を精査することを目的に、WAFのblock、countログだけをloadし、applicationのログと照合して、アクセスの意図を読み取れるようにしました。
次に、DeepSecurityの検知ログもloadし、精査できる対象を広げていきました。
さらに、lambdaでS3に溜まったすべてのsensorのログをElasticsearchにloadし、串刺し検索、drill downを行うことで、工数を軽減しようとしました。
2019年7月 Security Weekly始まる
それまで、CSIRT teamの進捗を確認するweeklyは行なっていましたが、security sensorの検知状況を共有するsecurity weeklyが開かれるようになりました。
security weeklyでは、sensorの検知状況の概略と、注目すべき誤検知、検知漏れを報告し、その場で次にやるべき AI*3を決めます。
例えば、IP blacklistでお客様のアクセスが止められていると判明した時、以下の3通りの判断が考えられます。
- 通常の利用のみ = 自動でIP blacklistから除外されるが、念のためwhitelistに入れる
- お客様のIPから通常ではあり得ないアクセスが発生している = freeeからお客様に連絡を差し上げる
- 判断が難しい = ログを増やす、といった仕組み上の対処を行う
1.や2.であれば、担当のteamに連絡をすることで、AIを前に進めることができますが、3.だけは別で時間を確保する必要があります。
そこで、kaizen hourでは、仕組み上の対処が必要となった作業を実施します。収集するログを増やしたり、ログのカラムを揃えて串刺し検索ができるようにしたり、といった作業が多いです。
meetに皆で集まってワイワイやっています。一人ずつやっていることが別だったり、内職している人もいます。docsに、ゆるく"やること"と"やったこと"のログを残すことで、やっている感を記録するのが大切です。
Incident Handlingは、slackに飛んでくるアラートや問い合わせを契機に突発的に発生します。OODA loopなので、回す順番や回数に制限はありません。
tdtdsさん発案で、:psirt: の絵文字をつけるだけで、問い合わせchannelにlinkが飛ぶreakujiを利用するようになってから、気軽に尋ねてもらえることが増えました。
アラートは、正規表現でマッチしたrequestや、閾値を超えたresourceを知らせるもので、既知の危険が発生したことを教えてくれるだけです。誤検知や検知漏れを判定できる情報も併せて通知し、基準は常に見直していく必要があります。
そして、アラートは飛んでいないけど、いつもと違うことを嗅ぎつける人の気づきは、とっても貴重です。せっかく気づいたのに、知らせる先がわからない、知らせるのが面倒といった障壁をなくすことで、知らせてくれた人とteamでfeedback loopを回す機会が増えます。こうすることで、昨日よりもsecureになっていくと、考えています。
もくもく会では、その週に検知したログを精査し、docsにまとめていきます。
それぞれのsensorの担当者が気になるもの、すぐに判断ができないものについて、画面共有をしながらdrill downを行なって、判断基準をshareするように心がけています。
2019年の暮れには、Elasticsearchで作った簡易的なSIEMで、誤検知の精査ができるようになってきました。
2020年3月 フルリモートワークへ
年が明けて2020年、当時はCSIRTだったので、社内ネットワークの組み直しを行なっていたのですが、COVID-19のニュースが取り沙汰されるようになり...
freee Tech Night Online vol.1 「3月1日のfreee全社員一斉リモートワークの裏側」 - YouTube
突貫で全員がリモートワークできるような環境を用意しました。
PSIRT
この時期まで、freeeのsecurity専任のteamはCSIRTだけでした。CSIRTは、Computer Security Incident Response Teamの略なので、社内外を問わずsecurityと名の付くtaskをすべて担当していたのですが、freeeの成長に伴い体制を拡充し、以下の2つに分けることになりました。
- CSIRT = CはCorporate : 社内担当、リスク管理、社内ネットワーク、endpoint security
- PSIRT = PはProduct : 社外担当、service infra、 production security
通常は、CSIRTは本社にいて社内や従業員のsecurityを担当し、PSIRTは工場にいて生産される製品のsecurityに目を光らせる。といった住み分けが多いのですが、freeeでは、社内のシステムと社外向けのserviceが、どちらもIaaSであるAWSやSaaSに存在するため、上記のような分担となっています。
PSIRTとはいっても、production security方面で手を動かしていたのは、livaさんと私の2人だけだったので、一緒に手を動かしてくれるメンバーを募る必要がありました。
freeeはengineerの採用にengineer自身が参加する文化なので、採用活動に力を入れました。何百人もの人に声をかけて、百人近い人とお話をして、半年近い時間をかけて、良い人に選んでもらえるように頑張りました。
2020年7月 PSIRT発足
そして、junyaさん、taichiさん、tdtdsさんの3名の方にjoinしていただきつつ、7月にPSIRTが発足しました。
私は古株として、1ヶ月ずつメンターとして並走して、freeeでの仕事の進め方、PSIRTでの担当などについてのガイドに徹しました。
2020年12月 SIEM on OpenSearch運用開始
一番最初にfreeeにjoinしたjunyaさんは、半年後にはSIEMを刷新してくれました。
それまでの簡易的なSIEMには検知したblock、countログだけをloadしていましたが、allowログも含めてloadできるようになりました。
WAF、DeepSecurity IPS、CloudTrailを串刺しで検索して、drill downできるのはとっても便利です。
色々紆余曲折もあって、一筋縄ではいかない面もありましたが、苦労した点とその解決方法、日々のincident handlingについて、以下の登壇で触れています。
今では、このSIEMなしでのincident responseはあり得ないです。
忘れてはいけないのは、SIEMが得意なのは検知した異常の時系列の表示や影響範囲の特定であって、相関分析で未知の攻撃がみつけられるわけではないということです。
2021年6月 EKS移行
そして、これはSREの皆さんの成果ですが、freeeの主要なserviceのEKS移行がほぼ完了しました。
この作業と並行して、2人目にjoinしたtaichiさんが、EKS環境でSOC1 type2を満たす仕組みを作ってくれました。SOC1 type2は、内部統制の国際基準の一つです。
あと、taichiさんといえば、AWS WAFのClassic→v2移行もしれっと終わらせてくれました。感謝!
2021年6月 新人さんjoin
PSIRTに21卒のMBさんが、やってきてくれました!
freeeでsecurityを担当してきたteamにとって、初めての新人さんです。
新卒採用の時点でsecurity担当のような区分での採用はしていなかったので、security未経験であることは承知していました。
security未経験の方をガイドするときには、自分の知っている範囲から徐々に視野を広げてもらうことを心がけています。
MBさんは、Railsを組める人だったので、それをbaseにしつつ、まずはinfra方面のcatch upをしてもらいました。
web applicationを組んだ経験はあった方が良いので、freeeの場合はrails チュートリアルをやってもらうことになると思います。
Ruby on Rails チュートリアル:プロダクト開発の0→1を学ぼう
AWS consoleでポチポチして作ったinstanceにssh loginして設定するところから始まって、ansible-playbookを書いてもらった後、terraformでVPC、subnet、ALB、ASG、Launch Template、Security Group、IAM込みで同じものを作ってみると言った感じです。
github actionsで簡単なCI/CDも書いてもらいました。
輪読会の形式で、攻撃側の視点も学んでもらいました。
読み合わせるだけでなく、livaさんと一緒に実際に被害を受けた事象(日本で報道されているもの、いないものどちらも)の実例を挙げつつ、docsにまとめていきました。
新人さん向けに今でも行なっているhardeningには、受講者(防御側)として参加してもらいました。次からは攻撃側として参加することになります。
攻撃に気付いて守ることの難しさは、実際に攻撃された経験がないと理解できないと思います。
2021年4月には、去年の新人さん向けのhardeningも行っていました。
freee Tech Night Online #11 「脆弱なサービスを守れ!hardening研修」 - YouTube
MBさんは、10月からrisk based authenticationの検知状況の確認、ruleのtuning、および、検知対象の拡充の実装を担当してもらっています。
risk based authenticationは、ログインに成功したアカウントの行動をログ上で比較して、アカウントの乗っ取りや、悪意あるアカウントの行動を検知して、悪さを未然に防ぐ仕組みです。
十分なログが揃っていないと正確な判定ができないので、ログの取得内容を修正する。明らかに怪しい場合は自動で再認証を要求するworkflowを作成する。検知内容に誤りがないか精査する。と言った地道な作業を行ってもらってます。
せっかく、securityに興味を持ってくれているので、今は、できる限りの知識や手法へのpointerを渡して、自分の手で触ってもらいたいと思っています。
いろいろな経験の中から、得意なもの、好きなもの、貢献できるものを自分のものにしてくれることを願ってます。将来、彼女がどんなengineerになるのか楽しみです。
これから Blue teamとRed team
freeeのPSIRTは、防御を担当するblue teamとしてproductを守るservice infraを構築し、既知の脆弱性や攻撃を防ぐことができるようになりました。
何かincidentが発生すれば、それにreactiveに対処を行うことができる状態です。
でも、これだけでは、真の意味での攻撃には対処することができません。 攻撃者は、防御する側が用いる手段を特定した上で、それらに検知されないことを確認してから攻略を試みるからです。 攻撃者の視点でfreeeを攻略することで、未知の脆弱性をproactiveに検知し、未然に対処する体制を組んでいきたいと思っています。
PSIRT JM*4のtdtdsさんは、攻撃を担当するred team視点の人です。社内で実施された障害訓練では、APT攻撃を成立させてしまいました。詳細については、以下で聴けますので、ぜひ登録してみてください。
明日は21卒engのtomoriさんが、内定してからの過ごし方について教えてくれます。お楽しみに!