Lambda が S3 で AccessDenied になるときの確認ポイント ── 実行ロールにポリシーを付ける

目次

概要

S3 にファイルが置かれたら Lambda 関数で読み込んで変換し、別のバケットへ書き出す。よくある構成ですが、作ってみると関数のログに AccessDenied が出て、S3 の読み書きができないことがあります。コードもバケット名も合っているのに動かない場合、まず疑うのは関数がどの権限で動いているかです。

Lambda 関数が AWS のサービスを呼ぶときの権限は、関数に割り当てた 実行ロール(IAM ロール)で決まります。S3 や CloudWatch Logs への権限を書いた IAM ポリシーを用意しても、それを実行ロールにアタッチしなければ関数には効きません。IAM ユーザーを作ってアクセスキーを環境変数に入れる、という方法は使いません。

この記事では、実行ロールの仕組みと、権限を渡す方法の正しい・誤りを整理します。実践では、S3 トリガーで動く関数がまず AccessDenied で失敗することを確かめ、用意したポリシーを実行ロールにアタッチして成功させます。

S3 へのファイル配置で Lambda が呼ばれ、実行ロールの権限で読み書きする
S3 へのファイル配置で Lambda が呼ばれ、実行ロールの権限で読み書きする
クラウドおさる

荷運びの若猿(Lambda)に「倉庫から荷を出せ」と言っても、倉庫番に見せる役目札(実行ロール)を持たせていなければ追い返されるのでござる。今日はその役目札を正しく持たせるでござるよ。

この記事のメリット

  • Lambda 関数の権限が実行ロールで決まる仕組みを説明できるようになる
  • IAM ユーザーやアクセスキーではなく、実行ロールで権限を渡すべき理由が分かる
  • S3 トリガーで動く関数の AccessDenied を、実行ロールのポリシーから切り分けられるようになる
  • 用意済みの IAM ポリシーを実行ロールにアタッチできるようになる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

実行ロールとは

実行ロールは、Lambda 関数に AWS のサービスやリソースへのアクセスを許可する IAM ロールです。関数を作るときに指定し、関数が呼び出されると Lambda がこのロールを引き受け、一時的な認証情報で SDK の呼び出しを行います。コードの中で認証情報を扱う必要はありません。

実行ロールには 2 種類のポリシーが関わります。

ポリシー書いてあること
信頼ポリシーこのロールを引き受けてよいのは lambda.amazonaws.com(Lambda のサービス)
許可ポリシー関数が実行してよい操作(例: s3:GetObject、logs:PutLogEvents)

コンソールで関数を作るときに「基本的な Lambda アクセス許可で新しいロールを作成」を選ぶと、CloudWatch Logs への出力だけを許可したロールが自動で作られます。S3 などの権限は、自分で足す必要があります。

権限を渡す方法の比較

方法結果
IAM ポリシーを実行ロールにアタッチし、そのロールを関数に割り当てる正しい。Lambda がロールを引き受けて権限が効く
IAM ユーザーを作り、ポリシーをユーザーに付けて「関数に割り当てる」できない。関数に割り当てられるのはロールだけ
IAM ユーザーのアクセスキーを環境変数に入れる動くことはあるが、長期の認証情報が設定に残り、漏えいとローテーションの問題を抱える
ロールの名前や ARN を環境変数に入れる権限は付かない。関数が使うのは「実行ロール」の設定だけ
クラウドおさる

「鍵(アクセスキー)を荷札に書いて若猿に持たせる」のは、落としたら倉庫が開けっぱなしになるのと同じでござる。権限は役目札、つまり実行ロールで渡すのが正解でござるぞ。

AccessDenied のときの確認ポイント

S3 トリガーで動く関数が AccessDenied になったら、次の順に確認します。

  1. 関数の実行ロール: 「設定」→「アクセス権限」で、どのロールで動いているかを確認する
  2. ロールの許可ポリシー: そのロールに、必要な操作(読むなら s3:GetObject、書くなら s3:PutObject)が、正しいバケットの ARN(arn:aws:s3:::バケット名/*)で許可されているか
  3. バケットポリシー: バケット側で明示的に拒否していないか
  4. 暗号化: バケットが SSE-KMS のカスタマー管理キーで暗号化されているなら、キーの kms:Decrypt(読み取り)・kms:GenerateDataKey(書き込み)も要る

S3 から Lambda を呼び出す許可(関数のリソースベースポリシー)は、関数が S3 を読み書きする権限とは別物です。コンソールで S3 トリガーを追加すると、呼び出しの許可は自動で入りますが、実行ロールの権限は増えません。

権限の向きは 2 つ。呼び出しの許可と、読み書きの権限は別物
権限の向きは 2 つ。呼び出しの許可と、読み書きの権限は別物
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ハンズオンガイド7 ステップ画面 5 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

S3 の転送元バケットに .txt ファイルが置かれたら、内容を大文字に変換して出力先バケットへ書き出す Lambda 関数 dva-convert-fn を作ります。関数はコンソールの既定の実行ロールで作るので、最初は S3 の権限がありません。AccessDenied を確かめてから、用意済みのポリシー dva-convert-s3-policy を実行ロールにアタッチします。

前提条件

  • リージョン: ap-northeast-1(東京)
  • 以下のリソースが作成済みであること

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
S3 バケット(転送元)dva-convert-src-<アカウントID>変換前のテキストファイルを置くAmazon S3 でバケットを作成しオブジェクトを管理する
S3 バケット(出力先)dva-convert-dst-<アカウントID>変換後のファイルを置く同上
IAM ポリシー(カスタマー管理)dva-convert-s3-policy転送元の s3:GetObject、出力先の s3:PutObject、CloudWatch Logs への出力を許可AWS IAM でユーザー・ロール・ポリシーを作成しアクセス制御する

作成するリソース一覧

リソース種別リソース名用途
Lambda 関数dva-convert-fnテキストファイルを変換して出力先に書く
IAM ロールdva-convert-fn-role-xxxxxxxx(自動作成)関数の実行ロール
S3 トリガー(転送元バケット・サフィックス .txt)ファイルの配置で関数を呼ぶ

手順 1: 関数を作る

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに Lambda と入力し、「Lambda」を選択します。

「関数を作成」をクリックし、以下を設定します。

  • 「一から作成」を選択
  • 関数名: dva-convert-fn
  • ランタイム: Python 3.13
  • 実行ロール: 「その他の設定」の「カスタム実行ロール」はオフ(デフォルト)のまま。CloudWatch Logs への出力だけを許可する実行ロールが自動で作られます
関数の作成画面(関数名・ランタイム・実行ロールの設定)
関数の作成画面(関数名・ランタイム・実行ロールの設定)

画面下部の「関数を作成」をクリックします(作成後に案内のダイアログが出たら閉じます)。「コード」タブのエディタで lambda_function.py を次の内容に置き換え、「Deploy」をクリックします。DST_BUCKET の <アカウントID> は自分のアカウント ID に置き換えます。

import urllib.parse

import boto3

s3 = boto3.client("s3")
DST_BUCKET = "dva-convert-dst-<アカウントID>"


def lambda_handler(event, context):
    for record in event["Records"]:
        src_bucket = record["s3"]["bucket"]["name"]
        key = urllib.parse.unquote_plus(record["s3"]["object"]["key"])
        body = s3.get_object(Bucket=src_bucket, Key=key)["Body"].read().decode("utf-8")
        converted = body.upper()   # 変換処理の代わりに大文字にする
        out_key = key.rsplit(".", 1)[0] + ".converted.txt"
        s3.put_object(Bucket=DST_BUCKET, Key=out_key, Body=converted.encode("utf-8"))
        print(f"converted s3://{src_bucket}/{key} -> s3://{DST_BUCKET}/{out_key}")

手順 2: S3 トリガーを追加する

関数の概要の「トリガーを追加」をクリックし、以下を設定します。

  • ソース: S3
  • バケット: dva-convert-src-<アカウントID>(一覧から選んで「入力が無効です」と表示される場合は、arn:aws:s3:::dva-convert-src-<アカウントID> と ARN で入力します)
  • イベントタイプ: 「すべてのオブジェクト作成イベント」
  • サフィックス – オプション: .txt
  • 「再帰呼び出し」の確認のチェックボックスにチェック(出力先は別のバケットなので、再帰にはなりません)
トリガーの追加画面(S3・転送元バケット・サフィックス .txt)
トリガーの追加画面(S3・転送元バケット・サフィックス .txt)

「追加」をクリックします。

手順 3: ファイルを置いて AccessDenied を確かめる

S3 のコンソールで dva-convert-src-<アカウントID> を開き、次の内容の hello.txt をアップロードします。

hello from the banana warehouse

Lambda のコンソールに戻り、dva-convert-fn の「モニタリング」タブ →「CloudWatch Logs を表示」をクリックして、最新のログストリームを開きます。An error occurred (AccessDenied) when calling the GetObject operation のエラーが記録されています。トリガーで関数は呼ばれたものの、関数が転送元バケットを読めなかったことが分かります。

CloudWatch Logs のログ(GetObject の AccessDenied)
CloudWatch Logs のログ(GetObject の AccessDenied)
クラウドおさる

若猿は呼ばれて倉庫まで来たのに、役目札に「この倉庫の荷を出してよい」と書いていないので、倉庫番に断られたのでござるな。呼ぶ許可と、荷を出す許可は別物でござる。

手順 4: 実行ロールにポリシーをアタッチする

dva-convert-fn の「設定」タブ →「アクセス権限」を選択します。「実行ロール」に表示されているロール名(dva-convert-fn-role- で始まる名前)をクリックすると、IAM コンソールでロールが開きます。「許可ポリシー」には、CloudWatch Logs への出力だけを許可するポリシーが付いています。

「許可を追加」→「ポリシーをアタッチ」を選択します。検索欄に dva-convert-s3-policy と入力し、チェックを入れて「許可を追加」をクリックします。

実行ロールの許可ポリシーに dva-convert-s3-policy が追加された画面
実行ロールの許可ポリシーに dva-convert-s3-policy が追加された画面

手順 5: もう一度ファイルを置く

S3 のコンソールで、転送元バケットに hello.txt をもう一度アップロードします(同じ名前で上書きすると、新しい作成イベントとして関数が呼ばれます)。

出力先の dva-convert-dst-<アカウントID> を開くと、hello.converted.txt が作られています。オブジェクトを開いて「開く」をクリックすると、内容が HELLO FROM THE BANANA WAREHOUSE になっていることを確認できます。CloudWatch Logs にも converted s3://... -> s3://... のログが記録されます。

出力先バケットに hello.converted.txt が作られた状態
出力先バケットに hello.converted.txt が作られた状態
クラウドおさる

コードもトリガーも同じまま、役目札にポリシーを足しただけで荷が運べたでござる。Lambda の AccessDenied は、まず実行ロールを見に行く。これでござるな。

まとめ

困りごと確認するところ
関数のログに S3 の AccessDenied が出る実行ロールの許可ポリシー(操作とバケットの ARN)
SSE-KMS のバケットで読めない・書けない実行ロールの kms:Decrypt / kms:GenerateDataKey と、キーポリシー
S3 から関数が呼ばれないトリガーの設定と、関数のリソースベースポリシー(呼び出しの許可)
  • Lambda 関数の権限は実行ロール(IAM ロール)で決まる。関数の呼び出し時に Lambda がロールを引き受ける
  • 権限は IAM ポリシーを実行ロールにアタッチして渡す。IAM ユーザーを関数に割り当てることはできない
  • アクセスキーを環境変数に入れるのは避ける。ロール名を環境変数に入れても権限は付かない
  • コンソールの既定のロールは CloudWatch Logs への出力だけ。S3 などの権限は自分で足す
  • S3 → Lambda の呼び出し許可(リソースベースポリシー)と、Lambda → S3 の読み書きの権限(実行ロール)は別物

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

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

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次