Azure API Management の解説とハンズオンの復習

渋谷ヒカリエの [Azure Antenna](https://azure.connpass.com/) で開催された [Azure API Management ハンズオン](https://azure.connpass.com/event/101306/)に参加してきました。
当日の講義内容を復習するつもりでここに記していこうと思います。

# Azure API Management とは
[Azure API Management](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-key-concepts?WT.mc_id=AZ-MVP-5003113) は、Azure が提供するマネージドな API ゲートウェイのサービスで、バックエンドにあるサービスを提供する API を一括で管理して様々な処理 (セキュリティ、レート制限、データ変換、監視、など) を仲介するものです。

# API Management の機能概要
- API の保護と最適化
    - ポリシーでアクセス制限、キャッシュ管理、データ変換、などなど
- 開発者エクスペリエンス
    - ポータル利用で容易に開発
- 統一された管理/分析
    - リアルタイムの使用量、応答性能、正常性分析
- あらゆる配置に適応
    - インターネットも VPN/ExpressRoute も
- 柔軟なスケーリング
    - スケールアップ/スケールアウト

# 導入事例
- [システム間を緩やかにつなぐ「API ゲートウェイ」を Azure で実現、既存システムの資産を有効活用した新サービスを短期間で立ち上げられる基盤を確立](https://customers.microsoft.com/en-us/story/toyko-gas-azure-api-management-functions-storage-log-analytic-jp-japan)
- [PaaSのみでオープンAPI基盤をスピード開発、セブン銀行がAzure導入](http://ascii.jp/elem/000/001/607/1607230/)
- [Microsoft Cognitive Services](https://azure.microsoft.com/ja-jp/services/cognitive-services/?WT.mc_id=AZ-MVP-5003113) の基盤は API Management を採用しているそうです。

# API Management の構成
以下のコンポーネントで構成されます。
![apim_component.png](https://qiita-image-store.s3.amazonaws.com/0/230264/ce253835-6ecc-8d29-ed63-5ab40be06aae.png)



- Azure ポータル...API 群を管理
    - バックエンド API のスキーマ定義をインポート & 編集
    - Product (API の管理単位?) で API をまとめる
    - API のアクセス制御、キャッシュ、データ変換などのポリシーを設定
    - 使用量、応答性能、正常性などの分析
    - ユーザー (管理者、開発者、ゲスト) 管理
- 開発者ポータル...開発者向けの Web プレゼンス
    - API ドキュメントを参照
    - API のテスト
    - API キーの管理
    - などなど
- API ゲートウェイ
    - API の呼び出しを受けて、バックエンドの API にルーティング
    - 資格情報 (キー、JWT トークン、証明書など) を検証
    - 使用量クォータとレート制限を適用
    - バックエンド API のレビジョン、バージョン管理
    - などなど

# API ライフサイクル
API のライフサイクルに沿って、工程と役割を整理します。

## API 構築
API 開発者の役割。
Open API (Swagger)、REST API (WADL)、SOAP API (WSDL) や Azure 上にデプロイした Logic App、API App、Function をインポートすることができます。
![apim_addapi.png](https://qiita-image-store.s3.amazonaws.com/0/230264/06b464ec-96d4-78ad-1b20-a3bbfe3ee932.png)

API の仕様はインポートしたスキーマ定義が自動的に反映されます。
※Azure ポータル上で編集することもできます。
![apim_addapi1.png](https://qiita-image-store.s3.amazonaws.com/0/230264/625e617d-7819-dece-57cf-cadda1945b62.png)
※バックエンド API の仕様

![apim_addapi2.png](https://qiita-image-store.s3.amazonaws.com/0/230264/cf42faef-dae7-2fb8-ca34-93e4d7ffc1a5.png)
※API Management に追加した結果 (開発者ポータル)

- [参考：最初の API のインポートと発行](https://docs.microsoft.com/ja-jp/azure/api-management/import-and-publish?WT.mc_id=AZ-MVP-5003113)
- [参考：API の編集](https://docs.microsoft.com/ja-jp/azure/api-management/edit-api?WT.mc_id=AZ-MVP-5003113)
- [参考：手動による API の追加](https://docs.microsoft.com/ja-jp/azure/api-management/add-api-manually?WT.mc_id=AZ-MVP-5003113)
- [参考：OpenAPI 仕様のインポート](https://docs.microsoft.com/ja-jp/azure/api-management/import-api-from-oas?WT.mc_id=AZ-MVP-5003113)
- [参考：SOAP API のインポート](https://docs.microsoft.com/ja-jp/azure/api-management/import-soap-api?WT.mc_id=AZ-MVP-5003113)
    - [参考：SOAP API のインポートと REST への変換](https://docs.microsoft.com/ja-jp/azure/api-management/restify-soap-api?WT.mc_id=AZ-MVP-5003113)
- [参考：Logic App を API としてインポートする](https://docs.microsoft.com/ja-jp/azure/api-management/import-logic-app-as-api?WT.mc_id=AZ-MVP-5003113)
- [参考：API App を API としてインポートする](https://docs.microsoft.com/ja-jp/azure/api-management/import-api-app-as-api?WT.mc_id=AZ-MVP-5003113)
- [参考：Function を API としてインポートする](https://docs.microsoft.com/ja-jp/azure/api-management/import-function-app-as-api?WT.mc_id=AZ-MVP-5003113)

また、バックエンド API が存在しなくても (使用できなくても)「モック API」として作成、テストすることもできます。

- [参考：API の応答の模擬テストを実行する](https://docs.microsoft.com/ja-jp/azure/api-management/mock-api-responses?WT.mc_id=AZ-MVP-5003113)

## API 発行
API 管理者の役割。
インポートした API は、作成した「Product」という API の管理単位 (と私は解釈したが、ユーザーが利用する契約の単位となる) にまとめます。Product には複数の API を入れることができます。
Product に API を含めることによって、管理者、開発者がその API を呼び出せるようになります。
![apim_product.png](https://qiita-image-store.s3.amazonaws.com/0/230264/d8530a4b-e5af-5900-204a-05dd68a17bff.png)

そして、Product、または API ごとにポリシーを適用して API の保護と最適化を行います。
ポリシーは、API のリクエスト、レスポンスなどに対して順に実行される一連のステートメントの集まりです。
ステートメントの例としては、リクエスト本文やレスポンス本文を XML から JSON に変換、API の呼び出し回数を制限するなどがあります。
なお、ポリシーの適用は、Global > Product > API の順で行われます。
![apim_apipolicy.png](https://qiita-image-store.s3.amazonaws.com/0/230264/70d9f0d0-411c-8da2-4998-c0ab43b8b011.png)

- [参考：Product を作成して発行する](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-howto-add-products?WT.mc_id=AZ-MVP-5003113)
- [参考：API を変換および保護する](https://docs.microsoft.com/ja-jp/azure/api-management/transform-api?WT.mc_id=AZ-MVP-5003113)
- [参考：Azure API Management のポリシー](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-howto-policies?WT.mc_id=AZ-MVP-5003113)
- [参考：API Management のポリシー リファレンス](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-policies?WT.mc_id=AZ-MVP-5003113)

※既定の Product「Starter」のポリシーは、1分間に上限5回まで、週に最大100回まで呼び出すことができると定義されています。
![apim_starter.png](https://qiita-image-store.s3.amazonaws.com/0/230264/9b60acdb-abf9-90ef-5259-524adf5ea1d0.png)

また、バージョン管理、リビジョン管理をサポートしているので、API の変更やライフサイクルの管理に柔軟にコントロールすることができます。

- [API のリビジョンの追加](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-get-started-revise-api?WT.mc_id=AZ-MVP-5003113)
- [API の複数のバージョンの追加](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-get-started-publish-versions?WT.mc_id=AZ-MVP-5003113)

## API 利用
アプリ開発者 (API 利用者) の役割。
API を Product に含めたので、その API を呼び出すことができます。API のドキュメントも確認できます。
※開発者ポータルにアプリ開発者を登録して利用させる

API のテストは、Azure ポータル、開発者ポータルから実施することができます。
※下図は、開発者ポータルでテストを実行した結果
![apim_test00.png](https://qiita-image-store.s3.amazonaws.com/0/230264/9c4a7a23-4c07-a09f-d729-16b7f1b96101.png)

なお、API のテストを実施する際は、「サブスクリプションキー」が必要です。この「サブスクリプションキー」は、開発者ポータルの PRODUCTS > API を含めた Product から入手することができます。
![apim_test01.png](https://qiita-image-store.s3.amazonaws.com/0/230264/38ee80cb-e17a-6f31-13fc-b7e59a2e7231.png)

また、開発者ポータルのデザインをカスタマイズすることもできます。

[参考：開発者ポータル ページのスタイルをカスタマイズする](https://docs.microsoft.com/ja-jp/azure/api-management/api-management-customize-styles?WT.mc_id=AZ-MVP-5003113)

## API 運用
API 管理者の役割。
API の利用状況、パフォーマンス、メトリックなどを分析する機能があります。
※この機能は、Azure ポータルにはまだ移行しきれておらず、「発行者ポータル (まもなく廃止予定)」で確認。(2018年10月現在)
※REST API で取得することも可能。
![apim_ops01.png](https://qiita-image-store.s3.amazonaws.com/0/230264/2846306b-55a3-5aca-b5cb-1a14cf46c51a.png)
![apim_ops02.png](https://qiita-image-store.s3.amazonaws.com/0/230264/27373bf3-b60a-8f28-c090-74d5d856e0fe.png)

# API Management のセキュリティ
Azure API Management には、API 管理者向け、アプリ開発者向け、アプリケーション向けに機能を提供していますが、それぞれにアクセス制御を施しています。
![apim_access.png](https://qiita-image-store.s3.amazonaws.com/0/230264/7a4a01fb-5861-4136-9664-a47af155f1ac.png)

※API ゲートウェイーAPI 間にある「OAuth 2.0」と「OpenID Connect」は、API ゲートウェイ側の機能ではなく、API サーバー側でこの認証が行っていれば使えるようになっているという意味。

# 配置パターン
想定される配置パターンは以下のとおり。

## 配置パターンその１

|||
|:--|:--|
|仮想ネットワーク|オフ|
|サービス エンドポイント|パブリック|
|バックエンド API|パブリック|
|アクセス方法|インターネットから|

以下は、基本的な配置です。すべての価格レベルで実現できます。
![apim_pattern01.png](https://qiita-image-store.s3.amazonaws.com/0/230264/d12000db-1e34-f2cd-e779-4a6b60b3e984.png)

## 配置パターンその２

|||
|:--|:--|
|仮想ネットワーク|外部|
|サービス エンドポイント|パブリック|
|バックエンド API|VNET 上 & オンプレミス上|
|アクセス方法|インターネットから|

以下は、社内ネットワーク上の API をインターネットに公開する場合の配置です。
API Management を仮想ネットワークに接続するには、価格レベルで「Premium (Developer)」を選択します。
![apim_pattern02.png](https://qiita-image-store.s3.amazonaws.com/0/230264/37f5ec3f-0b9a-6d8c-54c2-cbdad6fe8f5a.png)

## 配置パターンその３

|||
|:--|:--|
|仮想ネットワーク|内部|
|サービス エンドポイント|プライベート|
|バックエンド API|VNET 上 & オンプレミス上|
|アクセス方法|社内ネットワークから|

以下は、社内ネットワーク上の API を社内から利用する場合の配置です。
※先と同様、API Management を仮想ネットワークに接続するには、価格レベルで「Premium (Developer)」を選択します。
![apim_pattern03.png](https://qiita-image-store.s3.amazonaws.com/0/230264/6956517f-b7f3-b6bd-e87a-a689300abff1.png)

## 配置パターンその４

|||
|:--|:--|
|仮想ネットワーク|内部|
|サービス エンドポイント|プライベート|
|バックエンド API|VNET 上 & オンプレミス上|
|アクセス方法|インターネットから|
||社内ネットワークから|

以下は、社内ネットワーク上の API を社内外から利用する場合は、API Management だけでは実現できないため、インターネット公開用として Application Gateway を用いて実現します。
※先と同様、API Management を仮想ネットワークに接続するには、価格レベルで「Premium (Developer)」を選択します。
![apim_pattern04.png](https://qiita-image-store.s3.amazonaws.com/0/230264/c0620953-c80c-cb02-0bff-3f17f6d187e5.png)

実運用で仮想ネットワークに接続したいとなった場合、価格レベルの選択肢が「Premium」しかない ([お値段がとてもお高い!!](https://azure.microsoft.com/ja-jp/pricing/details/api-management/?WT.mc_id=AZ-MVP-5003113)) のがとても厳しいですね...:cold_sweat:
※近い将来(?)、[Consumption Tier (従量課金) が設定される模様](https://forms.office.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR105TOAy5JtIg_J0zROqUERURTRDNEQxNVVNS1lMSUtBUVNFVlhCTjE5US4u)。

# ハンズオン!!

## API Management のインスタンスを作成
以下の記事の手順に従って作成しましょう。
料金レベルは、お試しなら「開発者 (SLA なし)」を選択しましょう。
なお、作成完了するまで20分くらいかかります。

[参考：Azure API Management サービスの新しいインスタンスの作成](https://docs.microsoft.com/ja-jp/azure/api-management/get-started-create-service-instance?WT.mc_id=AZ-MVP-5003113)

## API の準備
バックエンドの API として、今回は Open API で作ったものを用意しました。
![apim_addapi1.png](https://qiita-image-store.s3.amazonaws.com/0/230264/625e617d-7819-dece-57cf-cadda1945b62.png)

## API のインポート
先ほど作った API のスキーマ定義をインポートします。
API Management インスタンス > API > Add API をクリックして、[OpenAPI specification] をクリック
![apim_handson02.png](https://qiita-image-store.s3.amazonaws.com/0/230264/9a48b550-82cb-bdb2-dede-914b2eadff50.png)

[OpenAPI specification] に API のスキーマ定義を入力して [Create] をクリック
※[Display Name] と [Name] は、(スキーマ定義を読み込んで) 自動的にセットされる
![apim_handson03.png](https://qiita-image-store.s3.amazonaws.com/0/230264/008ed6aa-eb9b-5fe7-cc4b-40a4cdaf4455.png)

インポート完了。
![apim_handson04.png](https://qiita-image-store.s3.amazonaws.com/0/230264/859e19d0-9e74-8443-9ea1-8a01f1b9b176.png)

しかし、「Product」に追加せずに API をテストしてみると、401 が返ってきます。
![apim_handson05.png](https://qiita-image-store.s3.amazonaws.com/0/230264/3310684e-5911-7686-bf2c-f8fbf74fff9f.png)

API は Product に追加しないと利用できないので、Product に追加します。
![apim_handson06.png](https://qiita-image-store.s3.amazonaws.com/0/230264/007a956f-892e-26cf-80c6-8635ea2f6111.png)

## API を呼び出してみる
API Management インスタンス > API > インポートした API をクリックし、[Test] タブを開きます。
![apim_handson07.png](https://qiita-image-store.s3.amazonaws.com/0/230264/dd6f1652-18de-a7b3-1601-51006fe0cfdc.png)

任意の operation を選択、パラメーターなどを入力して [Send] をクリックします。
![apim_handson08.png](https://qiita-image-store.s3.amazonaws.com/0/230264/f4367325-d75a-9bcf-4e6c-9c8bf0b7cace.png)

「200 OK」と戻り値が返ってきたことを確認します。
![apim_handson09.png](https://qiita-image-store.s3.amazonaws.com/0/230264/4d28a2ec-7293-8103-64e3-e0283416fafd.png)

開発者ポータルでも同様のことができます。
![apim_handson11.png](https://qiita-image-store.s3.amazonaws.com/0/230264/d6a76429-5e29-0461-1d6c-1ff5cab564f0.png)

## API の呼び出しレートを設定してみる
"Addition" operation にポリシーを設定してみます。
inbound ポリシーに「Limit call rate」を追加して、呼び出しレートを IP アドレスごとに制限します。
ここでは、以下のとおりに設定してみます。

- Number of calls (Renewal period で指定した期間中に許容する呼び出し回数) ... 3 回
- Renewal period (クォータのリセット間隔) ... 3 秒
- Counter key (レート制限ポリシーに使用するキー) ... 呼び出し元 IP アドレス
- Increment condition (クォータに対して要求の件数をカウントする条件) ... 「2xx」を返却した時

![apim_handson12.png](https://qiita-image-store.s3.amazonaws.com/0/230264/47c3d066-526b-0014-7d8e-c5773dc16501.png)

では、Postman を使ってテストしてみます。
[Send] を何回か連打してみます。
![apim_handson14.png](https://qiita-image-store.s3.amazonaws.com/0/230264/3b8b3124-9340-88ef-0ddd-37b2884dc615.png)

しばらく連打していると、以下のようなレスポンスが返却され、レートが制限されていることが確認できます。
![apim_handson15.png](https://qiita-image-store.s3.amazonaws.com/0/230264/478334d8-9219-e5dd-3e50-9a69adbf9c01.png)

ここで注目すべきことは「API 発行」で先述したように、「ポリシーの適用は、Global > Product > API の順で行われる」ということです。
例えば、インポートした API を Product「Starter」に追加した場合、「Starter」のポリシーには「1分間に上限5回まで、週に最大100回まで呼び出し可」というものが適用されており、API のポリシーよりこのポリシーのほうが優先的に適用されます。

# まとめ
API は簡単に公開することができますが、その際に「認証はどうするか」、「どのようにアクセス制限すべきか」、「利用状況の確認方法はどうするか」などを API の本来の目的以外のことを考えて実装する必要があります。Azure API Management を API のゲートウェイとして設置することで一括で管理でき、各 API のこれらの懸念点から解放されるだろうと実感しました。
ただ、社内ネットワーク上の API を管理しようとなると、コストがネックになりそうです。今後改善されることを期待したいです。