背景
AWS使ってサーバーレスで自分用の家計簿的なwebサービスを勉強も兼ねて開発中。メイン機能は大分出来てきて、あとは残課題の対応という形。前の記事でCognitoは対応していたが、フロント部分のみ。APIGateway部分にはCognito制御をしていない。せっかくCognito使ってるので、APIGateway側でも制御を入れたい。
まずAWS側設定
手法検討
色々ページを見ていると、CloudFormationでやっているケースあればSwaggerでやってるケースもあり。今回、API部分はSwaggerでやっているのでSwaggerで出来る部分はSwaggerでやりたい。
やってみた。
色々なページを参考にさせてもらうと、lambdaで認証しているケースが多い。世の中はlambdaで認証チェックするのが主流らしい。Cognitoでやろうという所はあまりないらしい。色々試してみたが、swagger書式でないとか言われたり、エラーは出なかったが、APIGatewayのオーソライザーのタブ見ても新規生成されていなかったり。階層やその表現を色々変えてやったが上手く行かず、手動でやってしまおうかとも考えた。が、結果的に以下の設定でAWSへの反映は出来た。
# トップ階層(componentsセクション配下の方が良いのか?その場合はsecuritySchemes?)
securityDefinitions:
# このapi_keyは既存部分(Cognito使ったらもう要らないか?)
api_key:
type: "apiKey"
name: "x-api-key"
in: "header"
# この名前を各メソッド設定で使用
myhomeAccountAuthorizer:
type: "apiKey"
# 認証に使うトークンを格納するヘッダーのキー
name: "Authorization"
# ここを変えたらヘッダー以外でも可能?
in: "header"
x-amazon-apigateway-authtype: "cognito_user_pools"
x-amazon-apigateway-authorizer:
type: cognito_user_pools
# 999999999999はアカウントID、ap-northeast-1_hogehogeはCognitoユーザープールID
providerARNs:
- "arn:aws:cognito-idp:ap-northeast-1:999999999999:userpool/ap-northeast-1_hogehoge"
identityValidationExpression: ".*"
paths:
/api/download:
get:
produces:
- "application/json"
parameters:
# ・・中略・・
responses:
# ・・中略・・
security:
- api_key: []
# で使用したオーソライザーの名前を指定
- myhomeAccountAuthorizer: []
AWSコンソール側でのオーソライザーテスト
成功すると、AWSコンソール側で、APIGateway => API => オーソライザーで、作成したオーソライザーが表示される。そこでオーソライザーのトークンテストが出来る。
今回、クライアント側ではVue.jsを使用している。javaScriptのawsライブラリ使用中。
session.getAccessToken().getJwtToken() で取得した値を入れてみたが、Unauthorized requestになってしまった。
session.getIdToken().getJwtToken()で取得した値を入れてみたら、AWSコンソール上でのテストは成功。
参考
そしてクライアント側設定
もちろんAPIGateway側で認証設定をしたので何もしないとAPI実行で403エラーが返ってくる様になる。ヘッダにAuthorizerキーで、上記IDトークンを指定すればいいはず。開発環境で普通に成功した。
// key, idtokenは変数名
headers: {
'Content-Type': 'application/json',
'x-api-key': key,
'Authorization': idtoken
}
これで今まで通りに使える、と思っていたら、CloudFront経由のアクセス(本番)でうまく行かない。
x-amzn-errortype: UnauthorizedException
x-amzn-requestid: ************
x-cache: Error from cloudfront
あ、CloudFrontからAPIGatewayに、ヘッダのAuthorizer情報渡ってない・・・
↓ですね。
【小ネタ】カスタム認証を使うAPI GatewayをCloudFrontの後ろに置いたらAPIを叩けなくなった
こちらの神ページを参考に、ヘッダキャッシュ制御の種別をwhitelist指定にして、Authorizerヘッダをwhitelistに追加する事により解消。CloudFrontまわりはCloudFormationでの構築しているのだが、該当部分は以下の形になった。
※この時、ついでに後で使うかもしれないヘッダーを幾つか追加してみたらアクセスエラーになった。使ってもないヘッダーは指定しない方がよさそう。
CacheBehaviors:
- TargetOriginId: ApiGatewayOrigin
AllowedMethods:
- GET
- HEAD
- OPTIONS
- PUT
- PATCH
- POST
- DELETE
ForwardedValues:
Cookies:
Forward: all
# ここを指定する事でwhitelist指定となる。
Headers:
- Authorization
QueryString: True
ViewerProtocolPolicy: redirect-to-https
SmoothStreaming: False
Compress: True
PathPattern: api/*
MinTTL: 0
MaxTTL: 0
DefaultTTL: 0
参考にさせてもらったページ
- AWS::ApiGateway::Authorizer
- AWS::CloudFront::Distribution Cookies
- AWS::CloudFront::Distribution ForwardedValues
- x-amazon-apigateway-authorizer オブジェクト
- ユーザープールのトークンの使用
- Cognitoから払い出されたIdTokenをAPI Gateway カスタムオーソライザーのLambda(Python3.6)で検証する方法
- AWS Cognitoにサインインしないと見れないLambdaを作る
- Amazon API Gateway の Custom Authorizer を使い、OAuth アクセストークンで API を保護する
- AWS APIGateway with Cognito Authorizer defined in OpenAPI Spec
- 【小ネタ】カスタム認証を使うAPI GatewayをCloudFrontの後ろに置いたらAPIを叩けなくなった
- Cognitoのサインイン時に取得できる、IDトークン・アクセストークン・更新トークンを理解する