AzureのAPI Gateway(API Management)を用いてOpenID Connect Providerより発行されたJWTを検証

こんにちは、サイオステクノロジー 技術部武井です。今回は、AzureのAPI Gateway(API Management)を用いてOpenID Connect Providerより発行されたJWTを検証してみます。

API Gatewayとは?

AzureのAPI Managementは、API Gatewayの製品です。プロダクトのWebサイトには以下のような説明がありました。

API Management を使用するには、管理者が API を作成します。 API はそれぞれ、少なくとも 1 つの操作で構成され、1 つまたは複数の成果物に追加することができます。 API を使用する開発者は、その API を含んだ成果物をサブスクライブしたうえで、使用ポリシーが適用されていればその範囲の中で、API の操作を呼び出すことができます。 

ワケ(´・ω・`)ワカ(´ε`;)リマ( ;∀;)セン(ノД`)

多分こういうことだと思います。

APIに関わる横断的な処理を一手に引き受けてくれます。つまり、APIを開発する際、今までAPIの認証、ロギング、課金管理などはAPIごとに実装していました。しかし、そうではなく、全てのAPIへのアクセスは、一旦、API Gatewayなるものに全てアクセスさせて、そこで認証、ロギングなどを行い、それからAPIにその要求を引き渡すということをしてくれます。

API Gatewayがない場合は、こんな感じだったと思います。APIごとに認証やロギングを実装しています。

Screen Shot 2018-08-03 at 7.30.46

 

API Gatewayを使えば、こんなにハッピーになれます。認証やロギングをまず一手にAPI Gatewayで引き受けて、その処理が正常に完了したものだけ、バックエンドにあるAPIにその要求を引き渡します。

Screen Shot 2018-08-03 at 7.30.56

 

今回のゴール

今回は、このAPI Gatewayを使って、OpenID ConnectのProviderで発行されたID Token(JSON Web Token)を検証して、Open ID ConnectのProviderで認証を受けていないAPIは、その要求を拒否(HTTPステータスコード401を返す)ということをしたいのです。

つまり絵にすると、以下のようになります。

Screen Shot 2018-08-03 at 7.49.14

上図のとおりなのですが、今回はOpenID ConnectのプロバイダーとしてYahooを使います。Yahooが発行するID Tokenは、API Management(後述)で検証可能なJSON Web Tokenの仕様に準じているからです。

API GatewayにはAzureのAPI Managementを使います。OpenID Connectのプロバイダーが発行したID Token(JSON Web Token)の検証が行えます。

API Gatewayの背後に置くAPIについては、何でもよかったのですが、API ManagementからさくっとインポートできるAzure Functionsをチョイスしました。

実際にやってみましょう

では、早速いつもどおり実践してみます(๑•̀ㅂ•́)و✧

APIを作る

まずAPI Gatewayの背後に置くAPIを作ります。Azure Functionsでさっくり作ります。このあたりあまり今回の本質ではないので、説明はざっくりしてしまいます。もし、ご自分で公開されているAPIをお持ちであれば、そちらを使っていただいても構いません。

Azureポータルにログインして、「リソースの作成」をクリックして、「function」と入力してフィルターすると「Function App」が出てきますので、クリックします。

Screen Shot 2018-08-03 at 8.10.40

 

「作成」をクリックします。

Screen Shot 2018-08-03 at 8.10.52

「アプリ名」は任意の名称、「サブスリプション」「リソースグループ」「Storage」は環境に応じたものを、他は以下のように入力して、「作成」をクリックします。

Screen Shot 2018-08-03 at 8.11.53

 

しばらくすると、Azureポータルの上の通知アイコン(鈴みたいなやつ)に以下のように作成に成功した旨が表示されるので「リソースグループに移動」をクリックします(切れてますが)。

Screen Shot 2018-08-03 at 8.18.25

 

「関数」のとなりにある「+」をクリックします。

Screen Shot 2018-08-03 at 8.18.55

 

今回はRestAPIを作成しますので、「webhook + API」を選択して、言語は「JavaScript」を選択します。言語は何でもいいのですが、私がJavaな人間なので、JavaScriptにしました。最後に「この関数を作成する」をクリックします。

Screen Shot 2018-08-03 at 8.19.42

 

こんな感じでAPIが出来ます。Postでnameというパラメータに値を渡すと「Hello [名前]」というレスポンスが返ってくる単純なものです。実行してみましょう。「関数のURLの取得」をクリックしてください。

Screen Shot 2018-08-03 at 8.20.10

 

「コピー」をクリックします。

Screen Shot 2018-08-03 at 8.35.18

上記でコピーしたURLを元に以下のcurl文でリクエストを投げてみてください。

# curl -H 'Content-Type:application/json' -d "{\"name\":\"hoge\"}"  https://apim-test-api.azurewebsites.net/api/HttpTriggerJS1?code=XXXXXX

 

“Hello hoge”と返ってくれば成功です。

 

とりあえずAPI(Azure Functions)のところは終わりました。次は、YahooでOpenID ConnectのProviderを作ります。

Screen Shot 2018-08-03 at 17.17.35

 

OpenID ConnectのProviderを作る

以下のURLにアクセスしてください。

https://e.developer.yahoo.co.jp/dashboard/

 

「新しいアプリケーションを開発」をクリックします。

Screen Shot 2018-08-02 at 23.02.01

 

「サーバーサイド」の方をチェックします。

Screen Shot 2018-08-02 at 23.02.19

 

「アプリケーション名」に任意のアプリケーション名を入力します。あとはデフォルトのままでOKです。

Screen Shot 2018-08-03 at 17.29.57

 

「同意する」をチェックして「確認」をクリックします。

Screen Shot 2018-08-02 at 23.03.07

 

入力内容に問題ないことを確認して「登録」をクリックします。

Screen Shot 2018-08-03 at 17.33.32

 

「Client ID」「シークレット」をメモっておいてください。後で使います。

Screen Shot 2018-08-03 at 17.38.09

 

OpenID ConnectのProvider構築まで完了しました。

Screen Shot 2018-08-03 at 17.59.30

 

API Gatewayを作る

Azureポータルにアクセスして、「すべてのサービス」をクリックして、下記のように「api」と入力すると、「API Managementサービス」が表示されますので、クリックします。

Screen Shot 2018-08-02 at 23.14.34

 

「追加」をクリックします。

Screen Shot 2018-08-02 at 23.15.03

 

「名前」「組織名」に任意の名称、「サブスリプション」「リソースグループ」「場所」は環境に応じた値を、「管理者のメールアドレス」はAPI Managementサービスの作成が完了したときに通知されるメールアドレスを、「価格レベル」は「開発者(いいえ SLA)」を選択して、「作成」をクリックします。しばらくするとAPI Managementのサービスが作成されます。

Screen Shot 2018-08-03 at 6.56.47

 

そして、これからこのAPI Gatewayの背後に配置するAPIを設定します。それが先程Azure Functionsで作成したものになるわけですが、その前にもう一つやることがあります。API ManagementにAPIを配置するまえにAPIの定義を作成しなければなりません。これはOpen APIという仕様で定義されているのですが、このAPIがどのようなMethod(Post or Get or …)やどのようなパラメータを取るかを定義したものです。この定義を作成するために一旦、先程のAzure Functionsの画面に戻ります。以下の画面の右下の方にある「APIの定義」をクリックしてください。

Screen Shot 2018-08-03 at 18.18.23

 

「関数(プレビュー)」をクリックします。

Screen Shot 2018-08-03 at 18.19.06

 

「API定義テンプレートを生成する」→「保存」の順にクリックします。これでAPIの定義が出来上がりました。

Screen Shot 2018-08-03 at 18.19.40

 

では、API Managementの画面に戻りましょう。以下の画面で「API」をクリックします。

Screen Shot 2018-08-03 at 18.12.40

 

 

API Managementの背後に、先程作成したAzure Functionsを配置したいので「Function App」をクリックします。

Screen Shot 2018-08-03 at 18.12.55

 

「Browse」をクリックすると、Azure Functionsを選択する画面が表示されますので、先程作成したAzure Functionsをクリックします。また「Products」には「Unlimited」を選択して、「Create」をクリックします。

Screen Shot 2018-08-03 at 18.31.48

 

デフォルトではAzure Functionsはキーで保護されています。つまり、Azure Functionsを呼び出す際、URLのクエリパラメーターのcodeに、Azure Functionsを作成した際に発行されたキーを指定しないとAzure Functionsが呼び出せないのです。先程、以下のcurlコマンドを打って、Azure Functionsを試したと思います。

# curl -H 'Content-Type:application/json' -d "{\"name\":\"hoge\"}"  https://apim-test-api.azurewebsites.net/api/HttpTriggerJS1?code=XXXXXX

上記のcode=XXXXXXで指定されているXXXXXXの値をメモっておいてください。API ManagementからAPI、つまりAzure Functionsを呼び出すときにはこのcodeを渡さないといけないので、これからこのcodeの定義を行います。以下の画面の「名前付きの値」をクリックします。

Screen Shot 2018-08-03 at 18.54.16

 

リストに表示されているAzure Functionsをクリックします。

Screen Shot 2018-08-03 at 18.54.16

 

「値の表示」をクリックすると、テキストボックスが表示されますので、その中に先程のcodeの値を入力します。これでAPI ManagementからAPI(Azure Functions)を呼び出したときに

codeの値がクエリパラメーターとして渡されるようになります。

Screen Shot 2018-08-03 at 18.54.27

 

これからOpenID ConnectのProviderから発行されるID Token(JSON Web Token)を検証するためのポリシーを設定します。「API」→「api-test-api.azurewebsite…(先ほどインポートしたAzure Functions)」→「Post ・・・」の順にクリックします(ちなみにここにGETやらPUTやらいろんなメソッドのAPIのインターフェースが表示されていますが、これは先程作成したAPIの定義に基づくものです)。

Screen Shot 2018-08-03 at 18.55.56

 

 

「Inbound processing」の鉛筆マークをクリックします。

Screen Shot 2018-08-03 at 18.56.13

 

「</> Code View」をクリックします。

Screen Shot 2018-08-03 at 18.56.19

 

右のメニューから「Validate JWT」をクリックして、以下のようなXMLを作成します。

Screen Shot 2018-08-03 at 19.55.18

 

先程のXMLを整形して、<validate-jwt>~</validate-jwt>を以下のようなXMLにします。最後に「Save」をクリックします。

これで設定は全て終わりです。

Screen Shot 2018-08-03 at 21.19.17

試してみる

では、早速試してみたいと思います。OpenID ConnectのProviderで発行されるID Tokenを取得します。以下のURLをブラウザのURL入力欄に入力します。

https://auth.login.yahoo.co.jp/yconnect/v2/authorization?client_id=[Yahooの設定画面で取得したClient ID]
&response_type=id_token&redirect_uri=https://developer.yahoo.co.jp/start/&scope=openid&state=hoge&nonce=hoge

※stateとnonceは適当です(´・ω・`)

response_typeはOAuthでいうところのフローを選択する項目なのですが、ここではid_tokenつまりImplicit Flowを選択してます。

以下のURLにリダイレクトされます。

https://developer.yahoo.co.jp/start/#state=hoge&id_token=[ID Token]

id_tokenのクエリパラメータで指定されている値がID Tokenになります。ペイロードの部分をBase64エンコードしてみます。

{
"iss":"https://auth.login.yahoo.co.jp/yconnec/v2",
"sub":"LBHNLYCPWDV3UTO5HVVBFIXTMA",
"aud":[Yahooの設定画面で取得したClient ID],
"exp":1535714821,
"iat":1533295621,
"amr":["pwd"],
"nonce":"hoge"
}

おおっ。JSON Web Tokenっぽい(๑•̀ㅂ•́)و✧

そして次はAPI Managementで定義されたAPIを叩いてみましょう。まずその前にAPIのURLを取得します。

「API」→「api-test-api.azurewebsite…(先ほどインポートしたAzure Functions)」→「Settings」の順にクリックして表示される「Web Service URL」がAPIのURLになりますので、メモします。
Screen Shot 2018-08-03 at 21.34.13

 

次にそのまま「Test」のタブをクリックします。「Ocp-Apim-Subscription-Key」の値をメモします(目のマークをクリックすると表示されます)。

Screen Shot 2018-08-03 at 21.36.59

 

以下のcurlコマンドを実行します。

curl -D - -H 'Content-Type:application/json' -H 'Ocp-Apim-Subscription-Key:[先程メモしたOcp-Apim-Subscription-Keyの値]' -H 'Authorization:Bearer [先程メモしたID Token]' -d "{\"name\":\"hoge\"}" [先程メモしたAPIのURL]/api/HttpTriggerJS1

すると・・・

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 12
Content-Type: application/json; charset=utf-8
Expires: -1
X-Powered-By: ASP.NET
Date: Fri, 03 Aug 2018 11:35:42 GMT

"Hello hoge"

おおヮ(゚д゚)ォ!

API Managementの背後に置いてあるAzure Functionsが実行されました(๑•̀ㅂ•́)و✧

最後に

今までは、ID Tokenの検証はアプリケーションの中で実装してたのですが、API Managementがあればそんな実装は不要ですね。Azureバンザイ٩(๑´3`๑)۶

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

2人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です