Apigeeはじめました その１ HelloWorld, API Keyでの認証, Cloud Function, スロットリング, Extensionを使ったCloud Functionとのインテグレーション

#はじめに
APIの開発と管理を行うためのプラットフォームであるApigeeを試してみます。

#試したこと
以下の項目を試してみました。公式のドキュメントURLも貼っておきます。
1.チュートリアル通りHello world!
https://docs.apigee.com/api-platform/get-started/get-started?hl=ja
2.ターゲットをCloud Functionsに変更
https://cloud.google.com/functions/docs/tutorials/http?hl=ja
3.スロットリング
https://docs.apigee.com/api-platform/reference/policies/spike-arrest-policy
4.APIキーで認証
https://docs.apigee.com/api-platform/reference/policies/verify-api-key-policy
5.ターゲットのCloud Functionsに認証を追加
https://docs.apigee.com/api-platform/reference/endpoint-properties-reference
6.ターゲットのCloud Functionsに認証を追加 w/Extensions
https://docs.apigee.com/api-platform/tutorials/add-extension/intro?hl=ja
https://docs.apigee.com/api-platform/reference/extensions/google-cloud-functions/google-cloud-functions-extension-105

#1.チュートリアルでHello world!
以下のチュートリアル通りやってみたいと思います。
https://docs.apigee.com/api-platform/get-started/get-started?hl=ja

評価版を選択してサインアップしたあと、API Proxyを作成します。
左のペインからAPI Proxiesを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/7ef8cbdd-4779-75aa-2423-7bc7c43dfdca.png)

以下の種類から選択できます。チュートリアル通りにReverse proxyを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/fd2850b2-f6a2-83ae-c705-d3f8f305e46b.png)
No Targetってどんな時に使うのかよくわからなかったですが、後ほど試すExtension使った構成のときに使いました。

Nameを「getstarted」にして、Targetに「https://mocktarget.apigee.net」」を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/fd7258fe-7ea7-d902-324f-97b119dcdcec.png)

Pass throughを選択し、認証なしでAPIを実行できるようにします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/8ed9c05a-de92-0b04-530d-e31a179d386a.png)

デフォルトのままで次へ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/6ca42c8f-7236-b469-24be-f54dd0fe59c9.png)

Deploy Environmentsの横のtest環境を選択し、Build and Deployをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/3676abcf-a004-a17e-e50b-d16aabb73c73.png)

API Proxyが作成されます。

curlコマンドを実行し「Hello, Guest!」が表示されることを確認します。

```
$ curl https://*****.apigee.net/getstarted
Hello, Guest!
```

#2.ターゲットをCloud Functionsに変更
以下を参考にCloud Functionを作成します。テストなので未認証でInvokeできるようにします。
https://cloud.google.com/functions/docs/tutorials/http?hl=ja
curlコマンドで確認するとHellow world!が返されます。

```
$ curl  https://***.cloudfunctions.net/helloGET
Hello World!
```

先ほど作成したAPI ProxyのターゲットをCloud Functionに変更します。
https://docs.apigee.com/api-platform/get-started/change-endpoint?hl=ja

作成済みのAPI proxyクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/4d97769e-454d-5897-78a5-f7d44503f07e.png)

右上になるDeveloperタブをクリックして、Target endpointをクリックして、URLを作成したCloud FunctionsのURLに変更してSaveをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/121fe029-d11f-f923-04d7-b0c6375f8ccd.png)

curlコマンドを実行し「Hello, World!」が表示されることを確認します。

```
$ curl https://***.apigee.net/getstarted
Hello World!
```

#3.スロットリング
https://docs.apigee.com/api-platform/reference/policies/spike-arrest-policy
Proxy EndpointののPreFlowでHookするため、Proxy EndpointののPreFlowをクリックし右上の＋Stepをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/f23dc660-a417-25c4-d4ab-d3f8150d2543.png)

デフォルトだと以下のようなイメージで組まれています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/4ca4396d-88b7-b662-59f7-ebf8ff1d772f.png)

Spike Arrestを選択しAddします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/bfcaec3c-a770-2fa4-5e2e-4c39ee9e1052.png)

ちなみに似たようなPoicyが3つあります。
*QuotaとSpike ArrestとConcurrent Rate Limitの使い分け
https://docs.apigee.com/api-platform/develop/comparing-quota-spike-arrest-and-concurrent-rate-limit-policies

以下の記事がわかりやすかったです！ありがとうございます！
https://apps-gcp.com/apigee-traffic-management-policy/

今回はテストなので、Rateを1psにします。これは１分間に１リクエストに制限する設定になります。

```
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SpikeArrest async="false" continueOnError="false" enabled="true" name="Spike-Arrest-1">
    <DisplayName>Spike Arrest-1</DisplayName>
    <Rate>1ps</Rate>
</SpikeArrest>
```

Saveします。

Proxy EndpointのXMLに、Spike Arrest-1が追加されていることを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/97f1d2fb-7978-e059-f31e-fceee4e5d477.png)

レスポンスコードを確認するために右上のTRACEタブをクリックし、GETメソッドをSendします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/b7b683e4-a2ff-e244-9fd8-5f5dd37804d2.png)

5回くらいSENDすると429 Too Many Requestsが返されます。
*マニュアルだと500が返るってことになってるが、、🤔

>
* Quota ポリシーと SpikeArrest ポリシーの場合、レート上限を超えていることを表すデフォルトの HTTP ステータス コードは汎用の 500 Internal Server Error になります。このポリシーのステータス コードを 429 Service Unavailable に変更するには、組織レベルのプロパティ（features.isHTTPStatusTooManyRequestEnabled）を追加します。クラウドをご利用のお客様は、Apigee サポートに連絡してプロパティの有効化を依頼してください

#4.APIキーで認証
https://docs.apigee.com/api-platform/reference/policies/verify-api-key-policy

API EndpointのPreFlowをクリックして、Verify API KeyをクリックしてAddします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/e746c2e8-04bf-b542-e42f-a72f60192c9a.png)

Saveして新しいRevisionを作成し、Test環境にデプロイします。

curlコマンドで確認するとAPI keyが指定されていないためエラーになります。

```
$ curl https://***.apigee.net/getstarted
{"fault":{"faultstring":"Failed to resolve API Key variable request.queryparam.apikey","detail":{"errorcode":"steps.oauth.v2.FailedToResolveAPIKey"}}}
```

##APIキーを発行します。
DeveloperとApp productとAppと言うものを作成するのですが、関係性のイメージは以下の様な感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/62e7a2dc-0b7c-677b-393a-ce73691d7623.png)

Publish>Developer>+Developerをクリックし開発者を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/261bc0c0-e7c7-a125-fa17-a01b56a90d9d.png)

Publish>API Products+API Productをクリックし、API Productを作成します。
Product Name: getstarted
Display Name: getstarted
Description: getstarted
Environment: test
Access: Private
API Proxies: getstarted

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/23b93929-215b-edf0-e54d-fceba12a715d.png)

Publish>Apps>+Appをクリックし、APPを作成します。
Name: getstarted
Display Name: getstarted
Developer: 先程作成した開発者
Product: getstarted

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/b9905e89-440a-6c4f-2386-d03d9267509b.png)

curlでAPI Keyを追加して確認してみるとエラーなくレスポンスが取得できます。

```
$ curl https://***.apigee.net/getstarted/?apikey=el0eZGCgx4ms5xJPrAAYN**********
Hello World!
```

#5.バックエンドのCloud Functionsに認証を追加

そもそものCloud Functionsにおける認証はIAMで管理できます。
まずは、既存の関数で認証を必須にします。
Google cloud consoleで対象のCloud Functionsを選択し、Cloud Functions InvokerからallUserを削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/19e4cb36-0dd6-4afc-8d45-17376c0a55e4.png)

また、任意のサービスアカウントにもしくはユーザアカウントにCloud Functions InvokerのIAMロールを付与します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/ee8d9cfe-a1c2-a146-d247-bd02276bb2be.png)

この状態でAuthorizationなしでアクセスするとエラーになります。

```
$ curl https://***.cloudfunctions.net/helloGET

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/helloGET</code> from this server.</h2>
<h2></h2>
</body></html>
```

Authorizationありでアクセスすると成功します。

```
$ curl https://***.cloudfunctions.net/helloGET -H "Authorization: bearer $(gcloud auth print-identity-token )"
Hello World!
```

もちろん現状のままAPI ProxyのEndpointにアクセスするとTarget Endpoint(=Cloud Functions)のエラーが返ります。

```
$ curl https://***.apigee.net/getstarted/?apikey=el0eZGCgx4ms5***********

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>403 Forbidden</title>
</head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Forbidden</h1>
<h2>Your client does not have permission to get URL <code>/helloGET?apikey=el0eZGCgx4ms5xJPrAA*******</code> from this server.</h2>
<h2></h2>
</body></html>
```
API Proxyの設定を変更します。対象のAPI Proxyを選択し、Target EndpointのRequest Header設定でAuthorizationをターゲット サービスへの送信リクエストに引き継ぐ設定します。
###Extension使えば簡単に設定できますが、勉強のためやってみます。

https://docs.apigee.com/api-platform/reference/endpoint-properties-reference
Property name="request.retain.headersを設定します。

```
    <HTTPTargetConnection>
        <URL>https://***.cloudfunctions.net/helloGET</URL>
        <Properties>
          <Property name="request.retain.headers">Authorization</Property>
        </Properties>
    </HTTPTargetConnection>
</TargetEndpoint>
```

Authorizationヘッダーを指定してcurlコマンドを実行すると、ターゲット(=Cloud Function)まで認証情報が連携され成功します。

```
curl https://***.apigee.net/getstarted/?apikey=el0eZGCgx4ms5xJPrAAYN******* -H "Authorization: bearer $(gcloud auth print-identity-token )"
Hello World!
```

#6. バックエンドのCloud Functionsに認証を追加 w/Extension
先ほどは、request.retain.headersで認証情報を渡してましたが、ApigeeにGCPの認証情報を保持してターゲットにアクセスする際にその認証情報を使う構成の方がスマートです。Google Cloud Functions 拡張機能を使うと、Apigee側に認証情報を保持できます。
https://docs.apigee.com/api-platform/reference/extensions/google-cloud-functions/google-cloud-functions-extension-105

設定方法は以下のマニュアルに記載があります。
https://docs.apigee.com/api-platform/tutorials/add-extension/intro?hl=ja

前提作業として、Cloud Function Invoker roleが付与されたサービスアカウントを作成して、Create Keyして認証用のJOSNファイルをダウンロードします。

次にExtensionを作成します。Extensionbは連携したいGCPやAWSサービスのクレデンシャル情報などの設定情報を保持します。

Admin>Extensions>+ Add Extensionをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/34b881ef-52a2-5ed8-3886-2376395d9a99.png)

Google Cloud Functionを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/4a8e087c-3d8f-1772-655c-1b4ad5117cc8.png)

名前を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/a577539f-4368-b7a2-3b9d-9abe3b58f640.png)

Environment Configurationsでtest環境をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/f7144249-59b6-5ca6-77de-e8745fce33b8.png)

Credentialとして、先程ダウンロードしたJSONファイルの内容を入力してSaveします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/7fc84271-174a-c21b-d6fe-3d0b8f94cd5d.png)

Deployをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/c6f65c64-f52a-d5a4-3e1e-8b839887fa56.png)

数分待つとDeployが完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/12a83c21-88d3-f143-4e50-dd747d2e75be.png)

テスト用に新規にAPI Proxyを作成します。
Develop>API Proxies>+Proxyをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/2abc30ec-b1f2-8628-f594-86f702ecc019.png)

ターゲット設定は、Extensionのポリシーで定義するためNo Targetで作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/8ba8e2c9-f5f1-5c49-491f-b6f0fdca9734.png)

名前を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/86b17ac9-b588-e2bd-1e13-968791c67130.png)

デフォルトのまま次にすすんで、ExtensionがDeployされてるtest環境を選択してCreate and deployします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/763182f3-8659-97c7-f309-8dc22a5b0431.png)

作成したAPI ProxyのDevelopmentタブからPreFlowにExtension Calloutポリシーを追加します。
Extensionは、作成したExtensionを指定し、ActionはInvokeを選択しAddします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/707a3b5c-e08f-b9f7-3a16-9fb3f8ba1e3d.png)

API Proxyの設定をSaveして、Traceタブでテストします。正しくInvokeできました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78184/370baec5-9ae3-e154-3cf0-1bd7e49a64cc.png)


#投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。