Bluemix Platform上のCloud FoundryアプリでセキュアにAPI公開する

毎週のように気づきのあるCloud Platformですが、書き込んでいきたいと思います。
本日のお題はCloud FoundryアプリのAPI公開です。気がついたら標準機能にAPI Managementなる項目が追加されていますので、ためしてみました。

![API_Connect.png](https://qiita-image-store.s3.amazonaws.com/0/101771/e3859a60-9328-5818-39f4-1bb0e49914fd.png)

# そもそもAPI Connectあったけど
Bluemix上のCloud Foundryアプリので作成したWeb APIを別のサービスと組み合わせて1つのAPIに組み上げ直したり、公開したAPIにレート制限(1分につき500コールまで、みたいな設定)やAPIキーを発行するなどの付加機能を提供するためのサービスとしてAPI Conenctサービスが提供されています。

ただ、考慮点が1つ。どうしてもこれまでのAPI Connectを用いてBluemix Platform上のCloud Foundryアプリを公開すると、アプリにはデフォルトで「[(なし)|eu-gb|au-syd|eu-de].mybluemix.net」というドメイン名が提供され、インターネットからアクセスできるようになるのに対し、エンドポイントのFQDNが「api.[us|en|au|de(?ドイツは使ったことない)].apiconnect.ibmcloud.com」としてもう1つ用意されてしまいます。仕組み上は直接「[(なし)|eu-gb|au-syd|eu-de].mybluemix.net」というドメイン名のアプリにはアクセスできないようになるとされていますが、そもそも「[(なし)|eu-gb|au-syd|eu-de].mybluemix.net」のままセキュアに公開したいですよね?

そんな要望にお応えしたかのような、組み込みのAPI management機能が実装されました。こちら実際に使ってみたいと思います。


# まずはAPIを定義する
既にBluemix Platform上に公開したいAPIを持つアプリが動いているとします。

Cloud Foundryアプリの「API Management」欄を選択すると、以下のような画面が初回に表示されます。画面真ん中にある「Get started」をクリックします。

<img width="1438" alt="スクリーンショット 2017-06-02 13.57.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/a604caae-4bc8-b589-5612-2ccfccb5015b.png">

すると、APIの定義(Definition)画面が表示されます。
<img width="1438" alt="スクリーンショット 2017-06-02 14.11.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/ebadbb4a-a21e-c675-699e-54a4ebaa414f.png">

この画面からAPIの定義を行っていきます。

## API Info
まず、「API Info (API情報)」でどのようなAPIを公開するかの定義ファイルを登録します。
・・・ってここがAPI新参者にはいきなりの最難関な気がします。

やり方はいくつかありますが、自分がよくやる方法は以下の2つです:
1. (Liberty for Javaのみ)[Exposing WebSphere Liberty REST APIs with Swagger](https://developer.ibm.com/wasdev/blog/2016/02/17/exposing-liberty-rest-apis-swagger/)に記載されるようにapiDiscoveryフィーチャーで生成する
2. API ConnectサービスのAPI Manager画面で生成してしまう
3. API Designerで生成してしまう  

JAX-RSでAPIを書くだけなら1.がすごく楽です。Java以外だったらば2.や3.が良いかもです。
とりあえず自分は1.で生成したファイルを「Import API definition」のボタンからアップロードしました。

もし、API定義ファイルが手元にない場合はどうなるか？答えはすべてのHTTPメソッドの「/」に対しAPIが公開されているものとして処理されます。どんなリクエストでもAPIとして管理の対象となってしまうので、設定には注意です。

## Security (API key)
まだ英語のままですが、「Require consuming applications to authenticate via API key」にチェックを入れると、APIキーでの認証を設定することができます。Methodの部分でAPIキーだけとするか、APIキーに対するシークレットも合わせて指定するかを選ぶことができます。今回は「API key and secret」を選択し、APIキーは「X-IBM-Client-ID」ヘッダー、APIシークレットは「X-IBM-Client-Secret」ヘッダーに指定する設定としました。

## Rate Limit
「Limit API call rate on a per-key basis」にチェックを入れると、APIに対しレート制限をかけることができるようになります。指定できるのは秒、分、時間、日あたりのAPIコール数です。今回は1分内に10回までの制約を課しています。

<img width="1126" alt="スクリーンショット 2017-06-02 14.12.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/b5eff7af-029e-fe6d-1985-d3a89094c4b7.png">

## OAuth
Google認証など、OAuthによるソーシャル・ログインを必須としたい場合には「Require end users to authenticate via OAuth social login」にチェックを入れます。今回はそこまでは求めないのでチェックはしませんでした。

## CORS
Same Origin Policy回避のためにCORSを利用できますが、有効化したい場合には「Enable CORS so that browser-based applications can call this API」にチェックを入れます。今回はデフォルトのまま、チェックを入れました。

<img width="1127" alt="スクリーンショット 2017-06-02 14.12.45.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/86152da1-fbfe-4955-82a4-3f7aedb50834.png">

以上で設定は終了です。あとは「Save」をクリックすると構成が保存されます。

# APIを公開する
構成の保存が完了すると、以下のような画面が出てきます。画面の右上にある「Expose Managed API」の部分をクリックするとAPIの公開が始まります!!

![API_Connect2.png](https://qiita-image-store.s3.amazonaws.com/0/101771/a01bcaf1-8954-6c17-4c78-8ed71615cced.png)

# 何が公開されているか確認する
APIの定義の際にアップロードしたファイルに記載されているAPIドキュメント内容が「API Explorer」タブに表示されます。このアプリにアクセスできる人はここからAPIの詳細が確認できますね。

<img width="1162" alt="スクリーンショット 2017-06-02 15.24.07.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/a1798bc2-ef8b-02f8-2793-a3a4840fd069.png">

# APIをシェアする
APIに対し、APIキーでの認証を求める設定を行なった場合、「Sharing」でAPIキーを発行することになります。

<img width="1437" alt="スクリーンショット 2017-06-02 14.14.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/abc52800-9b03-fadc-6cf1-4802b347c377.png">

「Create API key」をクリックすると、APIキーおよびシークレット(必須とした場合)が発行されますので、メモしておきます。そして、「Create」をクリックしてAPIキーを保存します。

![API_Connect3.png](https://qiita-image-store.s3.amazonaws.com/0/101771/5b257e67-0056-558e-7a6e-11a869b1ecf0.png)

APIキーは5つまで、APIシークレットに関しては確認できませんので注意です。
また、APIの公開を停止すると、現在の仕様としてはAPIキーは全て失効しますのでご注意を。

![API_Connect4.png](https://qiita-image-store.s3.amazonaws.com/0/101771/0f02256f-a070-822c-6c8f-c5356e163075.png)

# APIドキュメントをBluemixアカウントを持っていないユーザーに公開する
同じく「Sharing」タブに「Sharing Outside of Bluemix Organization」の項目があります。こちらで「Create API key」をクリックし、APIを作成すると、以下の画面のようにURLが生成されます。

<img width="1129" alt="スクリーンショット 2017-06-02 14.18.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/d23d1df0-76fe-9d6c-1848-565a73ded3b1.png">

このリンクにアクセスすると、APIドキュメントが確認できます。このURLをBluemix外の方に見せれば使い方を教えるのが楽になります。

<img width="1438" alt="スクリーンショット 2017-06-02 18.17.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/01ef0a85-1f03-9195-00bb-a677a94f90c0.png">

このAPIドキュメントに関しても5つまで、API公開を停止すると失効するのでご注意を。

# APIを使う
では設定が正しく反映されているか確認します。

APIキーなしでアクセスすると・・・

```bash
$curl --request GET \
>   --url https://backend-app-01.mybluemix.net/api/students \
>   --header 'accept: application/json'
{"status":401,"message":"Error: X-IBM-Client-ID required"}
```
はい、X-IBM-Client-IDがないと怒られました。APIシークレットを指定しないと・・・

```bash
$curl --request GET \
>   --url https://backend-app-01.mybluemix.net/api/students \
>   --header 'accept: application/json' \
>   --header 'x-ibm-client-id: XXXX'
{"status":401,"message":"Error: X-IBM-Client-Secret required"}
```
はい、X-IBM-Client-Secretがないと怒られました。では両方指定すると・・・

```bash
$curl --request GET \
>  --url https://backend-app-01.mybluemix.net/api/students \
>  --header 'accept: application/json' \
>  --header 'x-ibm-client-id: XXXX' \
  --header 'x-ibm-client-secret: XXXX'
{"result":"OK","jsessionid":"BgbhkbOgtRJfeF7zC7z1J1C","region":"US","students":{},"startTime":"2017/06/02T18:29:39.089","endTime":"2017/06/02T18:29:39.176","execTime":87}
```

よし、このアプリとしては正しい応答が返ってきたのでOKです。そして、コールしすぎると・・・

```bash
$curl --request GET \
>  --url https://backend-app-01.mybluemix.net/api/students \
>  --header 'accept: application/json' \
>  --header 'x-ibm-client-id: XXXX' \
  --header 'x-ibm-client-secret: XXXX'
{"status":429,"message":"Error: Rate limit exceeded"}
```

「"Error: Rate limit exceeded"」がでますね。OKです。

# APIの利用状況を確認する
APIの利用状況は「Summary」タブから確認可能です。1時間内の利用状況が確認できるようです。

<img width="1126" alt="スクリーンショット 2017-06-02 18.30.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/1bfaf948-dc02-c58b-1d40-cb95c05e1b3a.png">

# まとめ
以上ざっくりとした使い方でしたが、冒頭にもお伝えしましたようにドメインが「〜.mybluemix.net」でもAPIのレート制限をかけられるようになったのが大きい変更です。一方で、APIをより洗練したい、もっと細かくレート制限やAPIのバージョン管理をしたい、のようなことを求めるのであれば、これまでと同様API Connectサービスを使うのが適切な判断だと思います。

また、FaaS(Function as a Service)のOpenWhiskにも上記と同様のインターフェースのAPI公開の仕組みが現在利用可能になっています。こちらについても近々触れたいかなと思っています。