Pod内のGoアプリから、ServiceAccountに割り当てた権限でk8sリソースにアクセスする
最初に
k8sのリソースに対してプログラムなどから操作したくなることがあります。
操作自体はGo言語であればclient-goで、ローカルから操作するときは、~/.kube/config
を読み込ませて操作できます。
ただ実際に動かすなら、同じk8sクラスター内にPodでこのプログラムを動かしたくなります。
この時に、このPodにkube/configを渡すのは、セキュリティ的に避けたいですね。
AWSのIAM Roleのような安全に必要最低限の権限だけを与えて、割り当てられたEC2インスタンスだけが利用できるようにしたいです。k8sでは、これをServiceAccount, Role, Role-bindingsというリソースで実現できます。
この記事では、
- client-goでPodに割り当てられたService Accountの権限を取得する
- Service Accountに必要最低限の権限を付与する例
について記載します
client-goでPodに割り当てられたService Accountの権限を取得する
kubeconfigの取得方法を次のように2つから取るようにします
func getK8sConfig() (*rest.Config, error) {
// ①InClusterConfigの取得処理
config, err := rest.InClusterConfig()
// k8s Cluster内でないなら、エラーが返ってくる
// その場合は次のローカルのkubeconfig取得処理へ
if err == nil {
return config, nil
}
// ②ローカルのkubeconfigからconfigを作成する
var kubeconfig *string
if home := homedir.HomeDir(); home != "" {
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
} else {
kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
}
flag.Parse()
return clientcmd.BuildConfigFromFlags("", *kubeconfig)
}
上記のようなconfig取得のutil関数を用意する
rest.InClusterConfig()
は下記のようなコードになっており、よしなにService Accountを読み込んでくれる
これで取得できない場合は、ホームディレクトリのkubeconfigを読みに行っている
そして、このutil関数をもとにclientset
を作成すると、Service Account(or kubeconfig)に割り当てた権限で操作できるclientが作成できる
config, err := getK8sConfig()
if err != nil {
panic(err)
}
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err)
}
Service Accountに必要最低限の権限を付与する例
前述の通りで
k8sでは、Role
に対して権限を割り当て、Role
をRoleBindings
でServiceAccount
に割り当て、PodにServiceAccount
を指定することで、Podの特定の位置に認証情報がマウントされるので、それを読み込むことで、Role
で指定した権限が利用可能となる -> Role Based Access Control(RBAC)というやつ
実際に適当な例を作ってみます
sample-saというservice accountを作ります
apiVersion: v1
kind: ServiceAccount
metadata:
name: sample-sa
namespace: default
sample-roleというroleを作ります。deploymentリソースの情報の取得(get)とreplica数更新(/scale, update)権限を付与しています。
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: sample-role
rules:
- apiGroups: ["extensions", "apps"]
resources: ["deployments", "deployments/scale"]
verbs: ["get", "update"]
RoleBindingsでsample-roleをsample-saに紐づけます
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: sample-rb
namespace: default
subjects:
- kind: ServiceAccount
name: sample-sa
namespace: default
roleRef:
kind: Role
name: sample-role
apiGroup: rbac.authorization.k8s.io
最後にDeploymentリソースを作成します。sepc.template.spec.serviceAccountName
でsample-saを指定します
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample
namespace: default
spec:
replicas: 1
template:
spec:
serviceAccountName: sample-sa
containers: {}
これで作られるk8s podで上記のようなservice accountの権限読み込むコードを動かすと、deploymentリソースに対して操作が可能となります。
Discussion