Python Serverless Microframework for AWS (Chalice) を使うと、サーバーレスアーキテクチャの IAM ポリシーの管理が劇的に簡単になる!

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

Python Serverless Microframework for AWS (Chalice)

先日、アマゾンデータサービスジャパン株式会社様との共催の勉強会「実践SERVERLESS」を開催いたしました。お陰様で多くのかたに好評いただけました。お越し下さった皆さま、誠にありがとうございました!

「実践SERVERLESS」勉強会を開催しました! #cmdevio

この勉強会では「AWS Lambda と Amazon API Gateway の管理」というテーマでお話させていただきました。その中で、サーバーレスアーキテクチャを管理するツールの一つとして「Python Serverless Microframework for AWS (Chalice)」をデモも交えながらご紹介しました。こちらは弊社のブログでも既に紹介していますが、速く、直感的にシステムを構築することができるツールとして、最近注目を集めています。

【新機能】Python Serverless Microframework for AWS(プレビュー版)が登場!

Chalice は AWS Lambda と Amazon API Gateway をまとめて簡単に管理できるところがよく取り上げられますが、これまでのツールではあまり見られない IAM ポリシーを自動生成する 機能があります。この機能によって、サーバーレスアーキテクチャの IAM ポリシーの管理が劇的に簡単になっています。個人的に非常に好感が持てましたので、ご紹介したいと思います。

本記事で紹介する機能は、プレビュー版のものです。正式版がリリースされるまでに変更される可能性が有ります。予めご了承ください。

IAM ポリシー管理からの脱却

はじめに、なぜ IAM ポリシー生成がすごく良いのか?という話をします。

サーバーレスアーキテクチャのロジック部分を担当する Lambda は、1回の呼び出しにつき最大5分間の処理を行わせることができます。その処理の多くは他の AWS サービスと連係させるケースが多いので、Lambda ファンクションには必ず IAM ロールを付与しなければいけないようになっています。

この IAM ロールには Lambda の実装コードで扱っている AWS サービスの API を呼び出すことができるような権限を与える必要がありますが、実装コードを確認しながら、どのような IAM ポリシーを定義しなければならないかを考えなければいけません。また、Lambda ファンクションの実装者が IAM に詳しいかというと、その限りではないです。また逆も然りで、IAM を管理する立場の人が実装コードを見ながら書くというのも、それはそれで大変そうです。まさに Dev と Ops のような関係性ですが、担当者が分かれているとこのような課題が顕著に現れます。

ここを、Chalice ではうまいこと解決してくれています。なんと、デプロイ時にソースコードからどの API を使っているか調べ、自動的に IAM ロールのポリシーを更新してくれる のです。

Chalice を使いながら理解する

論より証拠、Chalice を実際に使いながらどのような機能なのか見ていきましょう。

Chalice のインストールとプロジェクトの作成

まずは Chalice をインストールし、プロジェクトを作成しましょう。ここでは virtualenv を使っています。

$ pip install virtualenv
$ virtualenv ~/.virtualenvs/chalice-demo
$ source ~/.virtualenvs/chalice-demo/bin/activate
$ pip install chalice

インストールが終わったら、プロジェクトを作成します。

$ chalice new-project helloworld
$ cd helloworld

新規作成したプロジェクトでは、とりあえずルートパスを叩くと {"hello": "world"} という JSON が返ってくるようになっています。

まずはデプロイ

~/.aws/credentials[default] が設定されていることを確認してから *1、まずは次のコマンドを叩いてデプロイしてみましょう。

$ chalice deploy
Initial creation of lambda function.
Creating role
Creating deployment package.
Lambda deploy done.
Initiating first time deployment...
Deploying to: dev
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/

デプロイのログが出力された後、最後に API のエンドポイントが出力されます。これを叩いてみると {"hello": "world"} が取得できます。

ここで、今回重要となるのが Creating role と書かれているところです。つまり Chalice では、API Gateway + Lambda 構成のアーキテクチャをデプロイするときに、Lambda に設定する IAM ロールも生成してくれていることを示しています。

自動で作成された IAM ロールを見てみる

ここで、IAM ロールを確認してみましょう。helloworld という名前の IAM ロールが作られていると思います。

$ aws iam get-role-policy --role-name helloworld --policy-name helloworld

デフォルトでは、下記のような IAM ポリシーがアタッチされています。CloudWatch Logs に関わるものしかありません。

{
    "RoleName": "helloworld",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "arn:aws:logs:*:*:*",
                "Effect": "Allow"
            }
        ]
    },
    "PolicyName": "helloworld"
}

AWS サービスを使ってみる

次に、AWS サービスの API を呼び出すように Lambda ファンクションの実装コードを修正しましょう。まずは AWS サービスの API が呼び出せるよう、boto3 をインストールしておきつつ、ライブラリの依存関係を記述するための requirements.txt ファイルに追加します。

$ pip install boto3
$ echo 'boto3==1.3.1' >> requirements.txt

次に app.py を次のように書き換えます。

import json
import boto3
from botocore.exceptions import ClientError

from chalice import Chalice
from chalice import NotFoundError

app = Chalice(app_name='helloworld')

S3 = boto3.client('s3', region_name='ap-northeast-1')
BUCKET = 'your-bucket-name'

@app.route('/objects/{key}', methods=['GET', 'PUT'])
def s3objects(key):
    request = app.current_request
    if request.method == 'PUT':
        S3.put_object(Bucket=BUCKET, Key=key,
                      Body=json.dumps(request.json_body))
    elif request.method == 'GET':
        try:
            response = S3.get_object(Bucket=BUCKET, Key=key)
            return json.loads(response['Body'].read())
        except ClientError as e:
            raise NotFoundError(key)

S3 の特定のバケットにファイルをアップロードしたりダウンロードしたりできるような API を実装しています(BUCKET は適宜書き換えてください)。この API を動作させるには、アップロードには s3:PutObject、ダウンロードには s3:GetObject という S3 のアクションが実行できる IAM ロールが必要です。

それではデプロイしてみましょう。

$ chalice deploy
Updating IAM policy.

The following actions will be added to the execution policy:

s3:GetObject
s3:PutObject

Would you like to continue?  [Y/n]:

新しいアクションを追加するけど良い?」と問われています。以前デプロイした時に作成した IAM ロールのポリシーに定義されているアクションと、いまデプロイしようとしている実装コードで必要とされるアクションの差分があると、このように確認してくれます。許可すると、IAM ロールが更新されます。

Would you like to continue?  [Y/n]: Y
Updating lambda function...
Creating deployment package.
Sending changes to lambda.
Lambda deploy done.
API Gateway rest API already found.
Deleting root resource id
Done deleting existing resources.
Deploying to: dev
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/

先ほどと同様、実際に更新された IAM ロールのポリシーを見てみましょう。

$ aws iam get-role-policy --role-name helloworld --policy-name helloworld
{
    "RoleName": "helloworld",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "s3:GetObject",
                    "s3:PutObject"
                ],
                "Resource": [
                    "*"
                ],
                "Effect": "Allow",
                "Sid": "f17bb2c05dc64712be1491cd352f6ba5"
            },
            {
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents"
                ],
                "Resource": "arn:aws:logs:*:*:*",
                "Effect": "Allow"
            }
        ]
    },
    "PolicyName": "helloworld"
}

アクションが増えていますね!

なお、デプロイコマンドに --no-autogen-policy を付けることで、 IAM ロールを更新しないようにもできます。

gen-policy コマンド

IAM ロールの更新は手動で行いたい!という場合に配慮した、gen-policy というコマンドも用意されています。こちらを使うと、デプロイ前に必要とされる IAM ポリシーをローカルで出力することができます。

$ chalice gen-policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": [
        "*"
      ],
      "Effect": "Allow",
      "Sid": "d7f966500e1d4281b13cd4e2ddb45894"
    }
  ]
}

IAM の管理者が明確に存在し、自動では行わない運用にしたい場合も簡単に管理することができます。IAM の管理者は gen-policy コマンドを叩くだけで、実装コードを読まずしてどんなアクションが使われているか知ることができるのです。

まとめ

Chalice を使ってみて、かなり便利だなぁと思った機能をご紹介しました。必要な IAM ポリシーは実装コードが全てを語る、といったところでしょうか。

サーバーレス限定とは言わず、AWS サービスを使うアプリケーション全てに使いたい機能ですよね。

脚注

  1. AWS の Credential についてはこちらを参照してください。