Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

IAMキー不要、Google CloudからAWSロールを引き受ける

By Avi KeinanSep 30, 20206 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

Google Cloud上で動くアプリケーションから、S3やSQSといったAWSリソースにアクセスしたい場面はよくあります。アクセスキーやシークレットキーをそのまま使うのはバッドプラクティスとされているため、最終的に Janus という小さなツールを自作しました。サービスアカウントを設定したGoogle Cloud Compute EngineインスタンスからAWSロールを引き受けられるツールです。

名前の由来は? ローマ神話で Janus(ヤヌス) は門と扉を司る二つの顔を持つ神。今回のユースケースにぴったりの比喩だと思いました ;-)

では Janusとは何か? Google Cloud Compute Engineインスタンス上で実行できる小さなコードで、AWS IAMキーを使わずにAWSロールを引き受けられるようにするものです。

なぜJanusを使うのか

たとえば、Google Cloud上のインスタンスやコンテナから、S3バケットにあるプライベートファイルを取得したいとします。ダウンロードするにはAWS IAMでの認証が必要です。

認証方法はいくつかあります。最も安全なのはインスタンスにIAMロールをアタッチする方法ですが、これはEC2インスタンス(AWSインフラ上で動くインスタンス)でしか使えません。

Google Cloudインスタンスの場合は選択肢が限られるため、多くの人がAWS IAMアクセスキーを発行し(しかも必要以上に広い権限を付けがちです)、ハードコードして保存してしまいます。

これは深刻なセキュリティリスクです。一度キーが漏洩すれば、それを手にした第三者は誰でもAWSアカウントにアクセスできてしまい、データ漏洩や金銭的被害につながりかねません。私が見てきた中で最も「軽い」例でも、ハッカーが暗号通貨マイニング用サーバーを立ち上げたり、アカウント内のデータやバックアップを暗号化して身代金を要求したりするケースでした。

では、ハードコードされたキーに頼らずに、GCPからAWSリソースへ安全に接続するにはどうすればよいのでしょうか?

Janusはこの課題を解決します。GCP Compute Engine上でGoogle Web Identityを使ってロールを引き受けられるようにする仕組みで、EC2でIAMロールを使うのと同じ感覚で利用できます。Janusは有効期間1時間の一時キーをAWSにリクエストします。

Janusの実装手順

例として、AWS S3バケットへの読み取り専用権限を付与し、後ほどGoogle Computeインスタンスから利用する流れを紹介します。

  1. GCPコンソールにログインし、左側のナビゲーションメニューから IAMと管理 を選択します。次に サービスアカウント をクリックし、+サービスアカウントを作成 をクリックします。

2. サービスアカウントに名前を付け、説明も詳しく記入します(これは常にベストプラクティスです)。その後、作成 ボタンをクリックします。

3. 続いて ロール ボックスをクリックし、サービスアカウント → サービスアカウント トークン作成者 を選択します。

もっと簡単なのは、フィルタするタイプを入力 検索ボックスに Token と入力する方法です。

4. 「このサービスアカウントへのユーザーアクセスを許可(オプション)」というページが表示されたら、完了 をクリックします。

5. サービスアカウント名をクリックし、固有ID をコピーします。

6. AWSアカウントにログインし、IAMコンソール ロール → ロールの作成 へ進みます。

7. 信頼されたエンティティ として ウェブアイデンティティ を選び、IDプロバイダーGoogle を指定し、Audience ボックスにGCPサービスアカウントの固有IDを貼り付けます。続いて 次のステップ: アクセス権限 ボタンをクリックします。

8. ロールに権限を付与します。今回は AmazonS3ReadOnlyAccess を使います。次のステップ: タグ ボタンをクリックします。

9. タグの設定は任意なので、ここではスキップします。次のステップ: 確認 ボタンをクリックしてください。

10. ロール名と詳しい説明を入力し、ロールの作成 をクリックします。

11. これでロールの準備は完了です。後の手順で使うので、ロールARN をクリックしてコピーしておきます。

12. GCPコンソール に戻り、新しいCompute Engine VMインスタンスを作成します。

少し下にスクロールして IDとAPIへのアクセス セクションを表示し、Compute Engineデフォルトサービスアカウント を、ステップ5で作成したサービスアカウントに置き換えます。

13. これでAWSとGCPの両方の設定が整い、GCPからAWSロールを引き受けられる状態になりました。あとは、Googleのウェブアイデンティティを使ってこの処理を実行するためのツールやコードが必要です。それを実現するために作ったのが Janus です。

Janus は、サポート対象のすべてのAWS SDKおよびAWS CLIに対して 一時的なAWS認証情報を返します

Janus を導入するには、rootユーザーで以下のコマンドを実行するだけです:

$ apt install python3-pip awscli
$ pip3 install boto3 requests
$ wget https://raw.githubusercontent.com/doitintl/janus/master/janus.py -O /usr/local/bin/janus
$ chmod 555 /usr/local/bin/janus

目的の IAMロールJanus を実行するには、ステップ10でコピーしたAWS Role ARNを指定します。

/usr/local/bin/janus arn:aws:iam::123456789012:role/s3-ro-from-gcp

14. /.aws/credentials ファイルに新しいプロファイルを作成します( はユーザーのホームディレクトリを表すショートカットです)。AWSのSDKは、このファイルに記述されたプロファイルを使ってAWSとの認証を行います。

ファイルが存在しない場合は新規作成します:

$ mkdir ~/.aws
$ touch ~/.aws/credentials

credentials ファイルを編集してプロファイルを追加します(デフォルトのプロファイル名は default です)。プロファイルは複数持てますが、今回は新しいデフォルトプロファイルを作成します:

credential_process = /usr/local/bin/janus arn:aws:iam::123456789012:role/s3-ro-from-gcp

15. 以上で完了です!!! これでGCPインスタンスからAWSが利用できるようになりました。

例として、AWS CLIを使ってAWS S3バケットから hello.txt というファイルをコピーしてみます:

仕組み

  • AWS SDKAWS CLI はAWSへアクセスするたびに、以下の場所からデフォルトプロファイルを探します:

Mac、Linux、Unixの場合は /.aws/credentials( はホームディレクトリのショートカット)

または

Windowsの場合は C:\Users\USERNAME\.aws\credentials

  • 続いて、引き受けたいAWSロール名を指定してJanusを実行します。
  • Janus はCompute EngineのメタデータサーバーからJWTトークンを取得し、指定されたAWSロール名でロールを引き受けます。
  • AWSはJWTトークンがAWSロールの設定と一致することを確認し、一時的なアクセスキーを返します:

  • この一時的なアクセスキーを使えば、AWSロールの権限でAWSにアクセスし、APIを呼び出すことができます。

どのインスタンスがAWSアカウントにアクセスしたかを追跡するには

追跡を容易にするため、Janus はカスタムセッション名でロールを引き受けます。セッション名は project-id.instance-name という形式です。

アカウントでAWS CloudTrailの証跡を有効にしていれば、AssumeRoleWithWebIdentity イベントをフィルタリングして、呼び出されたすべてのAPIを追跡できます。

イベントには次の情報が含まれます:

  1. GCPマシンのソースIP
  2. username — GCPサービスアカウントの固有ID
  3. セッションロールの「セッション名」 — プロジェクトIDとインスタンス名
  4. 引き受けたロール名

アクセスキーをもとに、そのインスタンスが実行したすべての操作を検索できます。