cloud-provider-openstackを使って、keystoneでk8sのユーザー認証を行う

v1.10より前のバージョンだと、apiserverででexperimental-keystone-url オプションを設定し、クライアントのkubeconfigでユーザー名とパスワードを設定すればkeystone認証できていた。しかし、v1.10ではこのオプションが削除されたため、別の方法としてcloud-provider-openstackを使う。このリポジトリはいろいろ混ざっていてややこしく、LBaaSやCinderとの連携機能についても提供している(別コマンド)。

さて、cloud-provider-openstackを使ってkeystoneによるユーザー認証を実現するにはクライアント側、サーバー側それぞれで設定が必要になる。クライアント側ではKeystoneからトークンを取得し、apiserverへ送る。サーバー側であるapiserverでは受け取ったトークンを使ってkeystoneに問い合わせ、そのトークンがユーザーが発行したものであることを確認する。

まずはクライアント側の設定についてだが、cloud-provider-openstackからclient-keystone-authをダウンロードし(ビルドしてもOK)、実行可能なPATHに配置する。そして、kubeconfigのユーザーとして以下のような設定を追加、コンテキストとして利用できるようにする。

次にサーバー側だが、apiserverでwebhookを有効にし、webhook先をk8s-keystone-authにする。

webhookconfig.yamlは以下の通り。10.233.0.3はk8s-keystone-auth用のサービスが持つClusterIPを指定する。

k8s-keystone-authはDeploymentとして動かしておく。

これで、v1.10以降でもKeystoneを使った認証を行うことができる。認可についても可能なようだが、今のところ認可はRBACを使っていて困っていないので認証だけでいいかな、という気持ち。

池袋 かえる食堂でチキンカレー

今日は自宅で仕事していたので、お昼に気になっていたかえる食堂へ。池袋西口から結構歩く必要がある。自分の場合はバスで近くまで行ったので楽だった。初回なので、シンプルにチキンカレーを選択。手羽先が柔らかくて美味しい。カレーはサラッとしていて、スパイシー感は控えめ。レモンがついていて、途中で気分を変えることができるのが好き。これはリピートして他のメニューも食べたいぞ。

池袋 スパイスらぁめん釈迦

池袋の西側にバスで行くと、よく降りるバス停前に最近できたお店。スパイスと言われると行かなければ!ということで行ってきた。

天空というおすすめのメニュー。他にも北インドラーメン、ミールスつけめんなどあり興味をひかれたがまずはイチオシメニュー。辛口だがスパイスラーメンならいけるだろうと思ったのだが、かなり辛かった。でもなかなか美味しい。次は北インド食べてみるかなー

GoのgRPCで独自の暗号化を行う

gRPCでは基本的にSSL/TLSを用いて通信の暗号化を行うのだが、何かしらの共通鍵暗号など独自の方式でやりたい!という場合があるかもしれない。そういう場合でもうまく拡張すれば実現できる。今回はAES+CTRを用いた実装を試みたので、その紹介をする。サンプルコードはtakaishi/hello2018/tree/master/grpc_with_record_cryptにある。

どうやるかというと、net.ConnのWrite()でデータを送る際に暗号化し、Read()で受け取る際に復号する。AES+CTRを用いた暗号化はGoだとライブラリがあるのでそれを使う。Go言語と暗号技術(AESからTLS)が参考になる。

Write/Read時の暗号化/復号をどうやるかだが、TransportCredentialsのClientHandshakeとServerHandshakeがポイント。この2つの関数はnet.Conn型であるrawConnを受け取り、net.Conn型の変数を返している。つまり、ここでrawConnをラップしたnet.Conn型を満たす構造体を用意し、その構造体のWrite/Readであれこれすればよい。これはATLSが使っている手法で、実装するにあたり大変参考になった。

net.Connをラップしたconnの例。これは暗号化・複合の処理は行わず、単純にラップするだけ。

暗号化・復号する処理を実装するとこんな感じになる。暗号化されたデータは元データとサイズが変わるため、Prefixとして暗号化されたデータのサイズを先に送り、そのサイズ分だけ読んだ後に復号する、というやりかたにした。

動かしてみる。暗号化しない場合、パケットキャプチャすると送受信したデータが読める(Hello!!!やThanks!!!など)ことがわかる。秘匿情報を送受信した場合、読まれる可能性があるだろう。

暗号化した場合はキャプチャしても以下のようになり、読むことが出来ない。共通鍵暗号なので、鍵がなければ解読できず、かなり安全になる。

ちょこちょこ書いて動くようになるまで1ヶ月ほどかかった。Read/Writeのラップがうまくいっていなかったのだけど、何もしない状態でテストを書くことで結果として暗号化・復号する場合でも同じ挙動になることが担保できたのでテストは大事だなと思う。