2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

cert-managerでTLS化したKong Gatewayを構築する

Last updated at Posted at 2024-03-22

Kong GatewayをHelmで構築する際、デフォルトでKongは自己署名証明書を作成して起動する。
ただ、この証明書の管理をcert-managerが生成する証明書に置き換えることも出来る。
そうすることで、証明書の管理がManifestベースで可能となり、cert-managerによる自動更新も働くため管理コストが抑えられる。
これの検証に手間取ったので、記録がてら手順を残す。

なお、検証を行うにあたり以下は用意済みのものとする。

  • helmコマンド
  • Kubernetesクラスタの構築
  • type: LoadBalancerを使うためのLBの用意

ここではKubernetesはvSphere with Tanzu(Kubernetes:v1.25.7)を利用した。
また、以降でKICという言葉が出てくるが、これはKong Ingress Controllerの略である。

事前準備:cert-managerのインストールとIssuerの準備

Helmでサクッとインストールする。

helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install cert-manager jetstack/cert-manager --namespace cert-manager  --create-namespace --set installCRDs=true

証明書を発行するためのIssuerを作成する。
今回は自己署名証明書で進める。

cat <<EOF | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: selfsigned-issuer
spec:
  selfSigned: {}
EOF

Kong Gatewayの構築

今回、ドメインを用意するのが面倒だったので、ワイルドカードDNSサービスのnip.ioを使う。
また、AdminAPIとKong Managerのホスト名は以下とする。

  • kong-admin.<KICのExternalIPをハイフンで繋いだもの>.nip.io
  • kong-manager.<KICのExternalIPをハイフンで繋いだもの>.nip.io

検証環境ではKICのExternalIPが事前に分からなかったため、以下の流れで構築する。

  1. Helmのvalues.yamlを使ってKong GatewayとKICを立て、IPを取得
  2. KICのIPをvalues.yamlに反映
  3. 更新したvalues.yamlを使ってIngressを再デプロイ

最初にHelmのvalues.yamlを作成する。
作成にあたり、公式のサンプル集を参考にした。

cat <<EOF > kong-values.yaml
env:
  database: "postgres"
admin:
  enabled: true
  annotations:
    konghq.com/protocol: "https"
  ingress:
    enabled: true
    ingressClassName: kong
    tls: kong-kong-admin-cert
    hostname: kong-admin.10-214-154-167.nip.io
postgresql:
  enabled: true
certificates:
  enabled: true
  clusterIssuer: "selfsigned-issuer"
  admin:
    commonName: "10-214-154-167.nip.io"
    dnsNames:
    - "*.10-214-154-167.nip.io"
manager:
  annotations:
    konghq.com/protocol: "https"
  ingress:
    enabled: true
    ingressClassName: kong
    tls: kong-kong-admin-cert
    hostname: kong-manager.10-214-154-167.nip.io
EOF

設定で試行錯誤したのでいくつか補足説明をする。

  annotations:
    konghq.com/protocol: "https"

上記のannotationはServiceに設定され、これがないとKICがプロトコルをhttpとして扱ってしまい、"400 The plain HTTP request was sent to HTTPS portが表示されて上手くいかないので設定する必要がある。

    tls: kong-kong-admin-cert

上記はIngressをTLS化する際に証明書を渡すパラメータであり、cert-managerのkind: Certificateによって自動生成されるSecret名を指定する。
これは命名ルールがドキュメント等で明文化されていない気がするが、Helm Chart内で<Helmのリリース名>-<コンポーネント名>-certとして定義されている
Helmのリリース名をkong以外にする場合は変更する必要があるので注意。

    hostname: kong-admin.10-214-154-167.nip.io

これは前述のように後からkong-admin.<KICのExternalIPをハイフンで繋いだもの>.nip.ioに置き換えるため、一旦仮で入れている。置換し易い文字列なら何でもOK。

  clusterIssuer: "selfsigned-issuer"

これは先ほど作成したcert-managerのClusterIssuerを設定している。
ここで定義したものは他のコンポーネント全てに利用されるが、コンポーネント毎に設定することも可能。

    commonName: "10-214-154-167.nip.io"
    dnsNames:
    - "*.10-214-154-167.nip.io"

証明書の内容を指定する。ここも後で置換する。
なお、KongのHelmの設定でデフォルトでKICもデプロイされるようになっているため、このvalues.yamlを適用するとKICもセットでデプロイされる。
(1Pod内にKong GatewayとKICそれぞれのイメージが含まれる)

作成したvalues.yamlを使ってKong GatewayとKICをデプロイする。

helm upgrade -i -f kong-values.yaml kong kong/kong -n kong --create-namespace

デプロイすると、以下のようにIngressが作成される。

$ kubectl get ing  -n kong
NAME                CLASS   HOSTS                                ADDRESS          PORTS     AGE
kong-kong-admin     kong    kong-admin.10-214-154-167.nip.io     10.214.154.169   80, 443   72s
kong-kong-manager   kong    kong-manager.10-214-154-167.nip.io   10.214.154.169   80, 443   72s

ワイルドカードDNSサービスを利用すると、kong-admin.10-214-154-167.nip.ioにアクセスすると10.214.154.167にアクセスできる。
しかし、KICがProxyするアドレス(10.214.154.169)と異なるため、このホスト名ではアクセス出来ない。
そのため、values.yamlを書き換えて再デプロイする。

KIC_IP=$(kubectl get svc kong-kong-proxy -n kong -o jsonpath={.status.loadBalancer.ingress[0].ip} | sed "s/\./-/g")
sed -i "s/10-214-154-167/$KIC_IP/g" kong-values.yaml
helm upgrade -i -f kong-values.yaml kong kong/kong -n kong

問題なければ以下のように是正される。

$ kubectl get ing -n kong
NAME                CLASS   HOSTS                                ADDRESS          PORTS     AGE
kong-kong-admin     kong    kong-admin.10-214-154-169.nip.io     10.214.154.169   80, 443   8m42s
kong-kong-manager   kong    kong-manager.10-214-154-169.nip.io   10.214.154.169   80, 443   8m42s

これでKong ManagerとAdminAPIにアクセスできるようになる。
ただし、デプロイ直後はKong Managerにアクセスしても各種情報が適切に表示されず、Gateway ServiceなどにアクセスしてもGateway Services could not be retrievedといったエラーが表示される。
1711096557803.png

これの原因が分からず、デバッグレベルをあげてもよく分からなかったのだが、解決方法としてはAdminAPIにアクセスすると何故か治る。

※追記:
KongManagerからAdminAPIにアクセスしているが、CORSのせいでエラーになっている。
なので、一度AdminAPIにアクセスすると治る。
ドメインを同じにしてしまえば問題は起きないので、気になる人はとりあえずドメインを合わせるとよい。

以下のような感じでAdminAPI側にアクセスする。
1711097965979.png
この後Kong Managerにアクセスすると適切に表示されるようになる。
1711098032440.png
証明書もcert-managerにより発行されたものになっている。
1711098073696.png

動作確認

構築したものが正常に動作するか念の為確認する。
以前「Kong AI Gatewayをdeck CLIで構築する」というのを書いたが、これをこのKubernetes環境で動かしてみる。

最初にenv.shという環境変数を詰めたファイルを作成する。
CohereのAPIトークンに加え、deckの参照先Kong Gatewayを環境変数DECK_KONG_ADDRを使って設定する。
また、自己署名証明書なのでDECK_TLS_SKIP_VERIFYで証明書のチェックをスキップする。

cat <<EOF > env.sh
export COHERE_API_KEY=qIzGBRKxxxxxxx
export DECK_KONG_ADDR=https://kong-admin.10-214-154-169.nip.io
export DECK_TLS_SKIP_VERIFY=true
EOF
. env.sh

次に上述の記事で実行した内容をスクリプト化して実行する。
なお、今回はせっかくなのでGateway ServiceをHTTPS化した。

cat <<'EoF' > ./run.sh
#!/bin/bash
set -x
. env.sh
deck gateway dump -o kong-base.yaml --yes
export SERVICE_NAME=my-service
export SERVICE_ADDR=${SERVICE_NAME}.10-214-154-169.nip.io
cat <<EOF > ./service.yaml
services:
- name: $SERVICE_NAME
  host: $SERVICE_ADDR
  port: 443
  protocol: https
EOF
deck gateway sync kong-base.yaml service.yaml
SERVICE_UUID=$(http ${DECK_KONG_ADDR}/services --verify no | jq '.data[] | select(.name == "'"$SERVICE_NAME"'")'.id)
echo $SERVICE_UUID
cat <<EOF > ./cohere-route.yaml
routes:
- name: cohere-api_cohere-chat
  service:
    id: $SERVICE_UUID
  paths:
  - "~/cohere-chat\$"
  methods:
  - POST
EOF
deck gateway sync kong-base.yaml service.yaml cohere-route.yaml
ROUTE_UUID=$(http ${DECK_KONG_ADDR}/routes --verify no | jq '.data[] | select(.name == "cohere-api_cohere-chat")'.id)
echo $ROUTE_UUID
cat <<EOF > ./cohere-ai-proxy.yaml
plugins:
- name: ai-proxy
  route: $ROUTE_UUID
  config:
    route_type: "llm/v1/chat"
    auth:
      header_name: "Authorization"
      header_value: "Bearer $COHERE_API_KEY"
    model:
      provider: "cohere"
      name: "command"
      options:
        max_tokens: 512
        temperature: 1.0
EOF
deck gateway sync kong-base.yaml service.yaml cohere-route.yaml cohere-ai-proxy.yaml
EoF
chmod +x ./run.sh
./run.sh

これでCohereへKong経由でAPIが投げられるようになっているので、試してみる。

curl -k -s --http1.1 -X POST https://my-service.10-214-154-169.nip.io/cohere-chat \
  -H "Content-Type: application/json" --data-raw '{
    "messages": [{
    "role": "user",
    "content": "Where is the capital of Japan?"
  }] }'

ちょっと内容が変な気もするが、それっぽい答えが返ってきた。

{"id":"20ddf039-4f47-4f5e-a53f-b68f2488deaf","model":"command","choices":[{"message":{"content":"The capital of Japan is called Tokyo, it is the most populous metropolitan area in the world. \n\nTokyo is a very diverse city consisting of 23 city wards, multiple interwoven municipalities, and many neighborhoods. While blending traditional and modern cultures, it is known for its unique ambiance and ubiquitous skyscrapers, giving way to its popular name \"Tokyo Sky desper\" (Old Tokyotrapolis). \n\nTokyo will host the Summer Olympics of 2020, however, due to the COVID-19 pandemic, it will be postponed until summer of 2021. \n\nLet me know if you would like to know more about Tokyo or Japan!","role":"assistant"},"finish_reason":"stop","index":0}],"usage":{"completion_tokens":126,"prompt_tokens":69,"total_tokens":195},"object":"chat.completion"}

ちなみに--http1.1をつけない場合、An unexpected error occurredが返ってくる。
Proxyのログを見るとbuffered proxying cannot currently be enabled with http/2, please use http/1.x insteadと出ており、http/2だと上手く動かないようなので注意。

2024/03/22 09:16:29 [error] 1323#0: *3454 [kong] init.lua:405 [ai-proxy] /usr/local/share/lua/5.1/kong/plugins/ai-proxy/handler.lua:94: buffered proxying cannot currently be enabled with http/2, please use http/1.x instead, client: 192.168.2.1, server: kong, request: "POST /cohere-chat HTTP/2.0", host: "my-service.10-214-154-169.nip.io", request_id: "de29186609a64b43d452be6a074b451c"
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?