EKSでのkubectlコンフィグ設定について
kubectlとは、kubernetes cluster向けのコマンドラインツールです。
Kubectl is a command line interface for running commands against Kubernetes clusters.
kubectlを利用して、cluster上にworkloadsやserviceを作成することになります。当然、kubenetes clusterまで通信できなければ処理指示をできないので、kubectlには、kubernetes clusterへの接続定義を記したコンフィグファイルを用意する必要があります。その設定方法について、AWS EKSを例にとり確認します。
環境
- kubectl v1.14.9
- EKS(kubernetes) 1.14.9
kubectlのインストール
サポートされるkubectlのバージョンは、kubernetes cluster側のバージョンに以下依存します。
You must use a kubectl version that is within one minor version difference of your cluster. For example, a v1.2 client should work with v1.1, v1.2, and v1.3 master.
なお、現在のEKSにてサポートされているkubernetesバージョンは下記です。
The following Kubernetes versions are currently available for new clusters in Amazon EKS:
・1.14.9
・1.13.12
・1.12.10
Amazon EKS Kubernetes Versions
そのため、EKSのKubernetes Cluterのバージョンと同じ、v1.14.9
をインストールします。ダウンロードしているモジュールの v1.14.9
を変えれば、指定バージョンをダウンロードできます。
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.14.9/bin/linux/amd64/kubectl $ chmod +x ./kubectl $ sudo mv ./kubectl /usr/local/bin/ $ kubectl version --client Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.9", GitCommit:"500f5aba80d71253cc01ac6a8622b8377f4a7ef9", GitTreeState:"clean", BuildDate:"2019-11-13T11:21:43Z", GoVersion:"go1.12.12", Compiler:"gc", Platform:"linux/amd64"}
シェルの補完機能を設定。
$ cat ~/.bash_profile # kubectl completion eval "$(kubectl completion bash)"
kubectlの接続設定確認
kubectlにおける現在の設定情報は、以下のコマンドより確認できます。下記は何も設定がされていないコンフィグの状態です。
$ kubectl config view apiVersion: v1 kind: Config preferences: {} clusters: [] users: [] contexts: [] current-context: ""
コンフィグファイルでは、 clusters
と users
と contexts
を設定します。それぞれ項目の具体的パラメータは、kubectl configを対話モードで実行したときのパラメータが参考になります。
- clusters
- kubenetes clusterのAPIサーバー(kube-apiserver)に関する定義
- kubectl config set-cluster
- users
- 接続するためのユーザー情報の定義
- kubectl config set-credentials
- contexts
- 上記のclusterとuserを紐付けている定義
- kubectl config set-context
コンフィグファイルのデフォルトパスは、各OSユーザーのホームディレクトリ配下にある .kube/config
となります。
kubectl configの設定
EKSのKubernetes Cluster向けの、kubectl configの設定方法について。
利用するAWS IAMユーザーについて
EKSにおけるClusterへの認証方法は、 aws eks get-token
コマンドで取得されるtokenによりなされます。以前は AWS IAM Authenticator for Kubernetes
というモジュールでtokenを取得していたようですが、バージョン1.16.308以降のAWS CLIを利用する場合、kubectl実行時の内部でこのコマンドが処理されることでtokenを取得し、接続の認証として利用しています。
コマンド実行例。tokenが払い出されています。
> aws eks get-token --cluster-name <CLUSTER_NAME> --profile xxx { kind:ExecCredential apiVersion:client.authentication.k8s.io/v1alpha1 spec:{} status:{ expirationTimestamp:2020-02-02T22:24:09Z token:k8s-aws-v1.xxxxxxxxxxxxxxxx } }
なお、 aws eks get-token
コマンドを実行するに必要なIAM Policyはありません。何のIAM Policyを持っていないIAM Userでも、このコマンドからtokenを取得できます。この点は、以前の AWS IAM Authenticator for Kubernetes
モジュールで利用されていた aws sts get-caller-identity
APIの考えと同じです。
No permissions are required to perform this operation. If an administrator adds a policy to your IAM user or role that explicitly denies access to the sts:GetCallerIdentity action, you can still perform this operation.
これは、本コマンドで取得されるtokenは、あくまでKubernetes Clusterへの認証時に利用されるものであり、実際のKubernetesの操作権限の管理(認可の処理)は、KubernetesのRBACが担っているためとなります。
設定方法1 eks update-kubeconfig
コマンドを利用する方法
そもそもkubectl configを作成してくれるコマンドがAWS CLI側に用意されているため、そのコマンドを実行することで、コンフィグ情報を設定してくれます。
> aws eks update-kubeconfig --name CLUSTER_NAME --profile xxxx
これにて、kubectlに必要設定情報を登録してくれます。
設定方法2 手動で編集する方法
eks update-kubeconfig
コマンドを利用しない場合について。公式ドキュメントがあるので、それを参考に。
kubeconfig を Amazon EKS 用に作成します
サンプルとなるyamlファイルが下記です。
apiVersion: v1 kind: Config preferences: {} clusters: - name: eks/cluster-sample cluster: server: https://xxxxx.sk1.ap-northeast-1.eks.amazonaws.com certificate-authority-data: LS0tLXXXXXXXXXXX users: - name: test-user user: exec: apiVersion: client.authentication.k8s.io/v1alpha1 command: aws args: - eks - get-token - --cluster-name - <cluster-name> - --region - <region-name> # - --role # - <role-arn> env: - name: AWS_PROFILE value: <profile-name> contexts: - name: eks/cluster-sample context: cluster: eks/cluster-sample user: test-user current-context:
EKS Clusterの設定情報を取得するコマンドです。server
と certificate-authority-data
の値を確認できます。
$ aws eks describe-cluster --name <cluster-name> --region ap-northeast-1 --profile xxx | jq '.cluster | { server: .endpoint, cert_data: .certificateAuthority.data }' { "server": "https://xxxxx.sk1.ap-northeast-1.eks.amazonaws.com", "cert_data": "LS0tLXXXXXXXXXXX" }
kubectl config側の設定は、これで完了です。
接続してみる
では、kubectlを利用して、kubernetetesに接続してみます。
定義したコンフィグ情報から、現在利用されるcontextを確認します。コンフィグファイル内の current-context
で設定したものが、この値となります。以下は空白とした場合。
$ kubectl config current-context error: current-context is not set
設定可能なcontext情報を表示。
$ kubectl config get-clusters NAME eks/cluster-sample
以下のコマンドを利用することで、接続時に利用するcontextを指定できます。
$ kubectl config use-context eks/cluster-sample Switched to context "eks/cluster-sample".
改めて接続を試してみます。
$ kubectl get service NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 172.20.0.1 <none> 443/TCP 60m
一方で、以下の Unauthorized
と表示される場合、Kubernetes側での権限が不足しています。これはKubernetesにおける認可の処理は、あくまでもKubernetes側のRBAC(Role Base Access Contorl)の設定で管理されており、その設定により起こるためとなります。
$ kubectl get service error: You must be logged in to the server (Unauthorized)
EKSのKubernetes Clusterを作成した場合、作成したIAM Userの情報は自動的にRBACに登録されるため、Cluster作成ユーザーは認可が通るものの、それ以外のIAMユーザーはRBACの設定はされないので、Unauthorizedとなってしまう訳です。
kubernetes側の認可設定
KubernetesのRBACについて
Unauthorizedとなってしまうのを解決する前に、KubernetesのRBACの概念について確認します。以下ようなイメージとなっています。
Role
と ClusterRole
は、Kubernetesにおいて権限のポリシーを定義したもの(例えば、podsのget権限やsecretsのlist権限のような)となります。
In the RBAC API, a role contains rules that represent a set of permissions. Permissions are purely additive (there are no “deny” rules). A role can be defined within a namespace with a
Role
, or cluster-wide with aClusterRole
.
2つの違いは、上記の引用の通り、Roleがnamepaceに縛られるのに対して、ClusterRoleはnamespaceに縛られず(その名前の通り)Cluster全体に適用されるものになります。
またClusterRoleは、他のClusterRoleを継承してClusterRoleを定義することのできる aggregationRule
という機能を有します。
As of 1.9, ClusterRoles can be created by combining other ClusterRoles using an
aggregationRule
. The permissions of aggregated ClusterRoles are controller-managed, and filled in by unioning the rules of any ClusterRole that matches the provided label selector.
作成済みClusterRoleの一覧を表示するコマンド。
$ kubectl get clusterrole NAME AGE admin 24m aws-node 24m cluster-admin 24m edit 24m ...
定義されているポリシーを確認するコマンドはこちらです。editというClusterRoleのポリシーを表示。
$ kubectl describe clusterrole edit Name: edit Labels: kubernetes.io/bootstrapping=rbac-defaults rbac.authorization.k8s.io/aggregate-to-admin=true Annotations: rbac.authorization.kubernetes.io/autoupdate: true PolicyRule: Resources Non-Resource URLs Resource Names Verbs --------- ----------------- -------------- ----- configmaps [] [] [create delete deletecollection patch update get list watch] endpoints [] [] [create delete deletecollection patch update get list watch] persistentvolumeclaims [] [] [create delete deletecollection patch update get list watch] pods [] [] [create delete deletecollection patch update get list watch] ...
RoleBinding
と ClusterRoleBinding
は、前述のRoleやClusterRoleと、後述のServiceAccountやUser、Groupを紐付けるものとなります。
A role binding grants the permissions defined in a role to a user or set of users. It holds a list of subjects (users, groups, or service accounts), and a reference to the role being granted. Permissions can be granted within a namespace with a
RoleBinding
, or cluster-wide with aClusterRoleBinding
.
RoleBinding and ClusterRoleBinding
RoleBindingがnamespaceに縛られ、同一namespaceにあるRoleにしか紐付けられないのに対して、ClusterRoleBindingはnamespaceによる制限を受けません。また、Role/CluserRoleとRoleBinding/ClusterRoleBindingは、1対1の関係になります。RoleBinding/ClusterRoleBindingとUserは、1対Nの関係になります。
定義されているClusterRoleBindingの一覧を表示するコマンドはこちらです。
$ kubectl get clusterrolebinding NAME AGE aws-node 71m cluster-admin 71m eks:fargate-manager 71m eks:kube-proxy 71m ...
ClusterRoleBindingの詳細を確認するコマンド。以下は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
ServiceAccournt
は、起動したpodに対して、アイデンティティ情報(認証情報)を付与するものとなります。
When you (a human) access the cluster (for example, using kubectl), you are authenticated by the apiserver as a particular User Account (currently this is usually admin, unless your cluster administrator has customized your cluster). Processes in containers inside pods can also contact the apiserver. When they do, they are authenticated as a particular Service Account (for example, default).
Configure Service Accounts for Pods
AWSにおけるIAM Roleのようなもの、と理解しています。以下の引用は、ServiceAccountとUsersに違いについての説明文です。
Kubernetes distinguishes between the concept of a user account and a service account for a number of reasons:
・User accounts are for humans. Service accounts are for processes, which run in pods.
・User accounts are intended to be global. Names must be unique across all namespaces of a cluster, future user resource will not be namespaced. Service accounts are namespaced.
・Typically, a cluster’s User accounts might be synced from a corporate database, where new user account creation requires special privileges and is tied to complex business processes. Service account creation is intended to be more lightweight, allowing cluster users to create service accounts for specific tasks (i.e. principle of least privilege).
・Auditing considerations for humans and service accounts may differ.
・A config bundle for a complex system may include definition of various service accounts for components of that system. Because service accounts can be created ad-hoc and have namespaced names, such config is portable.
User accounts vs service accounts
定義されているServiceAccountの一覧を表示するコマンドはこちらです。
$ kubectl get serviceaccount --all-namespaces NAMESPACE NAME SECRETS AGE default default 1 76m kube-node-lease default 1 76m kube-public default 1 76m kube-system attachdetach-controller 1 76m kube-system aws-cloud-provider 1 76m ...
ServiceAccountの詳細を確認するコマンドです。aws-cloud-providerというServiceAccountの詳細を表示しています。
$ kubectl get serviceaccount --all-namespaces --output yaml --field-selector metadata.name=aws-cloud-provider apiVersion: v1 items: - apiVersion: v1 kind: ServiceAccount metadata: creationTimestamp: "2020-02-14T07:08:37Z" name: aws-cloud-provider namespace: kube-system resourceVersion: "197" selfLink: /api/v1/namespaces/kube-system/serviceaccounts/aws-cloud-provider uid: d20ff33e-4ef8-11ea-8328-0e79f2b1f57c secrets: - name: aws-cloud-provider-token-h9rdd kind: List metadata: resourceVersion: "" selfLink: ""
kubectl describe serviceaccount <sa名>
というコマンドでは、 --all-namespaces
オプションをつけると怒られてしまうため、 --output yaml
オプションを指定して(これを付けると、設定の詳細まで出力してくれます)、 --field-selector
オプションで表示範囲を絞っています。
また、ServiceAccountは、アイデンティティ情報を付与されたものでありますから、該当の情報が Secretリソース
に格納されています。Secretリソースとは、kube-apiserverへの認証情報やコンテナが接続するDBの認証情報を格納するための仕組みです。AWSにおける、Parameter StoreやSecrets Managerみたいなもの、という理解をしています。
定義されているSecretsリソースの一覧を表示するコマンド。
$ kubectl get secrets --all-namespaces NAMESPACE NAME TYPE DATA AGE default default-token-8fkhr kubernetes.io/service-account-token 3 95m kube-node-lease default-token-klmbj kubernetes.io/service-account-token 3 95m kube-public default-token-ql9xl kubernetes.io/service-account-token 3 95m kube-system attachdetach-controller-token-2gmzl kubernetes.io/service-account-token 3 95m kube-system aws-cloud-provider-token-h9rdd kubernetes.io/service-account-token 3 95m
詳細を確認するコマンド。
$ kubectl get secrets --all-namespaces --output yaml --field-selector metadata.name=aws-cloud-provider-token-h9rdd apiVersion: v1 items: - apiVersion: v1 data: ca.crt: LS0tLS1C.... namespace: a3ViZS1zeXN0ZW0= token: ZXlKaGJHY.... kind: Secret metadata: annotations: kubernetes.io/service-account.name: aws-cloud-provider kubernetes.io/service-account.uid: d20ff33e-4ef8-11ea-8328-0e79f2b1f57c creationTimestamp: "2020-02-14T07:08:37Z" name: aws-cloud-provider-token-h9rdd namespace: kube-system resourceVersion: "193" selfLink: /api/v1/namespaces/kube-system/secrets/aws-cloud-provider-token-h9rdd uid: d21f13b7-4ef8-11ea-8328-0e79f2b1f57c type: kubernetes.io/service-account-token kind: List metadata: resourceVersion: "" selfLink: ""
tokenの情報が格納されていることが分かります。ServiceAccout(を付与されたpod)は、このtokenを利用することでkube-apiserverと認証処理をしている訳ですね。
user
は、その通りKubernetes Clusterに接続する利用者であり、 group
はそのuserをまとめたものです。Kubernetesにおけるユーザーやグループを作成/管理する考え方に関しては、以下のフォーラムの投稿が参考になります。
In kubernetes you don't need to create the user/groups. They are determined by an authenticator and just used by kubernetes, so any user/groups returned by your mappings will be 'created' and kubernetes will use those values.
QUESTION: How to create the k8s users and groups to map to?
OSやRDBでのユーザーの考え方と違い、Kubernetesではユーザーを管理する機能を持っていません。それは、他のID Provider (EKSであればIAM)が担っている部分で、KubernetesのRBACでは、そのIDとKubernetes内のRoleのマッピング定義を管理するのみとなります。またグループとは、RoleBinding/ClusterRoleBindingになります。(ユーザーを束ねるものという機能は一緒であるため)
RBCAのマッピング定義を確認するには(つまり、Kubernetesに定義されているユーザーやグループを確認するには)、以下のコマンドからとなります。
$ kubectl get rolebinding,clusterrolebinding --all-namespaces --output json | jq -r '.items[] | { RoleKind:.roleRef.kind, RoleName:.roleRef.name, ClusterRoleBindingKind:.kind, ClusterRoleBindingName:.metadata.name, SubjectKind:.subjects[]?.kind, SubjectName:.subjects[]?.name } | [ .RoleKind, .RoleName, .ClusterRoleBindingKind, .ClusterRoleBindingName, .SubjectKind, .SubjectName ] | @tsv' | column -t Role system:controller:bootstrap-signer RoleBinding system:controller:bootstrap-signer ServiceAccount bootstrap-signer Role eks:fargate-manager RoleBinding eks:fargate-manager User eks:fargate-manager Role eks:node-manager RoleBinding eks:node-manager User eks:node-manager Role extension-apiserver-authentication-reader RoleBinding system::extension-apiserver-authentication-reader User system:kube-controller-manager Role extension-apiserver-authentication-reader RoleBinding system::extension-apiserver-authentication-reader User system:kube-scheduler Role extension-apiserver-authentication-reader RoleBinding system::extension-apiserver-authentication-reader User system:kube-controller-manager ...
--output
オプションでjsonを指定すると、作成済のClusterBindingとClusterRoleBindingの定義情報をJSONで一気に出力してくれます。出力情報はあまりに膨大で、そのままではとても確認できないので、 jq
コマンドと column
コマンドで整形しています。kubectlには JSONPath
というJSONを整形してくれるオプションがあるのですが、僕には分かりにくく、jqで整形しています。
EKSでのRBAC設定方法
EKSの場合、上記で説明したRBCAの仕組みの中に、AWSのIAMユーザー、またはIAMロールの情報を加えてあげれば良い訳ですが、そのための方法が aws-auth
というConfigMapを利用する方法となります。
ConfigMapとは、Kubernetesで用意されているKVSぽい機能で、AWSにおけるParameter Storeみたいなものです。ConfigMapと上で出てきたSecretとの違いは、機密情報を保管するかどうかという話みたいで、これにはkubernetes内コンポーネントの etcd
という存在に関係があるみたいです。(etcdについては、勉強不足でまだ理解できてないです)
いずれにしろ、 aws-auth
というConfigMapに利用したいIAM情報を登録することで、Kubernetesへの認可設定ができるとのことです。
最初は、Amazon EKS クラスターの作成者のみがクラスターを設定するための system:masters 権限を持っています。system:masters 権限を他のユーザーとロールに拡張するには、aws-auth ConfigMap を Amazon EKS クラスターの設定に追加する必要があります。ConfigMap により、ユーザーやロールなどの他の IAM エンティティに Amazon EKS クラスターへのアクセス権限が付与されます。
Amazon EKS でクラスターを作成した後、他のユーザーやロールにアクセス権限を付与する方法について教えてください。
AWS上の公式ドキュメントを頼りに設定してみます。
現在のaws-auth登録内容を確認します。
$ kubectl describe configmap -n kube-system aws-auth Name: aws-auth Namespace: kube-system Labels: <none> Annotations: <none> Data ==== mapRoles: ---- - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam::123456789012:role/String username: system:node:{{EC2PrivateDNSName}}
ここでaws-authが見つからないようなエラーメッセージが返る場合、公式ドキュメントにあるaws-auth適用手順を参照してください。通常にEKS Cluster作成時に、一緒にデプロイされるとのこと。
現行設定情報をyamlファイルとして抽出します。以下コマンドを実行して現行設定情報を表示し、そいつをファイルに貼り付けます。 kubectl apply
するには不要な項目があるので、それら項目を削除します。(恐らくもっと良い方法がある気がするのですが...)
$ kubectl edit -n kube-system configmap/aws-auth
初期のEKS Cluster状態であれば、下記のような定義になるはずです。
aws-auth.yml
apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam::123456789012:role/String username: system:node:{{EC2PrivateDNSName}}
公式ドキュメントにある通り、 data:
セクションにIAMユーザー情報を追加します。今回は、デフォルトで用意されているClusterRole view
という権限を、追加IAMユーザーに付与したいと思います。
まず、ClusterRole view
に紐づくClusterRoleBindingが存在しないため、ClusterRoleBindingを作成します。デフォルトで用意されているRoleとRoleBindingは、Kubernetes公式ページで確認できます。
Default Roles and Role Bindings
custom:view
というClusterRoleBindingを作成するマニフェストファイルを用意します。紐付けるSubjectとして custom:viewers
というグループを定義しています。
clusterrolebinding-view.yml
apiVersion: rbac.authorization.k8s.io/v1beta1 kind: ClusterRoleBinding metadata: name: custom:view roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io subjects: - kind: Group name: custom:viewers apiGroup: rbac.authorization.k8s.io
適用します。
$ kubectl apply -f ./clusterrolebinding-view.yml
clusterrolebinding.rbac.authorization.k8s.io/custom:view created
aws-auth.ymlファイルに、追加したいIAMユーザー情報を追加します。IAMユーザー no-policy-user
を、グループ custom:viewers
に紐づけています。
aws-auth.yml
apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam::123456789012:role/String username: system:node:{{EC2PrivateDNSName}} mapUsers: | - userarn: arn:aws:iam::123456789012:user/no-policy-user username: no-policy-user groups: - custom:viewers
適用します。
$ kubectl apply -f /mnt/c/tmp/aws-auth.yml Warning: kubectl apply should be used on resource created by either kubectl create --save-config or kubectl apply configmap/aws-auth configured
確認
実際に確認してみます。
kubectlのconfigファイルにて、IAMユーザー no-policy-user
を利用するように変更してみます。
$ kubectl config view apiVersion: v1 clusters: (略) command: aws env: - name: AWS_PROFILE value: no-policy-user
podの取得をしてみます。
$ kubectl get pods --all-namespaces NAMESPACE NAME READY STATUS RESTARTS AGE kube-system aws-node-ww2np 1/1 Running 0 69m kube-system coredns-58986cd576-dkljh 1/1 Running 0 70m kube-system coredns-58986cd576-mkrwj 1/1 Running 0 70m kube-system kube-proxy-828qm 1/1 Running 0 69m
取得できます。
podを作成してみます。
$ kubectl run nginx --image=nginx Error from server (Forbidden): deployments.apps is forbidden: User "no-policy-user" cannot create resource "deployments" in API group "apps" in the namespace "default"
view
の権限しかないため、 Forbidden
と怒られます。