Cloud Run + API Gateway でAPIキー認証のリクエストを行う

# 背景
- CloudRunで簡単な認証付きAPIを作りたい
- 認証はAPIキーを渡す方式にしたい
- できれば、ヘッダーでAPIキーを渡したい
- API Gatewayで構築していきます
  - 似たサービスとしてCloudEndpointがありますが、ESPの扱いが面倒なのでAPI Gatewayにしました
  - この辺りのお話は↓が参考になりました

https://medium.com/google-cloud-jp/google-cloud-api-gateway-8024f970a019


# 流れ
- CloudRunアプリ作る
- 認証なしのAPI Gateway -> CloudRun の環境を用意する
- 認証設定を行う
  - クエリパラメーターにAPIキーを渡す場合
  - ヘッダーにAPIキーを渡す場合

## CloudRunアプリ作る

まずはCloudRunアプリを作ります.
以下のクイックスタートを参考にするといいかも.

https://cloud.google.com/run/docs/quickstarts/build-and-deploy/deploy-python-service?hl=ja

CloudRun作成時に以下の設定にします　
- Ingressの制御は"すべて"
- 認証は"認証が必要"


　　
## 認証なしのAPI Gateway -> CloudRun の環境を用意する
次にAPI Gatewayのチュートリアルを参考に API Gateway -> CloudRunの 認証なしのAPI構成を作ります。 

https://cloud.google.com/api-gateway/docs/get-started-cloud-run?hl=ja

endpointが"/"のみのシンプルなPathのアプリの場合、Configのyamlは以下のようになります

```yaml
swagger: '2.0'
info:
  title: sample this_is_test
  description: Sample API on API Gateway with a Cloud Run backend
  version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-backend:
  address: https://sample-xxxx-an.a.run.app
paths:
  /:
    get:
      summary: Cloud Run hello world
      operationId: hello
      responses:
        '200':
          description: A successful response
          schema:
            type: string
```


生成されたGatewayURLでリクエストすると認証なしのリクエストなので以下のような表示になるはずです

![スクリーンショット 2023-10-24 13.51.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/7db63f20-5c46-6e13-d01b-71c70e8e7387.png)

## 認証設定を行う

### クエリパラメーターにAPIキーを渡す場合

`http://example.com?key=xxxxx` のようにクエリパラメータにAPIキーを渡す場合の設定をしていきます

#### API Keyの生成
まずはAPI Keyの生成をします

https://cloud.google.com/api-gateway/docs/authenticate-api-keys

API Keyはメモしておきます

#### Gateway Configを認証付きで作り直す
Gateway Configに認証設定を追加したものを用意します.

- securityの項目を追加してます
- serucityDefinitionsの項目を追加してます

```yaml
swagger: '2.0'
info:
  title: sample by_query_params
  description: Sample API on API Gateway with a Cloud Run backend
  version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-backend:
  address: https://sample-xxx.a.run.app
paths:
  /:
    get:
      summary: Cloud Run hello world
      operationId: hello
      security:
        - api_key: []
      responses:
        '200':
          description: A successful response
          schema:
            type: string
securityDefinitions:
  api_key:
    type: "apiKey"
    name: "key"
    in: "query"
```

こちらの動画が参考になりました.

https://www.youtube.com/watch?v=xO6qz6__9vI

こちらの設定でGatewayConfigを作り直して、API Gatewayに紐付けます.

#### テスト

先ほどメモしたAPIキーをつけてリクエストするとアクセスできるはずです
```
https://sample-gateway-xxxx.an.gateway.dev/?key=YOUR_API_KEY
```

### ヘッダーにAPIキーを渡す場合

次にヘッダーにAPIキーを渡す場合の設定をしていきます


#### Gateway Configの認証設定をheader用に変更して作り直す
Gateway Configにヘッダー用の認証設定を追加したものを用意します.

- parameters の設定にheader項目を追加します. nameは任意ですが、 `x-api-key` とします. 
- `securityDefinitions.api_key.in` の値は header にします

```yaml
swagger: '2.0'
info:
  title: sample by_header
  description: Sample API on API Gateway with a Cloud Run backend
  version: 1.0.0
schemes:
- https
produces:
- application/json
x-google-backend:
  address: https://sample-xxx.a.run.app
paths:
  /:
    get:
      summary: Cloud Run hello world
      parameters:
          - in: "header"
            name: "x-api-key"
            required: true
            type: string
      operationId: hello
      security:
        - api_key: []
      responses:
        '200':
          description: A successful response
          schema:
            type: string
securityDefinitions:
  api_key:
    type: "apiKey"
    name: "key"
    in: "header"
```

以下の記事が参考になりました

https://medium.com/@nikhil.nagarajappa/securing-cloud-functions-with-gcp-api-keys-and-x-api-key-header-f5f88a5b59e3

こちらの設定でGatewayConfigを作り直して、API Gatewayに紐付けます.

#### テスト

先ほどメモしたAPIキーをつけたcurlを実行すると確認できます

```shell
curl -X GET -H "x-api-key: API_KEY" "https://xxxx.an.gateway.dev"
```