IAM対応されたCloudant NoSQL DBをcurlで操作する

色々気がつくと大きく変わっているIBM Cloudの気づきをメモしていくニッチな企画第１弾。
まずはIBM Cloud Platform (旧Bluemix)を利用している際に何かと利用しがちなCloudant NoSQL DBからです。

# What's New!? (2018年7月時点)
ドキュメントにまだ反映されていないのでorzなのですが、Cloudant NoSQL DBはCloud FoundryサービスからIAM対応サービスへと移行が完了しています。既存のインスタンスには大きな影響はないようですが、これから新規に利用する場合には要注意です。

そもそもCloud Foundryサービスとは、Cloud Foundryが中心だったBluemix時代の残滓の概念で、組織/スペースと呼ばれる概念と密接に結びついたサービスです。ユーザーは特定の組織/スペースにアクセス権限があれば、その組に対しデプロイされたサービスにアクセスできる仕組みになっていました。本番環境用のスペース、開発環境用のスペース、・・・のように環境面ごとに分けて、それぞれWatson APIのサービスをオーダーして使い分けるような方針で利用することが一般的でした。このサービスはスペースの単位がアクセス制御の最小範囲で、スペースに属するサービス1はAさんにアクセスさせたいけど、サービス2はAさんに見せたくない、みたいなことはできませんでした。

一方で、IAM対応サービスは、ざっくり言うと個々のサービスごとにアクセス制御を設定できる仕組みのことで、今後はこちらがIBM Cloud Platform提供のサービスでは主流になるようです。

以下がCloudant NoSQL DBオーダー時の画面です。これまでは組織とスペースを指定する項目のところが、リソース・グループ(IAM対応サービスのグループ)のみの指定に変わってしまっています。
<img width="1354" alt="スクリーンショット 2018-07-18 18.30.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/98d3ff04-5772-134b-7d36-02cc641371e1.png">


# Cloudant NoSQL DBにおいては何が変わったの?
IAM対応化されたため、これまでの通りAPIを呼び出すことができないケースがあります。スクリプトやアプリを書いている人は今後注意しましょう。

これまでのCloudant NoSQL DBの場合、BASIC認証でAPIを呼び出す仕組みになっており、使用するユーザー/パスワードはオーダー後にサービス資格情報から確認できました。あるいは、データベースに対し特定の処理のみを許容するapikey/passwordを別途発行することができ、それを使用してデータベースにアクセスすることができました。

しかしながら、IAM対応化されると、OpenID Connectベースでの認証が必須となります。

現状はどちらでも対応できるようデプロイ時にオプションが設けられています。「Use both legacy credentials and IAM」を選択するとOpenID Connectベースでの認証あるいはこれまでと同様BASIC認証でアクセスするためのユーザー/パスワードが生成されます。「Use Only IAM」の場合はBASIC認証はできません。。

<img width="458" alt="スクリーンショット 2018-07-18 18.37.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/6b777909-bf37-5c02-6bc9-1abfcb77c32a.png">

デプロイ直後はサービス資格情報は表示されませんので、「新規資格情報」をクリックしてアクセスするために必要な認証情報を生成します。

<img width="1102" alt="スクリーンショット 2018-07-18 18.42.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/f5d5e27f-6c13-652c-c1b3-6c211f5f396e.png">

フォーマットは以下のようになっており、これまでCloud Foundryサービスだったときと比べると項目がだいぶ変わっているのがわかります。(iam_*の部分が追加された付与情報)

```
{
  "apikey": "<IAMアクセストークンを生成するために必要な文字列>",
  "host": "xxxxxx-bluemix.cloudant.com",
  "iam_apikey_description": "Auto generated apikey during resource-key operation for Instance - crn:v1:bluemix:public:cloudantnosqldb:us-south:a/xxxx:xxxx::",
  "iam_apikey_name": "auto-generated-apikey-xxxx",
  "iam_role_crn": "crn:v1:bluemix:public:iam::::serviceRole:Manager",
  "iam_serviceid_crn": "crn:v1:bluemix:public:iam-identity::a/xxxx::serviceid:ServiceId-xxxx",
  "password": "<「Use both legacy credentials and IAM」を選択した時のみ表示されるBASIC認証のためのパスワード情報>",
  "port": 443,
  "url": "https://xxxx-bluemix:xxxx@xxxx-bluemix.cloudant.com",
  "username": "xxxx-bluemix"
}
```

なお、デプロイ完了し、インスタンスにログインしてみると、どちらのオプションであったとしてもデータベースに対しAPIキーを発行する機能は無くなっていました。。

<img width="1433" alt="スクリーンショット 2018-07-18 18.40.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/101771/7dfa4f4c-d06b-8239-59c7-cfecc7d26c59.png">

# IAM前提でどうアクセスする?
手順はシンプルで、以下の2ステップです：
(1) IAMアクセストークンを発行する
(2) Cloudantに対しREST APIで操作する

## (1) IAMアクセストークンを発行する
まずは以下のドキュメントにも記載があるように、アクセストークンをAPIキーを用いて取得します。
https://console.bluemix.net/docs/iam/apikey_iamtoken.html#iamtoken_from_apikey

```
curl -k -X POST \
    --header "Content-Type: application/x-www-form-urlencoded" \
    --header "Accept: application/json" \
    --data-urlencode "grant_type=urn:ibm:params:oauth:grant-type:apikey" \
    --data-urlencode "apikey=<Cloudantのサービス資格情報にあるapikeyの文字列を指定>" \
    "https://iam.bluemix.net/identity/token"
```

上記を叩くと、アクセストークンが取得できます。

## (2) CloudantにAPIを投げる
(1)で取得したアクセストークンを利用してCloudant NoSQL DBをREST APIで操作します。
以下は特定のデータベースの中身を全て取得する_all_docsを利用した例です。

```
curl --header "Authorization: Bearer <長いけどIAMアクセストークンを指定する>" \
　　　--header "Accept: application/json" \
　　　https://<CloudantのURL>/<DB名>/_all_docs
```

簡単ですが、今までBASIC認証で1発で実施していた分複雑になりましたね。まあ毎回認証情報を下手に指定する必要がなくなりましたし良いかなと。

#終わりに
今回はcurlで実施しましたが、他の言語での実装でも本質的には同じです。提供ライブラリがIAM対応されていない可能性も考えると、当面は「Use both legacy credentials and IAM」のオプションをデプロイ時に指定しないとダメかもしれません。利用するライブラリのREADMEを確認しましょう。

また、今回はCloudant NoSQL DBについてでしたが、他にもBASIC認証ベースのAPIに関しても今後は同様なステップでアクセスが必要になっていくものと思われます。要注意です。