[re:Invent2018] セッションで紹介されたLambdaのtipsを試してみた[2] ~AWS SAM ポリシーテンプレートの活用~

はじめに

こんにちは。データサイエンスチームのmotchieです。
この記事はNHN テコラス Advent Calendar 2018の22日目の記事です。

Optimizing Your Serverless Applications (SRV401-R2) のセッションから、特に使ってみたいLambdaのtipsをお届けします。

前回の記事はこちらになります。
[re:Invent2018] セッションで紹介されたLambdaのtipsを試してみた[1] ~環境変数とParameter Storeによる設定の管理~

上の記事を書いた後、早速実際の案件でParameter Storeを使う機会がありました。手順やIAMポリシーがうろ覚えで、自分が書いた記事を何度も確認してしまいました

Parameter Storeによる設定情報の一元管理、とても便利です。ぜひそちらも試してみてください。

今回の記事では、AWS SAMのポリシーテンプレートを使って、LambdaのIAMポリシーを作成する方法をご紹介します。

SAMのポリシーテンプレートを使うことで、権限の範囲が制限されたIAMポリシーの作成・Lambda関数のデプロイを、より便利に行うことが出来ます。

使用例として、この記事では、前回の記事で作成したSlack通知用Lambda関数を用いたいと思います。
前回は、マネジメントコンソールでLambda関数を作成し、IAMロールを作成してアタッチする、という手順を踏んでいました。
今回は、AWS SAMのポリシーテンプレートを使ってIAMポリシーを作成し、AWS SAM CLIを使って関数パッケージをデプロイしてみたいと思います。

セッションの資料

Optimizing Your Serverless Applications (SRV401-R2) のセッションは、スライドと動画が公開されています。

セッション全体の内容が気になる方は、ぜひこちらも見てみてください。

Optimizing Your Serverless Applications (SRV401-R2)のスライドp71において、全体のtipsがまとめられています。
この記事では主に、Execution Environmentのtipsの上から6つ目、AWS SAMのポリシーテンプレートを使ったIAM権限の管理について、詳しくご紹介したいと思います。

Execution Environment Recap:

  • IAM権限の範囲を最小化しよう
    • SAMのようなツールを活用しよう

AWS SAMとは

GitHub: AWS Serverless Application Model (AWS SAM)
AWS SAMは、AWS サーバーレスアプリケーションモデルの略です。
読んで字のごとく、サーバーレスアプリケーションの構築に特化したフレームワークです。
作成したいリソース情報を記載するAWS SAMテンプレート仕様と、デプロイに使用するAWS SAM CLIから構成されます。

デプロイの際には、SAMのテンプレートはCloudFormationのテンプレート・スタックに変換されます。
デプロイできるサービスの種類はCloudFormationの方が多いですが、SAMの方が記述がシンプルで済みます。
また、今回の記事では取り上げませんが、AWS SAM CLIにはLambda関数をローカル環境でテストする機能も提供されています。
そのため、Lambda、API Gatewayなど、サーバレスアプリケーションの構築用途では、CloudFormationよりもSAMがオススメです。

IAMポリシーの権限について

セッション後半(p62)では、 “Action”: “s3:*” makes puppies cry として、可愛い子犬のパグが泣いているスライドが登場します。

なぜこの子犬は悲しんでいるのでしょうか?
例えば、上の “Action”: “s3:*” では、s3:GetObject(読み込み)、s3:PutObject(書き込み)、s3:DeleteObject(削除)など、S3のオブジェクトに対するあらゆるオペレーションが許可されています。

しかし、用途によっては、実際に必要なのはオブジェクトの読み込み権限だけという場合もありそうです。
その場合、最小権限の原則に則ると、s3:GetObjectだけ許可するのがセキュリティ的に望ましいです。

また、実際には特定のバケットのオブジェクトだけ読み込めれば良いという場合もありそうです。
その場合、 “Resource”: “arn:aws:s3:::” でS3のバケットを絞るなど、リソース範囲も制限したほうが良いでしょう。

しかし、IAMポリシーの作成はなかなか手間がかかるため、結局範囲を絞らずに必要以上の権限を与えることになりがちかもしれません。

そこで登場するのがSAMのポリシーテンプレートです。

SAMのポリシーテンプレート

ポリシーテンプレートの概要
GitHub: awslabs/serverless-application-model: Policy Templates

SAMのテンプレートでリソース情報を記載する際、そのリソースに付与するIAMロールを指定したり、IAMロールを作成したりすることが出来ます。
その際、SAMのポリシーテンプレートを使ってIAMロールを作成することで、権限の範囲が制限されたIAMロールをより簡単に作成することが出来ます。

セッションの時点では、45種類以上の定義済ポリシーテンプレートが提供されています。
ポリシーテンプレートの一覧については、こちらから確認できます。今後益々種類が増えていくことが予想されます。
GitHub: awslabs/serverless-application-model: all_policy_templates.yaml

例えばS3の読み込み権限の場合、

- S3ReadPolicy:
    BucketName: name

といった形で、ポリシーテンプレートでバケット名を指定してポリシーを作成することで、
当該バケットの読み込み権限のみに制限したIAMポリシーを簡単に作成できます。

以降では、前回の記事でご紹介したSlack通知用のLambda関数を再び使いたいと思います。
この関数のIAMポリシーをSAMのポリシーテンプレートを使って作成し、AWS SAM CLIで関数パッケージをAWS上にデプロイしてみたいと思います。

AWS SAM CLIの使い方

AWS SAM CLIはpipを使ってインストールすることが出来ます。また、この記事では扱いませんが、AWS SAM CLIを使ってローカル環境でのLambda関数のテストを行うためには、Dockerのインストールも必要になります。

詳しい手順については、こちらもご覧ください。
AWS Documentation: Installing the AWS SAM CLI

$ pip install aws-sam-cli
$ sam --version

それでは実際にpython3.6のアプリケーションを作成してみます。

1.以下のコマンドで、サンプルアプリケーションをダウンロードします。

$ sam init --runtime python3.6

中身はこんな感じになっています。

$ tree sam-app/
sam-app/
├── README.md
├── hello_world
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-35.pyc
│   │   └── app.cpython-35.pyc
│   ├── app.py
│   └── requirements.txt
├── template.yaml
└── tests
    └── unit
        ├── __init__.py
        ├── __pycache__
        │   ├── __init__.cpython-35.pyc
        │   └── test_handler.cpython-35.pyc
        └── test_handler.py

このテンプレートを元に、ファイルを修正していきたいと思います。
2.hello_world/app.py[1]の記事のコードに置換します。
3.hello_world/requirements.txt を以下の内容に変更します

boto3

4.必要なパッケージとPythonコードをまとめておきます。

$ pip install -r hello_world/requirements.txt -t hello_world/build/
cp hello_world/*.py hello_world/build/

5.template.yamlを以下の内容に変更します。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Slack notification test app

Resources:
    SlackNotificationTestApp:
        Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
        Properties:
            CodeUri: hello_world/
            Handler: app.lambda_handler
            Runtime: python3.6
            Environment: # More info about Env Vars: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#environment-object
                Variables:
                    SlackChannelParam: /Prod/SlackTest/Lambda/ChannelName
                    HookUrlParam: /Prod/SlackTest/Lambda/HookUrl
            Policies:
                - KMSDecryptPolicy: # SAM Policy template
                    KeyId: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/Prod/SlackTest/Lambda/*
                - Version: "2012-10-17" # Policy Document
                  Statement:
                      - Effect: Allow
                        Action:
                          - logs:CreateLogGroup
                          - logs:CreateLogStream
                          - logs:PutLogEvents
                        Resource: "*"
                      - Effect: Allow
                        Action:
                          - ssm:GetParameters
                        Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/Prod/SlackTest/Lambda/* 
                      - Effect: Allow
                        Action:
                          - sts:AssumeRole 
                        Resource: "*"

17~18行目で、SAMのポリシーテンプレートからKMSでSlackのHookURLを復号化するためのポリシーを作成しています。
KeyIdを指定することで、リソースの権限を制限したポリシーを作成しています。

また19~34行目は通常の方法で作成したポリシーです。
ポリシーテンプレートではまだ用意されていないポリシーについては、通常のPolicy Documentも併用して指定することが可能です。

6.テンプレートの形式に問題がないか、チェックします。

$ sam validate -t template.yaml

7.パッケージを作成してS3のバケットにアップロードします。S3のバケットの値は自身のバケット名に置き換えて使ってください。

$ # S3のバケットを用意しておく
$ aws s3 mb s3://your-bucket-name
$ # SAMテンプレートからパッケージを作成・S3にアップする
$ sam package --template-file template.yaml --s3-bucket your-bucket-name --output-template-file packaged.yaml

8.デプロイを行います。

sam deploy --template-file packaged.yaml --stack-name yourstackname --capabilities CAPABILITY_IAM

以上で関数のデプロイは完了になります。
作成したリソースはAWSマネジメントコンソールのCloudFormationから確認することが出来ます。

まとめ

この記事では、AWS SAMのポリシーテンプレートを使ってIAMポリシーを作成し、AWS SAM CLIを使ってLambda関数をデプロイする方法をご紹介しました。
みなさんもぜひ試してみてください。

あなたにおすすめの記事