Workload Identityを利用してAWS Lambdaからスプレッドシートにアクセスする

今回はWorkload Identityを利用してAWS Lambdaでスプレッドシートにアクセスする手順をまとめます。

今回のポイントは以下のとおり

  • Workload Identityを利用して、認証のキーやシークレットを使わずに認証を通す
  • サービスアカウントの権限を利用(借用)する
  • 条件は特定のAssumeRole名とする
  • コンソール画面で設定する
  • Lambda側はPythonで実装する
    • スプレッドシート操作はgspreadライブラリを使用する

なお、以下については記載していませんのであしからず。

  • フェデレーションやWorkload Identityの仕組みについての解説
  • GCPプロジェクトやLambda関数作成等の基礎的な手順
  • Workload Identityを使ってスプレッドシートを取得できてからの処理

GCP内のサービスに直でアクセスする記事はあるのですが、ワークスペースのスプレッドシートへアクセスする手順などが書かれた記事がなかったので、同じ困難にぶつかった人の助けになれば嬉しいです。
詳細は聞かれてもわからないかもしれない

目次

準備

まずは準備段階として、以下を実施します。

  • AWSアカウントID(12桁の番号)を控えておく
  • Lambdaのロール名を決めておく(先に関数を作成してても大丈夫)
  • GCPプロジェクトの用意

ロール名はGCP側で登録が必要なため、あらかじめ決めておくと楽です。
名称が長すぎるとエラーになるため、CloudFormationを利用している方はデフォルトの名称にしているとエラー率高いです。

また、GCPプロジェクトはWorkload Identity管理用に専用のプロジェクトを作成することが推奨されています。
詳しくはGoogle Cloud公式ドキュメントの 専用のプロジェクトを使用して Workload Identity プールとプロバイダを管理する を参照してください。

GCP側の設定

まずはGCP側の設定をしましょう。以下の順番で実施します。

  1. サービスアカウントの作成
  2. Workload Identity設定
  3. サービスアカウントの権限借用設定
  4. IAM設定

サービスアカウントの作成

今回はGoogleワークスペースにアクセスするのでサービスアカウントを使用します。
GCPのサービス(Cloud StrageやらBigQueryやら)を使うだけであれば、サービスアカウントをわざわざ介さなくても問題ないはずです。

まずはサービスアカウントを作成します。

サービスアカウントはIAM管理の中で設定できます。

[IAMと管理] > [サービス アカウント]

サービスアカウントを作成し、Googleワークスペース(の中にスプレッドシート)にアクセスできるようアクセス権限を渡してください。

今回はWorkload Identityを利用するので、キーの作成は不要です。

ちなみに、Workload Identityの仕組みはサービスアカウントとしてアクセスするのではなく、サービスアカウントの権限を借用してアクセスする形になるそうです。

手順は解説するほどのことはないので割愛します。

Workload Identity設定

Workload Identityの設定画面はIAM設定の箇所から遷移できます。

[IAMと管理] > [Workload Identity 連携]

STEP
プールを作成する

遷移したらまずは”プールを作成”ボタンからプールを作成します。

Add Pool Screen.

プール名・説明は任意のものを入れてください。

“有効なプール”が有効状態になっていることを確認のうえ、”続行”ボタン。

STEP
プールにプロバイダを追加する
Add Provider Screen.

以下のとおり入力してください

  • プロバイダの選択: “AWS”を選択(選択すると以下2つの入力欄が表示されます)
  • プロバイダ名: 任意
  • AWSアカウントID: 準備のところで控えたAWSのアカウントID

入力したら”続行”で次に進みます。

STEP
プロバイダの属性を構成する(デフォのまま)
Configure provider attributes screen.

デフォルトのままでOK

今回は特に”attribute.aws_role: assertion.arn.contents(‘assume-role’)?”が入っていればOKのはずです。

下にある”保存”を押して確定しましょう。

サービスアカウントの権限借用設定

作成したプール・プロバイダでサービスアカウントの権限借用の設定をします。

[IAMと管理] > [Workload Identity 連携] > [作成したプール]

プールとプロバイダの作成が完了したら、Workload Identity 連携画面の一覧に作成したプールが表示されますので、リンクをクリックしてプールの詳細画面を開いてください。

上部にある”アクセスを許可”ボタンから、サービスアカウントの紐付け設定ができます。

STEP
サービスアカウントの紐付け
service account settings.

以下のように設定します。

  • サービス アカウントの権限借用を使用してアクセス権を付与するを選択
  • サービスアカウントを選択する: 作成したサービスアカウント
  • プリンシパル
    • 属性名: aws_role
    • 属性値: LambdaのAssumeRoleのArn(arn:aws:sts::{ID}:assumed-role/{AssumeRoleName})

“保存”を押してして次に進みます。

STEP
構成ファイルのダウンロード

サービスアカウントは固定で指定されていると思いますので、プロバイダ(プール作成時に追加したもの)を指定して、”構成をダウンロード”を押して完了します。

ここでダウンロードしたものがLambdaから認証を通す際に使用するものなので、適切に管理しましょう。

追記: プリンシパルで指定するロール名について

サービスアカウントの紐付けのところでarn:aws:sts::{ID}:assumed-role/*と記載すればロール名関係なく設定したAWS環境からアクセスできそうです。

当然セキュリティ的には弱くなるかと思いますので、おすすめはしません。

構成ファイルには機密情報が含まれていない

ここでファイルをダウンロードをするとなると、「結局、秘密鍵の含まれたcredentials.json的なものを管理することになるのでは?」と思うかもしれませんが、ここでダウンロードする構成ファイルには機密情報が含まれていません。
ここがサービスアカウントキーを使用する方法との決定的な違いになります。

GCPの公式ドキュメントでは、以下のように記載されています。

注: サービス アカウント キーとは異なり、認証情報の構成ファイルに秘密鍵が含まれていないため、機密情報として扱う必要はありません。認証情報の構成ファイルの詳細については、https://google.aip.dev/auth/4117 をご覧ください。

Google Cloud – AWS または Azure との Workload Identity 連携を構成する

IAM設定

GCP側最後の設定が、IAMの権限設定です。

[IAMと管理] > [IAM]

“アクセス件を付与”で以下の設定をしてください

  • プールの設定
    • プリンシパル: principalSet://iam.googleapis.com/projects/{Google Project ID}/locations/global/workloadIdentityPools/{Pool Name}/*
    • ロール: Workload Identity ユーザー
  • サービスアカウントの設定
    • プリンシパル: 作成したサービスアカウントのアドレス
    • ロール: サービス アカウント トークン作成者(その他ワークスペース処理で必要な権限)

これでLambdaからWorkload Identityでアクセスした際にサービスアカウントからのトークンが返されるようになり、それをもとにワークスペースへアクセスできます。

Lambda側の設定

GCP側の設定が完了したので、AWS(Lambda)側を作っていきます。

Lambda環境設定

環境設定について解説すると長いので、必要最低限のtemplate.yamlを記載します。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  SampleFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello_sample/
      Handler: app.lambda_handler
      Runtime: python3.9
      Architectures:
        - x86_64
      Environment:
        Variables:
          GOOGLE_CLOUD_PROJECT: "workload-identity-sample" # Workload Identity管理用に作成したGCPプロジェクト
          GOOGLE_APPLICATION_CREDENTIALS:  "clientLibraryConfig-sample-pool.json" # ダウンロードしてきた構成ファイルのパス
      Timeout: 10
      Role: !GetAtt SampleFuncRole.Arn
  SampleFuncRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: "sample-role" # 事前に決めておいたAssumeRole名
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action: sts:AssumeRole
            Principal:
              Service: lambda.amazonaws.com
      Policies:
        - PolicyName: sample-func-policy
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: "*"

今回特に意識すべきはコメントを記載した箇所ぐらいで、プロジェクト名やパスなどを任意で調整してもらえればと思います。

次に、今回使うライブラリをrequirements.txtに記載します。

google-auth
gspread
requests

スクリプトを作成

最後にLambdaのスクリプトを作成します。

ファイル構成とかは何も考えず1ファイルで書いてしまいます。

import os
import json

import gspread
from google.auth import aws

def lambda_handler(event, context):
    credentials = get_credentials()
    client = gspread.authorize(credentials)

    client.open_by_url("Spreadsheet URL") # スプレッドシートをURLから取得する

def get_credentials():
    config_path = os.path.dirname(os.path.abspath(__file__)) + "/" + os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
    with open(config_path, 'r') as cred_file:
        json_config_info = json.loads(cred_file.read())
    credentials = aws.Credentials.from_info(json_config_info)

    scoped_credentials = credentials.with_scopes([
        'https://spreadsheets.google.com/feeds',
        'https://www.googleapis.com/auth/drive',
        'https://www.googleapis.com/auth/spreadsheets'
    ])

    return scoped_credentials

これでスプレッドシートが取得できれば、あとはgspreadライブラリのとおりに使用するだけです。

template.yamlで設定した環境変数部分やスプレッドシートのURLなどは、ご自身で調整してください。

ここまでできたら、あとはデプロイして実行です。
無事にスプレッドシートが取得できれば、完了となります。

まとめ

Workload Identityを利用したアクセスは、外部に漏らしたくないCredentialsファイルなどを持たせる必要がないため、比較的安心して運用できるようになります。

追記したとおりロール名に関係なくアクセスできるようにできましたが、安全性を考えて個別に設定した方が良いのは間違いありません。
プロジェクト毎に権限を分けてアクセスさせる方が一般的でしょうし、それに応じてプールを追加し、アクセスできるロールを個別指定するのが一番綺麗かと思います。

また、今回はGCP側をコンソール上で設定しましたが、CLIで操作すればもっと楽にできるかもしれません。

そのあたりのTipsについても溜まってきたら書いていきたいと思います。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

都内Edtech企業のコーポレートエンジニア。
業務改善・自動化についての開発をしています。
エンジニア歴9年、コーポレートエンジニア歴4年。

目次