Python Serverless Microframework for AWS (Chalice) を使うと、サーバーレスアーキテクチャの IAM ポリシーの管理が劇的に簡単になる!
Python Serverless Microframework for AWS (Chalice)
先日、アマゾンデータサービスジャパン株式会社様との共催の勉強会「実践SERVERLESS」を開催いたしました。お陰様で多くのかたに好評いただけました。お越し下さった皆さま、誠にありがとうございました!
この勉強会では「AWS Lambda と Amazon API Gateway の管理」というテーマでお話させていただきました。その中で、サーバーレスアーキテクチャを管理するツールの一つとして「Python Serverless Microframework for AWS (Chalice)」をデモも交えながらご紹介しました。こちらは弊社のブログでも既に紹介していますが、速く、直感的にシステムを構築することができるツールとして、最近注目を集めています。
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 サービスを使うアプリケーション全てに使いたい機能ですよね。