pyてよn日記

一寸先は闇が人生

AWS:Serverless Framework における IAM ロールの設定

 Serverless Framework は npm で配布されている AWS Lambda のためのデプロイツールである.詳細は省くが,設定ファイル(serverless.yml という YAML 形式のファイル)を書けば,後はコマンドで AWS Lambda 上に関数をデプロイしてくれるとても便利なツール.

 本記事では,AWS Lambda にデプロイした関数のテストにおいて AWS リソースへのアクセス権限に関するエラーが出たのでその処理を行った過程を綴る.

AWS Lambda に登録した関数の権限エラー

 boto3(AWS SDK for Python)を用いて,毎日 Slack に利用料金を通知する関数をテストした際に下記のようなエラーが発生した.重要なのは [ERROR]... の部分.要約すると,現在のロールでは CloudWatch のメトリクス(利用料金を参照できるサービス)にアクセスする権限が無いとのこと.

エラー出力

START RequestId: ********** Version: $LATEST

[ERROR] ClientError: An error occurred (AccessDenied) when calling the GetMetricStatistics operation:
User: [my-ARN]/[my-app-name]-ap-northeast-1-lambdaRole/[my-app-name]-[my-funcname] is not authorized to perform: cloudwatch:GetMetricStatistics
Traceback (most recent call last):
  File "/var/task/[my-script-name].py", line 19, in main
    detail, color = get_aws_cost()
  File "/var/task/[my-script-name].py", line 39, in get_aws_cost
    Statistics=['Maximum'])
  File "/var/runtime/botocore/client.py", line 320, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/var/runtime/botocore/client.py", line 623, in _make_api_call
    raise error_class(parsed_response, operation_name)

END RequestId: [RequestId]
REPORT RequestId: [RequestId]    Duration: 772.58 ms
Billed Duration: 800 ms  Memory Size: 1024 MB  Max Memory Used: 429 MB

 ちなみに AWS Lambda の各関数のページでテストに失敗するとこんな感じでログが出力される.

f:id:pytwbf201830:20190808215906p:plain
Error Log

 ローカル環境で実行した際には以下のようにちゃんと料金が取れてきているので恐らくデプロイ先の設定が原因だと推測した.

f:id:pytwbf201830:20190808220021p:plain
local test

エラー原因の究明

 自分が設定したテスト用の IAM ロールは AdministratorAccess という AWS 上のほぼ全てのサービスにアクセスできるポリシーを付与していたため(良くない),なぜ上記のようなエラーが起こるのか不思議だったが,ログを見ると自分の想定した IAM ロールとは別の名前の IAM ロールが使われていることに気づいた.原因はローカル環境とデプロイ先の環境での IAM ロールの違いだった.

  • ローカル環境:AWS CLI 上の設定を AdministratorAccess の権限を持った IAM ロールから発行したアクセスキーを用いていた.
  • デプロイ先の環境:Serverless Framework のデフォルトで作られる IAM ロール(上記エラー 4 行目の [my-app-name]-ap-northeast-1-lambdaRole がデフォルトで作られるロール)が使われていた.

 公式ドキュメントに Serverless Framework におけるデフォルトの IAM ロールに関する記載があったので以下に示しておく.

f:id:pytwbf201830:20190808220135p:plain
Serverless Framework IAM

Serverless Framework - AWS Lambda Guide - IAM より引用

 以上を参照すると,デフォルトの IAM ロールには CloudWatch Logs への読み書き権限しか設定されていないようだ.これがエラーの根本原因である.IAM ロールのソース(JSON 形式)を見るとこんな感じ.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["logs:CreateLogStream"],
      "Resource": ["arn:aws:logs:[my-resource]"],
      "Effect": "Allow"
    },
    {
      "Action": ["logs:PutLogEvents"],
      "Resource": ["arn:aws:logs:[my-resource]"],
      "Effect": "Allow"
    }
  ]
}

 というわけで設定ファイル serverless.yml に特定のポリシーの設定を加えれば(or 自分で作成した IAM ロールを設定すれば)OK なはず.今回のエラーは cloudwatch:GetMetricStatistics へのアクセス権限が無いという内容だったため,CloudWatchReadOnlyAccess というポリシーを参考に serverless.yml を編集した.

CloudWatchReadOnlyAccess

f:id:pytwbf201830:20190808220449p:plain
CloudWatchReadOnlyAccess

設定前 serverless.yml

provider:
  name: aws
# 書かなければデフォルトの IAM ロールになる
# 以下略 ...

設定後 serverless.yml

provider:
  name: aws
  iamRoleStatements:
    - Effect: Allow
      Action:
        # default
        - logs:CreateLogStream # default
        - logs:PutLogEvents # default
        # - logs:CreateLogGroup
        # CloudWatchReacOnlyAccess
        - 'autoscaling:Describe*'
        - 'cloudwatch:Describe*'
        - 'cloudwatch:Get*'
        - 'cloudwatch:List*'
        - 'logs:Get*'
        - 'logs:List*'
        - 'logs:Describe*'
        - 'logs:TestMetricFilter'
        - 'logs:FilterLogEvents'
        - 'sns:Get*'
        - 'sns:List*'
      Resource:
        - '*'
# 以下略 ...

 そんでデプロイしてテストする.Python 側のエr... 無事成功.

f:id:pytwbf201830:20190808220549p:plain
test success

 ちゃんと Slack にも通知が来てた.これで毎日 AWS の料金を監視できるので安心して眠れそうです.

 他にも,関数ごとのロールの設定ができるなど,AWS マネージメントコンソール上で行える設定は柔軟に設定ファイルで設定できるようになっている.以下のドキュメントに Serverless Framework の IAM の設定の仕方が載っているので参照.Serverless Framework でデプロイの設定をバージョン管理できるため,一度設定してしまえば再現が取れるの本当に便利.

serverless.com

補足:Sereverless Framework の仕組み

 Serverless Framework によってローカルに CloudFormation のテンプレートファイルが生成されていたため,裏側で CloudFormation が動いているんだなあくらいしか考えていなかったが,この記事を書いている途中に Serverless Framework の中の仕組みが気になったので少しだけ調べてみた.具体的には,下記のリンク先の Deploy All > How It Works を読んだ.

serverless.com

該当箇所

f:id:pytwbf201830:20190808220656p:plain
How It Works

 Serverless Framework がどのようにデプロイを実現しているかが書いてある.大雑把に言うと,Serverless Framework は設定ファイル serverless.yml の構文を一つの AWS CloudFormation のテンプレートファイルに変換し,スタックを生成してデプロイを実現している.

終わりに

 IAM ロールの仕組みをちゃんと勉強した方が良さそう... 以下の記事読んで勉強する.

docs.aws.amazon.com

e-book-info.com

qiita.com

 あと,大半の方は既に使っているかもしれないが,知らない方への布教の意味も込めて Serverless Framework の公式 HP を貼っておく.

serverless.com

メモ

Serverless Framework の serverless.yml 内で変数を扱う方法.secret key などを扱う際に必要になりそう?

serverless.com

CloudWatchLogs 関連

docs.aws.amazon.com

qiita.com