API GatewayのAPIキーにスロットリングを効かせたりGitHubのSecretsに登録してActionsから利用したりする

# API GatewayのAPIキーにスロットリングを効かせたりGitHubのSecretsに登録してActionsから利用したりする

## はじめに
先日、[静岡県オープンデータカタログ(csv)からCOVID-19対策サイトのデータ(json)に変換して取得するAPI](https://qiita.com/w2or3w/items/55ff3159aea0c7a9e096)という記事を書きました。

この時点(4/11)で「認証なし」だったのですが、変な使われ方して課金されてしまったらイヤだなぁと思いまして、遅ればせながらAPIキーによる認証とスロットリングを効かせましたので記事にします。
またこのAPIはGitHub Actionsから呼んで利用しているのですが、そこでのAPIキーの管理方法(Secrets)についても記載します。

## API Gatewayに対してAPIキーによる認証設定をする
[この記事](https://qiita.com/w2or3w/items/55ff3159aea0c7a9e096#lambda%E3%82%92%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%99api-gateway)で、認証なしの状態で動作確認が出来ている状態からスタートします。

### APIキーによる認証を必須とする
リソース - GET - メソッドリクエスト
APIキーの必要性 を true に設定します。
![Screenshot 2020-04-15 at 21.08.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/7326f31c-8fa9-8868-95c9-6e785c11138c.png)

リソースの[アクション]ドロップダウンメニューから[APIのデプロイ]を選択し、デプロイし直します。
すると、今までWebブラウザから認証なしでJSONをGETできていたものができなくなります。
![Screenshot 2020-04-13 at 23.29.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/1f4c54e6-d545-a106-3f46-6b1ed2f0b42c.png)
403が返ってくるようになります。

### APIキーを作成する
AWSコンソール > API Gateway > API の左ペインにある「APIキー」を選択します。
APIキーの[アクション]ドロップダウンメニューから[APIキーの作成]を選択、任意の名前を設定して[保存]ボタンを押下。
![Screenshot 2020-04-15 at 21.11.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/5d99e1f9-5432-bdc0-2c7a-8ee49431f3da.png)

### スロットリング設定をしたAPIキーを目的のAPIに割り当てる
AWSコンソール > API Gateway > API の左ペインにある「使用量プラン」を選択。
使用量プランの[作成]ボタンを押下。任意の名前や設定をして[次へ]ボタンを押下。
![ink (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/ce1cb848-81a5-9660-9954-8c1b639a26fc.png)
利用想定としては、10分間隔のポーリング + たまにデプロイで呼ばれる感じです。
(ポーリングして更新があったら通知する仕掛けを作ろうとしているのです。)

[関連付けられた API ステージ]で、目的のAPIとステージを追加し、また、スロットリングの設定でリソースやメソッドも追加しておきます。

次に進んで表示される[使用量プランの API キー]で、スロットリングを設定するAPIキーを選択します。
[APIキーを使用量プランに追加]ボタン押下し、目的のAPIキーを選択。
[完了]ボタンを押下してください。

Pythonのコードは以下のようになります。

```tool/create_data_json.py
import requests
API_ADDRESS = "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/resource"
API_PASSWORD = "xxxxxxxxxxxxxxxxxxxxxxxx"
def process():
    try:  
        apiResponse = requests.get(API_ADDRESS, headers={"x-api-key": API_PASSWORD})
```

これで、APIキーがないとアクセスできず、また、APIキーが割れて大量に呼ばれてしまっても傷は浅いですね。

## APIキーをGitHubのSecretsに登録して利用する
キー認証が必要なAPIをGitHub Actionsから呼ぶ場合についてです。

最初、上で書いたようなPythonのコードをそのままコミットしてプルリクしたんですね。
スロットリングも効かせたし、いいかなと思いまして。

そしたら、、。

> 浜松のボス『
キーをそのまま記載すると良くないので、以下のやり方で渡すように変更できませんか？
https://help.github.com/ja/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets
』

お、おぅ、、ということで。

### APIキーをGitHubのSecretsへ登録する
GitHub目的のリポジトリ > Settings > Secrets > Add new Secret
任意の名前のValueへAPIキーを設定して Add secretボタン押下。
![Screenshot 2020-04-15 at 22.14.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/394775/55b8e0a9-e959-90f9-14c7-913254889168.png)

`APIKEY_CSV2JSON`という名前で登録しました。

### GitHubのSecretsへ登録したAPIキーをGitHub Actionsで利用する
Secretsへ登録したAPIキーをActionsのWorkflowで取得し、Pythonのファンクションへ渡します。

Pythonのコードは以下のようにAPIキーを引数で渡せるよう改修しました。

```tool/create_data_json.py
import requests
API_ADDRESS = "https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/resource"
def process(apiKey):
    try:  
        apiResponse = requests.get(API_ADDRESS, headers={"x-api-key": apiKey})
```

そしてそれを呼び出すWorkiflowのyml (呼び出し部分のみ) は以下のような感じとなりました。

```.github/workflows/create_data_json.yml
      run: |
        python3 -c "import os; os.chdir('tool'); import create_data_json; x = create_data_json.process('${{ secrets.APIKEY_CSV2JSON }}'); print(x)" > data/hamamatsu/data.json
```

.
.
めでたしめでたし😇


## あとがき
今回の件で初めてGitHub ActionsやSecretsを利用しました。というか存在を知りました。
そもそもGitHubを今まであまり利用する機会もなかったのですが、これを機にもっとGitHubを知り、もっと使いこなせるようになりたいなと思った次第です。

エンジョイ・オンライン！！(言いたいだけw)