クラウド環境
サーバーレス環境の管理に環境変数を用いる危険性
トレンドマイクロでは、サーバーレス環境サービスによるシークレットの管理法に潜むセキュリティリスクについて分析しました
サーバーレス環境は多くの場合、通常の業務運用に加えてビルトイン型のスケーラビリティ拡張や多地域対応、容易なコスト管理などの拡張サービスも提供しており、その利用はさらに広まりつつあります。ほとんど全ての主要なクラウドサービスプロバイダ(CSP)は、サーバーレス環境を何らかの形で提供しています。そうした中で特に有名なものとして、「Amazon Web Services(AWS) Lambda」や「Azure Functions」が挙げられます。
上記を踏まえ、サーバーレス環境で動くアプリケーションは、特定のクラウド・インフラ内で実行される部分的なコードと見なせます。こうしたコードは、APIエンドポイントへのHTTPアクセスや、特定のイベントなど様々な契機で起動されます。関連するセキュリティ事項として、コード自体の内容的な安全性と、コードを実行する環境の安全性という2つに分けて考えることができます。このうち、コード自体の内容は、その多くがプログラマや設計者の手に委ねられているため、CSP側でできることは限られています。一方、コードが実行される環境については、その提供者であるCSP側の手で制御できる部分が大きいでしょう。
トレンドマイクロでは以前、不適切なリスク管理に伴う危険性について解説しました。同様の危険性が、CSPやそれに関連するサービスにもあてはまります。こうした背景をもとに本稿では、これまで多くの開発者が実施してきた、クラウドサービスにも同様に引き継がれることになった、ある危険な習慣について解説します。
環境変数
調査の結果、環境変数に大きなセキュリティリスクが見出されました。環境変数の中には、今回取り上げるサーバーレス関数のように、実行コンテキストにリンクするサービスの事前認証に必要なトークンが格納されています。ここで重要なことは、Azureを例にとると、環境変数の運用方式が、シークレット情報の安全性に大きな影響を与えていることです。具体的に、シークレット情報は最初の時点で暗号化した状態で保存されていますが、それがセキュアなチャンネルを経由して転送され、最終的には平文状態で実行コンテキストの環境変数に格納されます。この環境変数が流出すると、さまざまな攻撃シナリオに発展する可能性があります。例えば、クラウドのアーキテクチャによってはリモートで任意のコードが実行されるケースが、シークレット情報が複数のアプリケーションに使用されている場合には、重要な企業情報が窃取されるケースが考えられます。
こうした状況は、セキュリティ上のあるべき姿からは遠くかけ離れたものです。環境変数は、実行コンテキスト内の全プロセスから利用可能です。つまり、実行中のいかなるプロセスからでも、例えシークレットを必要としないプロセスからでも、環境変数を通じてシークレットを平文で取得することが可能です。開発者側の視点からは、こうしたアーキテクチャ上の不備によるリスクが、効率化の代償として受け入れられている場合もあるでしょう。しかし、セキュリティ視点において、この習慣は明らかに危険であり、数多くのセキュリティ事象や攻撃シナリオを誘発する恐れがあります。
環境変数のリスク
以降、Azure Functionsの環境において発生が懸念される攻撃シナリオについて解説します。この攻撃が成功した場合、リモートによるコード実行(RCE:Remote Code Execution)、関数の実装コード流出および書き換えに発展する可能性があります。
今回述べる攻撃シナリオでは、デプロイされた関数および環境内に脆弱性があり、環境変数が流出することを前提とします。こうした前提に立ちながらも、今回の攻撃シナリオを通して新しい脆弱性を発見し、さらにサーバーレス環境の「正しい」使い方を見誤ってしまう状況を目の当たりにするでしょう。
Azure環境の情報流出によって発生するさまざまな攻撃の中で、特に不正利用されやすい環境変数として「AzureWebJobsStorage」が考えられます。この環境変数には、デプロイ済みの関数コードが格納された「Azure Storage」にアクセスする際のユーザ認証に必要な「接続文字列」が格納されています。接続先のAzure Storageでは、関数コードの参照に加え、削除や移動、アップロードといった基本的なファイル操作がサポートされています。
流出したストレージアカウントの不正使用に際しては、上記の接続文字列をストレージ管理ツール「Microsoft Azure Storage Explorer」上に入力するシナリオが考えられます。
接続に成功した攻撃者は、サーバーレス関数を容易に削除、または新しいバージョンをアップロードできるようになります。
動画1:環境変数に保存したシークレット情報の流出に関する概念実証(英語)
この攻撃に対してどのような方針を採るべきでしょうか? まず、開発者や開発チームはデプロイしたアプリケーション上で、重要なシークレット情報を環境変数に格納しないことを推奨します。
この方針に対して、シークレット情報を使用する際には、結局ある段階で復号してメモリ上に展開しなければならない、といった意見も挙がるでしょう。これは確かに事実ですが、大切なことは、シークレット情報がそうした危険な状態に晒される時間を可能な限り短縮し、できる限り早く確実にメモリから消去することです。機密情報の流出を避けるのであれば、その情報をいつまでもメモリ内に残しておく必要はないはずです。こうした方針は、さまざまなオペレーティング・システム(OS)用アプリケーションで採用されています。可能であるならば、DevOps(Development、Operations)でも同等の方針が採られるべきではないでしょうか。
また、特記事項として、サーバーレス関数用の接続文字列をシークレット管理サービス「Key Vault」から取得する場合にも、その接続文字列が環境変数に展開される可能性があります。
こうした部分も含めて対策するならば、シークレットや認証認可の取得に関わるアーキテクチャ自体を組み換え、シークレットを用いることなくセキュリティを強化するといった発想の転換が必要かも知れません。この実現手段として、ソースコード用ストレージへのアクセス権限として、サーバーレスコンテナには読み込み権限のみを付与するアプローチが挙げられます。
アーキテクチャに関する別の疑問として、利用可能な状態に置かれている機密情報は本当に全て必要なものなのか、それとも上位の環境から受け継がれただけなのか、という点が挙げられます。本当に必要な場合、最低でもロール・ベースのアクセス制御(Role-Based Access Control)の原則を適用すれば、削除やアップロードなどアプリケーションの機能には不要な操作を阻止できるはずです。
リスクの緩和と調査の範囲
以上に述べたリスクを緩和する方法として、ストレージアカウント設定のアカウントキーアクセスを無効化することが挙げられます。しかしこれは、開発ツール「Azure Visual Studio Code」の拡張機能などに影響を与え、ユーザが新しいサーバーレス関数をアップロードできなくなるといった不都合が生じる可能性もあります。別の対策として、仮想ネットワークからストレージアカウントへのアクセスを制限することが挙げられます。しかしこの場合も、ユーザ側の負担が大きくなる可能性があります。
最終的な話として、コード実行などの攻撃を完全に阻止することはできませんが(コード自体に脆弱性が潜んでいる場合もあるため)、遠隔コード実行などの攻撃に繋がる単純な情報流出を防ぐことは可能です。
さらに、下記の緩和策を実施することで、今回取り上げた攻撃シナリオのリスクを低減できます。
- Azureのドキュメントに記載されているセキュリティ推奨事項の実施を検討する
- セキュリティチームも含めてチーム内のピアコードレビューを定期的に行う
- サーバーレスアプリケーションで用いるAPIのセキュリティを強化し、API全体の公開は避ける
- サーバーレス関数の呼び出しに繋がる外部アクセスや、仮想ネットワーク内でのユーザ・アクセスを制限する
- 可能であれば、シークレットやその他機密情報を環境変数には格納しない;シークレットの保存に適した手段やツール(vaultなど)を使用し、特定の担当者のみに利用を許可し、セキュアな転送手段を使用する
- サーバーレス関数内での通信環境を適切に保護する
参考記事:
• 「Analyzing the Risks of Using Environment Variables for Serverless Management」
By: David Fiser
翻訳:清水 浩平(Core Technology Marketing, Trend Micro™ Research)