クラウド環境
Azure Functionsによるカスタムコンテナを使用した強固なクラウドセキュリティ
Azure Functionsのセキュリティ上の懸念を最小限に抑えるために、このブログではカスタムクラウドコンテナイメージ及びDistrolessの使用について解説します。
Azure Functionsのセキュリティ上の懸念を最小限に抑えるために、このブログではカスタムクラウドコンテナイメージ及びDistrolessの使用について解説します。
今日までトレンドマイクロは、Azure Functions 及び Azure App Services のセキュリティ上の懸念について、悪用された際の影響を含め広範囲に渡り解説を行ってきました。クラウドセキュリティを強化し、これらの懸念を最小化する方法の1つは、カスタムコンテナイメージを構築し、Distrolessを使用することです。今回は、主にAzure Functionにおけるセキュリティ上の脆弱性による影響を最小限に抑えるためのソリューションについて解説します。
Azure Functionsとは
Azure Functionsは、アプリケーションのデプロイとメンテナンスを簡素化することを目的としたサーバレスソリューションです。
まず、物理的なハードウェアを割り当てるApp Serviceプランがあり、これは仮想マシンとして機能します。その内部には、Dockerコンテナエンジンがインストールされています。このエンジンは、Azure-function-host ランタイムで構築されたコンテナイメージを実行します。Azure-function-host は、その名の通り Azure Function Runtime を効率的に管理しAzure のバックエンドとの伝達を担います。
このアーキテクチャにおいて、サーバレス機能がトリガされるとazure-functions-workerが実行され、提供されたファンクションコードにより実際のサーバレスアプリケーションが実行されます。
Azure Functionにおけるカスタムコンテナイメージ
選択したスタックのデフォルトのコンテナイメージは、カスタムのコンテナイメージに置き換えることが可能です。その場合、Azure Functions において適切に作動させるために、イメージには azure-function-host が含まれている必要があります。なお、カスタムコンテナを作成するオプションは、Azure Functions PremiumプランのLinuxプラットフォームでのみ利用可能となります。
ここでは、Azureのドキュメントに従い、Python をコードインタープリタとして使用したカスタムコンテナを作成しました。ただし、Azure 内のプライベートコンテナレジストリを選択しデプロイするように変更を加えています。
そして、コンテナイメージをローカルで構築し、サーバレス機能と連携するように設定したプライベートレジストリにプッシュします。
イメージの構築
ここでは、baseイメージとしてMicrosoft Container Registry 内の Azure Functions Base リストから mcr.microsoft.com/azure-functions/python:4-python3.9 を選択しました。
Azure Functionsの機能に影響を与えることなく、より安全に使用するための3つのゴールが以下になります。
- サーバレスアプリケーションの実行コンテキスト内の環境変数の削除
- アプリケーションに必要なコンテナイメージの削減と権限の制限
- Azure Functions 機能への影響の最小化
いくつかの環境変数は、function-hostを実行するために必要である可能性が高く、その結果サーバレスアプリケーション全体が作動するためにも同様に不可欠となります。ここで重要なことは、サーバレスアプリケーションによる機密性の高い変数へのアクセスを制限することです。
まず、azure-functions/mesh:3.7.1-python3.9 をベースに Azure functionを構築した場合及び Azure Function Base-Python イメージを使用して構築した場合の Python スタックの違いを認識する必要があります。
図5に示すように、前者では、root ユーザとしてラッパースクリプトの初期化を実行した後、sudo コマンドを使用しアプリケーションのユーザとなり WebHost.dll バイナリを実行しています。そして、すべての環境変数を WebHost.dll へ渡しています。これに対し、後者の場合には、デフォルトでrootユーザにおけるWebHost.dllのバイナリが実行されます。WebHost.dllはその後、サーバレスコードを実行するプロセスであるpython-workerを実行します。
機密性の高い環境変数の制限
WebHost.dllを実行するには、機密性の高い環境変数が内部に必要です。この性質上、機密情報は python-worker プロセスとそこから実行されるサーバレスコードに継承されます。この変数は、プロセスメモリの一部であるため、それを削除するオプションは限られます。なお、読み取り権限及び「/proc/ファイルシステム」の性質を利用することで、同じユーザで実行されている他のプロセスの環境変数をプリントすることが可能となります。
以上から、WebHost.dllバイナリ(または、その設定)機能を変更し、別ユーザとしてlanguage-workerを使用し、機密性の高い環境変数を使用せずに遂行することが最良の選択肢となります。
コンテナイメージの構築プロセスは既に認知されているため、オルタレーションポイントを調査することが可能となります。インタプリタはPythonであるため、コードをインジェクトする最も簡単な方法は、コンテナイメージ内のPythonバイナリの名前を変更し、元の名前のカスタムシェルスクリプトに置き換えることです。
シェルスクリプトの内容はシンプルです。環境変数を介さずにsudo -u www-data コマンドで別ユーザとして Python worker を実行します。
環境変数を介する場合には、unsetコマンド及びsudoのEパラメータを使用することにより機密性の高い変数へのアクセスを制限することができます。
図9が示すように、環境変数を取り除き、必要なときのみ機密性の高い変数にアクセスできるように制限することが可能となりました。
また、変更後もAzureの環境下でサーバレス機能を正常に実行できるか否かのテストも行いました。図11は、このテストの結果です。
Disrolessアプローチ:コンテナイメージの最小化及びパーミッションの制限
次に、コンテナのバイナリとイメージサイズを最小限まで減らしました。この方法は、Distrolessアプローチとして知られています。ここでは、アプリケーションの実行に不要かつエクスプロイトされた際に攻撃者に悪用される可能性があるバイナリを削除します。これにより、カスタムコンテナを削減します。
コンテナイメージから削除したバイナリは、すべて「 /bin ディレクトリ」のバイナリであり、シェルも含まれています。そのため、後ほど環境の微調整を行う必要があります。また、デモンストレーションでは、「/usr/binディレクトリ」にあるcurl、wget、及びperlのバイナリも削除しています。
被害に遭わないためには
攻撃者によって環境変数を悪用した攻撃が行われる可能性のある、アーキテクチャにおける設計上の欠陥について、トレンドマイクロは以前ブログを掲載しました。
Azure App Services の脅威モデルに関するブログでは、コンテナにおけるrootパスワードの使用や、機密情報を含む環境変数など、アーキテクチャ上の懸念について解説を行いました。また、環境変数として機密情報を保存することの危険性及び生じる結果についても解説しています。
トレンドマイクロでは、「クラウドセキュリティ上の懸念を最小限に抑えるためにできること」について啓蒙活動を行ってきました。私たちは、許可されたコンテナイメージに微調整を加えるだけで、これを実現することを目指しています。開発者は、表面下での動きを確認するだけではなく、デフォルトのイメージを信頼することには限界があることも留意しておく必要があります。信頼できるサービスを使用している場合であっても常に警戒を怠らないようにしなければなりません。
セキュリティを強固にし、同時にアプリケーションの機能を維持することは容易ではありません。トレンドマイクロでは、適切なコンテナイメージの設計により、環境変数を取り除き、機密性のない環境変数を権限の低い手段へ移すことが可能であることを証明しています。今後、このようなセキュリティ対策を行うことがより一般化していくでしょう。
参考記事
Stronger Cloud Security in Azure Functions Using Custom Cloud Container
By: David Fiser, Alfredo Oliveira
翻訳:新井 智士(Core Technology Marketing, Trend Micro™ Research)