Konnectに繋ぐData PlaneをCLIのみで起動する

Konnect環境を用意する際に自動化する上で大きな障壁となるのはData Planeの構築だったりする。
Conrol Planeの用意やKonnect内の設定はKonnectへのAPIでどうにでもなり、TerraformのProviderも提供されていたりするが、Data PlaneはCloud Gatewayを使わない限りはユーザー側が用意した基盤に導入する必要があり、この基盤へのData PlaneへのイントールはKonnectのAPIでは行う事が出来ない。

ここでは自動化の足がかりとして、このData Planeの導入をKonnectのUIを使わずCLIで実施する方法を検証する。

## Data Planeの導入手順確認
自動化するにあたり、そもそものData Planeの導入手順を確認する。
導入方法によって手順は異なるが、ここでは汎用性の高いDockerでの導入手順を確認する。
KonnectのUIでの導入手順を細分化すると以下となる。

1. 証明書の作成
2. 証明書のKonnectへの登録
3. 以下の環境固有情報をコンテナの環境変数にセットしてData Planeコンテナを起動
   - Control Planeのエンドポイン
   - Control Planeのテレメトリのエンドポイント
   - 作成した証明書の内容

2についてはUIで操作していると意識しないが、`Generate certificate`をクリックするとそのタイミングで自動的に登録されている。
（余談だが、これはその後のData Planeのインストール手順をキャンセルしても残るため、キャンセルした場合はその後手動で削除した方がいい）
3のControl Planeの各エンドポイントはUIで操作した場合はインストールコマンド内に自動で反映されているが、このURLを知る手段はUI上では提供されておらず、APIで取得する必要がある。
実際のコンテナ起動コマンドは以下のような感じになるが、エンドポイントのURLは`a123cc23ad.us.{cp0|tp0}.konghq.com`の部分であり、これをコンテナ起動前にどうにかして知る必要がある。
```sh
docker run -d \
-e "KONG_ROLE=data_plane" \
-e "KONG_DATABASE=off" \
-e "KONG_VITALS=off" \
-e "KONG_CLUSTER_MTLS=pki" \
-e "KONG_CLUSTER_CONTROL_PLANE=a123cc23ad.us.cp0.konghq.com:443" \
-e "KONG_CLUSTER_SERVER_NAME=a123cc23ad.us.cp0.konghq.com" \
-e "KONG_CLUSTER_TELEMETRY_ENDPOINT=a123cc23ad.us.tp0.konghq.com:443" \
-e "KONG_CLUSTER_TELEMETRY_SERVER_NAME=a123cc23ad.us.tp0.konghq.com" \
-e "KONG_CLUSTER_CERT=-----BEGIN CERTIFICATE-----
MIICBjCCAaygAwIBAgIBATAKBggqhkjOPQQDBDA0MTIwCQYDVQQGEwJVUzAlBgNV
：（省略）
yBWFKRSDwwIhAOZq+56ybcj2bDfKO+52slecKRhPeEHMcf76A0FYQuQB
-----END CERTIFICATE-----" \
-e "KONG_CLUSTER_CERT_KEY=-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgCkjOZDXO2vt4CGf/
：（省略）
Ei6vSHun
-----END PRIVATE KEY-----" \
-e "KONG_LUA_SSL_TRUSTED_CERTIFICATE=system" \
-e "KONG_KONNECT_MODE=on" \
-e "KONG_CLUSTER_DP_LABELS=created-by:quickstart,type:docker-macOsArmOS" \
-p 8000:8000 \
-p 8443:8443 \
kong/kong-gateway:3.9
```

## 検証
ここでは以下の手順で検証する。
1. 証明書の作成
2. 証明書のKonnectへの登録
3. Control Planeのエンドポイントの取得
4. Data Planeコンテナの起動

### 証明書の作成
[証明書の更新に関する公式ドキュメント](https://developer.konghq.com/gateway/cp-dp-communication/#generate-certificates-in-konnect)にCLIでの証明書の発行方法が記載されているので、こちらに従って作成する。
```sh
mkdir certs
openssl req -new -x509 -nodes -newkey rsa:2048 -subj "/CN=kongdp/C=US" -keyout ./certs/tls.key -out ./certs/tls.crt -days 3650
```
作成した証明書はUIで作った時と同じく10年の有効期限とした。
```sh
$ cat ./certs/tls.crt | openssl x509 -noout -dates
notBefore=Jan 31 01:18:45 2025 GMT
notAfter=Jan 29 01:18:45 2035 GMT
```
### 証明書のKonnectへの登録
作成した証明書をKonnectのControl Planeに紐づける。
紐づけるためのControl PlaneのIDを最初に取得する。
Konnectに接続するためにまず環境変数にトークンを設定する。
```sh
KONNECT_TOKEN=kpat_ER1WQ0rnLX82VJghexxx
```
トークンはKonnect上で右上の自分のアカウントをクリックし、`Personal Access Tokens`->`Generate Token`から取得できる。
（システムトークンを使った方が良いが、今回は割愛）

KonnectのAPIのエンドポイントを環境変数に設定する。
```sh
KONNECT_API=https://us.api.konghq.com/v2
```
Control Planeの一覧は`/control-planes`から[取得できる](https://docs.konghq.com/konnect/api/control-planes/latest/#/Control%20Planes/list-control-planes)ので、ここからIDを以下のようにして引っ張ってくる。

```sh
CP_NAME="default" #Control Planeの名前
CP_ID=$(curl -s -X GET \
  -H "Authorization: Bearer $KONNECT_TOKEN" \
  "${KONNECT_API}/control-planes" \
  | jq -r --arg name "$CP_NAME" '.data[] | select(.name==$name) | .id')
```
'25/5/8追記：
IDの取得方法が変わっているようで、上手く行かない人はこちらで


Control PlaneのIDが分かったら証明書を登録する。
先に証明書の内容を環境変数に設定する。
```sh
export CERT=$(awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' ./certs/tls.crt)
```

証明書の登録は`/control-planes/${CP_ID}/dp-client-certificates`にPOSTすることで[登録できる](https://docs.konghq.com/konnect/api/control-plane-configuration/latest/#/DP%20Certificates/create-dataplane-certificate)ので、以下手順で登録する。
```sh
curl -sX POST \
  -H "Authorization: Bearer $KONNECT_TOKEN" \
  ${KONNECT_API}/control-planes/${CP_ID}/dp-client-certificates \
  --json '{"cert":"'"$CERT"'"}'
```

### Control Planeの各エンドポイントの取得
Control Planeの各エンドポイントは先程Control PlaneのIDを取得したときと同じエンドポイントを叩いても取得できるが、せっかくControl PlaneのIDを取得したので個別のControl Planeの情報を取得するエンドポイント`/control-planes/${CP_ID}`から取得してみる。
```sh
CP_ENDPOINT=$(curl -s -X GET \
  -H "Authorization: Bearer $KONNECT_TOKEN" \
  "${KONNECT_API}/control-planes/${CP_ID}" \
  | jq -r '.config.control_plane_endpoint')
TP_ENDPOINT=$(curl -s -X GET \
  -H "Authorization: Bearer $KONNECT_TOKEN" \
  "${KONNECT_API}/control-planes/${CP_ID}" \
  | jq -r '.config.telemetry_endpoint')
```
取得した値は頭に`https://`がつくが、これは不要なので取っ払う。

```sh
CP_ENDPOINT=$(sed "s@https://@@" <<< $CP_ENDPOINT)
TP_ENDPOINT=$(sed "s@https://@@" <<< $TP_ENDPOINT)
```

### Data Planeコンテナの起動
Data Planeコンテナを起動する。
起動前に証明書の内容を環境変数に読ませておく。
```sh
CERT=$(cat ./certs/tls.crt)
CERT_KEY=$(cat ./certs/tls.key)
```
コンテナを起動する。
```sh
docker run -d \
--name konnect-dp-manual \
-e "KONG_ROLE=data_plane" \
-e "KONG_DATABASE=off" \
-e "KONG_VITALS=off" \
-e "KONG_CLUSTER_MTLS=pki" \
-e "KONG_CLUSTER_CONTROL_PLANE=${CP_ENDPOINT}:443" \
-e "KONG_CLUSTER_SERVER_NAME=${CP_ENDPOINT}" \
-e "KONG_CLUSTER_TELEMETRY_ENDPOINT=${TP_ENDPOINT}:443" \
-e "KONG_CLUSTER_TELEMETRY_SERVER_NAME=${TP_ENDPOINT}" \
-e "KONG_CLUSTER_CERT=${CERT}" \
-e "KONG_CLUSTER_CERT_KEY=${CERT_KEY}" \
-e "KONG_LUA_SSL_TRUSTED_CERTIFICATE=system" \
-e "KONG_KONNECT_MODE=on" \
-e "KONG_CLUSTER_DP_LABELS=created-by:manual,type:docker-macOsArmOS" \
-p 8000:8000 \
-p 8443:8443 \
kong/kong-gateway:3.9
```
問題なければ以下のような感じでKonnectにData Planeが認識される。
![20250131115409.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/374cfdaf-9275-948c-2e62-55969684245f.png)

ここで実施した手順をパイプライン化すれば、Data Planeのデプロイについても自動化できるはずだ。