kubeadm環境のKubernetesにてユーザーを追加

kubeadmにて作成したKubernntes Clusterに、Normal Userを追加する方法を確認します。

環境

実際の追加作業を実施する前に、Kubernetesにおける認証方式やユーザーの扱いについて確認しておきます。

Kubernetesにおける認証方式

kube-apiと認証をするに、様々な方法が用意されています。

Kubernetes uses client certificates, bearer tokens, an authenticating proxy, or HTTP basic auth to authenticate API requests through authentication plugins.

Authentication strategies

なお、kubeadmにて作成された環境では、client certificatesによる認証が有効になっています。以下は公式ドキュメントの説明ですが、

Client certificate authentication is enabled by passing the --client-ca-file=SOMEFILE option to API server. The referenced file must contain one or more certificate authorities to use to validate client certificates presented to the API server.

X509 Client Certs

実際にkube-apiのpodを確認すると、起動時に --client-ca-file というオプションが付与されています。

$ kubectl -n kube-system describe pod kube-apiserver-kubeadm-master | grep -iA10 command
    Command:
      kube-apiserver
      --advertise-address=10.146.0.2
      --allow-privileged=true
      --authorization-mode=Node,RBAC
      --client-ca-file=/etc/kubernetes/pki/ca.crt       # <-ここ
      --enable-admission-plugins=NodeRestriction
      --enable-bootstrap-token-auth=true
      --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
      --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
      --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key

kubeadmによるCluster初期化時に作成された認証局を、kube-api側に登録してくれています。

Kubernetesにおけるユーザーとは

公式ドキュメントでの説明。

All Kubernetes clusters have two categories of users: service accounts managed by Kubernetes, and normal users.

It is assumed that a cluster-independent service manages normal users in the following ways:

・an administrator distributing private keys

・a user store like Keystone or Google Accounts

・a file with a list of usernames and passwords

In this regard, Kubernetes does not have objects which represent normal user accounts. Normal users cannot be added to a cluster through an API call.

Even though a normal user cannot be added via an API call, any user that presents a valid certificate signed by the cluster's certificate authority (CA) is considered authenticated. In this configuration, Kubernetes determines the username from the common name field in the 'subject' of the cert (e.g., "/CN=bob"). From there, the role based access control (RBAC) sub-system would determine whether the user is authorized to perform a specific operation on a resource.

Users in Kubernetes

ユーザーというオブジェクトは存在しないものの、Kuberrnetes Cluster内の認証局にて署名された証明書をもつユーザーであれば認証するよ、という話でしょうか。

Kuberrnetes Cluster内の認証局とは、つまり上記でkube-api起動時に登録した認証局となる訳ですが、Kubernetesでは、この認証局で証明書を発行してくれる機能をAPIにて提供しています。 kind: CertificateSigningRequest というオブジェクトにCSR情報を含めて登録することで、証明書を発行してくれます。この発行された証明書をクライアント証明書として、kubectlのkubeconfigに設定することで、kube-apiとユーザー認証できるようなります。

ユーザーの追加

実際にユーザーを追加してみます。以下の公式ドキュメントに沿って作業。

Normal user

CSRファイルの作成

まず、Kubernetesに登録するためのCSRファイルを作成します。

秘密鍵の作成。

$ openssl genrsa -out zunko.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..................+++++
......................................+++++
e is 65537 (0x010001)

作成した秘密鍵をもとにCSRファイルを作成します。CN(Common Name)がユーザー名、O(Organization Name)がグループ名として利用されるとの事。

It is important to set CN and O attribute of the CSR. CN is the name of the user and O is the group that this user will belong to.

コモンネームを zunko として、CSRファイルを作成します。

$ openssl req -new -key zunko.key -out zunko.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:zunko
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

CSRファイルの登録

CSRを登録するにはBase64文字列としてする必要あるため、CSRファイルのBase64エンコードした文字列を取得します。

$ cat zunko.csr | base64 | tr -d "\n"
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21qQ0NBWUlDQVFBd1ZURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeApJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERU9NQXdHQTFVRUF3d0ZlblZ1CmEyOHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEQ2lEcHU3MFdpSTZwYkttekIKdlhyZUVPRy8yTXNHa0lVZ3NseGJvMmV1cy9QUllPb0gyZU1INkNOWTNMMmVsS1hueDBZcEQyT2I2QURpeVR5cQpQZEhzNnFXQVRabHJtRjZBcmJWaS8vU3BMWUNmR2ptSkp3VWVzN3k3VXBnZ2QwSE1LeWtyNFY1L2FzYlV5dVlOCklBRjhiN0ptbTRWZ3ovd1RMMzIvTDFEOVRNUXJLZ0FYNkFUMTdUZENrdEh2OW1nWXNMRDhQdDd6b0VZNnZnNDUKNTUwaWZRZ1V5blR3MjRCcjJzOXRValgxRjZtb1dHdjY2TmxuQmpqaVdKek1hQzlMWVVjUVhMU2htMEx6ekpLdwo3SHY5aWFNL0Ixcjc2Q3VBNEhuaFdZRlJRbDNIZEVqSzVGcUllUi8xOUVDb2ZFK2FObmplV2k4S1NmeEpIK0xLCjdMMFpBZ01CQUFHZ0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFVTGh1cnM1aWJ0N0VQdmo0R3hNOGFjOFgKTHBLOEg4RWZIVnNUcWJTd2hLL0w1TFNEbFBRaGNNdUlyZDdRL25oR1BvbkJ5SEVDQmFLKzZ3OHVaY0hUNFY0Lwo4Q21MSTAyUm04N1dpTVlmL0F3MFFIcGRWQUJiaTFtam0vanQ1aG1tM001MUYvSldtOG1YN0lkQnEyOW1uVGhzCkxJb3RkYnRIckk3dzZYelRJeGdMN2ZCT0IwM2l2aWd3M01qS29XUXB1SHdSQnBmVkF3b2NMdHR6L3NBbldmakwKYlBGZndVdExkS0VIWHVJOGVhTFo5eCtqVzNVZmNkdTluUUtudTZNUEcvbWh6eEx1aVRNYnZaQzdWcDltOSsvbApLcVltNzFXdVk0TnVXOEpkUGhTOVFEZE9Wc2k3bXRjd0FWZmFtYTlkY2NKUUdiUllwZG15a25tMzZrbnRJZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=

取得した文字列をもとに、以下の CertificateSigningRequestマニフェストファイルを作成します。

csr-zunko.yaml

apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
  name: zunko
spec:
  groups:
  - system:authenticated
  request: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0KTUlJQ21qQ0NBWUlDQVFBd1ZURUxNQWtHQTFVRUJoTUNRVlV4RXpBUkJnTlZCQWdNQ2xOdmJXVXRVM1JoZEdVeApJVEFmQmdOVkJBb01HRWx1ZEdWeWJtVjBJRmRwWkdkcGRITWdVSFI1SUV4MFpERU9NQXdHQTFVRUF3d0ZlblZ1CmEyOHdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUtBb0lCQVFEQ2lEcHU3MFdpSTZwYkttekIKdlhyZUVPRy8yTXNHa0lVZ3NseGJvMmV1cy9QUllPb0gyZU1INkNOWTNMMmVsS1hueDBZcEQyT2I2QURpeVR5cQpQZEhzNnFXQVRabHJtRjZBcmJWaS8vU3BMWUNmR2ptSkp3VWVzN3k3VXBnZ2QwSE1LeWtyNFY1L2FzYlV5dVlOCklBRjhiN0ptbTRWZ3ovd1RMMzIvTDFEOVRNUXJLZ0FYNkFUMTdUZENrdEh2OW1nWXNMRDhQdDd6b0VZNnZnNDUKNTUwaWZRZ1V5blR3MjRCcjJzOXRValgxRjZtb1dHdjY2TmxuQmpqaVdKek1hQzlMWVVjUVhMU2htMEx6ekpLdwo3SHY5aWFNL0Ixcjc2Q3VBNEhuaFdZRlJRbDNIZEVqSzVGcUllUi8xOUVDb2ZFK2FObmplV2k4S1NmeEpIK0xLCjdMMFpBZ01CQUFHZ0FEQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFVTGh1cnM1aWJ0N0VQdmo0R3hNOGFjOFgKTHBLOEg4RWZIVnNUcWJTd2hLL0w1TFNEbFBRaGNNdUlyZDdRL25oR1BvbkJ5SEVDQmFLKzZ3OHVaY0hUNFY0Lwo4Q21MSTAyUm04N1dpTVlmL0F3MFFIcGRWQUJiaTFtam0vanQ1aG1tM001MUYvSldtOG1YN0lkQnEyOW1uVGhzCkxJb3RkYnRIckk3dzZYelRJeGdMN2ZCT0IwM2l2aWd3M01qS29XUXB1SHdSQnBmVkF3b2NMdHR6L3NBbldmakwKYlBGZndVdExkS0VIWHVJOGVhTFo5eCtqVzNVZmNkdTluUUtudTZNUEcvbWh6eEx1aVRNYnZaQzdWcDltOSsvbApLcVltNzFXdVk0TnVXOEpkUGhTOVFEZE9Wc2k3bXRjd0FWZmFtYTlkY2NKUUdiUllwZG15a25tMzZrbnRJZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFIFJFUVVFU1QtLS0tLQo=
  signerName: kubernetes.io/kube-apiserver-client
  usages:
  - client auth

admin権限をもったユーザーにて、作成したマニフェストファイルを登録します。

$ kubectl apply -f csr-zunko.yaml 
certificatesigningrequest.certificates.k8s.io/zunko created

CSRの承認

登録されたCSRPending 状態となっています。

$ kubectl get csr
NAME    AGE   SIGNERNAME                            REQUESTOR          CONDITION
zunko   29s   kubernetes.io/kube-apiserver-client   kubernetes-admin   Pending

approveコマンドを実行することで、証明書を発行可能となります。

$ kubectl certificate approve zunko
certificatesigningrequest.certificates.k8s.io/zunko approved

approveされました。

$ kubectl get csr
NAME    AGE     SIGNERNAME                            REQUESTOR          CONDITION
zunko   2m39s   kubernetes.io/kube-apiserver-client   kubernetes-admin   Approved,Issued

証明書の取得

発行された証明書は、CSRオブジェクトの .status.certificate フィールドに記載されています。

$ kubectl get csr zunko -o jsonpath='{.status.certificate}'
LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURPekNDQWlPZ0F3SUJBZ0lSQU5Ga3pWek1zbHJPcjZBbU85L1FkdHd3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdBMVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TVRBeE1UWXlNVE0yTlROYUZ3MHlNakF4TVRZeQpNVE0yTlROYU1GVXhDekFKQmdOVkJBWVRBa0ZWTVJNd0VRWURWUVFJRXdwVGIyMWxMVk4wWVhSbE1TRXdId1lEClZRUUtFeGhKYm5SbGNtNWxkQ0JYYVdSbmFYUnpJRkIwZVNCTWRHUXhEakFNQmdOVkJBTVRCWHAxYm10dk1JSUIKSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJDZ0tDQVFFQXdvZzZidTlGb2lPcVd5cHN3YjE2M2hEaAp2OWpMQnBDRklMSmNXNk5ucnJQejBXRHFCOW5qQitnaldOeTlucFNsNThkR0tROWptK2dBNHNrOHFqM1I3T3FsCmdFMlphNWhlZ0syMVl2LzBxUzJBbnhvNWlTY0ZIck84dTFLWUlIZEJ6Q3NwSytGZWYyckcxTXJtRFNBQmZHK3kKWnB1RllNLzhFeTk5dnk5US9VekVLeW9BRitnRTllMDNRcExSNy9ab0dMQ3cvRDdlODZCR09yNE9PZWVkSW4wSQpGTXAwOE51QWE5clBiVkkxOVJlcHFGaHIrdWpaWndZNDRsaWN6R2d2UzJGSEVGeTBvWnRDODh5U3NPeDcvWW1qClB3ZGErK2dyZ09CNTRWbUJVVUpkeDNSSXl1UmFpSGtmOWZSQXFIeFBtalo0M2xvdkNrbjhTUi9peXV5OUdRSUQKQVFBQm8wWXdSREFUQmdOVkhTVUVEREFLQmdnckJnRUZCUWNEQWpBTUJnTlZIUk1CQWY4RUFqQUFNQjhHQTFVZApJd1FZTUJhQUZEMVByTnZCMkhJaXZCQ1pGT3VJL0dCNnQzNzZNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUJ6CmpuR1ZIaGNJYkVCbW56NzI1ZlR0RjN2RzJPUktlVFJxa3B4bkdQTHZYUjU1VEMwbVE4TUZRYnozckdNQzZDbmEKd2hhUWNEL2hmMGhadXBGdXdsaXhwamlMbElkRVpUYXIrc2JGc1VwL2JZSnFTVG5UV1E5TDZYWEQzbmVjUGtnbgpvemRnYnZ1bTUwb1JOS1djaHE0eVV4TkhQQkEzcWxnSWM3cXkrdXV1YTVZVnJPNkpIaHVXQkY3ZHdmVEowYU90ClZJbWs5R0FQTDFROGNjVk94YmwxOTc5Q1pKWHY5VzhDTkFXTTd0aVdtQVBCOG92bUkwaDJnTzg2WlY1OUttVzMKS2FYZ2hpUTk4SC9CL3hhRkQ0NDNHKzk0bUxXdWZJdjVhZW42WU95RWZidk1wcENZQkNsVGtwSjM2SHNLUHhqLwpiUkxjb2NmSG9tZHdvN2tmT1ZhUwotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==

ファイルに保存しておきます。なお、ファイル保存時にBase64デコードしておきます。

$ kubectl get csr zunko -o jsonpath='{.status.certificate}' | base64 -d > zunko.crt

RBACの設定

追加するzunkoユーザーで利用するRoleとRole Bindingを作成します。

clusterroleを作成。

$ kubectl create clusterrole pod-reader --verb=get,list,watch --resource=pods
clusterrole.rbac.authorization.k8s.io/pod-reader created

紐づくclusterrolebindingを作成。

$ kubectl create clusterrolebinding pod-reader_zunko --clusterrole=pod-reader --user=zunko
clusterrolebinding.rbac.authorization.k8s.io/pod-reader_zunko created

Cluster側で必要な設定は完了です。

kubeconfigの設定

kubeconfigに必要情報を設定します。

zunkoユーザーを追加します。

$ kubectl config set-credentials zunko --client-key=zunko.key --client-certificate=zunko.crt --embed-certs=true
User "zunko" set.

コンテキストを追加します。

$ kubectl config set-context zunko@kubernetes --cluster=kubernetes --user=zunko
Context "zunko@kubernetes" created.

確認。

$ kubectl config view
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.146.0.2:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
- context:
    cluster: kubernetes
    user: zunko
  name: zunko@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED
- name: zunko
  user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

確認

実際にzunkoユーザーでアクセスしてみます。

利用するコンテキストをzunkoユーザーに変更。

$ kubectl config use-context zunko@kubernetes
Switched to context "zunko@kubernetes".

確認。

$ kubectl get pod --all-namespaces
NAMESPACE     NAME                                       READY   STATUS    RESTARTS   AGE
default       sample-67df9696d9-nmpzx                    1/1     Running   2          31h
kube-system   calico-kube-controllers-744cfdf676-rp98f   1/1     Running   4          33h
kube-system   calico-node-rldrx                          1/1     Running   3          32h
kube-system   calico-node-xh97n                          1/1     Running   4          33h
kube-system   coredns-74ff55c5b-49hdn                    1/1     Running   4          33h
kube-system   coredns-74ff55c5b-5j9cf                    1/1     Running   4          33h
kube-system   etcd-kubeadm-master                        1/1     Running   0          5h42m
kube-system   kube-apiserver-kubeadm-master              1/1     Running   5          33h
kube-system   kube-controller-manager-kubeadm-master     1/1     Running   6          33h
kube-system   kube-proxy-7dhmd                           1/1     Running   3          32h
kube-system   kube-proxy-8v785                           1/1     Running   4          33h
kube-system   kube-scheduler-kubeadm-master              1/1     Running   6          33h
$
$ kubectl run sample --image=nginx --restart=Never
Error from server (Forbidden): pods is forbidden: User "zunko" cannot create resource "pods" in API group "" in the namespace "default"

上手くいってますね。