gcp
kubernetes
GKE

kubernetes REST API に外部から接続する

More than 1 year has passed since last update.

kubernetes には kubectl というコマンドがあり普段のオペレーションはそちらでやることが多いと思いますが、サーバから kubernetes をコントロールしたいというニーズもあるとも思います。

kubernetes には REST API が用意されているのでそれにアクセスすれば良いんですが、どうやって認証すればいいのか迷ったのでメモを残しておきます。

認証

いくつかの認証方式が用意されています。

  • X509証明書
  • BASIC認証
  • TOKEN
  • Service Account
  • OpenID

今回は TOKEN 方式でやってみます。

トークン取得

トークンや証明書は Pod の中に入って /var/run/secrets/kubernetes.io/ にあります。手動で取るのはさすがにかったるいので、下記コマンドを叩きます。

$(kubectl describe secret $(kubectl get secrets | grep default | cut -f1 -d ' ') \
  | grep -E '^token' | cut -f2 -d':' | tr -d '\t')

これでトークンが取得できるはずです。

APIサーバのIP

次に curl で叩く先のIPアドレスを取得します。以下のコマンドで取得できるんですが、複数のクラスタを設定している場合は複数出てしまうので注意してください。

kubectl config view | grep server | cut -f 2- -d ":" | tr -d " "

GKE だとコントロールパネルの以下の部分で確認ができます。

gke.png

アクセスしてみる

TOKEN=$(kubectl describe secret $(kubectl get secrets | \
  grep default | cut -f1 -d ' ') | \
  grep -E '^token' | cut -f2 -d':' | tr -d '\t')

curl https://example.com/api/v1/namespaces/default/pods \
  --header "Authorization: Bearer $TOKEN" --insecure

これで Pod の一覧が取得できるはずです。最高ですね。あとは、REST API のリファレンスを見て kubernetes と仲良くなってください。なお、バージョンによって使える API と使えない API があるので注意してください。

kubectl proxy というやり方も

公式ではこちらをオススメしてます。

kubectl proxy --port=8080 &
$ curl http://localhost:8080/api/
{
  "versions": [
    "v1"
  ]
}

クライアントライブラリ

クライアントライブラリも各言語ごとにいくつかあります。

公式では Go と Python ですね。Rubyだと abonas/kubeclient あたりが良さそうです。

abonas/kubeclient

Rubyのgem abonas/kubeclient を使ってAPIにアクセスしてみます。前述したTOKENの取得ができていれば環境変数などにブチ込んで接続するだけです。

auth_options = {
  bearer_token: ENV['K8S_API_TOKEN']
}

client = Kubeclient::Client.new(
  "https://#{ENV['K8S_API_HOST']}/api/", 'v1', auth_options: auth_options
)

client.get_pods

ただ、これだけだとSSLでエラーが出ると思います。kubernetesは独自の証明書を使っているため、そのままだと接続できないからです。 実際にコマンドを実行しようとすると、 KubeException: SSL_connect returned=1 errno=0 state=error: certificate verify failed こんな感じのエラーが出ます。

証明書の設定

OpenSSL::SSL::VERIFY_NONE にする手もありますがオススメはしません。

まず、接続用の証明書を作ります。

openssl genrsa -aes128 2048 > client.key
openssl req -new -key client.key > client.csr
openssl x509 -in client.csr -days 365000 -req -signkey client.key > client.crt
openssl rsa -in client.key -out client.key

次にkubernetesの証明書を取得します。Podの中の /var/run/secrets/kubernetes.io/serviceaccount/ca.crt にあります。

最後に abonas/kubeclient で接続します。

auth_options = {
  bearer_token: ENV['K8S_API_TOKEN']
}

ssl_options = {
  client_cert: OpenSSL::X509::Certificate.new(File.read(Rails.root.join("secrets", "k8s_client.crt"))),
  client_key:  OpenSSL::PKey::RSA.new(File.read(Rails.root.join("secrets", "k8s_client.key"))),
  ca_file:     Rails.root.join("secrets", "k8s_ca.crt"),
  verify_ssl:  OpenSSL::SSL::VERIFY_PEER
}

client = Kubeclient::Client.new(
  "https://#{ENV['K8S_API_HOST']}/api/", 'v1',
  auth_options: auth_options,
  ssl_options: ssl_options
)

client.get_pods

以上で接続できるようになります。