概要、実施したいこと
実施したいこととしては以下になります。
- AWS Chalice で API Gateway + Lambda をデプロイ
- ビルド・デプロイは CodePipeline で実行
- 1つの API Gateway で、API Key 認証と Cognito 認証を使い分けたい
1, 2点目は、開発効率の点を考慮したよくある構成かと思います。
3点目については、
アプリケーションユーザーからのリクエストに対しては Cognito 認証を、
外部システムからのリクエストに対しては API Key 認証を使いたい
…といった場合を想定した構成です。
上記3点を実装した際のポイントを紹介します。
ソースコードの内容
ソースコード (app.py) については以下のように実装しました。
import os from chalice import Chalice, Response, CognitoUserPoolAuthorizer from chalicelib import sample app = Chalice(app_name='chalice_api') cognito_authorizer = CognitoUserPoolAuthorizer( 'ChaliceUserPool', provider_arns=[ os.environ['COGNITO_USERPOOL_ARN'] ] ) @app.route('/app-user', authorizer=cognito_authorizer) def function(): return sample.hello_world() @app.route('/ext-system', api_key_required=True) def function(): return sample.hello_world()
API Key 認証と Cognito 認証を使い分けるために URL パスを分けました。
アプリケーションユーザー用パス(/app-user)には authorizer=cognito_authorizer
で Cognito 認証を設定し、
外部システム用パス(/ext-system)には api_key_required=True
で API Key 認証を設定しています。
ビルドの設定
CodePipeline の設定としては以下のようになっています。
Build ステージで CloudFormation テンプレートを作成し Deploy ステージに渡す必要があります。
そのため Build ステージで chalice package を実行しテンプレートを生成しています。
以下のような buildspec を使いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
version: 0.2 artifacts: discard-paths: no files: - '**/*' phases: install: runtime-versions: python: 3.9 commands: - pip install --upgrade chalice build: commands: - pip install -r requirements.txt -t vendor/ - python3 build.py --cognito-userpool-arn ${COGNITO_USERPOOL_ARN} # 独自のスクリプト、後述 - chalice --debug package . --template-format yaml |
chalice package の実行時にソースコード(app.py
)が参照されるため
ビルド時点で、ソースコードに定義された環境変数(COGNITO_USERPOOL_ARN)が利用できる必要があります。
このような環境変数はプロジェクトディレクトリの .chalice/config.json
に記載する必要があります。
Configuration File - environment_variables
ですが、ソースコード内に環境固有の値(COGNITO_USERPOOL_ARN)を記載することに抵抗があったので、
ソースコード外から COGNITO_USERPOOL_ARN を挿入する仕組みにしました。
それが上記 buildspec 内で実施している build.py
です。
プロジェクトディレクトリルートに config.json
の元になる chalice-config.json
を配置し、
build.py
がそこに COGNITO_USERPOOL_ARN (CodeBuild の環境変数) を追加し .chalice/config.json
として保存しています。
1 2 3 4 5 6 |
. ├── .chalice │ └── config.json (build.py で生成) ├── app.py ├── build.py └── chalice-config.json (config.json の元になるファイル) |
build.py
の内容は以下の通りです。
import argparse import os import json ROOT_PATH = os.path.dirname(os.path.abspath(__file__)) class Build(): def __init__(self, args): self.cognito_userpool_arn = args.cognito_userpool_arn def main(self) -> None: self.config = self.load_base_config() self.generate_config() self.output_config() def load_base_config(self) -> dict: with open(f'{ROOT_PATH}/chalice-config.json', 'r') as file: base_config = json.load(file) return base_config def generate_config(self) -> None: self.config['environment_variables'] = { 'COGNITO_USERPOOL_ARN': self.cognito_userpool_arn } def output_config(self) -> None: with open(f'{ROOT_PATH}/.chalice/config.json', 'w') as file: file.write(json.dumps(self.config, indent=2)) def main(): parser = argparse.ArgumentParser() parser.add_argument('--cognito-userpool-arn', required=True) args = parser.parse_args() return Build(args).main() main()
本当はこのような独自のスクリプトを作りたくなかったのですが、
そこまで複雑なスクリプトでもないので、これはこれで良しとしました。
まとめ
- Cognito 認証 / API Key 認証 を使い分けるには URL パスを分ける必要がある
- Chalice で Cognito 認証を設定する場合は
authorizer=...
で設定する - Chalice で API Key 認証を設定する場合は
api_key_required=True
で設定する - ビルド(chalice package)実行時に Cognito ユーザープール ARN が必要になるが、ARN をソースコードに含めたくない場合は今回紹介した
build.py
のような工夫が必要
共同著者: 神津
投稿者プロフィール
- 2015年8月入社。弊社はインフラ屋ですが、アプリも作ってみたいです。