Lambda から Transcribe の StartCallAnalyticsJob を実行する際に必要な IAM ロールについて

ポイントは PassRole と信頼関係でした。
2022.05.09

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

アノテーションの中村 (誠) です。
先日、Lambda から Transcribe の StartCallAnalyticsJob を実行する際に、IAM ロール関連でハマったので、原因と解決策を紹介します。

結論

StartCallAnalyticsJob を実行するには、Transcribe を信頼されたエンティティとした IAM ロールが必要です。

ハマった環境

S3

S3 バケットはデフォルト設定で作成し、mp3 ファイルをアップロードしました。

Lambda

・ランタイム
Python 3.9

・実行ロール
以下の IAM ポリシーを付与しました。

AWSLambdaBasicExecutionRole
AmazonS3FullAccess
AmazonTranscribeFullAccess

・コード

start_call_analytics_job.py

import boto3

transcribe = boto3.client('transcribe')


def lambda_handler(event, context):

    response = transcribe.start_call_analytics_job(
        CallAnalyticsJobName='test',
        Media={
            'MediaFileUri': '{S3-Object-URI}'
        },
        DataAccessRoleArn='{Lambda-Execution-Role}',
        ChannelDefinitions=[
            {
                'ChannelId': 0,
                'ParticipantRole': 'AGENT'
            },
            {
                'ChannelId': 1,
                'ParticipantRole': 'CUSTOMER'
            }
        ]
    )

    print(response)

ハマったこと

ここまでの設定で Lambda 関数を実行したところ、以下のエラーが発生しました。

An error occurred (AccessDeniedException) when calling the StartCallAnalyticsJob operation: User: arn:aws:sts::{Account-ID}:assumed-role/{Lambda-Execution-Role}/Transcribe-function is not authorized to perform: iam:PassRole on resource: arn:aws:iam::{Account-ID}:role/{Lambda-Execution-Role} because no identity-based policy allows the iam:PassRole action

iam:PassRole のアクセス許可がないというエラーです。

AWS のサービスにロールを渡すアクセス権限をユーザーに付与する - AWS Identity and Access Management

ユーザーがロール (とそのアクセス許可) を AWS サービスに渡すには、そのサービスにロールを渡すアクセス許可が必要になります。これにより、承認済みのユーザーのみが、アクセス許可を付与するロールを使用してサービスを設定できるようになります。ユーザーが AWS サービスにロールを渡すには、IAM ユーザー、ロール、またはグループに PassRole アクセス許可を付与する必要があります。

こちらのエラーは、Lambda の実行ロールに iam:PassRole の権限を付与することで解決できました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::{Account-ID}:role/*"
    }
  ]
}

この時点で Lambda の実行ロールに付与した権限は以下のようになりました。

この状態で再度 Lambda 関数を実行したところ、以下のエラーメッセージに変わりました。

An error occurred (BadRequestException) when calling the StartCallAnalyticsJob operation: The S3 URI that you provided can't be accessed. Make sure that you have read permission and try your request again.

今度は S3 にアップロードしたオブジェクトへのアクセスができていないというエラーのようです。
S3 へのアクセス権限は AmazonS3FullAccess で付与しており、同じアカウント内なのでバケットポリシーは設定しなくてもアクセスできるはずですが、エラーになってしまいました。

CloudTrail で調べてみた

StartCallAnalyticsJob を実行している userIdentity は以下の通り Lambda 関数の実行ロールでした。

arn:aws:sts::{Account-ID}:assumed-role/{Lambda-Execution-Role}/Transcribe-function

アクセス権限は S3 、Transcribe ともに FullAccess なので、Lambda の実行ロールのアクセス権限は問題ないと思っていました。

コンソールで StartCallAnalyticsJob をやってみる

Transcribe コンソールでも StartCallAnalyticsJob を実行可能なことがわかったので、AWS 公式ドキュメント を参考に、Transcribe コンソールから StartCallAnalyticsJob を実行してみました。

Name を入力し、Language は日本語を指定しました。

Input data は S3 にアップロードしてある mp3 ファイルを指定しました。

IAM ロールを作成する必要があるようなので、「Create an IAM role」を選択して新しく IAM ロールを作成しました。

その他の設定はデフォルトのまま、「Create job」をクリックして、ジョブを作成しました。

ジョブが始まり、しばらく Status が In progess となります。

しばらく待つと、Status が Complete になったので、ジョブの詳細を確認してみます。

画面下部の Application integration で DataAccessRoleArn を確認したところ、自動的に作成された IAM ロールが指定されていたので、この中身を IAM コンソールで確認してみます。

IAM コンソールで確認

Transcribe コンソールで StartCallAnalyticsJob を実行した際に自動的に作成された IAM ロールを確認してみます。

AmazonTranscribeServiceRole-{input-role-name} という名前の IAM ロールが作成されていました。

同時に AmazonTranscribeServicePolicy-{input-role-name} という IAM ポリシーも作成、アタッチされており、必要な権限も付与されていました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::{s3-bucket-name}/*"],
      "Effect": "Allow"
    },
    {
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::{s3-bucket-name}"],
      "Effect": "Allow"
    },
    {
      "Action": ["kms:Decrypt"],
      "Resource": ["arn:aws:kms:ap-northeast-1:{Account-ID}:key/*"],
      "Condition": {
        "StringLike": {
          "kms:ViaService": ["s3.*.amazonaws.com"]
        }
      },
      "Effect": "Allow"
    }
  ]
}

信頼関係も確認してみます。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "transcribe.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

なんと、信頼関係の Principal に指定されていたのは、transcribe.amazonaws.com でした。
先述のエラーはこの部分に関連していると推測したので、自動的に作成されたこちらの IAM ロールを Lambda 関数コード内の DataAccessRoleArn に指定してみました。

解決策

Lambda 関数の DataAccessRoleArn を以下のように変更しました。

start_call_analytics_job.py

import boto3

transcribe = boto3.client('transcribe')


def lambda_handler(event, context):

    response = transcribe.start_call_analytics_job(
        CallAnalyticsJobName='test',
        Media={
            'MediaFileUri': '{S3-Object-URI}'
        },
        DataAccessRoleArn='{IAM role automatically created by transcribe}',  # 変更箇所
        ChannelDefinitions=[
            {
                'ChannelId': 0,
                'ParticipantRole': 'AGENT'
            },
            {
                'ChannelId': 1,
                'ParticipantRole': 'CUSTOMER'
            }
        ]
    )

    print(response)

この状態で再度 Lambda 関数を実行したところ、以下のエラーメッセージに変わりました。

An error occurred (ConflictException) when calling the StartCallAnalyticsJob operation: The requested job name already exists. Use a different job name.

同じジョブ名があるというエラーなので、先ほどコンソールで実行したジョブを削除します。

再度 Lambda 関数を実行します。

今度は成功しました!

Transcribe コンソールでもジョブが作成されています。

しばらく待つと、Status が Complete となったので、問題なく実行できました。

Lambda 関数から StartCallAnalyticsJob を実行した際の挙動

上記の検証から、以下のような挙動になっていると思われます。

  1. Lambda 関数を実行
  2. Lambda 関数から StartCallAnalyticsJob を実行
  3. Lambda 関数から StartCallAnalyticsJob のパラメーターに指定した DataAccessRoleArnPassRole
  4. DataAccessRoleArn に指定した IAM ロールの権限で Transcribe が分析のために S3 などの AWS リソースへアクセス

Lambda 実行ロールに必要な権限の見直し

先述の挙動から、Lambda 実行ロールに必要な権限を見直しました。
StartCallAnalyticsJob を実行する IAM ロールには、先述の通り自動的に作成された IAM ポリシーが付与されています。このことから、Lambda 実行ロールに付与していた S3 へのアクセス権限は不要だと推測しました。
さらに、Lambda 関数から PassRole していることから、 Transcribe への FullAccess 権限も不要だと推測したので、以下の 2 つの権限を外しました。

AmazonS3FullAccess
AmazonTranscribeFullAccess

ただし、Transcribe の StartCallAnalyticsJob を実行する権限は必要だったため、Transcribe に関する権限は以下のように修正しました。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "VisualEditor0",
      "Effect": "Allow",
      "Action": "transcribe:StartCallAnalyticsJob",
      "Resource": "*"
    }
  ]
}

最終的に、Lambda 実行ロールは以下の状態になりました。

この状態でも Lambda 関数の実行は成功しました。
今回は Resource までは指定しませんでしたが、Action に関しては必要最小限に絞ることができました。

まとめ

今回は、Lambda から Transcribe の StartCallAnalyticsJob を実行する際に、IAM ロール関連でハマったので、原因と解決策を紹介しました。

あらためてポイントをまとめてみました。

・Lambda 関数から StartCallAnalyticsJob を実行するには、DataAccessRoleArnPassRole する権限が必要
StartCallAnalyticsJob を実行するための IAM ロールには 信頼関係の Principaltranscribe.amazonaws.com を指定する必要がある
・Transcribe コンソールから StartCallAnalyticsJob を実行することで、必要な権限を持った IAM ロールを自動的に作成することが可能
StartCallAnalyticsJobDataAccessRoleArn には、信頼関係の Principaltranscribe.amazonaws.com を指定した IAM ロールを指定する

参考になれば幸いです。

参考資料

アノテーション株式会社について

アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社 WEB サイトをご覧ください。