AWS IAM セキュア化の取り組み
この記事は Eureka Advent Calendar 2021 の 13日目の記事です。
はじめに
こんにちは、エウレカ SREチーム のハラダです!
2020年頃から今年にかけて、 エウレカのSREチームとSecurityチームではAWS IAMのセキュア化を注力ポイントのひとつとして、継続的に取り組んできました。
本記事では、その実践から学んできたIAM管理で守るべき大原則および、具体的にどうやってセキュアな理想像に近づけてきたか、今後の方向性などを話したいと思います。
Why “IAM” so important ?
そもそもなんでIAMが注力ポイントなの?と疑問に思われる方もいるでしょう。
クラウドの大きな強みである「すべてをAPI経由で操作できる」という性質ゆえに、IAMは大きなAttack Surfaceでもあります。
Gartner社の予測によると、2023年までにクラウドのセキュリティ侵害の75%はIAMの不適切な管理が原因となる (2020年時点では50%) と言われています。
クラウドのセキュア化、というとコンテナセキュリティ、データセキュリティ、インフラの堅牢化、検知/インシデントレスポンス … などな様々な分野がありますが、どの分野の強化に取り組むにしても、まずはIAM管理運用の基盤が固まってないことには実装のしようがなかったり、あるいはどんなに頑張っても片手落ち、となることも個人的には多いと感じています。そういった意味でもやはりIAMは最重要ポイントであり、クラウドのセキュア化を考える上で最初に取り組むべき分野と考えられます。
IAMを取り巻く脅威の具体例
具体的にはどういった脅威が考えられるのか、かいつまんで紹介します。
AWSの認証情報 (IAMアクセスキーや一時クレデンシャルなど) は以下に挙げるように、様々な理由で漏洩する可能性があります。
- 開発者が誤ってPublicなGitリポジトリにAWSキーをPushしてしまう
- SREにAWSを騙ったフィッシング / ソーシャルエンジニアリングを仕掛ける
- アプリケーションのSSRF脆弱性を突いてEC2メタデータから一時クレデンシャルを取得する
- アプリケーションのOSコマンドインジェクション脆弱性を突いて環境変数を読まれる
また、漏洩したクレデンシャルは様々に悪用される可能性があります。
- 事前に用意したAMIからEC2を勝手に立ててBitcoinを掘る
- 高額なリザーブドインスタンスを購入して会社の予算を食いつぶす
- S3やDynamoDBの顧客データを盗みだす
- データを暗号化して解除代金を請求する (ランサムウェア)
- アカウントをハイジャックしてデータを全部消失させる
外部からの攻撃のみならず、インサイダー (社内のエンジニアなど) に関しても考慮が必要です。本来必要でない権限を持っていると不用意な操作で本番環境を壊してしまうこともあるし、性悪説で考えれば、ローテーション対応がなされてないアクセスキーを退職時に持ち出してしまう、なんてことも考えられると思います。
AWS IAM管理の原則
こういった脅威に対応するため、AWS公式ドキュメントのIAMでのセキュリティのベストプラクティス や AWS Well-Archtected Framework Security PillarのIAMの章 のような指針に沿ってIAMを管理・運用していくことが求められます。これらの指針を整理すると、特に以下2つの項目が重要 だと考えています。
① IAM Userを使わず、IAM Roleを利用する
IAM Userのログインパスワードやアクセスキーは非常に長命なもので、漏洩すればその権限の範囲で何でもできてしまうため、管理にとても気を使わなければなりません。
この長命という性質から来るリスクを低減するために、定期的にキーのローテーションを行うことがベストプラクティスとされています。しかしながら、特に本番環境におけるローテーションは運用負担も大きく、現実的にはどんなにがんばっても〜数十日間隔でのローテーションが限度となるでしょう。
対して、IAM Roleで払い出すことのできる 一時的セキュリティ認証情報 は数分〜数時間の有効期限が設定され、非常に短命なため、長期にわたるクレデンシャルの管理を意識しなくてよい点が優れています。
IAMアクセスキーをアプリケーションで使う時は環境変数から固定で渡すことになりますが、その値の安全な保管方法なども課題になってきます。例えば、管理者だからといって本番環境のアクセスキーを参照/持ち出しできてしまってよいのか?といった問題があるでしょう。暗号化して保持するにせよ、アクセスキーの値を知らないままに環境変数を設定するというのは難しそうです。IAM Role (インスタンスプロファイル )を利用した場合はアプリケーションが自動でインスタンスからクレデンシャルを取り出すので、この問題も解決します。
② 最小権限付与の原則に従う
Role化で認証情報の生存期間を短くしても、アプリケーションやユーザーからはいつでもその一時的な認証情報を払い出して権限を使える状態です。…ということは、アプリケーションを実行するインスタンスや開発者の端末に万が一侵入された場合には、いくらでも認証情報を取得し放題です。最小権限付与を徹底することで、そうなったときにも被害を最小限に抑えることができます。これはインサイダーが原因となる問題 (オペミスによる障害や、退職時の持ち出しなど) の対策としても同様に有効です。
着手前の課題
エウレカは会社設立当時 ( 10年以上前 ) からがっつりAWSを使用しており、現在の代表プロダクトであるPairs, Pairs Engageをリリースする以前のものを含めると全体でAWSアカウント数は数十、IAM Userは数百ほど存在していました。
数が多く用途を把握しきれていない。もう使っていないものや用途がわからないものが多く存在する。Roleを使うべきところで使えておらず、アクセスキーの管理が手間だし、長期間ローテーションされていないものもある。構築時のスピード優先で権限付与を行われたまま、調整がなされず過剰な権限が付与されている。…などなど、先述の指針とは乖離した状態であったこと。
またセキュリティの観点のみならず運用する上でも、そのシステムが何のアクセスキーで動いているのかの調査から始まるとか、どういった粒度でIAMポリシーを書くべきかという権限付与の一貫した方針がないことで困ることも多くありました。
これはどうにかしたいよねということで、本記事で紹介する取り組みを進めることになりました。
各IAM Userの利用用途を把握する
自分たちが触ったことのないAWSアカウントも多く、「なんもわからん」状態からのスタートです。まずはリソース名、作成日を手がかりに、Slack/社内Wikiを検索、あるいは知ってそうな人に聞き取りをして すべてのIAM Userの大まかな利用箇所と用途の把握 をします。CloudTrailログのvpcEndpointId, sourceIPAddress, userAgent なども手がかりになります。
スプレッドシートなどにまとめて社内の開発者に展開、知ってる情報をなんでもいいから記入してもらう、といったやり方も有効だと思います。
不要なIAM Userを削除する
利用用途の把握と同時に、明らかに使われてないものを消していきます。最終アクセス時間を見て判断できるものや、命名から判断して個人検証用、もう利用していないSaaS用であると明らかにわかるもの、オーナーが消していいよと言ってるもの、などが削除の対象となります。
毎分空振りのAPI Callが実行されているので 最終使用日が1分前になっている ( = 消して良い) とか、最終使用日が3ヶ月前だけど、年に2,3回しかデプロイされないコンポーネントのCIで使っている ( = 消したらNG )といったケースもあり、最終アクセス時間だけで判断すると痛い目を見るので注意しましょう。
オーナーがもう退職しているものなど、確信が持てないときはアクセスキーの無効化機能を活用して、10分だけ無効化して戻す。数日後、1日無効化して戻す。数日後、無効化して1ヶ月寝かせる。問題なければ削除。 のように段階的に停止していくのもおすすめです。 (そして社内のどこからも悲鳴が上がらなければそのまま消してしまう)
※ ↑ 少々荒っぽい方法ではあるので、先に絶対落としちゃいけないシステムで使われてるキーはどれなのか洗い出しておく必要はあります
すべてをIaCで管理する
ある程度全体の利用用途も把握でき、不要なIAM Userを削除して数も減ったところで、すべてのIAM UserをTerraformにImportしていきました。
以前まではTerraform管理下のものとそうでないものが混在しており、いちいちこれはGUIから編集、これはPR出して、という判断が都度発生しており、またGUIからの作業になるとレビューできず不便だしチームとしてナレッジが蓄積しない、といった問題がありました。
IaCで管理することで、そのIAM Userや権限が必要な背景、オーナーが誰/どこのチームなのかなどのナレッジをコメントやタグで集約管理できたり、変更をレビューしやすい、履歴が追いやすい、など多くのメリットがあります。この後のRole移行時にもaws_iam_policy_documentリソースはそのまま使えますし、最小権限化のときにも1行ずつの差分でReviewできるなど、下準備にもなっています。
また、ある程度整理が終わってきた段階で TerraformのCI経由 でのみIAM Userを作成できるように権限を調整しました。CODEOWNERの設定でSREが必ずReviewに入るようになっており、今後無尽蔵にIAM Userが増えたり、理由なく過剰な権限がつくことを防いでいます。
IAM Roleへの移行
IAMを呼び出す主体によって分類をすると、 ①人間 / ② AWS上のワークロード / ③ AWS外のワークロード の3つになると思います。移行の方針をそれぞれ説明します。
① 人間のログインアカウント/ローカル用のクレデンシャルをRoleに移行する
これは AWS SSO を使い、ロールベースのログインをできるようにするのがおすすめです。AWS SSOはOrganizations / Control Towerとも統合されるなど、AWSマルチアカウント環境へログインするためのスタンダードになっていると思っていて、導入しない手はないのかなと思っています。
エウレカでは Okta を IdP基盤として採用しており、これを AWS SSOと統合させて使っています。Okta側のグループ (チーム)情報を元にして、AWS SSO に予め定義した PermissionSet ( ≒ IAM Role )で各AWSアカウントへのアサインが有効になります。情シスの方で行われるOkta上での入退社フローがそのままAWSの権限の追加/削除となるので、SRE側では作業がゼロ、新入社員もやりとりや待ち時間がなく、非常に快適です。
AWS SSOでは一時認証キーをGUI / CLI どちらからでも払い出せる機能があるので、ローカル検証用のキーの管理なども不要になります。これもめっちゃ便利です。( 以前はこういった仕組みを自前で組んでいたこともあったのですが、管理が大変すぎたので廃棄できてよかった …
② AWS上のワークロードをIAM UserからIAM Roleに移行する
AWS上で走らせているワークロードに関しては、各サービスごとにIAM Roleを取り出す標準の方法があるのでそれに従いましょう。
具体的には、 EC2のInstance Profile / Lambdaの実行ロール / ECSのTask Role / EKSのIAM Roles for Service Accounts /App Runnerのインスタンスロール などなど。(名前が全部微妙に違ってややこしい)
AWS SDK for Go などの場合はそのまま使ってると、環境変数(IAMアクセスキー)を渡さなければIAM Roleを見に行ってくれる、といった仕組みがあるのでうまく行けばそのままコードの変更なしで動くはずですが、独自で色々やってる場合クライアントの持ち方によってはうまく動かないとかもあったりするので、移行するときはドキドキです。念入りに検証を行いましょう。
③ AWS外のワークロードをIAM UserからIAM Roleに移行する
AWS外でAWSのIAMを必要とする場合にも、Roleを利用できる方法があるので積極的に導入していきます。
エウレカではCI/CDにはGithub Actionsをメインで使っていますが、最近出たGithub ActionsのOIDC機能をconfigure-aws-credentialsから使うと非常にラクにRoleへ移行できます。CI/CDはその性質上本番環境への強い権限を持つため、なるべくアクセスキーを撤廃したいと思っており、この機能が出て非常に嬉しいです。
GCPのサービスアカウントからAWS IAM Roleを利用する方法もあり、これもGithub Actionsと同じくIDプロバイダとしてGCPを信頼する、という仕組みになっています。
DatadogやBridgecrewなどのSaaSでは、CloudFormationスタックを展開し、Roleベースでの連携を行ってくれる、というパターンでIntegrationを行うことができます。
ツールによっては、こういったRoleベースでの連携の仕組みがなく、アクセスキーを渡さざるを得ないこともあります。そういった場合でも何が何でもNGというわけではなく、渡す権限の強さと導入して得られるメリットを天秤にかけて判断するのがよいかと思います。
最小権限の実践
過剰な権限を削減して「業務遂行のため必要最低限の権限」のみを持つという理想の状態に近づけていきます。システムが使うIAMなのか、人間の使うIAMなのかで異なるアプローチで進めるのがよいと思っています。
システム用の権限
システム(バックエンドアプリケーションや外部SaaSなど)の使うIAMが発するAPI Callは、仕様に基づいて固定されており、ローンチ前でも無い限りあまり大きく変更が起こるものでもないです。そのため、必要とされるアクションとリソースを洗い出し、厳密なホワイトリスト形式で IAMポリシーを書いていきます。洗い出しには後述するIAMアクセスアドバイザー、CloudTrailなどのツールを活用します。
また、できれば機械的にクエリで洗い出すだけではなく、そのシステムの大まかなユースケースを事前に把握し、terraformに「なぜその権限が必要なのか?」という観点でのコメントを残すことをおすすめします。IAMの変更をリリースする際の動作確認や切り戻し判断、将来的に他の人がIAMの棚卸しをまた行う際に役立ちます。
IAMポリシーの変更をリリースする際には、そのアプリケーションのエラーログやCloudTrailログをチェックして、想定外の権限不足エラーが出てないか注視、問題あればすぐロールバックします。
人間用の権限
私見ですが、十分に自動化が進んだ環境では「人間がやらないといけない仕事」というのはアドホックな前例のない操作になるはずなので、過去の履歴から必要最小限な権限を洗い出す、というやり方は人間にはあまり意味のないアプローチなのではないかと考えています。
また、AWSコンソールのある画面におけるGUI操作を行うときに必要な権限を厳密に洗い出す、というのもかなり大変で、権限調整のやり取りが何度も何度も発生してしまい生産的ではありません。
そのため、チーム(職能)ごとにどのような用途でAWSを利用しているのか?今後どういった利用が考えられるか?といったヒアリングを行い、以前よりはスリム化しつつ サービス単位の権限やAWS管理ポリシーも使ってある程度の幅をもたせたIAM Roleを作成しました。
とはいえここはマジで誰も触るな!とかこの操作は絶対やるな!という要件は存在しているので、主に本番系のAWSアカウントにおいては、DenyのポリシーをRoleに付与するとか、KMSキーポリシーを使ったリソース側での制御や、SCPでのDenyなどを組み合わせて担保しています。
最小権限付与という理想状態からはやや遠くなりますが、開発生産性とセキュリティのバランスを議論した結果、一旦はこういった着地になっています。
最小権限の実装に使えるツール群
最小権限の実装をするとき、そのIAMがどんな操作を普段行っているのか?という調査をする必要があります。以下ではその調査に役立つツールを紹介していきます。
まず、IAMアクセスアドバイザーは何のセットアップもなくデフォルトで使えるので活用しましょう。サービス単位での最終利用日時を見ることができます。
IAMアクセスアドバイザーでは細かい権限/リソースの単位までは見ることができないので、より細かく絞っていく場合はCloudTrailログを調査します。S3にログをエクスポートして、Partition Projectionを使用したAthenaテーブルを作成しておくとSQLを使って厳密に調査できるのでおすすめです。
今年リリースされた IAM Access AnalyzerのIAMポリシー生成機能 にも注目です。ただし以下記事でも触れられているように、アクションレベルでリスト化してくれないサービスがあったり、リソース部までの指定は生成されないなど厳密さには欠ける部分があるため、まだCloudTrailログでの直接調査の代替にはならないかな、と思っています。( のでPoC的に触っただけで個人的にはまだ活用できてないです … )
今後やっていきたいこと
IAMの棚卸しを定期イベントにする
直近はここまで話してきたような取り組みをロードマップに載せてゴリゴリと消化してきていますが、今後、仮に今見えている理想との乖離がすべて潰し切れたとしてもそこで終わりではありません。必要とされる権限の変化や、いつの間にか使われなくなったRole/Userが発生したりなど、時とともに徐々に最小権限の理想状態からは遠ざかっていくものだと思うので、各クォーターや年次で定期的に棚卸し、権限を減らしていく必要があるでしょう。諸事情でどうしてもアクセスキー運用をやめられない場合などにも、定期的にキーをローテーションすべきで、これも棚卸しの際に同時に対応するのがよさそうです。
開発者への啓蒙 / 管理権限の移譲
現状ではIAMの管理ノウハウを知っている人がSREや一部の個人に偏っており、属人性が高い状態になっています。
AWSを利用する以上、誰もがIAMを理解しておいてほしく、開発者には権限が必要なときには何の権限が必要なのか自分で把握して、直接PRを出してもらえると理想だなと思っています。現状ではチケット依頼が来て、具体的にはどの権限が要るんだ…のヒアリングと調査から始まる、ということもあるのですが、権限追加PRを開発者から直接もらい、SREがReviewしてApproveする、といった流れを徐々に増やせるとよいなと思っています。
もうひとつの観点として、IAMの管理権限の移譲を進めていく必要があります。エウレカではこれまでOps的な動きをするチームがSREのみでしたが、最近は注力分野 (プロダクトに直接関わる部分) 以外は徐々に情シス、機械学習基盤、データ基盤、など各分野の専任に管理を移譲していく動きがあります。各システムの専門家が、管掌分野のシステムにおいては責任を持ってIAMも管理を行ってもらい、SREは今後社内のクラウド環境を管理する元締めとして、最低限ここは守ってね、というルールを定める役割になってくると思います。以下の発表で紹介されているPermissions Boundaryなどを使い、ガードレールを実装した上で移譲していけるとよさそうです。
Security Breakglass の仕組み整備、そしてZero Touch Production へ …
現状ではSREおよびその他の管理者が比較的強い権限を持ってしまっていますが、ほぼすべてのインフラへの編集操作はCI経由でのTerraform Applyで行っているので、本当はその権限は日常的には必要なく、必要なタイミングは緊急時のみに限られるはずです。必要な時にだけ最強権限を適切なレビューのもと取得できる、という仕組みがSecurity Breakglassになります。メルペイさんのQray のような仕組みをAWS上で自前で実装してもよいし、もっとミニマムでやるならIAMのRevoke時に使われる AWSRevokeOlderSessions と似たポリシーをRoleに付けておき、必要な時にだけConditionのDateLessThanを1時間後とかに更新するといった運用フローでも最初は良いのかなと思っています。
そして、最終的には以下の記事で紹介されているような Zero Touch Production の状態を目指していくことになりそうです。
おわりに
いかがだったでしょうか。
まとめると すべてを棚卸しした上で、Roleを使おう & 最小権限やろう、という非常にシンプルな話ではありますが、実際に進めるとなると一筋縄ではいかず、かなり生々しいタスクになってきます。しっかり工数を確保し、優先度を付けて継続的に取り組むことで、セキュアな環境に近づけていきましょう。
事業規模や組織構成などによっては、この記事の進め方は最適ではない (もっと小規模な事業であれば固めすぎなくていいし、もっと大規模な組織なら1チームですべての棚卸しは不可能) かもしれないですが、同じような取り組みを進めたい誰かのヒントとして役立てば幸いです。
謝辞 Acknowledgments
I would particularly like to thank
. We worked together on this project. Without his guidance, we wouldn’t have been able to start this long journey! Also, こういったタスクに継続的に取り組めるようサポートしていただいた2人のボス と , 実運用についてよく議論させてもらった , , , and for helping me to set up SSO, 調査に協力していただいた社内の皆さま、本当にありがとうございました 🙏 ( 今後ともよろしくおねがいします 💪