この記事は、「Kubernetes Advent Calendar 2016」18日目の記事です
ここでは Kubernetes がサポートする認証方法全てを手元で試してみたいと思います。
機能の説明は書いてあるが実際の使い方まで詳しく書いておらず、使い方がわからないものがあったりしたのでこれを機に全パターン確認してみます。
また、この記事は kubernetes: 1.4.6
および minikube: v0.13.1
で確認しています。
まずは簡単に kubernetes における認証の流れについておさらいしておきます。
kubernetes においては、ユーザーからコンテナの操作要求(CLIなどを使って)を受け取ると、クラスタを利用可能なユーザーであるかを認証し、利用可能な操作を認可で確認するというのが基本的な認証・認可の流れになります。(+ AdmissionControl もある)
また、このときの認証方法は複数組み合わせることが可能です。例えば、 X.509 証明書を使った認証と Static Toke File を組み合わせるといった感じです。それぞれが別々のオプションになっているので、指定された分だけ有効になります。それぞれ、用途によって必要な分だけ有効化するとよいです。
下記にそれぞれひつ有効化の方法とクライアントが認証してもらうために必要な設定を整理してみました。
X.509 Client Certs
デジタル証明書を使ってユーザを認証する方法です。 kube-apiserver の引数に --client-ca-file=SOMEFILE
を与えます。
証明書が正しく検証された場合、証明書のサブジェクトの CN
がユーザ名として使用されます。
Example
kube-apiserverの引数に下記を追加します。
--client-ca-file=/etc/kubernetes/ca.crt
minikube を使ってテストする場合は下記を追加して start します。
--extra-config=apiserver.ClientCAFile=/path/to/ca.crt
クライアント側の準備として、設定ファイルにさきほどのクライアント証明書の情報とそれを利用するコンテキストの設定をします。
$ kubectl config set-credentials kubelet --client-certificate=/etc/kubernetes/ca.crt --client-key=/etc/kubernetes/ca.key
$ kubectl config set-context minikube-client-ca --cluster=minikube --user=hiyosi
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl config use-context minikube-client-ca
$ kubectl get pods
=> 正しく取得できることを確認
Static Token File
あらかじめファイルに記載されたトークンによりユーザを認証する方法です。 kube-apiserver の引数に --token-auth-file=SOMEFILE
を与えます。引数の値として以下のような形式で定義されたファイルを渡します。
token,user,uid,"group1,group2,group3"
example
kube-apiserverの引数に下記を追加します。
--token-auth-file="/etc/kubernetes/static-token.csv"
minikube を使ってテストする場合は下記を追加して start します。
--extra-config=apiserver.TokenAuthFile=/path/to/static-token.csv
ここで上記 static-token.csv
ファイルは下記のように記述されているとします。
31ada4fd-adec-460c-809a-9e56ceb75269,hiyosi,2001,"group1,group2,group3"
クライアント側の準備として、設定ファイルにさきほどのユーザ情報とそれを利用するコンテキストの設定をします。
$ kubectl config set-credentials hiyosi --token=31ada4fd-adec-460c-809a-9e56ceb75269
$ kubectl config set-context minikube-static-token --cluster=minikube --user=hiyosi
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl config use-context minikube-static-token
switched to context "minikube-static-token".
$ kubectl get pods
=> 正しく取得できることを確認する
Static Password File
先ほどのトークンと同じようにあらかじめファイルに記載されたユーザ名とパスワードによりユーザを認証します。 kube-apiserver に対して引数 basic-auth-file
を与えます。引数の値として以下のような形式で定義されたパスワードファイルを渡します。
password,user,uid
example
kube-apiserverの引数に下記を追加します。
--basic-auth-file="/etc/kubernetes/static-password.csv"
minikube を使ってテストする場合は下記を追加して start します。
--extra-config=apiserver.BasicAuthFile=/path/to/static-password.csv
ここで上記 static-password.csv
ファイルは下記のように記述されているとします。
Hogehoge,hiyosi,2001
クライアント側の準備として、設定ファイルにさきほどのユーザ情報とそれを利用するコンテキストの設定をします。
$ kubectl config set-credentials hiyosi --username=hiyosi --password=Hogehoge
$ kubectl config set-context minikube-static-password --cluster=minikube --user=hiyosi
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl use-context hiyosi
$ kubectl get pods
=> 正しく取得できていることを確認する
Service Account Tokens
Service Account Token はデフォルトで有効になっているようなので、利用するために特別必要なパラメータは必要ありません。
オプショナルなパラメータとして以下があります。
-
--service-account-key-file
- A file containing a PEM encoded key for signing bearer tokens. If unspecified, the API server’s TLS private key will be used.
-
--service-account-lookup
- If enabled, tokens which are deleted from the API will be revoked.
example
サービスアカウントを作成します。
$ kubectl create serviceaccount test-sv-account
サービスアカウントが作成されたことを確認します。
$ kubectl get serviceaccount test-sv-account -o yaml
上記の結果より、secrets
配下の name
の値を確認します。
apiVersion: v1
kind: ServiceAccount
metadata:
creationTimestamp: 2016-12-06T08:49:42Z
name: test-sv-account
namespace: default
resourceVersion: "6607"
selfLink: /api/v1/namespaces/default/serviceaccounts/test-sv-account
uid: ee443ef1-bb90-11e6-b0c2-f2228bfbd4f6
secrets:
- name: test-sv-account-token-61knx
次にその name
値のシークレット情報を取得します。
$ kubectl get secret test-sv-account-token-61knx -o yaml
上記の結果より、data
配下の token
の値を確認します。
apiVersion: v1
data:
ca.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQVRBTkJna3Foa2lHOXcwQkFRc0ZBREFWTVJNd0VRWURWUVFERXdwdGFXNXAKYTNWaVpVTkJNQjRYRFRFMk1URXhNVEEzTlRReU1Wb1hEVEkyTVRFd09UQTNOVFF5TVZvd0ZURVRNQkVHQTFVRQpBeE1LYldsdWFXdDFZbVZEUVRDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTEplClQwQWtiS0JOdEVReXFNTjJDR25yYlBCZzF0MlNSWllaQkJJTmFrNHNTUUVBOVdJWnRlREVXK3l3YWNOZGNJRm8KZ3AyQUhyRzB6Y0tWVGZzRC9ZWHNaWkRlRHp0ZHR6NkcxZmIxL2dsRWZ0WTJ2Wlh2L2xlUENwbG1YNFJnclc1UApubVBINnlJYVJIekRrbFVYTHBpVUZQaWpzZVZzTnp2blkzNjBYWjRsODhLSXV0RnlHdkYrVDJVQmxBMWpxRDN3CnVtVWFrM0xWNnNFNkhZdkw4YlpyeWJqbVFhYi81anRXSENNVlIraWtDVDd2UlRDTUg2QkdJRlVEZ09IcCtXNzkKV0NsVGJDeUw4bDJ5cUVYQXp5V0oxaDBJTnFRK3BOR2Z2NWNPZUhZejA0SlJUL1VnNVpQRm55VWR2Sm4zNTh1NApIelNrWnN4Y1F2ZCtpNUlvK2JjQ0F3RUFBYU5DTUVBd0RnWURWUjBQQVFIL0JBUURBZ0trTUIwR0ExVWRKUVFXCk1CUUdDQ3NHQVFVRkJ3TUNCZ2dyQmdFRkJRY0RBVEFQQmdOVkhSTUJBZjhFQlRBREFRSC9NQTBHQ1NxR1NJYjMKRFFFQkN3VUFBNElCQVFCUkMwS1FtdnhNOVkvUGJZVDlzaEY0SlJCT0NoSFFodGkyQkovai9za1hYK0R4czdaSgpMYm1sNmFuWlQxa1djc1RRQ1Zyb0xPcTRRd1NwY0p3UHJHK25wS2F4K1Uwa1pIN2pKQ3crTFBaV2RvMGJCcXZICnMvRXh0TnR4WEZycEljRkQvVFQxM1ZyekRaRkVuY0RJUFdGTUE5bWJNNTRHWU5STHhtMDdjWk5MWlFNZTJIVUEKU0VuaEpPWU1rLzB3TkYyOU9ObXpEK2M2d2x4OEhqU1VhYVhWaldxMUtpZDVOMVkwZ04wZXlNK3h4TStVOFZMcQpHVWlhM2l1UWcwSXAwKzlISjJoUW5VcC9weW8zRlJHQkx1ZFZ6MlgvMDJFdXVUVllueEJPUkVDUjhoWVR3UURMClVoSUdXL050SVpoemhwV2pzdmtMQllUQlFpcUtIbUlrSENNSwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
namespace: ZGVmYXVsdA==
token: ZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKcmRXSmxjbTVsZEdWekwzTmxjblpwWTJWaFkyTnZkVzUwSWl3aWEzVmlaWEp1WlhSbGN5NXBieTl6WlhKMmFXTmxZV05qYjNWdWRDOXVZVzFsYzNCaFkyVWlPaUprWldaaGRXeDBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5elpXTnlaWFF1Ym1GdFpTSTZJblJsYzNRdGMzWXRZV05qYjNWdWRDMTBiMnRsYmkwMk1XdHVlQ0lzSW10MVltVnlibVYwWlhNdWFXOHZjMlZ5ZG1salpXRmpZMjkxYm5RdmMyVnlkbWxqWlMxaFkyTnZkVzUwTG01aGJXVWlPaUowWlhOMExYTjJMV0ZqWTI5MWJuUWlMQ0pyZFdKbGNtNWxkR1Z6TG1sdkwzTmxjblpwWTJWaFkyTnZkVzUwTDNObGNuWnBZMlV0WVdOamIzVnVkQzUxYVdRaU9pSmxaVFEwTTJWbU1TMWlZamt3TFRFeFpUWXRZakJqTWkxbU1qSXlPR0ptWW1RMFpqWWlMQ0p6ZFdJaU9pSnplWE4wWlcwNmMyVnlkbWxqWldGalkyOTFiblE2WkdWbVlYVnNkRHAwWlhOMExYTjJMV0ZqWTI5MWJuUWlmUS5IR2Rrby1mblVSZUVEc3pOeWM4cEEwTUNZQjhPZWZIYzRFR0M4U2JDTGFKVHB2WC1leXJPMGNIc1N4RHBoVUJUM3NOUWpicW5Sbk5nUjloTkdXbW9NbkQzcmZWdUhvSmEwSEtfcWJEUE5EM0NjVlQxRnpUd0JvTWhoV0U0OV90ZWVFcGZuUXliS0llaHVmd0ZHam5iVVdnaTZDNHZFLWxpR3JUMWtkb2FhVEZ4ZGQ3MFlwTFNRU2hkQ1lqQzNCRHp6dkxvbEpwdXo2R2pkM2k5Nkw2SWhfWkhaQmFXeXB3cG1tamZiS3dmSnVfSVFZdDQ3cUxONHlVM1ZKNEtLeE5Fa2NrcXY3cGNweHIzTXIyOGZSakgyUERLcTBhY014cEgwVjAxSXgwczFKR3h2NDd3UWNqbGNHYVNBUllNaWdyVC1uNnhlLTRvaG1ITU12RzFGZGh5bUE=
kind: Secret
metadata:
annotations:
kubernetes.io/service-account.name: test-sv-account
kubernetes.io/service-account.uid: ee443ef1-bb90-11e6-b0c2-f2228bfbd4f6
creationTimestamp: 2016-12-06T08:49:42Z
name: test-sv-account-token-61knx
namespace: default
resourceVersion: "6606"
selfLink: /api/v1/namespaces/default/secrets/test-sv-account-token-61knx
uid: ee451e2b-bb90-11e6-b0c2-f2228bfbd4f6
type: kubernetes.io/service-account-token
上記 token
の値がクライアント側にセットするトークンになるので、以下のコマンドを実行してコンテキストを作成します。
token
の値は base64 エンコーディングされていますが、kubectl
でセットする際にはデコードした値を使います。
$ kubectl config set-credentials test-sv-account --token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6InRlc3Qtc3YtYWNjb3VudC10b2tlbi02MWtueCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJ0ZXN0LXN2LWFjY291bnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJlZTQ0M2VmMS1iYjkwLTExZTYtYjBjMi1mMjIyOGJmYmQ0ZjYiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDp0ZXN0LXN2LWFjY291bnQifQ.HGdko-fnUReEDszNyc8pA0MCYB8OefHc4EGC8SbCLaJTpvX-eyrO0cHsSxDphUBT3sNQjbqnRnNgR9hNGWmoMnD3rfVuHoJa0HK_qbDPND3CcVT1FzTwBoMhhWE49_teeEpfnQybKIehufwFGjnbUWgi6C4vE-liGrT1kdoaaTFxdd70YpLSQShdCYjC3BDzzvLolJpuz6Gjd3i96L6Ih_ZHZBaWypwpmmjfbKwfJu_IQYt47qLN4yU3VJ4KKxNEkckqv7pcpxr3Mr28fRjH2PDKq0acMxpH0V01Ix0s1JGxv47wQcjlcGaSARYMigrT-n6xe-4ohmHMMvG1FdhymA
$ kubectl config set-context minikube-serviceaccount-token --cluster=minikube --user=test-sv-account
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl config use-context minikube-serviceaccount-token
$ kubectl get pods
=> 正しく取得できていることを確認する
OpenID Connect Tokens
これは OpenID Connect の ID トークンによって認証してもらいます。 kubernetes がプロバイダになるわけではなく、外部プロバイダによって認証され、その結果を kubernetes に渡すイメージです。これは kube-apiserver に対して以下の引数を与えます。
-
--oidc-issuer-url
- OpenID Connect プロバイダの URL. (e.g. https://accounts.google.com )
-
--oidc-client-id
- OpenID Connect プロバイダから事前に発行済みのクライアントID
-
--oidc-ca-file
- API サーバーが OpenID Connect プロバイダとの安全な接続を確立して検証するために使用します。デフォルトはホストのルートCAです。
以下は Experimental です。
-
--oidc-username-claim
- デフォルトではユーザ名として JWT の
sub
クレームが利用されるが、別のクレーム値を利用したい場合に指定
- デフォルトではユーザ名として JWT の
-
--oidc-groups-claim
- ユーザが所属するグループを表すクレーム名を指定します。文字列の配列の形式である必要があります。
Example
kube-apiserver の引数に以下を追加します。
--oidc-issuer-url=https://op.example.com --oidc-client-id=323f821025127910eff78b1fee4bbaf7 --oidc-ca-file=/etc/kubernetes/cert.pem
minikube を使ってテストする場合は下記を追加して start します。
--extra-config=apiserver.OIDCIssuerURL=https://op.example.com --extra-config=apiserver.OIDCClientID= 323f821025127910eff78b1fee4bbaf7 --extra-config=apiserver.OIDCCAFile=/path/to/ca.pem
OpenID Connect プロバイダで認証後に発行される IDトークンをクレデンシャル情報としてセットします。
また、その他トークンのリフレッシュに必要な refresh_token の情報もセットします。
OpenID Connect まわりのパラメータはまだ公式ドキュメントに反映されていませんが、
http://qiita.com/superbrothers/items/3c4e3fc651e9b3e9ef02
こちらの記事でパラメータについての解説がされていますので、各パラメータについて知りたい方は参照してみてください。
$ kubectl config set-credentials hiyosi --token=<... id token ...> --auth-provider=oidc --auth-provider-arg=client-id=323f821025127910eff78b1fee4bbaf7 --auth-provider-arg=client-secret=9926aa8a396c616ac33b6f947b38b9a2 --auth-provider-arg=idp-certificate-authority=/etc/kubernetes/idp.crt --auth-provider-arg=refresh-token=<...refresh token...>
$ kubectl config set-context minikube-oidc --cluster=minikube --user=hiyosi
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl config use-context minikube-oidc
$ kubectl get pods
=> 正しく取得できていることを確認する
Webhoook Token Authentication
Webhook Token Authentication はクライアントから与えられたトークンをリモートサーバに問い合わせ、その結果を使って認証可否を判断するような挙動になります。
kube-apiserver に対して以下の引数を与える必要があります。
-
--authentication-token-webhook-config-file
- リモート webhook サービスの設定
-
--authentication-token-webhook-cache-ttl
(OPTIONAL)- デフォルト 2 min
-
--runtime-config=authentication.k8s.io/v1beta1=true
- 利用中の Kuberenetes のバージョンによっては指定する必要があると思います
config ファイルは以下のように kubeconfig
と同じフォーマットです
# clusters refers to the remote service.
clusters:
- name: name-of-remote-authn-service
cluster:
certificate-authority: /path/to/ca.pem # CA for verifying the remote service.
server: https://authn.example.com/authenticate # URL of remote service to query. Must use 'https'.
# users refers to the API server's webhook configuration.
users:
- name: name-of-api-server
user:
client-certificate: /path/to/cert.pem # cert for the webhook plugin to use
client-key: /path/to/key.pem # key matching the cert
# kubeconfig files require a context. Provide one for the API server.
current-context: webhook
contexts:
- context:
cluster: name-of-remote-authn-service
user: name-of-api-sever
name: webhook
example
kube-apiserver の引数に以下を追加します。
--authentication-token-webhook-config==/etc/kubernetes/webhook.config --runtime-config=authentication.k8s.io/v1beta1=true
clusters:
- name: name-of-remote-authn-service
cluster:
server: http://192.168.99.1:5000/auth
# 今回はクライアント認証使わないのでコメントアウト
# users:
# - name: name-of-api-server
# user:
# client-certificate: /Users/tousami/Documents/adv-cal/server.crt
# client-key: /Users/tousami/Documents/adv-cal/server.key
current-context: webhook
contexts:
- context:
cluster: name-of-remote-authn-service
user: name-of-api-sever
name: webhook
クライアント側の準備として、設定ファイルにトークンを利用するユーザ情報とそれを利用するコンテキストの設定をします。
$ kubectl config set-credentials hiyosi --token=31ada4fd-adec-460c-809a-9e56ceb75269
$ kubectl config set-context minikube-webhook --cluster=minikube --user=hiyosi
上記で作成したコンテキストを使ってポッドの情報を取得してみます。
$ kubectl config use-context minikube-static-token
switched to context "minikube-static-token".
$ kubectl get pods
=> 正しく取得できることを確認する
また、 curl コマンドを使って以下のように確認することもできます。
$ curl -H 'Authorization: Bearer 31ada4fd-adec-460c-809a-9e56ceb75269' -X GET https://<kube-apiserverのアドレス>/api/v1/nodes
リモートサーバ側は kube-apiserver からの問い合わせに対して、以下のように応答する必要があります。
- 問い合わせ
POST <PATH> HTTP/1.1
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"spec": {
"token": "(BEARERTOKEN)"
}
}
- 成功
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": true,
"user": {
"username": "janedoe@example.com",
"uid": "42",
"groups": [
"developers",
"qa"
],
"extra": {
"extrafield1": [
"extravalue1",
"extravalue2"
]
}
}
}
}
- 失敗
{
"apiVersion": "authentication.k8s.io/v1beta1",
"kind": "TokenReview",
"status": {
"authenticated": false
}
}
Autenticating Proxy
Authenticating Proxy は kube-apiserver の前段に認証処理を肩代わりしてくれるような Proxy サーバを設定する構成を想定しています。
有効にするにはkube-apiserver に対して以下の引数を与える必要があります。
-
--requestheader-username-header
- ユーザ名とし利用するヘッダ名。複数指定されていた場合には先頭が優先される。
-
--requestheader-client-ca-file
- クライアント証明書。ヘッダ名を取得する前に証明書の検証を実施する。
-
--requestheader-allowed-name
(OPTIONAL)- CN名のリスト。指定されていた場合には、指定されたリストのCNを持つ有効なクライアント証明書を提示する必要がある。
example
kube-apiserver に以下のオプションを追加します。
--requestheader-username-header=X-K8S-Remote-User --requestheader-client-ca-file=/path/to/ca.crt
minikube を使ってテストする場合には以下のオプションを追加して start します。
--extra-config=apiserver.RequestHeaderUsernameHeaders=X-K8S-Remote-User --extra-config=apiserver.RequestHeaderClientCAFile=/path/to/ca.crt
しかし今回テストで使用しているバージョンの minikube ではこのオプションに対応していないようで、認証が成功するところまで確認できませんでした。k8s-v1.5
のブランチには該当オプションは存在しているようだったので、 k8s-v1.5
ブランチをビルドして試してみましたが、こちらでもまだ動かないようでした。(https://github.com/kubernetes/minikube/blob/k8s-v1.5/vendor/k8s.io/kubernetes/pkg/genericapiserver/options/server_run_options.go#L107-L108)
2937 localkube.go:116] Setting RequestHeaderUsernameHeaders to X-Remote-User on apiserver.
2937 localkube.go:118] Unable to set RequestHeaderUsernameHeaders to X-Remote-User. Error: Unable to find field by name: RequestHeaderUsernameHeaders
仮に正しく動いていた場合には以下のように、認証後のプロキシサーバのように振る舞うことで動作確認ができるのかなと思います。
curl --key /etc/kubernetes/ca.key --cert /etc/kubernetes/ca.crt -H "X-K8s-Remote-User: hiyosi" https://192.168.99.100:8443/api/v1/nodes
また、 kubectl
コマンドには proxy サーバが求める認証に対しての設定を入れてやる必要があるのかなと思います。(ちゃんと試せていないのでよくわからない)
$ kubectl config set-credentials hiyosi --username=hiyosi <それぞれの認証方法をセット>
$ kubectl config set-context minikube-proxy --cluster=minikube --user=hiyosi
$ kubectl config use-context minikube-proxy
Keystone Password
これは OpenStack の認証コンポーネントである keystone に認証を依頼するような方式になります。 kube-apiserver には以下の引数を与えます。
-
--experimental-keystone-url
- OpenStack Keystone の URL
-
--experimental-keystone-ca-file
- KeyStone サーバの証明書を検証するための証明書
example
kube-apiserver の引数に下記を追加します。
--experimental-keystone-url=https://localhost:35357/v2.0 --experimental-keystone-ca-file=/etc/kubernetes/keystone.crt
minikube を使っている場合には以下のような形になりそうです。(今後変更されるかもしれないので今後も同じように指定できるかは不明です)
--extra-config=apiserver.KeystoneURL=https://localhost:35357/v2.0 --extra-config=apiserver.KeystoneCAFile=/etc/kubernetes/keystone.crt
しかし残念ながらこのオプションも現在は動かないように見えました。 過去には https://techblog.yahoo.co.jp/infrastructure/k8s_on_os/ のような記事もあるので、正しく連携できているときもあったのだとは思います。現在は minikube の環境がダメなのか、ちょっと上手くいきません。
keystone.go:46] Failed: Starting openstack authenticate client
handlers.go:37] Unable to authenticate the request due to an error: Failed to authenticate
エラーメッセージを調べていると以下の issue がありましたが、私の環境では v2 でも v3 でもどちらも同じようなエラーで連携できませんでした。
仮に動いていたとすると、基本的には basic 認証の挙動をするので以下のように設定してあげることで確認できたのではないかと思います。
$ kubectl config set-credentials hiyosi --username=hiyosi --password=fugafuga
$ kubectl config set-context minikube-keystone --cluster=minikube --user=hiyosi
$ kubectl config use-context minikube-keystone
まとめ
最後の2つが上手く動作しなかったために、ちょっと消化不良な感じに終わってしまいました。
minikube のリポジトリに入っている kubernetes は若干古かったのですが、先日リリースされた 最新版(v1.5.0)で試せば動くものもあるかもしれません。