Kubernetesのユーザー管理と認証・権限確認機構を理解しよう
Kubernetesはさまざまな環境で利用され、かつ不特定多数がクラスタにアクセスできることを前提に構築されており、そのため非常に柔軟なユーザー認証機構やユーザーの権限を管理する機能が組み込まれている。本記事ではこれらの認証や権限確認機構がどのように働くのかや、その仕組みについて解説する。
目次
Kubernetesにおける認証の必要性
Kubernetesはさまざまな企業・組織が参加するオープンな組織「Cloud Native Computing Foundation(CNCF)」によって開発が進められているが、元々はGoogleによってその開発がスタートしたプロジェクトであり、同社の持つコンテナクラスタ管理技術を元にしている。そのため、Kubernetesは当初から不特定多数がアクセスできるパブリッククラウドでの利用が想定されており、そういった環境でもセキュアかつ柔軟に利用できるよう設計されている。そのための機能の1つが、クラウドにアクセスするユーザー単位で利用できる機能を制限できる認証・権限確認機構だ。
Kubernetesでは、APIサーバー(api server)と呼ばれるコンポーネントに対しHTTP/HTTPSでリクエストを送信することで、クラスタに関する各種操作を行うする仕組みになっている。たとえばKubernetesではクラスタを操作するためのコマンドラインインターフェイスである「kubectl」が用意されているが、kubectlはコマンドラインでユーザーから指定されたコマンドに応じてAPIサーバーにリクエストを送信し、その結果を受信して画面に表示するという処理を行う。
パブリッククラウドにおいては、APIサーバーは外部(インターネット)からアクセスできるようになっており、またその仕様も公開されている。そのため、そのホスト名やIPアドレスさえ分かれば、誰もがAPIサーバーに対しリクエストを送信することができてしまう。そこで、クラスタの管理者とは無関係な第三者がAPIサーバーに対しリクエストを送信した場合、そのリクエストを不正なものと判断して却下する仕組みがAPIサーバーには設けられている。
具体的には、APIサーバーにアクセスするクライアントはリクエストの送信時にその送信者を確認するための情報(ユーザー名や認証トークン)などをリクエスト内容と一緒に送信する。APIサーバーはこれらの情報を照合することでリクエスト者の正当性を確認する仕組みになっている。
さらに、Kubernetesではユーザーごとに実行できる処理を制限できる機構も用意されている。これによって、たとえばクラスタの管理者が複数いる場合、ある管理者にはコンテナの稼働状況に関する情報取得は許可するが、コンテナの作成や削除といった処理は禁止したい、といったような需要に対応できる。
authenticationとauthorization、admission control
Kubernetesでは、リクエストを送信したユーザーがクラスタの正当な管理者であるかを確認する処理を「authentication(認証)」と呼ぶ。一般的なWebサービスなどではユーザー名とパスワードによる認証が一般的だが、Kubernetesではさまざまな認証方法が利用できるよう、この認証を行う部分自体をモジュール化し、目的やユースケースに応じて異なる認証手法を選択できるようになっている。標準でいくつかの認証モジュールが提供されているほか、認証を行うための独自のモジュールを実装したり、外部サービスと連携したりして認証を行うことも可能だ。
APIサーバーはリクエストを受信した際に、まず認証を行ってユーザーの正当性を確認する。認証が成功した場合、続いてそのユーザーに対しリクエストされた処理を実行する権限があるかどうかを確認する処理が行われる。この処理は、「authorization(認可)」と呼ばれている。authorizationについてもauthenticationと同様にモジュール化されており、利用者が必要に応じてその手法を選択できるようになっている。
さて、認証および認可ではリクエストを行ったユーザーの正当性と、そのリクエストを行う権限を確認するわけだが、この2つの処理に成功したからといって、そのリクエストが適切であるとは保証できない。誤ってKubernetesやクラスタの仕様・設定に反するリクエストを行ってしまう可能性もある。そのためAPIサーバーでは、認証および認可の後に「admission control(入力制御)」という処理が実行されるようになっている。admission controlはリクエストの内容をチェックする仕組みで、ここではあらかじめ指定していた条件に合致しないリクエストをブロックしたり、指定された条件に応じてリクエスト内容の修正をおこなったりする。
これらのauthenticationとauthorization、admission controlの流れをまとめたものが次の図1だ。
APIサーバーはリクエストを受信すると、この3つの処理を順に実行し、すべてにパスした場合のみ指定された処理が実行される仕組みになっている。
ちなみに、APIサーバーは暗号化された接続のみを受け付けるポート(Secure Port)と、暗号化されていない接続を受け付けるポート(Localhost Port)の2つを利用する。前者のデフォルトは6443番ポート、後者のデフォルトは8080番ポートだ。
Localhost PortはAPIサーバーと同じホスト上で動作するKubernetesの各種コンポーネントがAPIサーバーと通信するために使用されるもので、このポートに送信されたリクエストに対しては認証および認可処理がバイパスされ、admission controlのみが適用される。ほかのサービスやコンポーネント、ユーザーがこのポートにリクエストを送信することは可能ではあるものの、テストやクラウド環境の構築時の利用に限っての利用が推奨されている。
Kubernetesのユーザーとサービスアカウント
前述のとおり、Kubernetesクラスタに対して何らかの操作を行いたい場合にはAPIサーバーに対してリクエストを送信することになるのだが、APIサーバーにリクエストを送信するのは人間のユーザーだけではない。たとえばKubernetesクラスタ内で実行されるDNSサーバーであるCoreDNSは、APIサーバーにアクセスしてクラスタの情報を取得し、それに応じて設定やDNS情報を自動的に取得するようになっている。
こういったアプリケーションによるリクエストについても、不正なリクエストが通らないよう認証や認可、admission controlなどの処理を実行する必要がある。Kubernetesではこういったアプリケーションからのリクエストで使用することを想定した「service account(サービスアカウント)」と呼ばれる限定されたユーザーを用意する仕組みが用意されている。
サービスアカウントは「ServiceAccount」(sa)というリソースに紐付けられており、名前空間毎に独立しているという特徴がある。作成されているサービスアカウントは、「kubectl get sa」コマンドを用いて確認できる。たとえば次の例は、「kube-system」名前空間で作成されているサービスアカウント一覧を取得するものだ。
$ kubectl -n kube-system get sa NAME SECRETS AGE attachdetach-controller 1 19d bootstrap-signer 1 19d certificate-controller 1 19d clusterrole-aggregation-controller 1 19d coredns 1 19d cronjob-controller 1 19d daemon-set-controller 1 19d default 1 19d deployment-controller 1 19d disruption-controller 1 19d endpoint-controller 1 19d expand-controller 1 19d flannel 1 19d generic-garbage-collector 1 19d horizontal-pod-autoscaler 1 19d job-controller 1 19d kube-proxy 1 19d namespace-controller 1 19d node-controller 1 19d persistent-volume-binder 1 19d pod-garbage-collector 1 19d pv-protection-controller 1 19d pvc-protection-controller 1 19d replicaset-controller 1 19d replication-controller 1 19d resourcequota-controller 1 19d service-account-controller 1 19d service-controller 1 19d statefulset-controller 1 19d token-cleaner 1 19d ttl-controller 1 19d
サービスアカウントは名前空間毎に自動的にデフォルトのもの(名前はサービスアカウント名は「default」)が作成されるほか、「kubectl create sa」コマンドで手動で作成することもできる。サービスアカウントはトークンベースでの認証が行われるようになっており、その認証処理は後述する「Service Account Tokens」モジュールで実装されている。
なお、サービスアカウント以外の一般ユーザーについては、基本的にはKubernetes本体では管理は行われず、各認証モジュールが独立して管理するようになっている。そのためkubectlなどのインターフェイス経由でユーザー情報を取得することは基本的には行えない。
kubectlの「context」、「user」、「cluster」の設定
Kubernetesにアクセスするためのコマンドラインインターフェイスであるkubectlコマンドでは、「~/.kube/config」という設定ファイル内にKubernetesへアクセスする際に利用するユーザーの認証情報を保存する仕組みになっている。これによってkubectlコマンドの実行時に毎回ユーザー情報を入力せずとも各種操作を実行できる。また複数の異なるクラスタ、ユーザーを管理できるよう、接続先や使用するユーザーを切り替えるための「context」という仕組みも用意されている。このcontextという概念は厳密にはKubernetesの認証とは直接は関係ないのだが、混乱しやすいのでこちらについてもここで説明しておこう。
kubectlの設定ファイル(~/.kube/config)は以下のようなフォーマットとなっている。
apiVersion: v1 kind: Config preferences: <各種設定> users: - name: <ユーザー名> user: client-certificate-data: <認証のためのデータ> client-key-data: <クライアント鍵データ> clusters: - name: <クラスタ名> cluster: certificate-authority-data: <クラスタ認証のための鍵データ> server: https://<APIサーバーのIPアドレス>:<ポート> contexts: - name: <context名> context: cluster: <contextに紐付けるクラスタ名> user: <contextに紐付けるユーザー名> current-context: <現在のcontext>
ここで「users:」以下にはKubernetesで使用するユーザーの情報を、「clusters:」以下には接続先となるKubernetesクラスタのAPIサーバーの情報を記述する。この例ではどちらも1つずつしか記述していないが、複数のユーザーやクラスタを「users:」や「clusters:」以下に記述することも可能だ。そして、「users:」や「clusters:」で定義されたユーザーとKubernetesクラスタの情報を組み合わせたものがcontextとなる。
たとえば次の例では、「kubernetes-admin」という名前のユーザーと「kubernetes」という名前のクラスタ、そしてそれらを紐付けた「kubernetes-admin@kubernetes」という名前のcontextが定義されている。使用するcontextを指定する「current-context」でこの「kubernetes-admin@kubernetes」が指定されているため、kubectlコマンドはデフォルトでは「kubernetes」クラスタ(https://192.168.1.100:6443)に対し、「kubernetes-admin」というユーザー名でアクセスすることになる。
apiVersion: v1 kind: Config preferences: {} users: - name: kubernetes-admin user: client-certificate-data: <認証のためのデータ> client-key-data: <クライアント鍵データ> clusters: - name: kubernetes cluster: certificate-authority-data: <クラスタ認証のための鍵データ> server: https://192.168.1.100:6443 contexts: - name: kubernetes-admin@kubernetes context: cluster: kubernetes user: kubernetes-admin current-context: kubernetes-admin@kubernetes
ちなみに、現在のcontextは「kubectl config current-context」コマンドで確認できる。
$ kubectl config current-context kubernetes-admin@kubernetes
また、コンテキストの切り替えは「kubectl config use-context」コマンドで実行できる。詳しくは、「kubectl config --help」コマンドで表示されるオンラインヘルプを確認して欲しい。
Kubernetes標準のauthenticationモジュール
それでは、Kubernetesにおける認証の核となるauthenticationモジュールや、kubeadmで構築したクラスタで有効になっている認証方法について紹介していこう。authenticationモジュールは、APIサーバーへのリクエストに含まれていた認証情報を受け取り、その情報を照合してそのユーザーが適切なものかどうかを判断するという処理を行う。もしユーザーが適切なものだった場合、authenticationモジュールは次のような情報をユーザー情報として返す。
- ユーザー名
- UID(ユーザーを識別するためのユニークなID)
- グループ
- Extraフィールド
Extraフィールドは文字列をキーとしたマップ型オブジェクトで、任意のデータを格納できる。また、各ユーザーは複数のグループに所属できる。
ユーザー名やグループについては各モジュールが任意のものを提供できるようになっているが、Kubernetes共通で定められている特別なグループも存在する。たとえば、認証済みのユーザーは必ず「system:authenticated」というグループに所属するように定義されている。
また、一部のリクエストはユーザー認証なしの匿名ユーザーでも実行が可能だ。この場合、便宜的にユーザー名は「system:anonymous」、所属グループは「system:unauthenticated」に設定される。
Kubernetes(v1.13)では、以下のauthenticationモジュールが標準で提供されている。これらモジュールを有効にするには、APIサーバーの起動オプションで対応するものを指定すれば良い(表1)。
モジュール名 | 説明 | 設定オプション |
---|---|---|
X509 Client Certs | 公開鍵証明書認証を利用して認証を行う | --client-ca-file=<CAファイル> |
Static Token File | ユーザー名やトークンとなどを列挙したトークンファイルでユーザーを管理する | --token-auth-file=<トークンファイル> |
Bootstrap Tokens | ベータ機能。クラスタ構築時、まだ認証設定が行われていない状態で使われる。ユーザー情報は「kube-system」名前空間にSecretsとして格納される。ユーザーは有効期限付きで、一定期間で削除される | --enable-bootstrap-token-auth |
Static Password File | ユーザー名とパスワードなどを列挙したパスワードファイルでユーザーを管理する | --basic-auth-file=<パスワードファイル> |
Service Account Tokens | トークンを使って認証する、サービスアカウントの認証専用 | --service-account-key-file <PEM形式鍵ファイル> |
OpenID Connect Tokens | OAuth 2を使った認証 | --oidc-issuer-url=<認証URL>など |
Webhook Token Authentication | Webhookを使ってトークンを認証する | --authentication-token-webhook-config-file=<設定ファイル> |
Authenticating Proxy | 認証機能を持つプロクシなどが、「X-Remote-User」や「X-Remote-Group」といったHTTPヘッダを使って認証情報を付与する | --requestheader-username-headers=<使用するヘッダ名> |
たとえば、kubeadmで構築したKubernetesクラスタの初期状態ではAPIサーバー(kube-apiserver)プロセスの起動オプションとして次のものが指定されている。
--client-ca-file=/etc/kubernetes/pki/ca.crt --enable-bootstrap-token-auth=true --requestheader-allowed-names=front-proxy-client --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt --requestheader-extra-headers-prefix=X-Remote-Extra- --requestheader-group-headers=X-Remote-Group --requestheader-username-headers=X-Remote-User --service-account-key-file=/etc/kubernetes/pki/sa.pub
これにより、「X509 Client Certs」および「Bootstrap Tokens」、「Service Account Tokens」、「Authenticating Proxy」認証が有効になっていることが分かる。
まずX509 Client Certsだが、これはSSL/TLS等で使われるX.509公開鍵認証を使ってユーザーの認証を行うモジュールだ。このモジュールを使った認証では、各ユーザーはリクエスト時にクライアント証明書を送信し、APIサーバーは受け取った証明書を「--client-ca-file」オプションで指定したCAファイル(認証局情報ファイル)を使用してユーザーの正当性を検証する。証明書が正当なものであると判断された場合、証明書のcommon name(CN)フィールドで指定された文字列がユーザー名に、証明書のorganization(O)フィールドで指定された文字列が所属グループとして使用される。複数のorganizationフィールドを指定することで、複数のグループにユーザーを所属させることもできる。
たとえばkubeadmでクラスタを構築した場合、kubectl用の設定ファイルとして/etc/kubernetes/admin.confとして作成され、その中の「user:」以下の「client-certificate-data」にBASE64でエンコードされた証明書が格納される。この証明書の情報は、次のようにして確認できる。
# python -c 'import yaml, sys; print(yaml.load(sys.stdin)["users"][0]["user"]["client-certificate-data" ])' < /etc/kubernetes/admin.conf | base64 -d | openssl x509 -noout -text Certificate: Data: Version: 3 (0x2) Serial Number: 2279747390005043816 (0x1fa34a2c2edfe268) Signature Algorithm: sha256WithRSAEncryption Issuer: CN=kubernetes Validity Not Before: Feb 21 14:16:37 2019 GMT Not After : Feb 21 14:16:41 2020 GMT Subject: O=system:masters, CN=kubernetes-admin Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:a1:90:40:76:52:97:f0:30:18:d0:68:0f:2f:7c: 1f:97:a8:9d:13:6b:fd:2f:8c:01:96:38:29:bb:83: 2e:d9:73:c3:9c:ae:63:aa:83:35:00:b1:04:1e:8a: 08:73:94:94:1e:eb:cf:88:fa:05:df:8b:a7:a9:8d: 0f:0b:88:0b:d1:3b:e2:40:b6:3b:7a:ec:62:58:d9: ff:8e:d1:29:e2:8f:78:a6:78:41:d9:d2:aa:b5:54: a6:70:a7:49:a7:ec:22:cc:f2:e0:95:f4:4f:fc:85: 17:d4:52:5f:1a:fa:5a:f7:b6:47:62:8b:25:ad:23: 36:81:b4:7c:8e:bc:4b:69:81:43:8f:ea:10:48:52: 36:4e:e6:df:6a:1f:2a:8f:04:1c:1e:1e:65:4f:5f: ae:50:6a:2a:83:42:e0:21:f1:17:7a:1d:7a:6f:56: 43:cf:dc:7f:39:c0:f1:14:ea:02:1c:a4:a7:61:49: c6:f4:5b:8a:ad:a4:92:1b:ff:d1:49:0d:b7:4f:cb: 67:87:23:10:05:4b:79:b3:c1:df:50:b2:fb:a6:4f: cb:68:a6:4a:2a:c7:db:00:a5:4b:dc:e9:d7:8c:26: 06:f1:dd:49:9d:ef:9d:7d:6a:a4:1b:ae:c4:f5:b7: 8c:a1:f4:f9:24:cd:c9:f7:f1:93:4e:47:d8:5d:d1: 6b:ab Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Client Authentication Signature Algorithm: sha256WithRSAEncryption 8f:34:f4:94:6a:e8:9f:f8:d8:c9:f3:8e:2d:0f:de:4a:0f:39: 4b:55:50:03:3d:d4:35:94:7f:53:4b:b9:1f:5f:5e:5f:35:43: 32:4e:ca:b7:08:aa:d8:62:97:73:0d:c5:e9:71:73:18:90:69: ec:78:4c:fd:d3:34:07:f8:66:18:c9:4a:0e:82:5e:d3:d9:d6: 2e:ee:76:bd:04:c4:de:90:71:15:a6:38:d7:a4:c0:1a:49:66: a4:cd:f6:b6:bd:6f:9d:3e:e0:6f:f9:4b:89:97:5f:ad:4b:dd: 35:be:d5:a2:62:8d:4e:06:84:3d:a8:3e:53:34:59:2b:db:21: e6:a8:81:76:1e:8e:46:d6:c0:be:7c:11:7f:db:e0:6f:78:38: 6f:1f:b7:b5:57:ef:2c:20:d1:bb:78:c1:aa:af:30:34:6c:5a: 08:79:14:01:24:32:6d:9a:7e:96:26:1b:28:21:60:6f:ec:f7: 35:93:c5:5c:7c:fb:f7:7c:11:a9:67:82:a7:0e:10:85:00:43: fe:94:4e:c6:d9:cc:75:d3:f9:86:5c:17:c0:5f:e8:36:5f:8d: 3d:2e:b8:e9:0d:11:3f:cc:fa:bb:de:59:9d:98:ee:76:10:f6: 4b:92:1d:7a:29:d6:bf:58:76:22:99:ea:1e:29:81:69:2b:4c: 4d:e8:26:a9
これを見ると、common nameは「kubernetes-admin」、organizationは「system:masters」となっており、この証明書で認証されたユーザーはユーザー名が「kubernetes-admin」、所属グループが「system:masters」になることが分かる。
また、ユーザーを追加するにはAPIサーバーの--client-ca-fileオプションで指定されているCAファイルを使って証明書を作成し、その情報をkubectlの設定ファイルに追加すれば良い。CAファイルが/etc/kubernetes/pki/ca.crtである場合、これは次のようにして行える。
まず、秘密鍵ファイル(以下では「user.key」)を作成する。
# openssl genrsa -out user.key 2018 Generating RSA private key, 2018 bit long modulus .............................................+++ .....................+++ e is 65537 (0x10001)
続いて作成した秘密鍵ファイルを元に署名リクエストファイル(CSRファイル、以下では「user.csr」)を作成する。ここでは国名や県名などを入力できるが、Kubernetsで必要となるのは前述のとおりOrganizationとCommon Nameだけなので、それ以外は空のままで構わない。
# openssl req -new -key user.key -out user.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) [XX]: State or Province Name (full name) []: Locality Name (eg, city) [Default City]: Organization Name (eg, company) [Default Company Ltd]:test ←グループ名を入力 Organizational Unit Name (eg, section) []: Common Name (eg, your name or your server's hostname) []:testuser ←ユーザー名を入力 Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
最後にCA証明書とCA鍵ファイルを使ってCSRファイルから証明書ファイル(ここでは「user.crt」)を作成する。
# openssl x509 -req -in user.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out user.crt -days 10000 Signature ok subject=/C=XX/L=Default City/O=test/CN=testuser Getting CA Private Key
作成した証明書の内容は、次のようにして確認できる。
# openssl x509 -noout -text -in user.crt Certificate: Data: Version: 1 (0x0) Serial Number: ad:09:56:44:1c:12:dc:20 Signature Algorithm: sha256WithRSAEncryption Issuer: CN=kubernetes Validity Not Before: Mar 14 11:49:48 2019 GMT Not After : Jul 30 11:49:48 2046 GMT Subject: C=XX, L=Default City, O=test, CN=testuser Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2018 bit) Modulus: 02:ea:f1:23:98:79:53:f3:ed:d4:3a:5b:8c:b6:03: 1b:6d:bf:df:27:2c:2d:c7:f2:73:b0:13:86:dd:78: bb:f6:c3:0b:04:be:ec:1c:39:d7:c5:c2:a8:bc:e0: 23:51:68:21:6b:3b:82:f4:50:aa:64:8e:5e:c2:1d: 95:c7:c4:81:d0:76:b1:2b:f4:4c:b7:00:1a:6d:44: 4b:d6:f8:b2:e9:82:75:dd:c3:b4:d0:68:6f:f7:82: d4:65:64:4e:6e:b7:f5:6f:fe:cb:34:cc:a6:d5:dd: b5:23:9e:2e:a3:3d:b9:8b:74:67:b5:e3:b8:3e:34: f2:f2:0f:b2:e5:69:02:d2:fc:3d:a3:f0:9b:86:6e: 7d:ad:c1:86:f0:1c:42:c0:8f:73:da:21:c2:d9:de: 30:86:92:05:0f:0a:4a:0e:49:22:ab:01:4b:e2:95: a7:3e:e7:ee:97:22:f7:0b:95:90:65:7b:c9:a9:29: 07:61:48:30:42:85:38:8a:cc:be:ec:89:35:c6:d3: 99:53:ab:66:d1:cb:59:62:a7:42:2b:39:03:65:6f: 12:63:d7:12:3a:9f:56:11:7a:c0:8e:de:82:bd:65: 16:5a:ba:67:74:33:66:ea:83:41:ca:90:d2:b5:c0: 26:e2:fe:b7:a8:61:72:23:1b:f5:ea:45:55 Exponent: 65537 (0x10001) Signature Algorithm: sha256WithRSAEncryption 1e:f7:e0:6d:01:0d:ac:5a:ad:89:e1:d6:d3:f1:78:33:96:52: 10:02:33:e2:d3:77:8d:25:8a:f6:de:14:62:e6:bd:93:be:72: d8:0f:f8:a6:5b:08:37:ed:73:53:14:83:7b:04:0e:0f:53:f7: cd:15:ad:fc:93:3d:6b:8d:da:37:9a:76:ed:e7:7d:a1:e3:3b: 3d:db:b0:83:15:17:e9:d8:47:25:f6:ac:d0:8e:9a:54:07:88: bc:7d:7d:49:77:97:71:c2:4e:ab:21:f6:5f:b7:74:7d:a3:2f: 32:72:91:78:fe:f8:b2:3b:cc:83:51:8a:46:8b:14:0a:57:4f: 3a:a3:c3:b3:52:25:ec:fa:54:2e:05:a5:e7:8d:ad:22:d9:c1: cc:77:13:2b:22:f8:b3:07:64:cb:1d:12:c9:36:07:0d:45:3d: 4d:b8:43:c1:37:bf:22:6c:37:9e:f8:74:b3:6f:d5:a5:f4:4e: 35:fb:e1:65:15:4d:46:c9:ae:90:f2:10:d8:c5:11:30:77:5d: b6:22:ad:02:95:26:4e:d8:fe:f0:d0:1c:2a:e1:24:44:88:bf: 6c:f4:d8:f4:0d:cc:7d:51:ab:0d:67:68:8d:bf:2b:0b:20:19: 73:00:c8:07:0c:38:58:71:0a:63:fb:e0:b4:9e:27:40:bf:30: 19:39:20:2d
作成した証明書をAPIサーバーとの認証に利用するには、「kubectl config set-credentials <ユーザー名>」コマンドで設定ファイルに使用する証明書情報を追加すれば良い。たとえば「testuser」というユーザー名で追加するには、次のように実行する。
$ kubectl config set-credentials testuser --client-certificate=user.crt --client-key=user.key --embed-certs=true User "test" set.
さて、それでは作成したこのユーザーでKubernetesクラスタにアクセスしてみよう。前述のとおり、kubectlコマンドではcontextという単位で使用するユーザーとクラスタの情報を管理している。そこで、まず作成したtestuserを使用するcontextを次のようにして作成し、それを使用するcontextとして指定する。
↓設定されているクラスタ名を確認する $ kubectl config get-clusters NAME kubernetes ↓「kubernetes」クラスタと「testuser」ユーザーを紐付けた「test」contextを作成する $ kubectl config set-context test --user=testuser --cluster=kubernetes Context "test" created. ↓使用するcontextを「test」に切り替える $ kubectl config use-context test Switched to context "test". ↓contextの情報を確認する $ kubectl config get-contexts CURRENT NAME CLUSTER AUTHINFO NAMESPACE kubernetes-admin@kubernetes kubernetes kubernetes-admin * test kubernetes testuser
これで、「testuser」ユーザーでクラスタにアクセスできるようになった。ただし、現時点ではこのユーザーには権限が設定されていないため、クラスタの操作を行うことはできない。たとえば、「kubectl get pod」コマンドで稼動中のPodの情報を取得しようとすると次のようにエラーとなり、「testuser」には指定した処理を実行する権限がないという旨が表示される。
$ kubectl get pod Error from server (Forbidden): pods is forbidden: User "testuser" cannot list resource "pods" in API group "" in the namespace "default"
なお、この状態ではクラスタに対し何も操作が行えないので、ユーザー認証に成功したことを確認したら元のユーザーに戻しておこう。
$ kubectl config use-context kubernetes-admin@kubernetes Switched to context "kubernetes-admin@kubernetes".
サービスアカウントトークンの管理
このようにX509 Client Certs認証では証明書を使って認証を行う仕組みになっているが、別の認証モジュールではまったく異なる方法で認証が行われる。たとえばService Account Tokensモジュールでは、サービスアカウント毎に用意されたトークンを使って認証が行われる。具体的には、リクエスト時に「Authorization: Bearer <トークン>」HTTPヘッダとしてトークンを送信し、そのトークンが登録されているものと一致するかどうかで認証を行う仕組みだ。
前述のとおり、作成されているサービスアカウント一覧は「kubectl get sa」コマンドで確認できる。
$ kubectl get sa --all-namespaces=true NAMESPACE NAME SECRETS AGE default default 1 20d kube-public default 1 20d kube-system attachdetach-controller 1 20d kube-system bootstrap-signer 1 20d kube-system certificate-controller 1 20d kube-system clusterrole-aggregation-controller 1 20d kube-system coredns 1 20d kube-system cronjob-controller 1 20d kube-system daemon-set-controller 1 20d kube-system default 1 20d kube-system deployment-controller 1 20d kube-system disruption-controller 1 20d kube-system endpoint-controller 1 20d kube-system expand-controller 1 20d kube-system flannel 1 20d kube-system generic-garbage-collector 1 20d kube-system horizontal-pod-autoscaler 1 20d kube-system job-controller 1 20d kube-system kube-proxy 1 20d kube-system namespace-controller 1 20d kube-system node-controller 1 20d kube-system persistent-volume-binder 1 20d kube-system pod-garbage-collector 1 20d kube-system pv-protection-controller 1 20d kube-system pvc-protection-controller 1 20d kube-system replicaset-controller 1 20d kube-system replication-controller 1 20d kube-system resourcequota-controller 1 20d kube-system service-account-controller 1 20d kube-system service-controller 1 20d kube-system statefulset-controller 1 20d kube-system token-cleaner 1 20d kube-system ttl-controller 1 20d
また、個々のサービスアカウントの詳細は「kubectl describe sa」コマンドで確認できる。
$ kubectl describe sa default Name: default Namespace: default Labels: <none> Annotations: <none> Image pull secrets: <none> Mountable secrets: default-token-tgwlm Tokens: default-token-tgwlm Events: <none>
認証に使用するトークン本体は「Secret」というリソースに格納されており、そこで「Tokens:」に紐付けられている文字列がその名前となる。上記の場合、secret名は「default-token-tgwlm」になるので、次のように実行することでトークン文字列を確認できる。
$ kubectl describe secret default-token-tgwlm Name: default-token-tgwlm Namespace: default Labels: <none> Annotations: kubernetes.io/service-account.name: default kubernetes.io/service-account.uid: 65925a6d-35e3-11e9-892f-9ca3ba2d9e1b Type: kubernetes.io/service-account-token Data ==== ca.crt: 1025 bytes namespace: 7 bytes token: eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tdGd3bG0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjY1OTI1YTZkLTM1ZTMtMTFlOS04OTJmLTljYTNiYTJkOWUxYiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.AqzEjdGceWdssZpQgvorwiqx7rhZeoP3DLfJ58OM0oHRGfqDNbVMDCnm0-8t0aj7zMVaBa281HfacRLl0VESaWrcXRdarJCRJ5l0VO2TIhoV0TCXzblGEu1oX-qJipIS8Hr_2Ne2JOJ49tvUwwfCnfSyAe4yBJC4N6TDgy8x35Rqj92bL8NSV915nYTRYpEZA8E8r88Y3cMqeXfd7yTDIqCzhoPzXzDTh9wgyKMw5ACDAKEDrdyRByQ4frbbgS19E8OnlGML1IEtm8zj6L5Zryv0ndf4-M_PNncXI0oxMgi_pgel_sZGAnBAZhlpaOnrTbSsOcU-uvDiZ7jxaBmXYQ
クライアントは、APIサーバーへのリクエスト時に「Authorization: Bearer <トークン文字列>」というHTTPヘッダを使ってこのトークンを送信することで認証を受けることができる。たとえばcurlコマンドでは、次のようにしてこのトークンを使ってリクエストを送信できる。
$ curl -k https://<APIサーバーのホスト名/IPアドレス>:<ポート>/api/v1/namespaces/default/pods -H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tdGd3bG0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjY1OTI1YTZkLTM1ZTMtMTFlOS04OTJmLTljYTNiYTJkOWUxYiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.AqzEjdGceWdssZpQgvorwiqx7rhZeoP3DLfJ58OM0oHRGfqDNbVMDCnm0-8t0aj7zMVaBa281HfacRLl0VESaWrcXRdarJCRJ5l0VO2TIhoV0TCXzblGEu1oX-qJipIS8Hr_2Ne2JOJ49tvUwwfCnfSyAe4yBJC4N6TDgy8x35Rqj92bL8NSV915nYTRYpEZA8E8r88Y3cMqeXfd7yTDIqCzhoPzXzDTh9wgyKMw5ACDAKEDrdyRByQ4frbbgS19E8OnlGML1IEtm8zj6L5Zryv0ndf4-M_PNncXI0oxMgi_pgel_sZGAnBAZhlpaOnrTbSsOcU-uvDiZ7jxaBmXYQ" { "kind": "Status", "apiVersion": "v1", "metadata": { }, "status": "Failure", "message": "pods is forbidden: User \"system:serviceaccount:default:default\" cannot list resource \"pods\" in API group \"\" in the namespace \"default\"", "reason": "Forbidden", "details": { "kind": "pods" },
Kubernetes内ではサービスアカウントのユーザー名は「system:serviceaccount:<名前空間名>:<サービスアカウント名>」となり、「system:serviceaccounts」および「system:serviceaccounts:<名前空間名>」グループに所属する。ここでは適切な権限設定を行っていないためリクエストは失敗しているが、リクエストを行ったユーザーが「system:serviceaccount:default:default」であることは認識されていることが確認できる。
なお、Podの作成時にサービスアカウントに関する情報はコンテナ内の/var/run/secrets/kubernetes.io/serviceaccountディレクトリに自動的にマウントされ、ファイルとしてその情報にアクセスできる。このディレクトリ内の「ca.crt」ファイルにサービスアカウントのトークン作成に使われるCA証明書が、「namespace」ファイルにPodが稼動している名前空間が、「token」ファイルにトークンが格納されており、コンテナ内からは次のように自由にアクセスできる。
# cat /var/run/secrets/kubernetes.io/serviceaccount/token eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImRlZmF1bHQtdG9rZW4tdGd3bG0iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiZGVmYXVsdCIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjY1OTI1YTZkLTM1ZTMtMTFlOS04OTJmLTljYTNiYTJkOWUxYiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmRlZmF1bHQifQ.AqzEjdGceWdssZpQgvorwiqx7rhZeoP3DLfJ58OM0oHRGfqDNbVMDCnm0-8t0aj7zMVaBa281HfacRLl0VESaWrcXRdarJCRJ5l0VO2TIhoV0TCXzblGEu1oX-qJipIS8Hr_2Ne2JOJ49tvUwwfCnfSyAe4yBJC4N6TDgy8x35Rqj92bL8NSV915nYTRYpEZA8E8r88Y3cMqeXfd7yTDIqCzhoPzXzDTh9wgyKMw5ACDAKEDrdyRByQ4frbbgS19E8OnlGML1IEtm8zj6L5Zryv0ndf4-M_PNncXI0oxMgi_pgel_sZGAnBAZhlpaOnrTbSsOcU-uvDiZ7jxaBmXYQ
ここでマウントされるサービスアカウント情報は基本的には各名前空間内の「default」サービスアカウントのものだが、PodのSpecの「seviceAccountName」項目で紐付けるサービスアカウント名を明示的に指定することも可能だ。たとえば次のように指定した場合、「foobar」というサービスアカウントの情報がコンテナ内にマウントされる。
spec: serviceAccountName: foobar containers: - name: httpd image: httpd
なお、サービスアカウントの認証トークンは上記のようにSecretリソースとして管理されるため、Secretリソースにアクセスできるユーザーは誰でもこのアカウントを利用できてしまう点には注意したい。
権限認証の流れ
続いて、authorization(認可)モジュールとその動作について見ていこう。authorizationモジュールはauthenticationモジュールによってユーザーの正当性が確認された後に、そのユーザーがリクエストした処理の権限を持っているかどうかを判断し、権限が無ければリクエストを却下するという処理を行う。
ユーザーが権限を持っているかどうかはユーザー名および所属グループといったauthorizationモジュールが付与した属性と、リクエストされたAPIのパスや処理内容、対象リソース、名前空間といった処理内容によって判断される。
ユーザーが所有している権限一覧を取得するような機能は用意されていないが、ユーザーに指定した操作を実行する権限が与えられているかどうかは「kubectl auth can-i」コマンドで確認できる。たとえばPodの情報を取得する権限があるかどうかは、次のようにして確認できる。
$ kubectl auth can-i get pod yes
権限がある場合は、このように「yes」が返される。一方権限が無い場合は「no」という結果となる。
authorizationモジュールはauthenticationモジュールと同様にモジュール化されており、APIサーバーの起動時にどのモジュールを利用するかを「--authorization-mode=<モジュール名>」コマンドラインオプションで指定する。Kubernetes v1.13にて標準で利用できるauthorizationモジュールは次の表2のとおりだ。
モジュール名 | 説明 |
---|---|
Node | 各クラスタノードで動作するコンポーネントであるkubeletからのリクエストを認可するためのモジュール |
ABAC | 「Attribute-Based Access Control」の略。APIサーバーの「--authorization-policy-file=<ポリシーファイル>」オプションで指定した設定ファイルでユーザーやユーザーの属性毎に許可するリクエストを定義する |
RBAC | 「Role-Based Access Control」の略。「Role」や「ClusterRole」、「RoleBinding」、「ClusterRoleBinding」といったリソースを作成して認可ルールを定義する |
Webhook | Webhookを利用して外部サービスに問い合わせを行い、その結果を元にして権限認可を行う仕組み |
AlwaysDeny | テスト用モジュール。常にすべてのリクエストを拒否する |
AlwaysAllow | テスト用モジュール。常にすべてのリクエストを認可する |
使用するauthenticationモジュールは複数を同時に指定でき、その場合先に指定したほうが優先される。たとえばkubeadmで構築したクラスタの場合、デフォルト設定ではAPIサーバーの起動時に「--authorization-mode=Node,RBAC」オプションが指定されていた。この場合、まずNodeモジュールでの認可が試みられ、続いてRBACモジュールでの認可が試みられるという流れになる。
デフォルトで使われている「RBAC」
kubeadmで構築したクラスタにてデフォルトで使われている「RBAC」は、Kubernetes v1.8より安定扱いになったauthorizationモジュールだ。RBACでは「Role」リソースと「ClusterRole」リソースでルールを作成し、「RoleBinding」および「ClusterRoleBinding」リソースでルールをユーザーやグループに紐付けることで、各ユーザーが利用できるリクエストを制限する仕組みとなっている。
RoleリソースとClusterRoleリソースの違いだが、Roleリソースは指定した名前空間内でのみ有効なルールで、ClusterRoleはクラスタ全体で有効となるという点が異なる。たとえばkubeadmで構築したクラスタでは、次のようなRoleおよびClusterRoleリソースがデフォルトで作成されている。
$ kubectl get role --all-namespaces=true NAMESPACE NAME AGE kube-public kubeadm:bootstrap-signer-clusterinfo 21d kube-public system:controller:bootstrap-signer 21d kube-system extension-apiserver-authentication-reader 21d kube-system kube-proxy 21d kube-system kubeadm:kubelet-config-1.13 21d kube-system kubeadm:nodes-kubeadm-config 21d kube-system system::leader-locking-kube-controller-manager 21d kube-system system::leader-locking-kube-scheduler 21d kube-system system:controller:bootstrap-signer 21d kube-system system:controller:cloud-provider 21d kube-system system:controller:token-cleaner 21d
$ kubectl get clusterrole --all-namespaces=true NAME AGE admin 21d cluster-admin 21d edit 21d flannel 21d system:aggregate-to-admin 21d system:aggregate-to-edit 21d system:aggregate-to-view 21d system:auth-delegator 21d system:aws-cloud-provider 21d system:basic-user 21d system:certificates.k8s.io:certificatesigningrequests:nodeclient 21d system:certificates.k8s.io:certificatesigningrequests:selfnodeclient 21d system:controller:attachdetach-controller 21d system:controller:certificate-controller 21d system:controller:clusterrole-aggregation-controller 21d system:controller:cronjob-controller 21d system:controller:daemon-set-controller 21d system:controller:deployment-controller 21d system:controller:disruption-controller 21d system:controller:endpoint-controller 21d system:controller:expand-controller 21d system:controller:generic-garbage-collector 21d system:controller:horizontal-pod-autoscaler 21d system:controller:job-controller 21d system:controller:namespace-controller 21d system:controller:node-controller 21d system:controller:persistent-volume-binder 21d system:controller:pod-garbage-collector 21d system:controller:pv-protection-controller 21d system:controller:pvc-protection-controller 21d system:controller:replicaset-controller 21d system:controller:replication-controller 21d system:controller:resourcequota-controller 21d system:controller:route-controller 21d system:controller:service-account-controller 21d system:controller:service-controller 21d system:controller:statefulset-controller 21d system:controller:ttl-controller 21d system:coredns 21d system:csi-external-attacher 21d system:csi-external-provisioner 21d system:discovery 21d system:heapster 21d system:kube-aggregator 21d system:kube-controller-manager 21d system:kube-dns 21d system:kube-scheduler 21d system:kubelet-api-admin 21d system:node 21d system:node-bootstrapper 21d system:node-problem-detector 21d system:node-proxier 21d system:persistent-volume-provisioner 21d system:volume-scheduler 21d view 21d
これらRoleおよびClusterRoleリソースで定義された認可ルールをどのユーザーに対し紐付けるかを定義するのがRoleBindingおよびClusterRoleBindingリソースで、kubeadmで構築したクラスタでは以下のようなRoleBindingおよびClusterRoleBindingが定義されていた。
$ kubectl get rolebinding --all-namespaces=true NAMESPACE NAME AGE kube-public kubeadm:bootstrap-signer-clusterinfo 21d kube-public system:controller:bootstrap-signer 21d kube-system kube-proxy 21d kube-system kubeadm:kubelet-config-1.13 21d kube-system kubeadm:nodes-kubeadm-config 21d kube-system system::leader-locking-kube-controller-manager 21d kube-system system::leader-locking-kube-scheduler 21d kube-system system:controller:bootstrap-signer 21d kube-system system:controller:cloud-provider 21d kube-system system:controller:token-cleaner 21d
$ kubectl get clusterrolebinding --all-namespaces=true NAME AGE cluster-admin 21d flannel 21d kubeadm:kubelet-bootstrap 21d kubeadm:node-autoapprove-bootstrap 21d kubeadm:node-autoapprove-certificate-rotation 21d kubeadm:node-proxier 21d system:aws-cloud-provider 21d system:basic-user 21d system:controller:attachdetach-controller 21d system:controller:certificate-controller 21d system:controller:clusterrole-aggregation-controller 21d system:controller:cronjob-controller 21d system:controller:daemon-set-controller 21d system:controller:deployment-controller 21d system:controller:disruption-controller 21d system:controller:endpoint-controller 21d system:controller:expand-controller 21d system:controller:generic-garbage-collector 21d system:controller:horizontal-pod-autoscaler 21d system:controller:job-controller 21d system:controller:namespace-controller 21d system:controller:node-controller 21d system:controller:persistent-volume-binder 21d system:controller:pod-garbage-collector 21d system:controller:pv-protection-controller 21d system:controller:pvc-protection-controller 21d system:controller:replicaset-controller 21d system:controller:replication-controller 21d system:controller:resourcequota-controller 21d system:controller:route-controller 21d system:controller:service-account-controller 21d system:controller:service-controller 21d system:controller:statefulset-controller 21d system:controller:ttl-controller 21d system:coredns 21d system:discovery 21d system:kube-controller-manager 21d system:kube-dns 21d system:kube-scheduler 21d system:node 21d system:node-proxier 21d system:volume-scheduler 21d
たとえば、「cluster-admin」というClusterRoleBindingリソースは次のようになっている。
$ kubectl describe clusterrolebinding cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true Role: Kind: ClusterRole Name: cluster-admin Subjects: Kind Name Namespace ---- ---- --------- Group system:masters
この設定は「system:masters」というグループに所属しているユーザーに対し、「cluster-admin」というClusterRoleで定義されている権限を付与するという設定だ。また、「cluster-admin」ClusterRoleは次のように定義されている。
$ kubectl describe clusterrole cluster-admin Name: cluster-admin Labels: kubernetes.io/bootstrapping=rbac-defaults Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- *.* [] [] [*] [*] [] [*]
これは、すべてのリソースに対しすべての処理を許可するという内容になっている。これにより、「system:masters」グループに所属するユーザーはすべてのリクエストが認可されるようになっている。
ユーザーに対し権限を追加する
さて、新規に定義したユーザーに対して権限を与えるには、まず許可する権限を定義したRoleもしくはClusterRoleリソースを作成し、それらをユーザーもしくはグループに紐付けるRoleBindingもしくはClusterRoleBindingリソースを作成すれば良い。たとえば次の設定例は、すべての「get」および「list」、「watch」操作を許可する「readonly-for-all」というClusterRoleリソースと、それを先に作成しておいた「testuser」というユーザーに紐付けるClusterRoleBindingを定義するものだ。
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-for-all rules: - apiGroups: ["*"] resources: ["*"] verbs: ["get", "list", "watch"] - nonResourceURLs: ["*"] verbs: ["get", "list", "watch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: readonly-for-test subjects: - kind: User name: testuser apiGroup: rbac.authorization.k8s.io roleRef: kind: ClusterRole name: readonly-for-all apiGroup: rbac.authorization.k8s.io
これを「readonly-for-all.yaml」というファイルに保存し、「kubectl apply」コマンドで適用する。
$ kubectl apply -f readonly-for-all.yaml clusterrole.rbac.authorization.k8s.io/readonly-for-all unchanged clusterrolebinding.rbac.authorization.k8s.io/readonly-for-test created ↓「readonly-for-all」ClusterRoleの内容を確認 $ kubectl describe clusterrole readonly-for-all Name: readonly-for-all Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRole","metadata":{"annotations":{},"name":"readonly-for-all"},"rules":[{"apiGr... PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- *.* [] [] [get list watch] [*] [] [get] [*] [] [list] [*] [] [watch] ↓「readonly-for-test」ClusterRoleBingingの内容を確認 $ kubectl describe clusterrolebinding readonly-for-test Name: readonly-for-test Labels: <none> Annotations: kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"rbac.authorization.k8s.io/v1","kind":"ClusterRoleBinding","metadata":{"annotations":{},"name":"readonly-for-test"},"roleRef... Role: Kind: ClusterRole Name: readonly-for-all Subjects: Kind Name Namespace ---- ----
これでtestuserユーザーに権限が設定され、先ほどは実行できなかったget系の操作が行えるようになる。
↓使用するcontextを「test」に切り替える $ kubectl config use-context test Switched to context "test". $ kubectl get pod NAME READY STATUS RESTARTS AGE busybox 1/1 Running 1 21d
一方で書き込み系の操作については権限が与えられていないので、たとえばPodを作成するような動作についてはエラーとなる。
$ kubectl apply -f httpd.yaml Error from server (Forbidden): error when creating "httpd.yaml": pods is forbidden: User "testuser" cannot create resource "pods" in API group "" in the namespace "default"
admission control
authenticationおよびauthorizationによってリクエストが許可された後、最後に実行されるのがadmission control処理だ。この処理はリソースの作成時、もしくは既存リソースの変更時にのみ実行されるもので、前述のとおりリクエストの内容が適切なものであるかを検証したり(validating)、あらかじめ指定された条件に応じてリクエスト内容を変更したりする処理(mutating)が行われる。
admission controlもauthenticationやauthorizationと同様にモジュール化されており、APIサーバーの起動オプションで有効/無効にするモジュール(admission controller)を指定できるようになっている。具体的には、「 --enable-admission-plugins=<プラグイン>」オプションで有効にするadmission controlモジュールを、「--disable-admission-plugins=<プラグイン>」で無効にするモジュールを指定するようになっている。
ちなみに、Kubernetes v1.13では表3のadmission controllerがデフォルトとなっている。
名称 | 説明 |
---|---|
NamespaceLifecycle | リクエスト時に指定された名前空間の存在を検証したり、システムで予約されている名前空間を削除しないようチェックしたりする |
LimitRanger | リクエストが名前空間に設定された「LimitRange」制限に引っかからないかをチェックする |
ServiceAccount | サービスアカウント関連の処理を自動化する |
TaintNodesByCondition | Podが不適切なノードで実行されないようチェックする(ベータ機能) |
Priority | priorityClassNameフィールドの設定を行う |
DefaultTolerationSeconds | Podリソースの作成時、Podが利用可能になるまでの最大待機時間を5分に設定する |
DefaultStorageClass | 「PersistentVolumeClaim」リソースの作成時に自動的にデフォルトのストレージクラスを追加する |
PersistentVolumeClaimResize | 「PersistentVolumeClaim」リソースのリサイズリクエストを検証する |
MutatingAdmissionWebhook | webhookを使ったリクエストの変更を行う |
ValidatingAdmissionWebhook | webhookを使ったリクエストを検証する |
ResourceQuota | リクエストを監視し、名前空間に設定された「ResourceQuota」制限に引っかからないかをチェックする |
そのほか、Kubernetesではデフォルトで多数のadmission controllerが用意されている。詳しくはドキュメントを参照して欲しい。
ユーザー認証・認可・admission controlの全体像を把握しておこう
このように、Kubernetesではリクエストを検証・制限する方法として認証・認可・admission controlという3段階のステップを踏むようになっており、かつそれぞれがモジュール化されて柔軟に利用できるようになっている。そのため全貌を把握しておかないと、認証や権限設定が難しいようなイメージがあるかもしれない。とはいえ、このようにそれぞれの動き自体はシンプルなので、理解してうまく活用していこう。