最小権限の原則による Cloud Run のデプロイ保護
Google Cloud Japan Team
Cloud Run リソースへの必要なアクセスのみを許可することで安全なデプロイを実現
※この投稿は米国時間 2023 年 2 月 18 日に、Google Cloud blog に投稿されたものの抄訳です。
Cloud Run を使用すれば、デベロッパーは、Google のスケーラブルなインフラストラクチャ上で実行されるサーバーレス環境に本番環境のウェブ アプリケーションと API を簡単にデプロイできます。開発チームは Cloud Run を活用して開発のアジリティを向上させ、迅速に反復処理できますが、多くの場合、インフラストラクチャのセキュリティ体制が見落とされています。十分な注意が払われていないセキュリティの側面として特に注目すべきなのが、アクセス管理と最小権限の原則です。
最小権限の原則とは、あるリソースに対してその機能に必要なリソースのみへのアクセスを許可することを示します。この原則は、ID の侵害によって攻撃者に幅広いリソースへのアクセスが許可されるリスクに対応するべく考案されました。幸いなことに、Google Cloud にはきめ細かいアクセス制御と、その適用に役立つツールが用意されています。今回の投稿では、インバウンド(ユーザーとサービスが Cloud Run にアクセスする場合)とアウトバウンド(Cloud Run サービス自体が他のサービスにアクセスする場合)の両方のシナリオに最小権限の原則を適用することで、Cloud Run のセキュリティ体制を改善する方法をご紹介します。
最小権限の原則に沿う Cloud Run の構成方法とは
大まかに、ユーザー向け(フロントエンド)アプリケーションと内部(バックエンド)アプリケーションという 2 つの Cloud Run ユースケースを考えてみましょう。どちらのユースケースも、バックエンドの Cloud Run サービスがフロントエンドの Cloud Run サービスから直接呼び出されるか、イベントに応答して呼び出される、一般公開ウェブアプリに見ることができます。このようなシナリオの例として、次の図に示すような単純な PDF 変換ウェブアプリを挙げることができます。
この架空のウェブサイトでは、ユーザーは PDF に変換したいドキュメントをアップロードできます。ウェブサイトにはサインアップ機能とログイン機能が実装されているため、認証を受けたユーザーは自分の変換履歴にアクセスでき、そのユーザーのドキュメントにアクセスできるのはそのユーザーのみであることを確認できます。ユーザーデータの保持には Cloud SQL データベースが使用され、ドキュメントは Cloud Storage バケットに保存されます。
前の図に示すとおり、新しいドキュメントが Cloud Storage にアップロードされるたびに、メッセージが Cloud Pub/Sub にパブリッシュされ、push サブスクリプションを使用して Backend Worker サービスがトリガーされると、変換が実行されます。ファイルが変換されると、サービスは新しいファイルを Cloud Storage バケット内の別の場所にアップロードします。この単純な例では、バックエンド サービスによって Cloud SQL データベースは更新されません(より現実的なシナリオでは、バックエンド サービスによって Cloud SQL データベースが更新されることに注意してください)。
つまり、この例では、ユーザー向けの一般公開フロントエンド アプリと、Cloud Pub/Sub サービスによってトリガーされる内部バックエンド アプリの 2 つの Cloud Run サービスがあることになります。
公開ウェブサイトであるため、フロントエンドの Cloud Run サービスは、認証を受けたユーザーのみにアクセスを制限することはできません。認証や承認を必要とする内部アプリ機能は、いずれも適切な認証メカニズムとコード ライブラリを使用して処理する必要があります。エンドユーザーの認証の対応方法はこの記事では説明しませんが、詳細にご興味がある方は、こちらの便利なチュートリアルを参照してください。ここで説明するのは、前の図で強調表示されているトラフィック フローの 3 つのダウンストリーム領域で最小権限の原則を適用する方法です。
App Frontend サービスからバッキング サービスへのアクセス
内部サービス(Cloud Pub/Sub)から Backend Worker サービスへのアクセス
Backend Worker サービスからバッキング サービスへのアクセス(1 に類似)
この 3 つの領域に対応するために、また、一般に Cloud Run アプリに最小権限の原則を実装するために把握する必要があることは、Cloud Run サービスを呼び出す内部ユーザーとサービスのアクセスを制限することと、他の Google Cloud サービスにアクセスする Cloud Run サービスのアクセスを制限することの 2 つにまとめられます。
内部ユーザーとサービスが Cloud Run サービスを呼び出す場合
未認証のアクセスを許可しない
内部 Cloud Run サービスがある場合、それがウェブまたはモバイル バックエンド、プライベート API、軽量の自動化ジョブのいずれであっても、最小権限の原則に準拠するうえで必要となる重要なアクションは、未認証のアクセスを許可しないことです。gcloud を使用すれば、サービスのデプロイ時に no-allow-unauthenticated オプションを指定することでこれを実現できます。コンソールを使用して同様のことを実現するには、サービスの作成時に [Require authentication](認証が必要)ボックスをチェックする必要があります。
この設定を適用すると、サービスは未認証のリクエストを HTTP 403 Forbidden エラーで拒否するようになります。
では、正当なリクエストが確実に通過するようにするにはどうすればよいでしょうか。この例では、Cloud Pub/Sub の push サブスクリプションのみが Cloud Run サービスを呼び出せるようにします。他のサービスやユーザーがそれを実行できてはいけません。どうすればそれを実現できるか見てみましょう。
カスタム サービス アカウントを作成する
サービス アカウントを指定せずに Cloud Pub/Sub の push サブスクリプションを作成しても、リクエストは認証されません。Cloud Run サービスが未認証のリクエストを受け入れれば話は別ですが、今は最小権限の原則を適用して内部サービスを保護する前提に基づいて話をします。ここでは、認証済みのリクエストのみを受け入れるように Cloud Run を構成しました。したがって、Cloud Run へのリクエストの認証を受けるには、どのような場合でも Cloud Pub/Sub の push サブスクリプションが必要です。最初のステップは、カスタム サービス アカウントを作成することです。
gcloud を使用してサービス アカウントを作成するには、次のコマンドを実行します。
サービス アカウント名は、プロジェクト内で一意である必要があり、その使用目的が見てわかるものであることが理想です。たとえば、サービス アカウントには pubsub-cloud-run-invoker-sa という名前を付けることができます。display-name オプションを使用して、よりわかりやすい表示名を定義することもできます。たとえば、次のようなものです。
最小限の権限で IAM ポリシー バインディングを構成する
新規に作成されたサービス アカウントには権限が関連付けられていないため、何も実行できません。
Cloud Run サービスを呼び出す権限をサービス アカウントに付与するには、事前定義ロールを割り当てるか、必要な権限セットを持つカスタム ロールを作成します。オーナー、編集者、閲覧者などの基本的なロールは、必要以上の権限が付与される可能性があるため、避けるのが賢明です。事前定義ロールとは、プロジェクト全体または特定のリソースに適用できる Google Cloud 用にキュレートされたサービス固有のロールです。事前定義ロールの中から必要最小限の権限を持ち、不要な権限を持たないものを見つけたら、それを優先的に利用するべきでしょう。Cloud Run で利用できるオプションを見てみましょう。
利用可能なオプションの中でも Cloud Run 起動元ロールには、ちょうど私たちが必要としている権限である「サービスの呼び出し」があることがわかります。不要な権限はなく、必要最小限の権限を備えたロールといえるでしょう。
このロールをサービス アカウントに割り当てるには、Cloud Run サービスに IAM ポリシー バインディングを追加する必要があります。gcloud を使用してこれを実現するには、次のコマンドを実行します。
SERVICE_ACCOUNT_ID
は、サービス アカウントの識別に使用されるメールアドレスです。これには次のフォーマットが使用されます。
[SERVICE_ACCOUNT_NAME]@[PROJECT_ID].iam.gserviceaccount.com
pubsub-cloud-run-invoker という名前のサービス アカウントの場合、プロジェクト ID が my-project であると仮定すると、メールアドレスは次のようになります。
pubsub-cloud-run-invoker@my-project.iam.gserviceaccount.com
IAM ポリシー バインディングを追加すると、バックエンドの Cloud Run サービスを呼び出す権限がサービス アカウントに付与されます。
呼び出し側のサービスを有効にして Cloud Run を呼び出す
認証された Cloud Run リクエストは、Google Cloud の署名付き OpenID Connect トークンをリクエストの一部として追加することにより、呼び出し側のサービスの ID の証明を提示する必要があります。そのため、サービス(この例では Cloud Pub/Sub)にそのトークンを生成する権限を付与する必要があります。
2021 年 4 月 8 日以前に作成された Google Cloud プロジェクトの場合、サービス アカウント トークン作成者ロールを Google マネージド サービス アカウントであるservice-[PROJECT_NUMBER]@gcp-sa-pubsub.iam.gserviceaccount.com
に付与する必要があります。このロールにより、プリンシパルは OAuth 2.0 アクセス トークンと OpenID Connect(OIDC)ID トークンを作成し、JSON Web Token(JWT)に署名できるようになります。サービス アカウントにこのロールを付与するポリシー バインディングを追加するには、gcloud を使用して次のコマンドを実行します。2021 年 4 月 8 日より後に作成されたプロジェクトの場合、このロールを付与する必要はありません。Google Cloud が管理する Pub/Sub サービス アカウントには、同じ権限を持つサービス エージェントのロールがあるためです。
最後のステップは、ユーザーが管理するカスタム サービス アカウントを使用するよう Pub/Sub の push サブスクリプションに「指示」することです。これを実行するには、push サブスクリプションを作成する gcloud コマンドに --push-auth-service-account
プロパティを含めます。
これにより、この Cloud Run サービスを呼び出す権限を他のユーザーまたはサービスに付与しない限り、処理されるすべてのリクエストは Pub/Sub からのものであることになります。さらに、Cloud Pub/Sub サブスクリプションは、Cloud Run 起動元ロールで許可されている唯一のアクションであるため、Cloud Run サービスを呼び出す以外のアクションを実行できないことはすでにわかっています。以上が最小権限の原則の使用例です。
Cloud Run サービスが他のサービスにアクセスする場合
カスタム サービス アカウントを指定しない限り、Cloud Run はデフォルトの Compute Engine サービス アカウントをデフォルトとして使用します。このデフォルトのサービス アカウントにはプロジェクトの編集者ロールがあり、Google Cloud プロジェクトのすべてのリソースに対する読み取りと書き込みの権限が付与されています。そのため、特に Google Cloud を使い始めたばかりのユーザーにとっては、シームレスで便利な開発エクスペリエンスが可能になります。ただし、これは最小権限の原則に反するため、本番環境では避けるのが賢明です。
Cloud Pub/Sub で行った場合と同じように、Cloud Run のカスタム サービス アカウントを作成して、必要最小限の権限セットを付与できます。では、どのような権限が必要でしょうか。この例のフロントエンド アプリには、Cloud SQL データベースへの読み取りおよび書き込みアクセスが必要です。また、Cloud Storage バケット内のオブジェクトを取得、作成、削除、管理するためのアクセスも必要になります。バックエンド アプリに必要なのは、オブジェクトを Cloud Storage バケットにアップロードすることだけです。
Cloud Run サービス ID を作成し、最小限の権限を付与する
Cloud Run では、各サービス リビジョンが 1 つのサービス アカウントにリンクされています。このサービス アカウントは Cloud Run サービス ID と呼ばれます。Google は、サービス間で ID を再利用するのではなく、Cloud Run サービスごとに独自の専用 ID を設けることをおすすめしています(異なるサービス間で同一の権限が必要な場合であっても)。
そのため、2 つのカスタム サービス アカウントを作成する必要があります。ここでは、それらのアカウントを frontend-app-sa
と backend-app-sa
と呼ぶことにします。gcloud では、次のコマンドを実行できます。
gcloud iam service-accounts create frontend-app-sa
gcloud iam service-accounts create backend-app-sa
Google Cloud では、1 つの ID に複数のポリシー バインディングを追加できます。これは、サービス アカウントに複数のロールを割り当てられることを意味します。この場合、フロントエンド アプリ サービス アカウントに Cloud SQL クライアントのロールと Storage オブジェクト管理者ロールを割り当てることができます。バックエンド アプリ サービス アカウントには、Storage オブジェクト作成者ロールを使用できます。
gcloud を使用して、次のコマンドを実行できます。
これで、私たちが必要とする最小限の権限しか持たないユーザー管理のサービス アカウントを構成できました。
オプション: IAM ポリシー条件を追加する
最小権限の原則にもう一歩踏み込みたい場合は、特定の条件が満たされた場合にのみリソースへのアクセスが許可されるようにすることもできます。たとえば、お使いのアプリケーションが平日にのみ使用される社内アプリケーションであるとします。誰も(少なくとも正当なユーザーが)週末にサービスを使用しない場合は、フロントエンド サービスによるデータベースへのアクセスを平日のみに制限することで、セキュリティ体制をさらに強化できます。
これを実行する際は、より簡単に IAM 条件を作成できる Google Cloud コンソールを使用しましょう。
IAM と管理コンソールで、[IAM] に移動してプリンシパルのリストを表示します。以前に作成した app-frontend-sa サービス アカウントの横にある鉛筆アイコンをクリックして編集します。編集ページは次のようになります。
次に [Add IAM Condition](IAM の条件を追加)をクリックします。[Condition Builder](条件ビルダー)タブでは、グラフィカル ユーザー インターフェースを使用してアクセス条件を構成できます。この例では、平日のみのアクセスを許可したいので、構成の具体例は次のようになります。
完了したら変更を保存します。これで、週末はフロントエンド アプリからデータベースにアクセスできなくなります。この際、フロントエンドのコードを更新して、その弊害に適切に対処できるようにするのが理想です。たとえば、週末にサービスが利用できないことを伝えるフレンドリーなメッセージを週末の作業員に表示するなどです。
日時以外に適用できるその他の IAM 条件は次のとおりです。
アクセスレベル
宛先 IP アドレスとポート(IAP TCP トンネリングの場合)
想定 URL ホスト / パス(IAP の場合)
ただし実際は、IAM 条件を設定することで、望ましくない形でユーザー エクスペリエンスを妨げてしまうケースが多くあります。このステップがオプションであり、限られたシナリオでのみ考慮すべき事項であるのはそのためです。
新しいサービス ID を使用して Cloud Run サービスをデプロイする
ユーザー管理のサービス ID を使用して Cloud Run サービスをデプロイするには、(gcloud を使用して)以下のコマンドを実行するだけです。
次のコマンドで既存のサービスを更新することもできます。
注: カスタム サービス アカウントを使用して Cloud Run サービスをデプロイするには、そのサービス アカウントの権限を借用できる権限が必要です。
この例では、フロントエンド サービスとバックエンド サービスがすでに存在すると仮定して、次のコマンドを実行します。
これで、最小権限の原則に基づいて Cloud Run アプリを保護できました。いや、ひょっとするとできていないかもしれません。
アクセスの監査と IAM Recommender の使用
優れたセキュリティ体制には、適切な設定を適用するだけでなく、適切なプロセスに従うことが不可欠です。ID とアクセス管理の場合、これは定期的な監査を行い、長期にわたってアクセスをモニタリングすることを意味します。プロジェクトで、誰が、いつ、何にアクセスしているのか、可視性を損なわないことが重要です。プロジェクトが時間の経過とともに進化するにつれて、アクセス パターンも変化する可能性があるため、付与されているが不要になった権限について IAM ポリシーを定期的に見直す必要があります。
誰が、いつ、何にアクセスしているかを確認する方法
Google Cloud では、すべてのプラットフォーム アクティビティが Cloud Audit Logs に記録されます。これは、すべての Google Cloud プロジェクトにおいてデフォルトで有効になっており、無効にすることはできません。こうしたログは、「誰が、いつ、何をしたか」という疑問に答えるうえで役立ちます。ログを見つけるには、Logging コンソールからログ エクスプローラに移動します。[Query](クエリ)ペインの右上にある [Log name](ログ名)をクリックすると、ログを名前でフィルタできます。次の画像に示すように、[Cloud Audit] の [activity](アクティビティ)を選択して、アクティビティ ログのみを表示します。
[Apply](適用)をクリックすると、ログ エクスプローラのページにすべてのアクティビティ ログの一覧が表示されます。各エントリを展開して、アクティビティの詳細を調べることができます。
他にもコンソールの [Activity](アクティビティ)ページに移動すれば、簡略化された監査ログエントリを表示することもできます。
データアクセス監査ログ
データアクセス監査ログは、リソースの構成またはメタデータを読み取る API 呼び出しと、ユーザー提供のリソースデータを作成、変更、または読み取るユーザー主導の API 呼び出しを含む、特別な種類の監査ログです。BigQuery を除き、これらのログはデフォルトで無効になっています。なぜなら、非常に大量のログが生成される可能性があるからです。
BigQuery 以外の Google Cloud サービスにデータアクセス監査ログを書き込む場合は、こちらの手順に沿って明示的に有効にする必要があります。
アラート
監査ログに特定のメッセージが表示されたときに通知を受け取りたい場合は、Cloud Monitoring を使用してログベースのアラートを作成できます。たとえば、一部の機密データへのアクセスがデータアクセス監査ログに記録された場合や、プロジェクトのセキュリティ設定の変更など、頻度が低く影響の大きい特定のアクティビティが実行された場合に、アラートをトリガーすることが考えられます。
ログベースのアラートを作成するには、こちらの手順に沿って操作してください。
監査ログの調査とアラートの設定のほかに、IAM Recommender を使用することもできます。
IAM Recommender とその使用方法
IAM Recommender はロールの推奨事項を生成するもので、この推奨事項サービスが提供する提案の一つを参考にして、ユーザーはプリンシパルの過剰な権限を特定し、削除できます。各ロールの推奨事項によって、プリンシパルに過剰な権限を付与しているロールの削除または置換が提案されます。最小権限の原則に準拠できるように、こうした提案を活用するとよいでしょう。
推奨事項を表示するには、Recommendations コンソールに移動します。次の図はロールの推奨事項の表示例です(ロールの作成後、表示されるまでに最長 90 日間かかる場合があります)。この推奨事項は、推定で 12,340 件の過剰な権限があることを示しています。これは、編集者ロールを持つ未使用のサービス アカウントが 2 つあるためです。[View all](すべて表示)をクリックすると、Recommender が参照しているプリンシパルを調べることができます。プリンシパルごとに、不要と思われる権限の一覧も確認できます。
前述のように、編集者ロールには多数の権限が含まれているため、厳密に必要な場合を除き、使用を避けるのが賢明です。ただし、IAM Recommender は編集者ロールだけを確認するわけではありません。過剰な権限がある可能性があるロールの割り当てがあれば、それを調べます。
ちなみに、Cloud Run サービス用にユーザー管理のサービス アカウントを作成し忘れている場合は、同様に作成することをおすすめします。
まとめと行動喚起
デベロッパーが Cloud Run を選択するのは、スケーラブルで柔軟なアプリケーション プラットフォームだからです。その反面、アクセス権限の管理と最小権限の原則の適用は、しばしば見落とされる重要なセキュリティ プラクティスです。幸いなことに、Google Cloud は、プラットフォーム全体に最小権限の原則を適用できるツールと機能を提供しています。これには、IAM コントロールだけでなく、IAM Recommender サービスと Cloud Audit Logs も含まれており、長期にわたってセキュリティ体制を維持することも可能です。
ただし、この記事で触れたのは、最小権限の原則の観点から見たセキュリティのみであることを忘れないでください。理想的には、データベースをインターネットから分離すること、VPC ネットワークを保護すること、VPC Service Controls を使用して機密データを保護すること、Cloud KMS や Secret Manager などのサービスを活用することなども検討すべきでしょう。より包括的で安全なサーバーレス アーキテクチャについては、安全なサーバーレス アーキテクチャのブループリントをご覧ください。
この記事で学んだ原則を応用できるハンズオン ラボについては、Google Cloud Skills Boost の Serverless Cloud Run Development クエストをご確認ください。ID とアクセス管理の経験をさらに深めるには、Ensure Access & Identity in Google Cloud クエストのラボをご確認ください。